From 281ded8cc9364302d824d14569c8b7f2ba68d976 Mon Sep 17 00:00:00 2001 From: Gareth Kirwan Date: Thu, 28 Nov 2024 14:44:31 +0700 Subject: [PATCH] Exchanges: Rename StoreAssetPairStore Previously we were calling it "Format", but accepting everything from the PairStore. We were also defaulting to turning the Asset on. Now callers need to get their AssetEnabled set as they want it, so there's no magic This change also moves responsibility for error wrapping outside to the caller. --- cmd/exchange_template/wrapper_file.tmpl | 10 +-- docs/ADD_NEW_EXCHANGE.md | 10 +-- engine/rpcserver_test.go | 4 +- exchanges/binance/binance_wrapper.go | 86 ++++++++++-------------- exchanges/binanceus/binanceus_wrapper.go | 8 ++- exchanges/bitfinex/bitfinex_wrapper.go | 39 +++++------ exchanges/bitmex/bitmex_wrapper.go | 44 +++++------- exchanges/btse/btse_wrapper.go | 40 ++++------- exchanges/bybit/bybit_wrapper.go | 8 +-- exchanges/deribit/deribit_wrapper.go | 13 ++-- exchanges/exchange.go | 26 +++---- exchanges/exchange_test.go | 46 +++++-------- exchanges/huobi/huobi_wrapper.go | 53 +++++---------- exchanges/kraken/kraken_wrapper.go | 49 +++++--------- exchanges/kucoin/kucoin_wrapper.go | 35 +++++----- 15 files changed, 181 insertions(+), 290 deletions(-) diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl index 68e1639ca31..c1c4e7e8888 100644 --- a/cmd/exchange_template/wrapper_file.tmpl +++ b/cmd/exchange_template/wrapper_file.tmpl @@ -55,22 +55,24 @@ func ({{.Variable}} *{{.CapitalName}}) SetDefaults() { // can use this example below: fmt1 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true}, } fmt2 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"}, } - err = {{.Variable}}.StoreAssetPairFormat(asset.Spot, fmt1) + err = {{.Variable}}.StoreAssetPairStore(asset.Spot, fmt1) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", {{.Variable}}.Name, asset.Spot, err) } - err = {{.Variable}}.StoreAssetPairFormat(asset.Margin, fmt2) + err = {{.Variable}}.StoreAssetPairStore(asset.Margin, fmt2) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", {{.Variable}}.Name, asset.Margin, err) } // Fill out the capabilities/features that the exchange supports diff --git a/docs/ADD_NEW_EXCHANGE.md b/docs/ADD_NEW_EXCHANGE.md index 41e5712d192..f90d260f1f3 100644 --- a/docs/ADD_NEW_EXCHANGE.md +++ b/docs/ADD_NEW_EXCHANGE.md @@ -156,6 +156,7 @@ Similar to the configs, spot support is inbuilt but other asset types will need ```go spot := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{ Uppercase: true, Delimiter: "/", @@ -166,6 +167,7 @@ Similar to the configs, spot support is inbuilt but other asset types will need }, } futures := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{ Uppercase: true, Delimiter: "-", @@ -176,14 +178,14 @@ Similar to the configs, spot support is inbuilt but other asset types will need }, } - err := f.StoreAssetPairFormat(asset.Spot, spot) + err := f.StoreAssetPairStore(asset.Spot, spot) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `spot` default asset formats: %s", bi.Name, err) } - err = f.StoreAssetPairFormat(asset.Futures, futures) + err = f.StoreAssetPairStore(asset.Futures, futures) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `futures` default asset formats: %s", bi.Name, err) } ``` diff --git a/engine/rpcserver_test.go b/engine/rpcserver_test.go index 1f687e7a6b2..9661d6a2d3e 100644 --- a/engine/rpcserver_test.go +++ b/engine/rpcserver_test.go @@ -1548,6 +1548,7 @@ func TestCheckVars(t *testing.T) { for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.CoinMarginedFutures, asset.USDTMarginedFutures} { fmt := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, } @@ -1558,8 +1559,7 @@ func TestCheckVars(t *testing.T) { case asset.USDTMarginedFutures: fmt.ConfigFormat = ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} } - require.NoError(t, b.StoreAssetPairFormat(a, fmt), "StoreAssetPairFormat must not error") - require.NoError(t, b.CurrencyPairs.SetAssetEnabled(a, true), "SetAssetEnabled must not error") + require.NoError(t, b.StoreAssetPairStore(a, fmt), "StoreAssetPairStore must not error") } err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT)) diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 475f274814d..87082747d7a 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -36,6 +36,29 @@ import ( "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" ) +var defaultAssetPairStores = map[asset.Item]currency.PairStore{ + asset.Spot: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, + }, + asset.Margin: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, + }, + asset.CoinMarginedFutures: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + }, + asset.USDTMarginedFutures: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + }, +} + // SetDefaults sets the basic defaults for Binance func (b *Binance) SetDefaults() { b.Name = "Binance" @@ -45,60 +68,18 @@ func (b *Binance) SetDefaults() { b.API.CredentialsValidator.RequiresSecret = true b.SetValues() - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{ - Delimiter: currency.DashDelimiter, - Uppercase: true, - }, - } - coinFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - usdtFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.Margin, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.DisableAssetWebsocketSupport(asset.Margin) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.CoinMarginedFutures, coinFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.DisableAssetWebsocketSupport(asset.CoinMarginedFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.USDTMarginedFutures, usdtFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for a, ps := range defaultAssetPairStores { + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } - err = b.DisableAssetWebsocketSupport(asset.USDTMarginedFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + + for _, a := range []asset.Item{asset.Margin, asset.CoinMarginedFutures, asset.USDTMarginedFutures} { + if err := b.DisableAssetWebsocketSupport(a); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, a, err) + } } + b.Features = exchange.Features{ Supports: exchange.FeaturesSupported{ REST: true, @@ -196,6 +177,7 @@ func (b *Binance) SetDefaults() { }, } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimits())) diff --git a/exchanges/binanceus/binanceus_wrapper.go b/exchanges/binanceus/binanceus_wrapper.go index d3992d4e73e..fe107c9281a 100644 --- a/exchanges/binanceus/binanceus_wrapper.go +++ b/exchanges/binanceus/binanceus_wrapper.go @@ -40,15 +40,15 @@ func (bi *Binanceus) SetDefaults() { bi.SetValues() fmt1 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{ Delimiter: currency.DashDelimiter, Uppercase: true, }, } - err := bi.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := bi.StoreAssetPairStore(asset.Spot, fmt1); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `spot` default asset formats: %s", bi.Name, err) } bi.Features = exchange.Features{ @@ -122,6 +122,8 @@ func (bi *Binanceus) SetDefaults() { }, }, } + + var err error bi.Requester, err = request.New(bi.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 04cba828676..a1ad35281f1 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -41,33 +41,23 @@ func (b *Bitfinex) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - } - - fmt2 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"}, - } - - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.Margin, fmt2) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.MarginFunding, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.MarginFunding} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Margin { + ps.ConfigFormat.Delimiter = ":" + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } // Margin WS Currently not fully implemented and causes subscription collisions with spot - err = b.DisableAssetWebsocketSupport(asset.Margin) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := b.DisableAssetWebsocketSupport(asset.Margin); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, asset.Margin, err) } // TODO: Implement Futures and Securities asset types. @@ -162,6 +152,7 @@ func (b *Bitfinex) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index eea24d81326..3648430e884 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -42,37 +42,22 @@ func (b *Bitmex) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - configFmt := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} - standardRequestFmt := ¤cy.PairFormat{Uppercase: true} - spotRequestFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} - - spot := currency.PairStore{RequestFormat: spotRequestFormat, ConfigFormat: configFmt} - err := b.StoreAssetPairFormat(asset.Spot, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - perp := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.PerpetualContract, perp) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - futures := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - index := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.Index, index) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.PerpetualContract, asset.Futures, asset.Index} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Spot { + ps.RequestFormat = ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } - err = b.DisableAssetWebsocketSupport(asset.Index) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := b.DisableAssetWebsocketSupport(asset.Index); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, asset.Index, err) } b.Features = exchange.Features{ @@ -139,6 +124,7 @@ func (b *Bitmex) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 72d25f42925..1e8324e43c5 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -45,33 +45,18 @@ func (b *BTSE) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - fmt2 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err = b.StoreAssetPairFormat(asset.Futures, fmt2) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Spot { + ps.RequestFormat.Delimiter = currency.DashDelimiter + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } b.Features = exchange.Features{ @@ -143,6 +128,7 @@ func (b *BTSE) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index acb3ae66949..a64874be51b 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -61,15 +61,15 @@ func (by *Bybit) SetDefaults() { by.API.CredentialsValidator.RequiresSecret = true for _, n := range assetPairFmts { - ps := currency.PairStore{RequestFormat: n.reqFmt, ConfigFormat: n.cfgFmt} - if err := by.StoreAssetPairFormat(n.asset, ps); err != nil { - log.Errorf(log.ExchangeSys, "%v %v", n.asset, err) + ps := currency.PairStore{AssetEnabled: true, RequestFormat: n.reqFmt, ConfigFormat: n.cfgFmt} + if err := by.StoreAssetPairStore(n.asset, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", by.Name, n.asset, err) } } for _, a := range []asset.Item{asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.USDCMarginedFutures, asset.Options} { if err := by.DisableAssetWebsocketSupport(a); err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", by.Name, a, err) } } diff --git a/exchanges/deribit/deribit_wrapper.go b/exchanges/deribit/deribit_wrapper.go index 38023875caa..67be25905cf 100644 --- a/exchanges/deribit/deribit_wrapper.go +++ b/exchanges/deribit/deribit_wrapper.go @@ -65,13 +65,12 @@ func (d *Deribit) SetDefaults() { dashFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} underscoreFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} - err := d.StoreAssetPairFormat(asset.Spot, currency.PairStore{RequestFormat: underscoreFormat, ConfigFormat: underscoreFormat}) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := d.StoreAssetPairStore(asset.Spot, currency.PairStore{AssetEnabled: true, RequestFormat: underscoreFormat, ConfigFormat: underscoreFormat}); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", d.Name, asset.Spot, err) } - for _, assetType := range []asset.Item{asset.Futures, asset.Options, asset.OptionCombo, asset.FutureCombo} { - if err = d.StoreAssetPairFormat(assetType, currency.PairStore{RequestFormat: dashFormat, ConfigFormat: dashFormat}); err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Futures, asset.Options, asset.OptionCombo, asset.FutureCombo} { + if err := d.StoreAssetPairStore(a, currency.PairStore{AssetEnabled: true, RequestFormat: dashFormat, ConfigFormat: dashFormat}); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", d.Name, a, err) } } @@ -149,6 +148,8 @@ func (d *Deribit) SetDefaults() { }, }, } + + var err error d.Requester, err = request.New(d.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimits()), diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 5df91dd0891..5068deb5258 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -55,6 +55,7 @@ var ( ) var ( + errStoreAssetPairStore = errors.New("error storing asset pair store") errEndpointStringNotFound = errors.New("endpoint string not found") errConfigPairFormatRequiresDelimiter = errors.New("config pair format requires delimiter") errSetDefaultsNotCalled = errors.New("set defaults not called") @@ -990,26 +991,18 @@ func (b *Base) EnableRateLimiter() error { return b.Requester.EnableRateLimiter() } -// StoreAssetPairFormat initialises and stores a defined asset format -func (b *Base) StoreAssetPairFormat(a asset.Item, f currency.PairStore) error { +// StoreAssetPairStore initialises and stores a defined asset format +func (b *Base) StoreAssetPairStore(a asset.Item, f currency.PairStore) error { if a.String() == "" { - return fmt.Errorf("%s cannot add to pairs manager, no asset provided", - b.Name) - } - - if f.RequestFormat == nil { - return fmt.Errorf("%s cannot add to pairs manager, request pair format not provided", - b.Name) + return asset.ErrInvalidAsset } - if f.ConfigFormat == nil { - return fmt.Errorf("%s cannot add to pairs manager, config pair format not provided", - b.Name) + if f.RequestFormat == nil || f.ConfigFormat == nil { + return currency.ErrPairFormatIsNil } if f.ConfigFormat.Delimiter == "" { - return fmt.Errorf("exchange %s cannot set asset %s pair format %w", - b.Name, a, errConfigPairFormatRequiresDelimiter) + return errConfigPairFormatRequiresDelimiter } if b.CurrencyPairs.Pairs == nil { @@ -1017,6 +1010,7 @@ func (b *Base) StoreAssetPairFormat(a asset.Item, f currency.PairStore) error { } b.CurrencyPairs.Pairs[a] = &f + return nil } @@ -1453,9 +1447,7 @@ func getURLTypeFromString(ep string) (URL, error) { // check availability of asset type. func (b *Base) DisableAssetWebsocketSupport(aType asset.Item) error { if !b.SupportsAsset(aType) { - return fmt.Errorf("%s %w", - aType, - asset.ErrNotSupported) + return fmt.Errorf("%s %w", aType, asset.ErrNotSupported) } b.AssetWebsocketSupport.m.Lock() if b.AssetWebsocketSupport.unsupported == nil { diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index e555ca22098..b5e958b4b7e 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -1396,47 +1396,37 @@ func TestGetFormattedPairAndAssetType(t *testing.T) { } } -func TestStoreAssetPairFormat(t *testing.T) { +func TestStoreAssetPairStore(t *testing.T) { b := Base{ Config: &config.Exchange{Name: "kitties"}, } - err := b.StoreAssetPairFormat(asset.Empty, currency.PairStore{}) - if err == nil { - t.Error("error cannot be nil") - } + err := b.StoreAssetPairStore(asset.Empty, currency.PairStore{}) + assert.ErrorIs(t, err, asset.ErrInvalidAsset) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{}) - if err == nil { - t.Error("error cannot be nil") - } + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{}) + assert.ErrorIs(t, err, currency.ErrPairFormatIsNil) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}}) - if err == nil { - t.Error("error cannot be nil") - } + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{RequestFormat: ¤cy.PairFormat{Uppercase: true}}) + assert.ErrorIs(t, err, currency.ErrPairFormatIsNil) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{ RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true}}) - if !errors.Is(err, errConfigPairFormatRequiresDelimiter) { - t.Fatalf("received: '%v' but expected: '%v'", err, errConfigPairFormatRequiresDelimiter) - } + assert.ErrorIs(t, err, errConfigPairFormatRequiresDelimiter) - err = b.StoreAssetPairFormat(asset.Futures, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Futures, currency.PairStore{ RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) + assert.False(t, b.CurrencyPairs.Pairs[asset.Futures].AssetEnabled, "StoreAssetPairStore should not magically enable AssetTypes") - err = b.StoreAssetPairFormat(asset.Futures, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Futures, currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) + assert.True(t, b.CurrencyPairs.Pairs[asset.Futures].AssetEnabled, "AssetEnabled should be respected") } func TestSetGlobalPairsManager(t *testing.T) { @@ -1796,7 +1786,7 @@ func TestFormatSymbol(t *testing.T) { Uppercase: true, }, } - err := b.StoreAssetPairFormat(asset.Spot, spotStore) + err := b.StoreAssetPairStore(asset.Spot, spotStore) if err != nil { t.Error(err) } @@ -1908,7 +1898,7 @@ func TestAssetWebsocketFunctionality(t *testing.T) { t.Fatalf("expected error: %v but received: %v", asset.ErrNotSupported, err) } - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{ RequestFormat: ¤cy.PairFormat{ Uppercase: true, }, diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 76c461cb196..26e99dda6af 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -41,43 +41,21 @@ func (h *HUOBI) SetDefaults() { h.API.CredentialsValidator.RequiresKey = true h.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: false}, - ConfigFormat: ¤cy.PairFormat{ - Delimiter: currency.DashDelimiter, - Uppercase: true, - }, - } - coinFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - futuresFormatting := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err := h.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = h.StoreAssetPairFormat(asset.CoinMarginedFutures, coinFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = h.StoreAssetPairFormat(asset.Futures, futuresFormatting) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.CoinMarginedFutures, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + switch a { + case asset.Spot: + ps.RequestFormat.Uppercase = false + case asset.CoinMarginedFutures: + ps.RequestFormat.Delimiter = currency.DashDelimiter + } + if err := h.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", h.Name, a, err) + } } h.Features = exchange.Features{ @@ -165,6 +143,7 @@ func (h *HUOBI) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error h.Requester, err = request.New(h.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 610350c27f8..8bcfdc14d23 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -43,42 +43,22 @@ func (k *Kraken) SetDefaults() { k.API.CredentialsValidator.RequiresSecret = true k.API.CredentialsValidator.RequiresBase64DecodeSecret = true - pairStore := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Separator: ",", - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - Separator: ",", - }, - } - - futures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Delimiter: currency.UnderscoreDelimiter, - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - - err := k.StoreAssetPairFormat(asset.Spot, pairStore) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - err = k.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + } + if a == asset.Futures { + ps.RequestFormat.Delimiter = currency.UnderscoreDelimiter + } + if err := k.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", k.Name, a, err) + } } - err = k.DisableAssetWebsocketSupport(asset.Futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := k.DisableAssetWebsocketSupport(asset.Futures); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", k.Name, asset.Futures, err) } k.Features = exchange.Features{ @@ -171,6 +151,7 @@ func (k *Kraken) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error k.Requester, err = request.New(k.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(request.NewBasicRateLimit(krakenRateInterval, krakenRequestRate, 1))) diff --git a/exchanges/kucoin/kucoin_wrapper.go b/exchanges/kucoin/kucoin_wrapper.go index 12a2bc42216..d8c1d2a2978 100644 --- a/exchanges/kucoin/kucoin_wrapper.go +++ b/exchanges/kucoin/kucoin_wrapper.go @@ -44,26 +44,21 @@ func (ku *Kucoin) SetDefaults() { ku.API.CredentialsValidator.RequiresSecret = true ku.API.CredentialsValidator.RequiresClientID = true - spot := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - } - futures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, - } - err := ku.StoreAssetPairFormat(asset.Spot, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = ku.StoreAssetPairFormat(asset.Margin, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = ku.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Futures { + ps.RequestFormat.Delimiter = "" + ps.ConfigFormat.Delimiter = currency.UnderscoreDelimiter + } + if err := ku.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", ku.Name, a, err) + } } + ku.Features = exchange.Features{ CurrencyTranslations: currency.NewTranslations(map[currency.Code]currency.Code{ currency.XBT: currency.BTC, @@ -151,6 +146,8 @@ func (ku *Kucoin) SetDefaults() { }, Subscriptions: defaultSubscriptions.Clone(), } + + var err error ku.Requester, err = request.New(ku.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit()))