github.com/diadata-org/diadata@v1.4.593/pkg/model/exchanges.go (about)

     1  package models
     2  
     3  import (
     4  	// "encoding/json"
     5  	"context"
     6  	"database/sql"
     7  	"encoding/json"
     8  	"fmt"
     9  	"sort"
    10  	"time"
    11  
    12  	"github.com/diadata-org/diadata/pkg/dia"
    13  )
    14  
    15  // GetActiveExchangesAndPairs returns all exchanges the asset with @address and @blockchain was
    16  // traded on in the given time-range as keys of a map. The map's values are the underlying pairs.
    17  // Additionally, a map is returned where keys are exchange/pair identifier and values are the number
    18  // of trades in the respective time-range.
    19  // The pair has to have at least @numTrades trades in the given time-range in order to get returned.
    20  func (datastore *DB) GetActiveExchangesAndPairs(
    21  	address string,
    22  	blockchain string,
    23  	numTradesThreshold int64,
    24  	starttime time.Time,
    25  	endtime time.Time,
    26  ) (map[string][]dia.Pair, map[string]int64, error) {
    27  	exchangepairmap := make(map[string][]dia.Pair)
    28  	pairCountTradesMap := make(map[string]int64)
    29  
    30  	query := `
    31  	SELECT count(*)
    32  	FROM %s 
    33  	WHERE time>%d AND time<=%d 
    34  	AND quotetokenaddress='%s' AND quotetokenblockchain='%s'
    35  	AND verified='true'
    36  	GROUP BY "exchange","pair","basetokenaddress","basetokenblockchain"
    37  	`
    38  
    39  	q := fmt.Sprintf(query, influxDbTradesTable, starttime.UnixNano(), endtime.UnixNano(), address, blockchain)
    40  	res, err := queryInfluxDB(datastore.influxClient, q)
    41  	if err != nil {
    42  		return exchangepairmap, pairCountTradesMap, err
    43  	}
    44  
    45  	if len(res) > 0 && len(res[0].Series) > 0 {
    46  		for _, row := range res[0].Series {
    47  
    48  			if len(row.Values[0]) > 1 {
    49  				numTrades, err := row.Values[0][1].(json.Number).Int64()
    50  				if err != nil {
    51  					log.Warn("parse number of trades: ", err)
    52  				}
    53  
    54  				exchange := row.Tags["exchange"]
    55  				// Only include pair if it has more than @numTradesThreshold trades.
    56  				if numTrades >= numTradesThreshold {
    57  					pair := dia.Pair{
    58  						QuoteToken: dia.Asset{Blockchain: blockchain, Address: address},
    59  						BaseToken:  dia.Asset{Blockchain: row.Tags["basetokenblockchain"], Address: row.Tags["basetokenaddress"]},
    60  					}
    61  					exchangepairmap[exchange] = append(exchangepairmap[exchange], pair)
    62  					pairCountTradesMap[pair.PairExchangeIdentifier(exchange)] = numTrades
    63  				}
    64  			}
    65  		}
    66  	}
    67  
    68  	return exchangepairmap, pairCountTradesMap, nil
    69  
    70  }
    71  
    72  func (rdb *RelDB) GetExchangesForSymbol(symbol string) (exchanges []string, err error) {
    73  
    74  	query := fmt.Sprintf("select distinct(exchange) from %s where symbol=$1", exchangesymbolTable)
    75  	rows, err := rdb.postgresClient.Query(context.Background(), query, symbol)
    76  	if err != nil {
    77  		return
    78  	}
    79  	for rows.Next() {
    80  		exchange := ""
    81  		err = rows.Scan(&exchange)
    82  		if err != nil {
    83  			return []string{}, err
    84  		}
    85  		exchanges = append(exchanges, exchange)
    86  	}
    87  	return
    88  }
    89  
    90  // SetAvailablePairs stores @pairs in redis
    91  // TO DO: Setter and getter should act on RelDB
    92  func (datastore *DB) SetAvailablePairs(exchange string, pairs []dia.ExchangePair) error {
    93  	key := "dia_available_pairs_" + exchange
    94  	var p dia.Pairs = pairs
    95  	return datastore.redisClient.Set(key, &p, 0).Err()
    96  }
    97  
    98  // GetAvailablePairs a slice of all pairs available in the exchange in the internal redis db
    99  func (datastore *DB) GetAvailablePairs(exchange string) ([]dia.ExchangePair, error) {
   100  	key := "dia_available_pairs_" + exchange
   101  	p := dia.Pairs{}
   102  	err := datastore.redisClient.Get(key).Scan(&p)
   103  	if err != nil {
   104  		log.Errorf("Error: %v on GetAvailablePairs %v\n", err, exchange)
   105  		return nil, err
   106  	}
   107  	return p, nil
   108  }
   109  
   110  func (rdb *RelDB) SetExchange(exchange dia.Exchange) (err error) {
   111  	fields := fmt.Sprintf("INSERT INTO %s (name,centralized,bridge,contract,blockchain,rest_api,ws_api,pairs_api,watchdog_delay,scraper_active) VALUES ", exchangeTable)
   112  	values := "($1,$2,$3,NULLIF($4,''),$5,NULLIF($6,''),NULLIF($7,''),NULLIF($8,''),$9,$10)"
   113  	conflict := " ON CONFLICT (name) DO UPDATE SET contract=NULLIF($4,''),rest_api=$6,ws_api=$7,pairs_api=$8,watchdog_delay=$9,scraper_active=$10"
   114  
   115  	query := fields + values + conflict
   116  	_, err = rdb.postgresClient.Exec(context.Background(), query,
   117  		exchange.Name,
   118  		exchange.Centralized,
   119  		exchange.Bridge,
   120  		exchange.Contract,
   121  		exchange.BlockChain.Name,
   122  		exchange.RestAPI,
   123  		exchange.WsAPI,
   124  		exchange.PairsAPI,
   125  		exchange.WatchdogDelay,
   126  		exchange.ScraperActive,
   127  	)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return nil
   132  }
   133  
   134  func (rdb *RelDB) GetExchange(name string) (exchange dia.Exchange, err error) {
   135  	query := fmt.Sprintf(`
   136  	SELECT centralized,bridge,contract,blockchain,rest_api,ws_api,pairs_api,watchdog_delay,scraper_active 
   137  	FROM %s 
   138  	WHERE name=$1`,
   139  		exchangeTable,
   140  	)
   141  	var (
   142  		contract       sql.NullString
   143  		blockchainName sql.NullString
   144  		restAPI        sql.NullString
   145  		wsAPI          sql.NullString
   146  		pairsAPI       sql.NullString
   147  	)
   148  	err = rdb.postgresClient.QueryRow(context.Background(), query, name).Scan(
   149  		&exchange.Centralized,
   150  		&exchange.Bridge,
   151  		&contract,
   152  		&blockchainName,
   153  		&restAPI,
   154  		&wsAPI,
   155  		&pairsAPI,
   156  		&exchange.WatchdogDelay,
   157  		&exchange.ScraperActive,
   158  	)
   159  	if err != nil {
   160  		return
   161  	}
   162  	if contract.Valid {
   163  		exchange.Contract = contract.String
   164  	}
   165  	if blockchainName.Valid {
   166  		exchange.BlockChain.Name = blockchainName.String
   167  	}
   168  	if restAPI.Valid {
   169  		exchange.RestAPI = restAPI.String
   170  	}
   171  	if wsAPI.Valid {
   172  		exchange.WsAPI = wsAPI.String
   173  	}
   174  	if pairsAPI.Valid {
   175  		exchange.PairsAPI = pairsAPI.String
   176  	}
   177  	exchange.Name = name
   178  	return
   179  }
   180  
   181  // GetAllExchanges returns all exchanges existent in the exchange table.
   182  func (rdb *RelDB) GetAllExchanges() (exchanges []dia.Exchange, err error) {
   183  	query := fmt.Sprintf(`
   184  	SELECT name,centralized,bridge,contract,blockchain,rest_api,ws_api,pairs_api,watchdog_delay,scraper_active 
   185  	FROM %s`,
   186  		exchangeTable,
   187  	)
   188  	rows, err := rdb.postgresClient.Query(context.Background(), query)
   189  	if err != nil {
   190  		return []dia.Exchange{}, err
   191  	}
   192  	defer rows.Close()
   193  
   194  	for rows.Next() {
   195  		var exchange dia.Exchange
   196  		var contract sql.NullString
   197  		var blockchainName sql.NullString
   198  		var restAPI sql.NullString
   199  		var wsAPI sql.NullString
   200  		var pairsAPI sql.NullString
   201  		err := rows.Scan(
   202  			&exchange.Name,
   203  			&exchange.Centralized,
   204  			&exchange.Bridge,
   205  			&contract,
   206  			&blockchainName,
   207  			&restAPI,
   208  			&wsAPI,
   209  			&pairsAPI,
   210  			&exchange.WatchdogDelay,
   211  			&exchange.ScraperActive,
   212  		)
   213  		if err != nil {
   214  			return []dia.Exchange{}, err
   215  		}
   216  		if contract.Valid {
   217  			exchange.Contract = contract.String
   218  		}
   219  		if blockchainName.Valid {
   220  			exchange.BlockChain.Name = blockchainName.String
   221  		}
   222  		if restAPI.Valid {
   223  			exchange.RestAPI = restAPI.String
   224  		}
   225  		if wsAPI.Valid {
   226  			exchange.WsAPI = wsAPI.String
   227  		}
   228  		if pairsAPI.Valid {
   229  			exchange.PairsAPI = pairsAPI.String
   230  		}
   231  		exchanges = append(exchanges, exchange)
   232  	}
   233  
   234  	return exchanges, nil
   235  }
   236  
   237  // GetExchangeNames returns the names of all available exchanges.
   238  func (rdb *RelDB) GetExchangeNames() (allExchanges []string, err error) {
   239  	exchanges, err := rdb.GetAllExchanges()
   240  	if err != nil {
   241  		return
   242  	}
   243  	for _, exchange := range exchanges {
   244  		allExchanges = append(allExchanges, exchange.Name)
   245  	}
   246  	sort.Strings(allExchanges)
   247  	return
   248  }
   249  
   250  func GetExchangeType(exchange dia.Exchange) string {
   251  	if exchange.Centralized {
   252  		return "CEX"
   253  	} else if exchange.Bridge {
   254  		return "Bridge"
   255  	} else {
   256  		return "DEX"
   257  	}
   258  }