Get hourly and five minutes fiat rates

This commit is contained in:
Martin Boehm 2023-04-24 23:26:17 +02:00
parent d856618607
commit a4f7f5b965
5 changed files with 273 additions and 85 deletions

View File

@ -84,20 +84,6 @@ func unpackCurrencyRatesTicker(buf []byte) (*common.CurrencyRatesTicker, error)
return &ticker, nil return &ticker, nil
} }
// FiatRatesConvertDate checks if the date is in correct format and returns the Time object.
// Possible formats are: YYYYMMDDhhmmss, YYYYMMDDhhmm, YYYYMMDDhh, YYYYMMDD
func FiatRatesConvertDate(date string) (*time.Time, error) {
for format := FiatRatesTimeFormat; len(format) >= 8; format = format[:len(format)-2] {
convertedDate, err := time.Parse(format, date)
if err == nil {
return &convertedDate, nil
}
}
msg := "Date \"" + date + "\" does not match any of available formats. "
msg += "Possible formats are: YYYYMMDDhhmmss, YYYYMMDDhhmm, YYYYMMDDhh, YYYYMMDD"
return nil, errors.New(msg)
}
// FiatRatesStoreTicker stores ticker data at the specified time // FiatRatesStoreTicker stores ticker data at the specified time
func (d *RocksDB) FiatRatesStoreTicker(wb *grocksdb.WriteBatch, ticker *common.CurrencyRatesTicker) error { func (d *RocksDB) FiatRatesStoreTicker(wb *grocksdb.WriteBatch, ticker *common.CurrencyRatesTicker) error {
if len(ticker.Rates) == 0 { if len(ticker.Rates) == 0 {
@ -145,22 +131,6 @@ func (d *RocksDB) FiatRatesGetTicker(tickerTime *time.Time) (*common.CurrencyRat
// FiatRatesFindTicker gets FiatRates data closest to the specified timestamp, of the base currency, vsCurrency or the token if specified // FiatRatesFindTicker gets FiatRates data closest to the specified timestamp, of the base currency, vsCurrency or the token if specified
func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string, token string) (*common.CurrencyRatesTicker, error) { func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string, token string) (*common.CurrencyRatesTicker, error) {
// currentTicker := d.is.GetCurrentTicker("", "")
// lastTickerInDBMux.Lock()
// dbTicker := lastTickerInDB
// lastTickerInDBMux.Unlock()
// if currentTicker != nil {
// if !tickerTime.Before(currentTicker.Timestamp) || (dbTicker != nil && tickerTime.After(dbTicker.Timestamp)) {
// f := true
// if token != "" && currentTicker.TokenRates != nil {
// _, f = currentTicker.TokenRates[token]
// }
// if f {
// return currentTicker, nil
// }
// }
// }
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat) tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates]) it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
defer it.Close() defer it.Close()
@ -178,6 +148,26 @@ func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string,
return nil, nil return nil, nil
} }
// FiatRatesGetAllTickers gets FiatRates data closest to the specified timestamp, of the base currency, vsCurrency or the token if specified
func (d *RocksDB) FiatRatesGetAllTickers(fn func(ticker *common.CurrencyRatesTicker) error) error {
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
defer it.Close()
for it.SeekToFirst(); it.Valid(); it.Next() {
ticker, err := getTickerFromIterator(it, "", "")
if err != nil {
return err
}
if ticker == nil {
return errors.New("FiatRatesGetAllTickers got nil ticker")
}
if err = fn(ticker); err != nil {
return err
}
}
return nil
}
// FiatRatesFindLastTicker gets the last FiatRates record, of the base currency, vsCurrency or the token if specified // FiatRatesFindLastTicker gets the last FiatRates record, of the base currency, vsCurrency or the token if specified
func (d *RocksDB) FiatRatesFindLastTicker(vsCurrency string, token string) (*common.CurrencyRatesTicker, error) { func (d *RocksDB) FiatRatesFindLastTicker(vsCurrency string, token string) (*common.CurrencyRatesTicker, error) {
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates]) it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])

View File

@ -17,22 +17,6 @@ func TestRocksTickers(t *testing.T) {
}) })
defer closeAndDestroyRocksDB(t, d) defer closeAndDestroyRocksDB(t, d)
// Test valid formats
for _, date := range []string{"20190130", "2019013012", "201901301250", "20190130125030"} {
_, err := FiatRatesConvertDate(date)
if err != nil {
t.Errorf("%v", err)
}
}
// Test invalid formats
for _, date := range []string{"01102019", "10201901", "", "abc", "20190130xxx"} {
_, err := FiatRatesConvertDate(date)
if err == nil {
t.Errorf("Wrongly-formatted date \"%v\" marked as valid!", date)
}
}
// Test storing & finding tickers // Test storing & finding tickers
pastKey, _ := time.Parse(FiatRatesTimeFormat, "20190627000000") pastKey, _ := time.Parse(FiatRatesTimeFormat, "20190627000000")
futureKey, _ := time.Parse(FiatRatesTimeFormat, "20190630000000") futureKey, _ := time.Parse(FiatRatesTimeFormat, "20190630000000")

View File

@ -3,7 +3,7 @@ package fiat
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -86,7 +86,7 @@ func doReq(req *http.Request, client *http.Client) ([]byte, error) {
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -299,14 +299,43 @@ func (cg *Coingecko) CurrentTickers() (*common.CurrencyRatesTicker, error) {
return &newTickers, nil return &newTickers, nil
} }
func (cg *Coingecko) getHighGranularityTickers(days string) (*[]common.CurrencyRatesTicker, error) {
mc, err := cg.coinMarketChart(cg.coin, highGranularityVsCurrency, days, false)
if err != nil {
return nil, err
}
if len(mc.Prices) < 2 {
return nil, nil
}
// ignore the last point, it is not in granularity
tickers := make([]common.CurrencyRatesTicker, len(mc.Prices)-1)
for i, p := range mc.Prices[:len(mc.Prices)-1] {
var timestamp uint
timestamp = uint(p[0])
if timestamp > 100000000000 {
// convert timestamp from milliseconds to seconds
timestamp /= 1000
}
rate := float32(p[1])
u := time.Unix(int64(timestamp), 0).UTC()
ticker := common.CurrencyRatesTicker{
Timestamp: u,
Rates: make(map[string]float32),
}
ticker.Rates[highGranularityVsCurrency] = rate
tickers[i] = ticker
}
return &tickers, nil
}
// HourlyTickers returns the array of the exchange rates in hourly granularity // HourlyTickers returns the array of the exchange rates in hourly granularity
func (cg *Coingecko) HourlyTickers() (*[]common.CurrencyRatesTicker, error) { func (cg *Coingecko) HourlyTickers() (*[]common.CurrencyRatesTicker, error) {
return nil, nil return cg.getHighGranularityTickers("90")
} }
// HourlyTickers returns the array of the exchange rates in five minutes granularity // HourlyTickers returns the array of the exchange rates in five minutes granularity
func (cg *Coingecko) FiveMinutesTickers() (*[]common.CurrencyRatesTicker, error) { func (cg *Coingecko) FiveMinutesTickers() (*[]common.CurrencyRatesTicker, error) {
return nil, nil return cg.getHighGranularityTickers("1")
} }
func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*common.CurrencyRatesTicker, coinId string, vsCurrency string, token string) (bool, error) { func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*common.CurrencyRatesTicker, coinId string, vsCurrency string, token string) (bool, error) {

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"math/rand" "math/rand"
"os"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -15,14 +15,20 @@ import (
"github.com/trezor/blockbook/db" "github.com/trezor/blockbook/db"
) )
const CurrentTickersKey = "CurrentTickers" const currentTickersKey = "CurrentTickers"
const HourlyTickersKey = "HourlyTickers" const hourlyTickersKey = "HourlyTickers"
const FiveMinutesTickersKey = "FiveMinutesTickers" const fiveMinutesTickersKey = "FiveMinutesTickers"
const highGranularityVsCurrency = "usd"
const secondsInDay = 24 * 60 * 60
const secondsInHour = 60 * 60
const secondsInFiveMinutes = 5 * 60
// OnNewFiatRatesTicker is used to send notification about a new FiatRates ticker // OnNewFiatRatesTicker is used to send notification about a new FiatRates ticker
type OnNewFiatRatesTicker func(ticker *common.CurrencyRatesTicker) type OnNewFiatRatesTicker func(ticker *common.CurrencyRatesTicker)
// RatesDownloaderInterface provides method signatures for specific fiat rates downloaders // RatesDownloaderInterface provides method signatures for a specific fiat rates downloader
type RatesDownloaderInterface interface { type RatesDownloaderInterface interface {
CurrentTickers() (*common.CurrencyRatesTicker, error) CurrentTickers() (*common.CurrencyRatesTicker, error)
HourlyTickers() (*[]common.CurrencyRatesTicker, error) HourlyTickers() (*[]common.CurrencyRatesTicker, error)
@ -55,17 +61,6 @@ type FiatRates struct {
dailyTickersTo int64 dailyTickersTo int64
} }
func tickersToMap(tickers *[]common.CurrencyRatesTicker, granularitySeconds int64) (map[int64]*common.CurrencyRatesTicker, int64, int64) {
if tickers == nil || len(*tickers) == 0 {
return nil, 0, 0
}
halfGranularity := granularitySeconds / 2
m := make(map[int64]*common.CurrencyRatesTicker, len(*tickers))
from := ((*tickers)[0].Timestamp.UTC().Unix() + halfGranularity) % granularitySeconds
to := ((*tickers)[len(*tickers)-1].Timestamp.UTC().Unix() + halfGranularity) % granularitySeconds
return m, from, to
}
// NewFiatRates initializes the FiatRates handler // NewFiatRates initializes the FiatRates handler
func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTicker) (*FiatRates, error) { func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTicker) (*FiatRates, error) {
var config struct { var config struct {
@ -73,7 +68,7 @@ func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTick
FiatRatesParams string `json:"fiat_rates_params"` FiatRatesParams string `json:"fiat_rates_params"`
FiatRatesVsCurrencies string `json:"fiat_rates_vs_currencies"` FiatRatesVsCurrencies string `json:"fiat_rates_vs_currencies"`
} }
data, err := ioutil.ReadFile(configFile) data, err := os.ReadFile(configFile)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading file %v, %v", configFile, err) return nil, fmt.Errorf("error reading file %v, %v", configFile, err)
} }
@ -133,7 +128,11 @@ func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTick
is.HasTokenFiatRates = fr.downloadTokens is.HasTokenFiatRates = fr.downloadTokens
fr.Enabled = true fr.Enabled = true
currentTickers, err := db.FiatRatesGetSpecialTickers(CurrentTickersKey) if err := fr.loadDailyTickers(); err != nil {
return nil, err
}
currentTickers, err := db.FiatRatesGetSpecialTickers(currentTickersKey)
if err != nil { if err != nil {
glog.Error("FiatRatesDownloader: get CurrentTickers from DB error ", err) glog.Error("FiatRatesDownloader: get CurrentTickers from DB error ", err)
} }
@ -141,22 +140,23 @@ func NewFiatRates(db *db.RocksDB, configFile string, callback OnNewFiatRatesTick
fr.currentTicker = &(*currentTickers)[0] fr.currentTicker = &(*currentTickers)[0]
} }
hourlyTickers, err := db.FiatRatesGetSpecialTickers(HourlyTickersKey) hourlyTickers, err := db.FiatRatesGetSpecialTickers(hourlyTickersKey)
if err != nil { if err != nil {
glog.Error("FiatRatesDownloader: get HourlyTickers from DB error ", err) glog.Error("FiatRatesDownloader: get HourlyTickers from DB error ", err)
} }
fr.hourlyTickers, fr.hourlyTickersFrom, fr.hourlyTickersTo = tickersToMap(hourlyTickers, 3600) fr.hourlyTickers, fr.hourlyTickersFrom, fr.hourlyTickersTo = fr.tickersToMap(hourlyTickers, secondsInHour)
fiveMinutesTickers, err := db.FiatRatesGetSpecialTickers(FiveMinutesTickersKey) fiveMinutesTickers, err := db.FiatRatesGetSpecialTickers(fiveMinutesTickersKey)
if err != nil { if err != nil {
glog.Error("FiatRatesDownloader: get FiveMinutesTickers from DB error ", err) glog.Error("FiatRatesDownloader: get FiveMinutesTickers from DB error ", err)
} }
fr.fiveMinutesTickers, fr.fiveMinutesTickersFrom, fr.fiveMinutesTickersTo = tickersToMap(fiveMinutesTickers, 5*60) fr.fiveMinutesTickers, fr.fiveMinutesTickersFrom, fr.fiveMinutesTickersTo = fr.tickersToMap(fiveMinutesTickers, secondsInFiveMinutes)
} }
} else { } else {
return nil, fmt.Errorf("unknown provider %q", fr.provider) return nil, fmt.Errorf("unknown provider %q", fr.provider)
} }
fr.logTickersInfo()
return fr, nil return fr, nil
} }
@ -171,28 +171,208 @@ func (fr *FiatRates) GetCurrentTicker(vsCurrency string, token string) *common.C
return nil return nil
} }
// getTokenTickersForTimestamps returns tickers for slice of timestamps, that contain requested vsCurrency and token
func (fr *FiatRates) getTokenTickersForTimestamps(timestamps []int64, vsCurrency string, token string) (*[]*common.CurrencyRatesTicker, error) {
currentTicker := fr.GetCurrentTicker("", token)
tickers := make([]*common.CurrencyRatesTicker, len(timestamps))
var prevTicker *common.CurrencyRatesTicker
for i, t := range timestamps {
// check if the token is available in the current ticker - if not, return nil ticker instead of wasting time in costly DB searches
if currentTicker != nil {
var ticker *common.CurrencyRatesTicker
date := time.Unix(t, 0)
// if previously found ticker is newer than this one (token tickers may not be in DB for every day), skip search in DB
if prevTicker != nil && !date.After(prevTicker.Timestamp) {
ticker = prevTicker
} else {
ticker, _ := fr.db.FiatRatesFindTicker(&date, vsCurrency, token)
prevTicker = ticker
}
// if ticker not found in DB, use current ticker
if ticker == nil {
tickers[i] = currentTicker
prevTicker = currentTicker
} else {
tickers[i] = ticker
}
}
}
return &tickers, nil
}
// GetTickersForTimestamps returns tickers for slice of timestamps, that contain requested vsCurrency and token
func (fr *FiatRates) GetTickersForTimestamps(timestamps []int64, vsCurrency string, token string) (*[]*common.CurrencyRatesTicker, error) {
// token rates are not in memory, them load from DB
if token != "" {
return fr.getTokenTickersForTimestamps(timestamps, vsCurrency, token)
}
fr.mux.RLock()
defer fr.mux.RUnlock()
tickers := make([]*common.CurrencyRatesTicker, len(timestamps))
var prevTicker *common.CurrencyRatesTicker
for i, t := range timestamps {
dailyTs := normalizedUnix(t, secondsInDay)
// use higher granularity only for non daily timestamps
if t != dailyTs {
if t >= fr.fiveMinutesTickersFrom && t <= fr.fiveMinutesTickersTo {
if ticker, found := fr.fiveMinutesTickers[normalizedUnix(t, secondsInFiveMinutes)]; found && ticker != nil {
if common.IsSuitableTicker(ticker, vsCurrency, token) {
tickers[i] = ticker
continue
}
}
}
if t >= fr.hourlyTickersFrom && t <= fr.hourlyTickersTo {
if ticker, found := fr.hourlyTickers[normalizedUnix(t, secondsInHour)]; found && ticker != nil {
if common.IsSuitableTicker(ticker, vsCurrency, token) {
tickers[i] = ticker
continue
}
}
}
}
if prevTicker != nil && dailyTs >= prevTicker.Timestamp.Unix() {
tickers[i] = prevTicker
continue
} else {
var found bool
if dailyTs < fr.dailyTickersFrom {
dailyTs = fr.dailyTickersFrom
}
var ticker *common.CurrencyRatesTicker
for ; dailyTs <= fr.dailyTickersTo; dailyTs += secondsInDay {
if ticker, found = fr.dailyTickers[dailyTs]; found && ticker != nil {
if common.IsSuitableTicker(ticker, vsCurrency, token) {
tickers[i] = ticker
prevTicker = ticker
break
} else {
found = false
}
}
if !found {
tickers[i] = fr.currentTicker
prevTicker = fr.currentTicker
}
}
}
}
return &tickers, nil
}
func (fr *FiatRates) logTickersInfo() {
glog.Infof("fiat rates %s handler, %d (%s - %s) daily tickers, %d (%s - %s) hourly tickers, %d (%s - %s) 5 minute tickers", fr.provider,
len(fr.dailyTickers), time.Unix(fr.dailyTickersFrom, 0).Format("2006-01-02"), time.Unix(fr.dailyTickersTo, 0).Format("2006-01-02"),
len(fr.hourlyTickers), time.Unix(fr.hourlyTickersFrom, 0).Format("2006-01-02 15:04"), time.Unix(fr.hourlyTickersTo, 0).Format("2006-01-02 15:04"),
len(fr.fiveMinutesTickers), time.Unix(fr.fiveMinutesTickersFrom, 0).Format("2006-01-02 15:04"), time.Unix(fr.fiveMinutesTickersTo, 0).Format("2006-01-02 15:04"))
}
func normalizedTimeUnix(t time.Time, granularity int64) int64 {
return normalizedUnix(t.UTC().Unix(), granularity)
}
func normalizedUnix(t int64, granularity int64) int64 {
unix := t + (granularity >> 1)
return unix - unix%granularity
}
// loadDailyTickers loads daily tickers to cache
func (fr *FiatRates) loadDailyTickers() error {
fr.mux.Lock()
defer fr.mux.Unlock()
fr.dailyTickers = make(map[int64]*common.CurrencyRatesTicker)
err := fr.db.FiatRatesGetAllTickers(func(ticker *common.CurrencyRatesTicker) error {
normalizedTime := normalizedTimeUnix(ticker.Timestamp, secondsInDay)
// remove token rates from cache to save memory (tickers with token rates are hundreds of kb big)
ticker.TokenRates = nil
if len(fr.dailyTickers) > 0 {
// check that there is a ticker for every day, if missing, set it from current value if missing
prevTime := normalizedTime
for {
prevTime -= secondsInDay
if _, found := fr.dailyTickers[prevTime]; found {
break
}
fr.dailyTickers[prevTime] = ticker
}
} else {
fr.dailyTickersFrom = normalizedTime
}
fr.dailyTickers[normalizedTime] = ticker
fr.dailyTickersTo = normalizedTime
return nil
})
return err
}
// setCurrentTicker sets current ticker // setCurrentTicker sets current ticker
func (fr *FiatRates) setCurrentTicker(t *common.CurrencyRatesTicker) { func (fr *FiatRates) setCurrentTicker(t *common.CurrencyRatesTicker) {
fr.mux.Lock() fr.mux.Lock()
defer fr.mux.Unlock() defer fr.mux.Unlock()
fr.currentTicker = t fr.currentTicker = t
fr.db.FiatRatesStoreSpecialTickers(CurrentTickersKey, &[]common.CurrencyRatesTicker{*t}) fr.db.FiatRatesStoreSpecialTickers(currentTickersKey, &[]common.CurrencyRatesTicker{*t})
}
func (fr *FiatRates) tickersToMap(tickers *[]common.CurrencyRatesTicker, granularitySeconds int64) (map[int64]*common.CurrencyRatesTicker, int64, int64) {
if tickers == nil || len(*tickers) == 0 {
return make(map[int64]*common.CurrencyRatesTicker), 0, 0
}
m := make(map[int64]*common.CurrencyRatesTicker, len(*tickers))
from := int64(0)
to := int64(0)
for i := range *tickers {
ticker := (*tickers)[i]
normalizedTime := normalizedTimeUnix(ticker.Timestamp, granularitySeconds)
dailyTime := normalizedTimeUnix(ticker.Timestamp, secondsInDay)
dailyTicker, found := fr.dailyTickers[dailyTime]
if !found {
// if not found in historical tickers, use current ticker
dailyTicker = fr.currentTicker
}
if dailyTicker != nil {
// high granularity tickers are loaded only in one currency, add other currencies based on daily rate between fiat currencies
vsRate, foundVs := ticker.Rates[highGranularityVsCurrency]
dailyVsRate, foundDaily := dailyTicker.Rates[highGranularityVsCurrency]
if foundDaily && dailyVsRate != 0 && foundVs && vsRate != 0 {
for currency, rate := range dailyTicker.Rates {
if currency != highGranularityVsCurrency {
ticker.Rates[currency] = vsRate * rate / dailyVsRate
}
}
}
}
if len(m) > 0 {
// check that there is a ticker for each period, set it from current value if missing
prevTime := normalizedTime
for {
prevTime -= granularitySeconds
if _, found := m[prevTime]; found {
break
}
m[prevTime] = &ticker
}
} else {
from = normalizedTime
}
m[normalizedTime] = &ticker
to = normalizedTime
}
return m, from, to
} }
// setCurrentTicker sets hourly tickers // setCurrentTicker sets hourly tickers
func (fr *FiatRates) setHourlyTickers(t *[]common.CurrencyRatesTicker) { func (fr *FiatRates) setHourlyTickers(t *[]common.CurrencyRatesTicker) {
fr.db.FiatRatesStoreSpecialTickers(hourlyTickersKey, t)
fr.mux.Lock() fr.mux.Lock()
defer fr.mux.Unlock() defer fr.mux.Unlock()
fr.hourlyTickers, fr.hourlyTickersFrom, fr.hourlyTickersTo = tickersToMap(t, 3600) fr.hourlyTickers, fr.hourlyTickersFrom, fr.hourlyTickersTo = fr.tickersToMap(t, secondsInHour)
fr.db.FiatRatesStoreSpecialTickers(HourlyTickersKey, t)
} }
// setCurrentTicker sets hourly tickers // setCurrentTicker sets hourly tickers
func (fr *FiatRates) setFiveMinutesTickers(t *[]common.CurrencyRatesTicker) { func (fr *FiatRates) setFiveMinutesTickers(t *[]common.CurrencyRatesTicker) {
fr.db.FiatRatesStoreSpecialTickers(fiveMinutesTickersKey, t)
fr.mux.Lock() fr.mux.Lock()
defer fr.mux.Unlock() defer fr.mux.Unlock()
fr.fiveMinutesTickers, fr.fiveMinutesTickersFrom, fr.fiveMinutesTickersTo = tickersToMap(t, 5*60) fr.fiveMinutesTickers, fr.fiveMinutesTickersFrom, fr.fiveMinutesTickersTo = fr.tickersToMap(t, secondsInFiveMinutes)
fr.db.FiatRatesStoreSpecialTickers(FiveMinutesTickersKey, t)
} }
// RunDownloader periodically downloads current (every 15 minutes) and historical (once a day) tickers // RunDownloader periodically downloads current (every 15 minutes) and historical (once a day) tickers
@ -245,13 +425,18 @@ func (fr *FiatRates) RunDownloader() error {
glog.Error("FiatRatesDownloader: UpdateHistoricalTickers error ", err) glog.Error("FiatRatesDownloader: UpdateHistoricalTickers error ", err)
} else { } else {
lastHistoricalTickers = time.Now().UTC() lastHistoricalTickers = time.Now().UTC()
ticker, err := fr.db.FiatRatesFindLastTicker("", "") if err = fr.loadDailyTickers(); err != nil {
if err != nil || ticker == nil { glog.Error("FiatRatesDownloader: loadDailyTickers error ", err)
glog.Error("FiatRatesDownloader: FiatRatesFindLastTicker error ", err)
} else { } else {
glog.Infof("FiatRatesDownloader: UpdateHistoricalTickers finished, last ticker from %v", ticker.Timestamp) ticker, found := fr.dailyTickers[fr.dailyTickersTo]
if is != nil { if !found || ticker == nil {
is.HistoricalFiatRatesTime = ticker.Timestamp glog.Error("FiatRatesDownloader: dailyTickers not loaded")
} else {
glog.Infof("FiatRatesDownloader: UpdateHistoricalTickers finished, last ticker from %v", ticker.Timestamp)
fr.logTickersInfo()
if is != nil {
is.HistoricalFiatRatesTime = ticker.Timestamp
}
} }
} }
if fr.downloadTokens { if fr.downloadTokens {

View File

@ -168,12 +168,12 @@ func newPostRequest(u string, body string) *http.Request {
} }
func insertFiatRate(date string, rates map[string]float32, tokenRates map[string]float32, d *db.RocksDB) error { func insertFiatRate(date string, rates map[string]float32, tokenRates map[string]float32, d *db.RocksDB) error {
convertedDate, err := db.FiatRatesConvertDate(date) convertedDate, err := time.Parse("20060102150405", date)
if err != nil { if err != nil {
return err return err
} }
ticker := &common.CurrencyRatesTicker{ ticker := &common.CurrencyRatesTicker{
Timestamp: *convertedDate, Timestamp: convertedDate,
Rates: rates, Rates: rates,
TokenRates: tokenRates, TokenRates: tokenRates,
} }