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

     1  package models
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"strconv"
     8  	"time"
     9  
    10  	clientInfluxdb "github.com/influxdata/influxdb1-client/v2"
    11  )
    12  
    13  const influxDbForeignQuotationTable = "foreignquotation"
    14  
    15  // SaveForeignQuotationInflux stores a quotation which is not from DIA to an influx batch
    16  func (datastore *DB) SaveForeignQuotationInflux(fq ForeignQuotation) error {
    17  	fields := map[string]interface{}{
    18  		"price":              fq.Price,
    19  		"priceYesterday":     fq.PriceYesterday,
    20  		"source":             fq.Source,
    21  		"volumeYesterdayUSD": fq.VolumeYesterdayUSD,
    22  	}
    23  	tags := map[string]string{
    24  		"symbol": fq.Symbol,
    25  		"name":   fq.Name,
    26  	}
    27  	pt, err := clientInfluxdb.NewPoint(influxDbForeignQuotationTable, tags, fields, fq.Time)
    28  	if err != nil {
    29  		log.Errorln("NewOptionInflux:", err)
    30  	} else {
    31  		datastore.addPoint(pt)
    32  	}
    33  	err = datastore.WriteBatchInflux()
    34  	if err != nil {
    35  		log.Errorln("Write influx batch: ", err)
    36  	}
    37  
    38  	return err
    39  }
    40  
    41  // GetForeignQuotationInflux returns the last quotation of @symbol before @timestamp
    42  func (datastore *DB) GetForeignQuotationInflux(symbol, source string, timestamp time.Time) (ForeignQuotation, error) {
    43  	retval := ForeignQuotation{}
    44  
    45  	unixtime := timestamp.UnixNano()
    46  	q := fmt.Sprintf(
    47  		"SELECT price,priceYesterday,volumeYesterdayUSD,\"name\" FROM %s WHERE source='%s' and \"symbol\"='%s' and time<%d order by time desc limit 1",
    48  		influxDbForeignQuotationTable,
    49  		source,
    50  		symbol,
    51  		unixtime,
    52  	)
    53  	res, err := queryInfluxDB(datastore.influxClient, q)
    54  	if err != nil {
    55  		fmt.Println("Error querying influx")
    56  		return retval, err
    57  	}
    58  
    59  	if len(res) > 0 && len(res[0].Series) > 0 {
    60  		layout := "2006-01-02T15:04:05Z"
    61  		vals := res[0].Series[0].Values[0]
    62  
    63  		retval.Time, err = time.Parse(layout, vals[0].(string))
    64  		if err != nil {
    65  			log.Error(err)
    66  		}
    67  		retval.Price, err = vals[1].(json.Number).Float64()
    68  		if err != nil {
    69  			log.Error(err)
    70  		}
    71  		retval.PriceYesterday, err = vals[2].(json.Number).Float64()
    72  		if err != nil {
    73  			log.Error(err)
    74  		}
    75  		retval.VolumeYesterdayUSD, err = vals[3].(json.Number).Float64()
    76  		if err != nil {
    77  			log.Error(err)
    78  		}
    79  
    80  		if vals[4] != nil {
    81  			retval.Name = vals[4].(string)
    82  		}
    83  		retval.Source = source
    84  		retval.Symbol = symbol
    85  
    86  		return retval, nil
    87  
    88  	}
    89  	return retval, err
    90  }
    91  
    92  // GetForeignPriceYesterday returns the average price of @symbol on @source from yesterday
    93  func (datastore *DB) GetForeignPriceYesterday(symbol, source string) (float64, error) {
    94  
    95  	// Get time range for yesterday in order to average the price
    96  	now := time.Now()
    97  	secondsFromYesterday := now.Hour()*60*60 + now.Minute()*60 + now.Second()
    98  	timeFinal := int(now.Unix()) - secondsFromYesterday - 1
    99  	timeInit := timeFinal - 24*60*60
   100  	unixtimeFinal := strconv.Itoa(timeFinal) + "000000000"
   101  	unixtimeInit := strconv.Itoa(timeInit) + "000000000"
   102  
   103  	// Make corresponding influx query
   104  	q := fmt.Sprintf("SELECT price FROM %s WHERE source='%s' and symbol='%s' and time>%s and time<%s", influxDbForeignQuotationTable, source, symbol, unixtimeInit, unixtimeFinal)
   105  	res, err := queryInfluxDB(datastore.influxClient, q)
   106  	if err != nil {
   107  		fmt.Println("Error querying influx")
   108  		return 0, err
   109  	}
   110  
   111  	// Simple average over all yesterday's prices
   112  	var price float64
   113  	errs := 0
   114  	if len(res) > 0 && len(res[0].Series) > 0 && len(res[0].Series[0].Values) > 0 {
   115  		numPrices := len(res[0].Series[0].Values)
   116  		for i := range res[0].Series[0].Values {
   117  			pricepoint, err := res[0].Series[0].Values[i][1].(json.Number).Float64()
   118  			if err != nil {
   119  				log.Error(err)
   120  				errs++
   121  			} else {
   122  				price += pricepoint
   123  			}
   124  
   125  		}
   126  		if numPrices > errs {
   127  			return price / float64(numPrices-errs), nil
   128  		}
   129  	}
   130  	return 0, errors.New("no data available from yesterday")
   131  }
   132  
   133  // GetForeignSymbolsInflux returns a list with all symbols available for quotation from @source.
   134  func (datastore *DB) GetForeignSymbolsInflux(source string) (symbols []string, err error) {
   135  
   136  	q := fmt.Sprintf("SELECT symbol,source FROM %s WHERE time>now()-7d and source='%s'", influxDbForeignQuotationTable, source)
   137  	res, err := queryInfluxDB(datastore.influxClient, q)
   138  	if err != nil {
   139  		fmt.Println("Error querying influx")
   140  		return
   141  	}
   142  
   143  	if len(res) > 0 && len(res[0].Series) > 0 {
   144  		// make unique list of symbols
   145  		vals := res[0].Series[0].Values
   146  		set := make(map[string]struct{})
   147  		symsUnique := []string{}
   148  		for _, val := range vals {
   149  			if _, ok := set[val[1].(string)]; !ok {
   150  				symsUnique = append(symsUnique, val[1].(string))
   151  				set[val[1].(string)] = struct{}{}
   152  			}
   153  		}
   154  
   155  		// fill return slice
   156  		for _, sym := range symsUnique {
   157  			symbols = append(symbols, sym)
   158  		}
   159  	}
   160  	return
   161  }