exchanges/wrappers: Refactor fetch orderbook/ticker/account info funcs (#1440)

* acrost: Pull thread, examine

* fix tests

* linter

* fix_linter

* revert rm ctx param to limit breakages when merging usptream

* linter fix

* Add in priority update grouping so that tests pass

* Update cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious nits

* fixed spelling

* whoopsie

* aanother whoops

* glorious: NITTERS!

* glorious: further nitters

* srry linter gods

* glorious: nits continued

* sub test p ara lel

* drop main t.Parallel

* fix whoops

* wrappertests: use context with cancel (test)

* linter: fix

* ensure primary execution

* kucoin test fix

* revert standards test changes and bypass non critical errors

* rm single override

* wrap exported error for accounts

* thrasher: nits ch name

* gk: nits

* gk: nits FetchTickerCached -> GetCachedTicker

* gk: nits rn FetchOrderbookCached -> GetCachedOrderbook

* gk: nits rn FetchAccountInfoCached -> GetCachedAccountInfo

* linter: fix

* gk: nits

* thrasher: nitters 1

* thrasher: nitters tmpls

* gk: nitter

---------

Co-authored-by: shazbert <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
Ryan O'Hara-Reid
2025-02-19 10:47:10 +11:00
committed by GitHub
parent 2fc7e8e3e3
commit 08e015a125
122 changed files with 545 additions and 1962 deletions

View File

@@ -20,6 +20,8 @@ import (
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -310,35 +312,24 @@ func getAllActiveOrderbooks(m iExchangeManager) []EnabledExchangeOrderbooks {
}
orderbookData := make([]EnabledExchangeOrderbooks, 0, len(exchanges))
for x := range exchanges {
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
var exchangeOB EnabledExchangeOrderbooks
exchangeOB.ExchangeName = exchName
for y := range assets {
currencies, err := exchanges[x].GetEnabledPairs(assets[y])
for _, e := range exchanges {
var orderbooks []orderbook.Base
for _, a := range e.GetAssetTypes(true) {
pairs, err := e.GetEnabledPairs(a)
if err != nil {
log.Errorf(log.APIServerMgr,
"Exchange %s could not retrieve enabled currencies. Err: %s\n",
exchName,
err)
log.Errorf(log.APIServerMgr, "Exchange %s could not retrieve enabled currencies. Err: %s\n", e.GetName(), err)
continue
}
for z := range currencies {
ob, err := exchanges[x].FetchOrderbook(context.TODO(), currencies[z], assets[y])
for _, pair := range pairs {
ob, err := e.GetCachedOrderbook(pair, a)
if err != nil {
log.Errorf(log.APIServerMgr,
"Exchange %s failed to retrieve %s orderbook. Err: %s\n", exchName,
currencies[z].String(),
err)
log.Errorf(log.APIServerMgr, "Exchange %s failed to retrieve %s orderbook. Err: %s\n", e.GetName(), pair, err)
continue
}
exchangeOB.ExchangeValues = append(exchangeOB.ExchangeValues, *ob)
orderbooks = append(orderbooks, *ob)
}
orderbookData = append(orderbookData, exchangeOB)
}
orderbookData = append(orderbookData, exchangeOB)
orderbookData = append(orderbookData, EnabledExchangeOrderbooks{ExchangeName: e.GetName(), ExchangeValues: orderbooks})
}
return orderbookData
}
@@ -351,38 +342,27 @@ func getAllActiveTickers(m iExchangeManager) []EnabledExchangeCurrencies {
return nil
}
tickers := make([]EnabledExchangeCurrencies, 0, len(exchanges))
for x := range exchanges {
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
var exchangeTickers EnabledExchangeCurrencies
exchangeTickers.ExchangeName = exchName
for y := range assets {
currencies, err := exchanges[x].GetEnabledPairs(assets[y])
exchangeTickers := make([]EnabledExchangeCurrencies, 0, len(exchanges))
for _, e := range exchanges {
var tickers []*ticker.Price
for _, a := range e.GetAssetTypes(true) {
pairs, err := e.GetEnabledPairs(a)
if err != nil {
log.Errorf(log.APIServerMgr,
"Exchange %s could not retrieve enabled currencies. Err: %s\n",
exchName,
err)
log.Errorf(log.APIServerMgr, "Exchange %s could not retrieve enabled currencies. Err: %s\n", e.GetName(), err)
continue
}
for z := range currencies {
t, err := exchanges[x].FetchTicker(context.TODO(), currencies[z], assets[y])
for _, pair := range pairs {
t, err := e.GetCachedTicker(pair, a)
if err != nil {
log.Errorf(log.APIServerMgr,
"Exchange %s failed to retrieve %s ticker. Err: %s\n", exchName,
currencies[z].String(),
err)
log.Errorf(log.APIServerMgr, "Exchange %s failed to retrieve %s ticker. Err: %s\n", e.GetName(), pair.String(), err)
continue
}
exchangeTickers.ExchangeValues = append(exchangeTickers.ExchangeValues, *t)
tickers = append(tickers, t)
}
tickers = append(tickers, exchangeTickers)
}
tickers = append(tickers, exchangeTickers)
exchangeTickers = append(exchangeTickers, EnabledExchangeCurrencies{ExchangeName: e.GetName(), ExchangeValues: tickers})
}
return tickers
return exchangeTickers
}
// getAllActiveAccounts returns all enabled exchanges accounts
@@ -399,7 +379,7 @@ func getAllActiveAccounts(m iExchangeManager) []AllEnabledExchangeAccounts {
exchName := exchanges[x].GetName()
var exchangeAccounts AllEnabledExchangeAccounts
for y := range assets {
a, err := exchanges[x].FetchAccountInfo(context.TODO(), assets[y])
a, err := exchanges[x].GetCachedAccountInfo(context.TODO(), assets[y])
if err != nil {
log.Errorf(log.APIServerMgr,
"Exchange %s failed to retrieve %s ticker. Err: %s\n",
@@ -850,7 +830,7 @@ func wsGetTicker(client *websocketClient, data interface{}) error {
}
return err
}
tick, err := exch.FetchTicker(context.TODO(), p, a)
tick, err := exch.GetCachedTicker(p, a)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
@@ -877,14 +857,10 @@ func wsGetOrderbook(client *websocketClient, data interface{}) error {
return common.GetTypeAssertError("[]byte", data)
}
wsResp := WebsocketEventResponse{
Event: "GetOrderbook",
}
var orderbookReq WebsocketOrderbookTickerRequest
err := json.Unmarshal(d, &orderbookReq)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
if sendErr != nil {
log.Errorln(log.APIServerMgr, sendErr)
}
@@ -903,24 +879,22 @@ func wsGetOrderbook(client *websocketClient, data interface{}) error {
exch, err := client.exchangeManager.GetExchangeByName(orderbookReq.Exchange)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
if sendErr != nil {
log.Errorln(log.APIServerMgr, sendErr)
}
return err
}
ob, err := exch.FetchOrderbook(context.TODO(), p, a)
ob, err := exch.GetCachedOrderbook(p, a)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
if sendErr != nil {
log.Errorln(log.APIServerMgr, sendErr)
}
return err
}
wsResp.Data = ob
return nil
return client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Data: ob})
}
func wsGetExchangeRates(client *websocketClient, _ interface{}) error {

View File

@@ -140,8 +140,8 @@ type AllEnabledExchangeCurrencies struct {
// EnabledExchangeCurrencies is a sub type for singular exchanges and respective
// currencies
type EnabledExchangeCurrencies struct {
ExchangeName string `json:"exchangeName"`
ExchangeValues []ticker.Price `json:"exchangeValues"`
ExchangeName string `json:"exchangeName"`
ExchangeValues []*ticker.Price `json:"exchangeValues"`
}
// AllEnabledExchangeAccounts holds all enabled accounts info

View File

@@ -3,13 +3,15 @@ package engine
import (
"context"
"errors"
"strings"
"sync/atomic"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
)
@@ -252,24 +254,18 @@ func TestGetEventCounter(t *testing.T) {
func TestCheckEventCondition(t *testing.T) {
em := NewExchangeManager()
m, err := setupEventManager(&CommunicationManager{}, em, 0, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
require.NoError(t, err, "setupEventManager must not error")
m.m.Lock()
err = m.checkEventCondition(nil)
if !errors.Is(err, ErrSubSystemNotStarted) {
t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted)
}
assert.ErrorIs(t, err, ErrSubSystemNotStarted)
m.m.Unlock()
err = m.Start()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
require.NoError(t, m.Start(), "Start must not error")
m.m.Lock()
err = m.checkEventCondition(nil)
if !errors.Is(err, errNilEvent) {
t.Errorf("error '%v', expected '%v'", err, errNilEvent)
}
assert.ErrorIs(t, err, errNilEvent)
m.m.Unlock()
action := ActionSMSNotify + "," + ActionTest
@@ -279,67 +275,47 @@ func TestCheckEventCondition(t *testing.T) {
OrderbookAmount: 1337,
}
exch, err := em.NewExchangeByName(testExchange)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err, "NewExchangeByName must not error")
conf, err := exchange.GetDefaultConfig(context.Background(), exch)
if err != nil {
t.Error(err)
}
err = exch.Setup(conf)
if err != nil {
t.Error(err)
}
require.NoError(t, err, "GetDefaultConfig must not error")
require.NoError(t, exch.Setup(conf), "Setup must not error")
err = em.Add(exch)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
require.NoError(t, err, "ExchangeManager Add must not error")
_, err = m.Add(testExchange, ItemPrice, cond, currency.NewPair(currency.BTC, currency.USD), asset.Spot, action)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
require.NoError(t, err, "eventManager Add must not error")
m.m.Lock()
err = m.checkEventCondition(&m.events[0])
if err != nil && !errors.Is(err, ticker.ErrNoTickerFound) {
t.Error(err)
} else if err == nil {
t.Error("expected error")
}
assert.ErrorIs(t, err, ticker.ErrTickerNotFound)
m.m.Unlock()
_, err = exch.FetchTicker(context.Background(),
currency.NewPair(currency.BTC, currency.USD), asset.Spot)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
_, err = exch.UpdateTicker(context.Background(), currency.NewPair(currency.BTC, currency.USD), asset.Spot)
require.NoError(t, err, "UpdateTicker must not error")
m.m.Lock()
err = m.checkEventCondition(&m.events[0])
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
require.NoError(t, err, "checkEventCondition must not error")
m.m.Unlock()
m.events[0].Item = ItemOrderbook
m.events[0].Executed = false
m.events[0].Condition.CheckAsks = true
m.events[0].Condition.CheckBids = true
m.m.Lock()
err = m.checkEventCondition(&m.events[0])
if err != nil && !strings.Contains(err.Error(), "cannot find orderbook") {
t.Error(err)
} else if err == nil {
t.Error("expected error")
}
assert.ErrorIs(t, err, orderbook.ErrOrderbookNotFound)
m.m.Unlock()
_, err = exch.FetchOrderbook(context.Background(),
currency.NewPair(currency.BTC, currency.USD), asset.Spot)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
_, err = exch.UpdateOrderbook(context.Background(), currency.NewPair(currency.BTC, currency.USD), asset.Spot)
require.NoError(t, err, "UpdateOrderbook must not error")
m.m.Lock()
err = m.checkEventCondition(&m.events[0])
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
assert.NoError(t, err, "checkEventCondition should not error")
m.m.Unlock()
}

View File

@@ -50,10 +50,8 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/kucoin"
"github.com/thrasher-corp/gocryptotrader/exchanges/lbank"
"github.com/thrasher-corp/gocryptotrader/exchanges/okx"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/poloniex"
"github.com/thrasher-corp/gocryptotrader/exchanges/stats"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/yobit"
"github.com/thrasher-corp/gocryptotrader/gctscript/vm"
"github.com/thrasher-corp/gocryptotrader/log"
@@ -574,26 +572,6 @@ func GetRelatableCurrencies(p currency.Pair, incOrig, incUSDT bool) currency.Pai
return pairs
}
// GetSpecificOrderbook returns a specific orderbook given the currency,
// exchangeName and assetType
func (bot *Engine) GetSpecificOrderbook(ctx context.Context, p currency.Pair, exchangeName string, assetType asset.Item) (*orderbook.Base, error) {
exch, err := bot.GetExchangeByName(exchangeName)
if err != nil {
return nil, err
}
return exch.FetchOrderbook(ctx, p, assetType)
}
// GetSpecificTicker returns a specific ticker given the currency,
// exchangeName and assetType
func (bot *Engine) GetSpecificTicker(ctx context.Context, p currency.Pair, exchangeName string, assetType asset.Item) (*ticker.Price, error) {
exch, err := bot.GetExchangeByName(exchangeName)
if err != nil {
return nil, err
}
return exch.FetchTicker(ctx, p, assetType)
}
// GetCollatedExchangeAccountInfoByCoin collates individual exchange account
// information and turns it into a map string of exchange.AccountCurrencyInfo
func GetCollatedExchangeAccountInfoByCoin(accounts []account.Holdings) map[currency.Code]account.Balance {
@@ -830,7 +808,7 @@ func (bot *Engine) GetExchangeNames(enabledOnly bool) []string {
}
// GetAllActiveTickers returns all enabled exchange tickers
func (bot *Engine) GetAllActiveTickers(ctx context.Context) []EnabledExchangeCurrencies {
func (bot *Engine) GetAllActiveTickers() []EnabledExchangeCurrencies {
var tickerData []EnabledExchangeCurrencies
exchanges := bot.GetExchanges()
for x := range exchanges {
@@ -842,21 +820,16 @@ func (bot *Engine) GetAllActiveTickers(ctx context.Context) []EnabledExchangeCur
for y := range assets {
currencies, err := exchanges[x].GetEnabledPairs(assets[y])
if err != nil {
log.Errorf(log.ExchangeSys,
"Exchange %s could not retrieve enabled currencies. Err: %s\n",
exchName,
err)
log.Errorf(log.ExchangeSys, "Exchange %s could not retrieve enabled currencies. Err: %s\n", exchName, err)
continue
}
for z := range currencies {
tp, err := exchanges[x].FetchTicker(ctx, currencies[z], assets[y])
tp, err := exchanges[x].GetCachedTicker(currencies[z], assets[y])
if err != nil {
log.Errorf(log.ExchangeSys, "Exchange %s failed to retrieve %s ticker. Err: %s\n", exchName,
currencies[z].String(),
err)
log.Errorf(log.ExchangeSys, "Exchange %s failed to retrieve %s ticker. Err: %s\n", exchName, currencies[z].String(), err)
continue
}
exchangeTicker.ExchangeValues = append(exchangeTicker.ExchangeValues, *tp)
exchangeTicker.ExchangeValues = append(exchangeTicker.ExchangeValues, tp)
}
tickerData = append(tickerData, exchangeTicker)
}

View File

@@ -30,10 +30,8 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
"github.com/thrasher-corp/gocryptotrader/exchanges/stats"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/gctscript/vm"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -752,98 +750,6 @@ func TestGetExchangeNamesByCurrency(t *testing.T) {
}
}
func TestGetSpecificOrderbook(t *testing.T) {
t.Parallel()
e := CreateTestBot(t)
base := orderbook.Base{
Pair: currency.NewPair(currency.BTC, currency.USD),
Bids: []orderbook.Tranche{{Price: 1000, Amount: 1}},
Exchange: "Bitstamp",
Asset: asset.Spot,
}
err := base.Process()
if err != nil {
t.Fatal("Unexpected result", err)
}
btsusd, err := currency.NewPairFromStrings("BTC", "USD")
if err != nil {
t.Fatal(err)
}
ob, err := e.GetSpecificOrderbook(context.Background(),
btsusd, testExchange, asset.Spot)
if err != nil {
t.Fatal(err)
}
if ob.Bids[0].Price != 1000 {
t.Fatal("Unexpected result")
}
ethltc, err := currency.NewPairFromStrings("ETH", "LTC")
if err != nil {
t.Fatal(err)
}
_, err = e.GetSpecificOrderbook(context.Background(),
ethltc, testExchange, asset.Spot)
if err == nil {
t.Fatal("Unexpected result")
}
err = e.UnloadExchange(testExchange)
if err != nil {
t.Error(err)
}
}
func TestGetSpecificTicker(t *testing.T) {
t.Parallel()
e := CreateTestBot(t)
p, err := currency.NewPairFromStrings("BTC", "USD")
if err != nil {
t.Fatal(err)
}
err = ticker.ProcessTicker(&ticker.Price{
Pair: p,
Last: 1000,
AssetType: asset.Spot,
ExchangeName: testExchange})
if err != nil {
t.Fatal("ProcessTicker error", err)
}
tick, err := e.GetSpecificTicker(context.Background(),
p, testExchange, asset.Spot)
if err != nil {
t.Fatal(err)
}
if tick.Last != 1000 {
t.Fatal("Unexpected result")
}
ethltc, err := currency.NewPairFromStrings("ETH", "LTC")
if err != nil {
t.Fatal(err)
}
_, err = e.GetSpecificTicker(context.Background(),
ethltc, testExchange, asset.Spot)
if err == nil {
t.Fatal("Unexpected result")
}
err = e.UnloadExchange(testExchange)
if err != nil {
t.Error(err)
}
}
func TestGetCollatedExchangeAccountInfoByCoin(t *testing.T) {
t.Parallel()
CreateTestBot(t)

View File

@@ -792,7 +792,7 @@ func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, posit
}
return err
}
tick, err := exch.FetchTicker(context.TODO(), position.Pair, position.Asset)
tick, err := exch.GetCachedTicker(position.Pair, position.Asset)
if err != nil {
return fmt.Errorf("%w when fetching ticker data for %v %v %v", err, exch.GetName(), position.Asset, position.Pair)
}

View File

@@ -38,7 +38,7 @@ func (f omfExchange) CancelOrder(_ context.Context, _ *order.Cancel) error {
return nil
}
func (f omfExchange) FetchTicker(_ context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
func (f omfExchange) GetCachedTicker(p currency.Pair, a asset.Item) (*ticker.Price, error) {
return &ticker.Price{
Last: 1337,
High: 1337,

View File

@@ -392,7 +392,7 @@ func (s *RPCServer) GetExchangeInfo(_ context.Context, r *gctrpc.GenericExchange
// GetTicker returns the ticker for a specified exchange, currency pair and
// asset type
func (s *RPCServer) GetTicker(ctx context.Context, r *gctrpc.GetTickerRequest) (*gctrpc.TickerResponse, error) {
func (s *RPCServer) GetTicker(_ context.Context, r *gctrpc.GetTickerRequest) (*gctrpc.TickerResponse, error) {
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
@@ -403,24 +403,14 @@ func (s *RPCServer) GetTicker(ctx context.Context, r *gctrpc.GetTickerRequest) (
return nil, err
}
err = checkParams(r.Exchange, e, a, currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
})
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, e, a, pair)
if err != nil {
return nil, err
}
t, err := s.GetSpecificTicker(ctx,
currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
},
r.Exchange,
a,
)
t, err := e.GetCachedTicker(pair, a)
if err != nil {
return nil, err
}
@@ -442,18 +432,13 @@ func (s *RPCServer) GetTicker(ctx context.Context, r *gctrpc.GetTickerRequest) (
// GetTickers returns a list of tickers for all enabled exchanges and all
// enabled currency pairs
func (s *RPCServer) GetTickers(ctx context.Context, _ *gctrpc.GetTickersRequest) (*gctrpc.GetTickersResponse, error) {
activeTickers := s.GetAllActiveTickers(ctx)
func (s *RPCServer) GetTickers(_ context.Context, _ *gctrpc.GetTickersRequest) (*gctrpc.GetTickersResponse, error) {
activeTickers := s.GetAllActiveTickers()
tickers := make([]*gctrpc.Tickers, len(activeTickers))
for x := range activeTickers {
t := &gctrpc.Tickers{
Exchange: activeTickers[x].ExchangeName,
Tickers: make([]*gctrpc.TickerResponse, len(activeTickers[x].ExchangeValues)),
}
for y := range activeTickers[x].ExchangeValues {
val := activeTickers[x].ExchangeValues[y]
t.Tickers[y] = &gctrpc.TickerResponse{
ticks := make([]*gctrpc.TickerResponse, len(activeTickers[x].ExchangeValues))
for y, val := range activeTickers[x].ExchangeValues {
ticks[y] = &gctrpc.TickerResponse{
Pair: &gctrpc.CurrencyPair{
Delimiter: val.Pair.Delimiter,
Base: val.Pair.Base.String(),
@@ -469,7 +454,7 @@ func (s *RPCServer) GetTickers(ctx context.Context, _ *gctrpc.GetTickersRequest)
PriceAth: val.PriceATH,
}
}
tickers[x] = t
tickers[x] = &gctrpc.Tickers{Exchange: activeTickers[x].ExchangeName, Tickers: ticks}
}
return &gctrpc.GetTickersResponse{Tickers: tickers}, nil
@@ -477,46 +462,33 @@ func (s *RPCServer) GetTickers(ctx context.Context, _ *gctrpc.GetTickersRequest)
// GetOrderbook returns an orderbook for a specific exchange, currency pair
// and asset type
func (s *RPCServer) GetOrderbook(ctx context.Context, r *gctrpc.GetOrderbookRequest) (*gctrpc.OrderbookResponse, error) {
func (s *RPCServer) GetOrderbook(_ context.Context, r *gctrpc.GetOrderbookRequest) (*gctrpc.OrderbookResponse, error) {
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
ob, err := s.GetSpecificOrderbook(ctx,
currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
},
r.Exchange,
a,
)
e, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
bids := make([]*gctrpc.OrderbookItem, 0, len(ob.Bids))
asks := make([]*gctrpc.OrderbookItem, 0, len(ob.Asks))
ch := make(chan bool)
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
go func() {
for _, b := range ob.Bids {
bids = append(bids, &gctrpc.OrderbookItem{
Amount: b.Amount,
Price: b.Price,
})
}
ch <- true
}()
for _, a := range ob.Asks {
asks = append(asks, &gctrpc.OrderbookItem{
Amount: a.Amount,
Price: a.Price,
})
ob, err := e.GetCachedOrderbook(pair, a)
if err != nil {
return nil, err
}
bids := make([]*gctrpc.OrderbookItem, len(ob.Bids))
for x := range ob.Bids {
bids[x] = &gctrpc.OrderbookItem{Amount: ob.Bids[x].Amount, Price: ob.Bids[x].Price}
}
asks := make([]*gctrpc.OrderbookItem, len(ob.Asks))
for x := range ob.Asks {
asks[x] = &gctrpc.OrderbookItem{Amount: ob.Asks[x].Amount, Price: ob.Asks[x].Price}
}
<-ch
resp := &gctrpc.OrderbookResponse{
Pair: r.Pair,
@@ -531,67 +503,50 @@ func (s *RPCServer) GetOrderbook(ctx context.Context, r *gctrpc.GetOrderbookRequ
// GetOrderbooks returns a list of orderbooks for all enabled exchanges and all
// enabled currency pairs
func (s *RPCServer) GetOrderbooks(ctx context.Context, _ *gctrpc.GetOrderbooksRequest) (*gctrpc.GetOrderbooksResponse, error) {
func (s *RPCServer) GetOrderbooks(_ context.Context, _ *gctrpc.GetOrderbooksRequest) (*gctrpc.GetOrderbooksResponse, error) {
exchanges, err := s.ExchangeManager.GetExchanges()
if err != nil {
return nil, err
}
obResponse := make([]*gctrpc.Orderbooks, 0, len(exchanges))
var obs []*gctrpc.OrderbookResponse
for x := range exchanges {
if !exchanges[x].IsEnabled() {
for _, e := range exchanges {
if !e.IsEnabled() {
continue
}
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
for y := range assets {
currencies, err := exchanges[x].GetEnabledPairs(assets[y])
for _, a := range e.GetAssetTypes(true) {
pairs, err := e.GetEnabledPairs(a)
if err != nil {
log.Errorf(log.RESTSys,
"Exchange %s could not retrieve enabled currencies. Err: %s\n",
exchName,
err)
log.Errorf(log.RESTSys, "Exchange %s could not retrieve enabled currencies. Err: %s\n", e.GetName(), err)
continue
}
for z := range currencies {
resp, err := exchanges[x].FetchOrderbook(ctx, currencies[z], assets[y])
for _, pair := range pairs {
resp, err := e.GetCachedOrderbook(pair, a)
if err != nil {
log.Errorf(log.RESTSys,
"Exchange %s failed to retrieve %s orderbook. Err: %s\n", exchName,
currencies[z].String(),
err)
log.Errorf(log.RESTSys, "Exchange %s failed to retrieve %s orderbook. Err: %s\n", e.GetName(), pair, err)
continue
}
ob := &gctrpc.OrderbookResponse{
Pair: &gctrpc.CurrencyPair{
Delimiter: currencies[z].Delimiter,
Base: currencies[z].Base.String(),
Quote: currencies[z].Quote.String(),
Delimiter: pair.Delimiter,
Base: pair.Base.String(),
Quote: pair.Quote.String(),
},
AssetType: assets[y].String(),
AssetType: a.String(),
LastUpdated: s.unixTimestamp(resp.LastUpdated),
Bids: make([]*gctrpc.OrderbookItem, len(resp.Bids)),
Asks: make([]*gctrpc.OrderbookItem, len(resp.Asks)),
}
for i := range resp.Bids {
ob.Bids[i] = &gctrpc.OrderbookItem{
Amount: resp.Bids[i].Amount,
Price: resp.Bids[i].Price,
}
ob.Bids[i] = &gctrpc.OrderbookItem{Amount: resp.Bids[i].Amount, Price: resp.Bids[i].Price}
}
for i := range resp.Asks {
ob.Asks[i] = &gctrpc.OrderbookItem{
Amount: resp.Asks[i].Amount,
Price: resp.Asks[i].Price,
}
ob.Asks[i] = &gctrpc.OrderbookItem{Amount: resp.Asks[i].Amount, Price: resp.Asks[i].Price}
}
obs = append(obs, ob)
}
}
obResponse = append(obResponse, &gctrpc.Orderbooks{
Exchange: exchanges[x].GetName(),
Orderbooks: obs,
})
obResponse = append(obResponse, &gctrpc.Orderbooks{Exchange: e.GetName(), Orderbooks: obs})
}
return &gctrpc.GetOrderbooksResponse{Orderbooks: obResponse}, nil
@@ -614,7 +569,7 @@ func (s *RPCServer) GetAccountInfo(ctx context.Context, r *gctrpc.GetAccountInfo
return nil, err
}
resp, err := exch.FetchAccountInfo(ctx, assetType)
resp, err := exch.GetCachedAccountInfo(ctx, assetType)
if err != nil {
return nil, err
}
@@ -692,7 +647,7 @@ func (s *RPCServer) GetAccountInfoStream(r *gctrpc.GetAccountInfoRequest, stream
return err
}
initAcc, err := exch.FetchAccountInfo(stream.Context(), assetType)
initAcc, err := exch.GetCachedAccountInfo(stream.Context(), assetType)
if err != nil {
return err
}
@@ -1143,12 +1098,6 @@ func (s *RPCServer) GetOrder(ctx context.Context, r *gctrpc.GetOrderRequest) (*g
return nil, errCurrencyPairUnset
}
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.Asset)
if err != nil {
return nil, err
@@ -1159,6 +1108,8 @@ func (s *RPCServer) GetOrder(ctx context.Context, r *gctrpc.GetOrderRequest) (*g
return nil, err
}
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, pair)
if err != nil {
return nil, err
@@ -1234,17 +1185,13 @@ func (s *RPCServer) SubmitOrder(ctx context.Context, r *gctrpc.SubmitOrderReques
return nil, errCurrencyPairUnset
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
@@ -1299,28 +1246,24 @@ func (s *RPCServer) SubmitOrder(ctx context.Context, r *gctrpc.SubmitOrderReques
// SimulateOrder simulates an order specified by exchange, currency pair and asset
// type
func (s *RPCServer) SimulateOrder(ctx context.Context, r *gctrpc.SimulateOrderRequest) (*gctrpc.SimulateOrderResponse, error) {
func (s *RPCServer) SimulateOrder(_ context.Context, r *gctrpc.SimulateOrderRequest) (*gctrpc.SimulateOrderResponse, error) {
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, asset.Spot, p)
if err != nil {
return nil, err
}
o, err := exch.FetchOrderbook(ctx, p, asset.Spot)
o, err := exch.GetCachedOrderbook(p, asset.Spot)
if err != nil {
return nil, err
}
@@ -1354,17 +1297,11 @@ func (s *RPCServer) SimulateOrder(ctx context.Context, r *gctrpc.SimulateOrderRe
// WhaleBomb finds the amount required to reach a specific price target for a given exchange, pair
// and asset type
func (s *RPCServer) WhaleBomb(ctx context.Context, r *gctrpc.WhaleBombRequest) (*gctrpc.SimulateOrderResponse, error) {
func (s *RPCServer) WhaleBomb(_ context.Context, r *gctrpc.WhaleBombRequest) (*gctrpc.SimulateOrderResponse, error) {
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
@@ -1375,12 +1312,14 @@ func (s *RPCServer) WhaleBomb(ctx context.Context, r *gctrpc.WhaleBombRequest) (
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
o, err := exch.FetchOrderbook(ctx, p, a)
o, err := exch.GetCachedOrderbook(p, a)
if err != nil {
return nil, err
}
@@ -1418,12 +1357,6 @@ func (s *RPCServer) CancelOrder(ctx context.Context, r *gctrpc.CancelOrderReques
return nil, errCurrencyPairUnset
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
@@ -1434,6 +1367,8 @@ func (s *RPCServer) CancelOrder(ctx context.Context, r *gctrpc.CancelOrderReques
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
@@ -1464,12 +1399,6 @@ func (s *RPCServer) CancelOrder(ctx context.Context, r *gctrpc.CancelOrderReques
// CancelBatchOrders cancels an orders specified by exchange, currency pair and asset type
func (s *RPCServer) CancelBatchOrders(ctx context.Context, r *gctrpc.CancelBatchOrdersRequest) (*gctrpc.CancelBatchOrdersResponse, error) {
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
assetType, err := asset.New(r.AssetType)
if err != nil {
return nil, err
@@ -1480,6 +1409,8 @@ func (s *RPCServer) CancelBatchOrders(ctx context.Context, r *gctrpc.CancelBatch
return nil, err
}
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, assetType, pair)
if err != nil {
return nil, err
@@ -1545,17 +1476,14 @@ func (s *RPCServer) ModifyOrder(ctx context.Context, r *gctrpc.ModifyOrderReques
if err != nil {
return nil, err
}
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, assetType, pair)
if err != nil {
return nil, err
@@ -2139,17 +2067,13 @@ func (s *RPCServer) GetOrderbookStream(r *gctrpc.GetOrderbookStreamRequest, stre
return err
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return err
@@ -2452,11 +2376,6 @@ func (s *RPCServer) GetHistoricCandles(ctx context.Context, r *gctrpc.GetHistori
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -2468,6 +2387,8 @@ func (s *RPCServer) GetHistoricCandles(ctx context.Context, r *gctrpc.GetHistori
return nil, err
}
pair := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, pair)
if err != nil {
return nil, err
@@ -3185,12 +3106,6 @@ func (s *RPCServer) GetSavedTrades(_ context.Context, r *gctrpc.GetSavedTradesRe
return nil, errInvalidArguments
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
@@ -3201,6 +3116,8 @@ func (s *RPCServer) GetSavedTrades(_ context.Context, r *gctrpc.GetSavedTradesRe
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
@@ -3261,11 +3178,6 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
if err != nil {
return nil, err
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -3277,6 +3189,8 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
@@ -3333,11 +3247,6 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
if r.End == "" || r.Start == "" || r.ExchangeName == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" || r.Interval <= 0 {
return nil, errInvalidArguments
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -3349,6 +3258,8 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.ExchangeName, exch, a, p)
if err != nil {
return nil, err
@@ -3425,11 +3336,6 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
if r.End == "" || r.Start == "" || r.ExchangeName == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return nil, errInvalidArguments
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -3441,6 +3347,8 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.ExchangeName, exch, a, p)
if err != nil {
return nil, err
@@ -3542,11 +3450,6 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
if r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return errInvalidArguments
}
cp := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -3558,6 +3461,8 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
return err
}
cp := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, cp)
if err != nil {
return err
@@ -3622,11 +3527,6 @@ func (s *RPCServer) GetRecentTrades(ctx context.Context, r *gctrpc.GetSavedTrade
if r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return nil, errInvalidArguments
}
cp := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
@@ -3638,6 +3538,8 @@ func (s *RPCServer) GetRecentTrades(ctx context.Context, r *gctrpc.GetSavedTrade
return nil, err
}
cp := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, exch, a, cp)
if err != nil {
return nil, err
@@ -3855,17 +3757,13 @@ func (s *RPCServer) UpsertDataHistoryJob(_ context.Context, r *gctrpc.UpsertData
return nil, err
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
e, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
p := currency.NewPairWithDelimiter(r.Pair.Base, r.Pair.Quote, r.Pair.Delimiter)
err = checkParams(r.Exchange, e, a, p)
if err != nil {
return nil, err
@@ -4886,7 +4784,7 @@ func (s *RPCServer) GetCollateral(ctx context.Context, r *gctrpc.GetCollateralRe
if !a.IsFutures() {
return nil, fmt.Errorf("%s %w", a, futures.ErrNotFuturesAsset)
}
ai, err := exch.FetchAccountInfo(ctx, a)
ai, err := exch.GetCachedAccountInfo(ctx, a)
if err != nil {
return nil, err
}
@@ -4942,9 +4840,9 @@ func (s *RPCServer) GetCollateral(ctx context.Context, r *gctrpc.GetCollateralRe
// cannot price currency to calculate collateral
continue
}
tick, err = exch.FetchTicker(ctx, tickerCurr, asset.Spot)
tick, err = exch.GetCachedTicker(tickerCurr, asset.Spot)
if err != nil {
log.Errorf(log.GRPCSys, "GetCollateral offline calculation error via FetchTicker %s %s", exch.GetName(), err)
log.Errorf(log.GRPCSys, "GetCollateral offline calculation error via GetCachedTicker %s %s", exch.GetName(), err)
continue
}
if tick.Last == 0 {

View File

@@ -303,7 +303,7 @@ func (f fExchange) GetMarginRatesHistory(context.Context, *margin.RateHistoryReq
return resp, nil
}
func (f fExchange) FetchTicker(_ context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
func (f fExchange) GetCachedTicker(p currency.Pair, a asset.Item) (*ticker.Price, error) {
return &ticker.Price{
Last: 1337,
High: 1337,
@@ -322,9 +322,9 @@ func (f fExchange) FetchTicker(_ context.Context, p currency.Pair, a asset.Item)
}, nil
}
// FetchAccountInfo overrides testExchange's fetch account info function
// GetCachedAccountInfo overrides testExchange's fetch account info function
// to do the bare minimum required with no API calls or credentials required
func (f fExchange) FetchAccountInfo(_ context.Context, a asset.Item) (account.Holdings, error) {
func (f fExchange) GetCachedAccountInfo(_ context.Context, a asset.Item) (account.Holdings, error) {
return account.Holdings{
Exchange: f.GetName(),
Accounts: []account.SubAccount{

View File

@@ -591,7 +591,7 @@ func (m *SyncManager) syncTicker(c *currencyPairSyncAgent, e exchange.IBotExchan
}
err = e.UpdateTickers(context.TODO(), c.Key.Asset)
if err == nil {
result, err = e.FetchTicker(context.TODO(), c.Pair, c.Key.Asset)
result, err = e.GetCachedTicker(c.Pair, c.Key.Asset)
}
m.tickerBatchLastRequested[key.ExchangeAsset{
Exchange: c.Key.Exchange,
@@ -602,9 +602,7 @@ func (m *SyncManager) syncTicker(c *currencyPairSyncAgent, e exchange.IBotExchan
if m.config.Verbose {
log.Debugf(log.SyncMgr, "%s Using recent batching cache", exchangeName)
}
result, err = e.FetchTicker(context.TODO(),
c.Pair,
c.Key.Asset)
result, err = e.GetCachedTicker(c.Pair, c.Key.Asset)
}
} else {
result, err = e.UpdateTicker(context.TODO(),