From f6a95da536dbed3775df7d753bf8ac03d8c86043 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 3 Jun 2024 11:57:31 +1000 Subject: [PATCH] exchanges/request: abstract and consolidate rate limiting code to request package (#1477) * initial consolidation of rate limiting code to request package to reduce bespoke code implementation * continued * finish abstraction * lint * exchanges: fix tests * linter: fix * poloniex: fix auth rate limit not being set * ratelimiter: convert from token to weight * glorious: nits addressed with fire * linter: rip * change func name set -> get * fix test * derbit: impl --------- Co-authored-by: Ryan O'Hara-Reid --- cmd/apichecker/apicheck.go | 6 +- currency/coinmarketcap/coinmarketcap.go | 2 +- .../currencyconverterapi.go | 2 +- .../exchangeratesapi.io/exchangeratesapi.go | 2 +- exchanges/binance/binance_cfutures.go | 2 +- exchanges/binance/binance_types.go | 5 - exchanges/binance/binance_wrapper.go | 2 +- exchanges/binance/ratelimit.go | 240 ++--- exchanges/binance/ratelimit_test.go | 38 +- exchanges/binance/type_convert.go | 22 - exchanges/binanceus/binanceus_wrapper.go | 2 +- exchanges/binanceus/ratelimit.go | 99 +-- exchanges/bitfinex/bitfinex_wrapper.go | 2 +- exchanges/bitfinex/ratelimit.go | 383 ++------ exchanges/bitflyer/bitflyer.go | 2 +- exchanges/bitflyer/bitflyer_wrapper.go | 2 +- exchanges/bitflyer/ratelimit.go | 56 +- exchanges/bithumb/bithumb_wrapper.go | 2 +- exchanges/bithumb/ratelimit.go | 26 +- exchanges/bitmex/bitmex.go | 2 +- exchanges/bitmex/bitmex_wrapper.go | 2 +- exchanges/bitmex/ratelimit.go | 26 +- exchanges/bitstamp/bitstamp_wrapper.go | 2 +- exchanges/btcmarkets/btcmarkets.go | 2 +- exchanges/btcmarkets/btcmarkets_wrapper.go | 2 +- exchanges/btcmarkets/ratelimit.go | 48 +- exchanges/btse/btse_wrapper.go | 2 +- exchanges/btse/ratelimit.go | 28 +- exchanges/bybit/bybit_wrapper.go | 2 +- exchanges/bybit/ratelimit.go | 346 ++------ exchanges/coinbasepro/coinbasepro.go | 2 +- exchanges/coinbasepro/coinbasepro_wrapper.go | 2 +- exchanges/coinbasepro/ratelimit.go | 26 +- exchanges/deribit/deribit_wrapper.go | 2 +- exchanges/deribit/ratelimit.go | 71 +- exchanges/exmo/exmo_wrapper.go | 2 +- exchanges/gateio/gateio_wrapper.go | 2 +- exchanges/gateio/ratelimiter.go | 90 +- exchanges/gemini/gemini.go | 2 +- exchanges/gemini/gemini_wrapper.go | 2 +- exchanges/gemini/ratelimit.go | 26 +- exchanges/hitbtc/hitbtc_wrapper.go | 2 +- exchanges/hitbtc/ratelimit.go | 36 +- exchanges/huobi/huobi_wrapper.go | 2 +- exchanges/huobi/ratelimit.go | 52 +- exchanges/kraken/kraken_wrapper.go | 2 +- exchanges/kucoin/kucoin_ratelimit.go | 187 +--- exchanges/kucoin/kucoin_wrapper.go | 2 +- exchanges/okcoin/okcoin_ratelimit.go | 366 ++------ exchanges/okcoin/okcoin_wrapper.go | 2 +- exchanges/okx/okx.go | 6 +- exchanges/okx/okx_test.go | 4 +- exchanges/okx/okx_websocket.go | 6 - exchanges/okx/okx_wrapper.go | 16 +- exchanges/okx/ratelimit.go | 838 ++++-------------- exchanges/poloniex/poloniex.go | 4 +- exchanges/poloniex/poloniex_wrapper.go | 2 +- exchanges/poloniex/ratelimit.go | 26 +- exchanges/request/limit.go | 108 ++- exchanges/request/options.go | 4 +- exchanges/request/request.go | 20 +- exchanges/request/request_test.go | 84 +- exchanges/request/request_types.go | 2 +- exchanges/yobit/yobit_wrapper.go | 2 +- 64 files changed, 780 insertions(+), 2577 deletions(-) diff --git a/cmd/apichecker/apicheck.go b/cmd/apichecker/apicheck.go index 8bf4594f..38417156 100644 --- a/cmd/apichecker/apicheck.go +++ b/cmd/apichecker/apicheck.go @@ -1226,11 +1226,11 @@ func sendGetReq(path string, result interface{}) error { if strings.Contains(path, "github") { requester, err = request.New("Apichecker", common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Hour, 60))) + request.WithLimiter(request.NewBasicRateLimit(time.Hour, 60, 1))) } else { requester, err = request.New("Apichecker", common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Second, 100))) + request.WithLimiter(request.NewBasicRateLimit(time.Second, 100, 1))) } if err != nil { return err @@ -1249,7 +1249,7 @@ func sendGetReq(path string, result interface{}) error { func sendAuthReq(method, path string, result interface{}) error { requester, err := request.New("Apichecker", common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(time.Second*10, 100))) + request.WithLimiter(request.NewBasicRateLimit(time.Second*10, 100, 1))) if err != nil { return err } diff --git a/currency/coinmarketcap/coinmarketcap.go b/currency/coinmarketcap/coinmarketcap.go index ec8a77e2..ee45fcc8 100644 --- a/currency/coinmarketcap/coinmarketcap.go +++ b/currency/coinmarketcap/coinmarketcap.go @@ -39,7 +39,7 @@ func (c *Coinmarketcap) SetDefaults() { var err error c.Requester, err = request.New(c.Name, common.NewHTTPClientWithTimeout(defaultTimeOut), - request.WithLimiter(request.NewBasicRateLimit(RateInterval, BasicRequestRate)), + request.WithLimiter(request.NewBasicRateLimit(RateInterval, BasicRequestRate, 1)), ) if err != nil { log.Errorln(log.Global, err) diff --git a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go index f1a1f8b0..afc99479 100644 --- a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go +++ b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go @@ -26,7 +26,7 @@ func (c *CurrencyConverter) Setup(config base.Settings) error { var err error c.Requester, err = request.New(c.Name, common.NewHTTPClientWithTimeout(base.DefaultTimeOut), - request.WithLimiter(request.NewBasicRateLimit(rateInterval, requestRate))) + request.WithLimiter(request.NewBasicRateLimit(rateInterval, requestRate, 1))) return err } diff --git a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go index d4c853de..1890caab 100644 --- a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go +++ b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go @@ -32,7 +32,7 @@ func (e *ExchangeRates) Setup(config base.Settings) error { var err error e.Requester, err = request.New(e.Name, common.NewHTTPClientWithTimeout(base.DefaultTimeOut), - request.WithLimiter(request.NewBasicRateLimit(rateLimitInterval, requestRate))) + request.WithLimiter(request.NewBasicRateLimit(rateLimitInterval, requestRate, 1))) return err } diff --git a/exchanges/binance/binance_cfutures.go b/exchanges/binance/binance_cfutures.go index 92cd3120..ac09e6ad 100644 --- a/exchanges/binance/binance_cfutures.go +++ b/exchanges/binance/binance_cfutures.go @@ -722,7 +722,7 @@ func getKlineRateBudget(limit int64) request.EndpointLimit { rateBudget := cFuturesDefaultRate switch { case limit > 0 && limit < 100: - rateBudget = cFuturesKline100Rate + rateBudget = cFuturesDefaultRate case limit >= 100 && limit < 500: rateBudget = cFuturesKline500Rate case limit >= 500 && limit < 1000: diff --git a/exchanges/binance/binance_types.go b/exchanges/binance/binance_types.go index ceb5316d..f21206ad 100644 --- a/exchanges/binance/binance_types.go +++ b/exchanges/binance/binance_types.go @@ -753,11 +753,6 @@ type UserAccountStream struct { ListenKey string `json:"listenKey"` } -type wsAccountInfo struct { - Stream string `json:"stream"` - Data WsAccountInfoData `json:"data"` -} - // WsAccountInfoData defines websocket account info data type WsAccountInfoData struct { CanDeposit bool `json:"D"` diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index cf59559e..4c15f27e 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -198,7 +198,7 @@ func (b *Binance) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimits())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/binance/ratelimit.go b/exchanges/binance/ratelimit.go index c56f1603..616a084a 100644 --- a/exchanges/binance/ratelimit.go +++ b/exchanges/binance/ratelimit.go @@ -1,12 +1,9 @@ package binance import ( - "context" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -77,7 +74,6 @@ const ( cFuturesOrderbook100Rate cFuturesOrderbook500Rate cFuturesOrderbook1000Rate - cFuturesKline100Rate cFuturesKline500Rate cFuturesKline1000Rate cFuturesKlineMaxRate @@ -96,173 +92,79 @@ const ( uFuturesSetMultiAssetMarginRate ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - SpotRate *rate.Limiter - SpotOrdersRate *rate.Limiter - UFuturesRate *rate.Limiter - UFuturesOrdersRate *rate.Limiter - CFuturesRate *rate.Limiter - CFuturesOrdersRate *rate.Limiter -} +// GetRateLimits returns the rate limit for the exchange +func GetRateLimits() request.RateLimitDefinitions { + spotDefaultLimiter := request.NewRateLimit(spotInterval, spotRequestRate) + spotOrderLimiter := request.NewRateLimit(spotOrderInterval, spotOrderRequestRate) + usdMarginedFuturesLimiter := request.NewRateLimit(uFuturesInterval, uFuturesRequestRate) + usdMarginedFuturesOrdersLimiter := request.NewRateLimit(uFuturesOrderInterval, uFuturesOrderRequestRate) + coinMarginedFuturesLimiter := request.NewRateLimit(cFuturesInterval, cFuturesRequestRate) + coinMarginedFuturesOrdersLimiter := request.NewRateLimit(cFuturesOrderInterval, cFuturesOrderRequestRate) -// Limit executes rate limiting functionality for Binance -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch f { - case spotDefaultRate: - limiter, tokens = r.SpotRate, 1 - case spotOrderbookTickerAllRate, - spotSymbolPriceAllRate: - limiter, tokens = r.SpotRate, 2 - case spotHistoricalTradesRate, - spotOrderbookDepth500Rate: - limiter, tokens = r.SpotRate, 5 - case spotOrderbookDepth1000Rate, - spotAccountInformationRate, - spotExchangeInfo: - limiter, tokens = r.SpotRate, 10 - case spotPriceChangeAllRate: - limiter, tokens = r.SpotRate, 40 - case spotOrderbookDepth5000Rate: - limiter, tokens = r.SpotRate, 50 - case spotOrderRate: - limiter, tokens = r.SpotOrdersRate, 1 - case spotOrderQueryRate: - limiter, tokens = r.SpotOrdersRate, 2 - case spotOpenOrdersSpecificRate: - limiter, tokens = r.SpotOrdersRate, 3 - case spotAllOrdersRate: - limiter, tokens = r.SpotOrdersRate, 10 - case spotOpenOrdersAllRate: - limiter, tokens = r.SpotOrdersRate, 40 - case uFuturesDefaultRate, - uFuturesKline100Rate: - limiter, tokens = r.UFuturesRate, 1 - case uFuturesOrderbook50Rate, - uFuturesKline500Rate, - uFuturesOrderbookTickerAllRate: - limiter, tokens = r.UFuturesRate, 2 - case uFuturesOrderbook100Rate, - uFuturesKline1000Rate, - uFuturesAccountInformationRate: - limiter, tokens = r.UFuturesRate, 5 - case uFuturesOrderbook500Rate, - uFuturesKlineMaxRate: - limiter, tokens = r.UFuturesRate, 10 - case uFuturesOrderbook1000Rate, - uFuturesHistoricalTradesRate: - limiter, tokens = r.UFuturesRate, 20 - case uFuturesTickerPriceHistoryRate: - limiter, tokens = r.UFuturesRate, 40 - case uFuturesOrdersDefaultRate: - limiter, tokens = r.UFuturesOrdersRate, 1 - case uFuturesBatchOrdersRate, - uFuturesGetAllOrdersRate: - limiter, tokens = r.UFuturesOrdersRate, 5 - case uFuturesCountdownCancelRate: - limiter, tokens = r.UFuturesOrdersRate, 10 - case uFuturesCurrencyForceOrdersRate, - uFuturesSymbolOrdersRate: - limiter, tokens = r.UFuturesOrdersRate, 20 - case uFuturesIncomeHistoryRate: - limiter, tokens = r.UFuturesOrdersRate, 30 - case uFuturesPairOrdersRate, - uFuturesGetAllOpenOrdersRate: - limiter, tokens = r.UFuturesOrdersRate, 40 - case uFuturesAllForceOrdersRate: - limiter, tokens = r.UFuturesOrdersRate, 50 - case cFuturesKline100Rate: - limiter, tokens = r.CFuturesRate, 1 - case cFuturesKline500Rate, - cFuturesOrderbookTickerAllRate: - limiter, tokens = r.CFuturesRate, 2 - case cFuturesKline1000Rate, - cFuturesAccountInformationRate: - limiter, tokens = r.CFuturesRate, 5 - case cFuturesKlineMaxRate, - cFuturesIndexMarkPriceRate: - limiter, tokens = r.CFuturesRate, 10 - case cFuturesHistoricalTradesRate, - cFuturesCurrencyForceOrdersRate: - limiter, tokens = r.CFuturesRate, 20 - case cFuturesTickerPriceHistoryRate: - limiter, tokens = r.CFuturesRate, 40 - case cFuturesAllForceOrdersRate: - limiter, tokens = r.CFuturesRate, 50 - case cFuturesOrdersDefaultRate: - limiter, tokens = r.CFuturesOrdersRate, 1 - case cFuturesBatchOrdersRate, - cFuturesGetAllOpenOrdersRate: - limiter, tokens = r.CFuturesOrdersRate, 5 - case cFuturesCancelAllOrdersRate: - limiter, tokens = r.CFuturesOrdersRate, 10 - case cFuturesIncomeHistoryRate, - cFuturesSymbolOrdersRate: - limiter, tokens = r.CFuturesOrdersRate, 20 - case cFuturesPairOrdersRate: - limiter, tokens = r.CFuturesOrdersRate, 40 - case cFuturesOrderbook50Rate: - limiter, tokens = r.CFuturesRate, 2 - case cFuturesOrderbook100Rate: - limiter, tokens = r.CFuturesRate, 5 - case cFuturesOrderbook500Rate: - limiter, tokens = r.CFuturesRate, 10 - case cFuturesOrderbook1000Rate: - limiter, tokens = r.CFuturesRate, 20 - case cFuturesDefaultRate: - limiter, tokens = r.CFuturesRate, 1 - case uFuturesMultiAssetMarginRate: - limiter, tokens = r.UFuturesRate, 30 - case uFuturesSetMultiAssetMarginRate: - limiter, tokens = r.UFuturesRate, 1 - default: - limiter, tokens = r.SpotRate, 1 + return request.RateLimitDefinitions{ + spotDefaultRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 1), + spotOrderbookTickerAllRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 2), + spotSymbolPriceAllRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 2), + spotHistoricalTradesRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 5), + spotOrderbookDepth500Rate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 5), + spotOrderbookDepth1000Rate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 10), + spotAccountInformationRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 10), + spotExchangeInfo: request.GetRateLimiterWithWeight(spotDefaultLimiter, 10), + spotPriceChangeAllRate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 40), + spotOrderbookDepth5000Rate: request.GetRateLimiterWithWeight(spotDefaultLimiter, 50), + spotOrderRate: request.GetRateLimiterWithWeight(spotOrderLimiter, 1), + spotOrderQueryRate: request.GetRateLimiterWithWeight(spotOrderLimiter, 2), + spotOpenOrdersSpecificRate: request.GetRateLimiterWithWeight(spotOrderLimiter, 3), + spotAllOrdersRate: request.GetRateLimiterWithWeight(spotOrderLimiter, 10), + spotOpenOrdersAllRate: request.GetRateLimiterWithWeight(spotOrderLimiter, 40), + uFuturesDefaultRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 1), + uFuturesKline100Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 1), + uFuturesOrderbook50Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 2), + uFuturesKline500Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 2), + uFuturesOrderbookTickerAllRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 2), + uFuturesOrderbook100Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 5), + uFuturesKline1000Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 5), + uFuturesAccountInformationRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 5), + uFuturesOrderbook500Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 10), + uFuturesKlineMaxRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 10), + uFuturesOrderbook1000Rate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 20), + uFuturesHistoricalTradesRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 20), + uFuturesTickerPriceHistoryRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 40), + uFuturesOrdersDefaultRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 1), + uFuturesBatchOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 5), + uFuturesGetAllOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 5), + uFuturesCountdownCancelRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 10), + uFuturesCurrencyForceOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 20), + uFuturesSymbolOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 20), + uFuturesIncomeHistoryRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 30), + uFuturesPairOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 40), + uFuturesGetAllOpenOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 40), + uFuturesAllForceOrdersRate: request.GetRateLimiterWithWeight(usdMarginedFuturesOrdersLimiter, 50), + cFuturesDefaultRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 1), + cFuturesKline500Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 2), + cFuturesOrderbookTickerAllRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 2), + cFuturesKline1000Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 5), + cFuturesAccountInformationRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 5), + cFuturesKlineMaxRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 10), + cFuturesIndexMarkPriceRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 10), + cFuturesHistoricalTradesRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 20), + cFuturesCurrencyForceOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 20), + cFuturesTickerPriceHistoryRate: request.GetRateLimiterWithWeight(coinMarginedFuturesLimiter, 40), + cFuturesAllForceOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 50), + cFuturesOrdersDefaultRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 1), + cFuturesBatchOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 5), + cFuturesGetAllOpenOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 5), + cFuturesCancelAllOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 10), + cFuturesIncomeHistoryRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 20), + cFuturesSymbolOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 20), + cFuturesPairOrdersRate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 40), + cFuturesOrderbook50Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 2), + cFuturesOrderbook100Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 5), + cFuturesOrderbook500Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 10), + cFuturesOrderbook1000Rate: request.GetRateLimiterWithWeight(coinMarginedFuturesOrdersLimiter, 20), + uFuturesMultiAssetMarginRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 30), + uFuturesSetMultiAssetMarginRate: request.GetRateLimiterWithWeight(usdMarginedFuturesLimiter, 1), } - - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - // Consume tokens 1 at a time as this avoids needing burst capacity in the limiter, - // which would otherwise allow the rate limit to be exceeded over short periods - reserves[i] = limiter.Reserve() - finalDelay = reserves[i].Delay() - } - - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - // Cancel all potential reservations to free up rate limiter if deadline - // is exceeded. - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - - time.Sleep(finalDelay) - return nil -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - SpotRate: request.NewRateLimit(spotInterval, spotRequestRate), - SpotOrdersRate: request.NewRateLimit(spotOrderInterval, spotOrderRequestRate), - UFuturesRate: request.NewRateLimit(uFuturesInterval, uFuturesRequestRate), - UFuturesOrdersRate: request.NewRateLimit(uFuturesOrderInterval, uFuturesOrderRequestRate), - CFuturesRate: request.NewRateLimit(cFuturesInterval, cFuturesRequestRate), - CFuturesOrdersRate: request.NewRateLimit(cFuturesOrderInterval, cFuturesOrderRequestRate), - } -} - -func bestPriceLimit(symbol string) request.EndpointLimit { - if symbol == "" { - return spotOrderbookTickerAllRate - } - - return spotDefaultRate } func openOrdersLimit(symbol string) request.EndpointLimit { diff --git a/exchanges/binance/ratelimit_test.go b/exchanges/binance/ratelimit_test.go index 2b511966..102d23c3 100644 --- a/exchanges/binance/ratelimit_test.go +++ b/exchanges/binance/ratelimit_test.go @@ -3,9 +3,11 @@ package binance import ( "context" "errors" + "net/http" "testing" "time" + "github.com/stretchr/testify/require" "github.com/thrasher-corp/gocryptotrader/exchanges/request" ) @@ -18,19 +20,21 @@ func TestRateLimit_Limit(t *testing.T) { Limit request.EndpointLimit Deadline time.Time }{ - "All Orderbooks Ticker": {Expected: spotOrderbookTickerAllRate, Limit: bestPriceLimit("")}, - "Orderbook Ticker": {Expected: spotDefaultRate, Limit: bestPriceLimit(symbol)}, - "Open Orders": {Expected: spotOpenOrdersSpecificRate, Limit: openOrdersLimit(symbol)}, - "Orderbook Depth 5": {Expected: spotDefaultRate, Limit: orderbookLimit(5)}, - "Orderbook Depth 10": {Expected: spotDefaultRate, Limit: orderbookLimit(10)}, - "Orderbook Depth 20": {Expected: spotDefaultRate, Limit: orderbookLimit(20)}, - "Orderbook Depth 50": {Expected: spotDefaultRate, Limit: orderbookLimit(50)}, - "Orderbook Depth 100": {Expected: spotDefaultRate, Limit: orderbookLimit(100)}, - "Orderbook Depth 500": {Expected: spotOrderbookDepth500Rate, Limit: orderbookLimit(500)}, - "Orderbook Depth 1000": {Expected: spotOrderbookDepth1000Rate, Limit: orderbookLimit(1000)}, - "Orderbook Depth 5000": {Expected: spotOrderbookDepth5000Rate, Limit: orderbookLimit(5000)}, - "Exceeds deadline": {Expected: spotOrderbookDepth5000Rate, Limit: orderbookLimit(5000), Deadline: time.Now().Add(time.Nanosecond)}, + "Open Orders": {Expected: spotOpenOrdersSpecificRate, Limit: openOrdersLimit(symbol)}, + "Orderbook Depth 5": {Expected: spotDefaultRate, Limit: orderbookLimit(5)}, + "Orderbook Depth 10": {Expected: spotDefaultRate, Limit: orderbookLimit(10)}, + "Orderbook Depth 20": {Expected: spotDefaultRate, Limit: orderbookLimit(20)}, + "Orderbook Depth 50": {Expected: spotDefaultRate, Limit: orderbookLimit(50)}, + "Orderbook Depth 100": {Expected: spotDefaultRate, Limit: orderbookLimit(100)}, + "Orderbook Depth 500": {Expected: spotOrderbookDepth500Rate, Limit: orderbookLimit(500)}, + "Orderbook Depth 1000": {Expected: spotOrderbookDepth1000Rate, Limit: orderbookLimit(1000)}, + "Orderbook Depth 5000": {Expected: spotOrderbookDepth5000Rate, Limit: orderbookLimit(5000)}, + "Exceeds deadline": {Expected: spotOrderbookDepth5000Rate, Limit: orderbookLimit(5000), Deadline: time.Now().Add(time.Nanosecond)}, } + + rl, err := request.New("rateLimitTest", &http.Client{}, request.WithLimiter(GetRateLimits())) + require.NoError(t, err) + for name, tt := range testTable { tt := tt t.Run(name, func(t *testing.T) { @@ -48,8 +52,7 @@ func TestRateLimit_Limit(t *testing.T) { defer cancel() } - l := SetRateLimit() - if err := l.Limit(ctx, tt.Limit); err != nil && !errors.Is(err, context.DeadlineExceeded) { + if err := rl.InitiateRateLimit(ctx, tt.Limit); err != nil && !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("error applying rate limit: %v", err) } }) @@ -64,13 +67,16 @@ func TestRateLimit_LimitStatic(t *testing.T) { "All Price Changes": spotPriceChangeAllRate, "All Orders": spotAllOrdersRate, } + + rl, err := request.New("rateLimitTest2", http.DefaultClient, request.WithLimiter(GetRateLimits())) + require.NoError(t, err) + for name, tt := range testTable { tt := tt t.Run(name, func(t *testing.T) { t.Parallel() - l := SetRateLimit() - if err := l.Limit(context.Background(), tt); err != nil { + if err := rl.InitiateRateLimit(context.Background(), tt); err != nil { t.Fatalf("error applying rate limit: %v", err) } }) diff --git a/exchanges/binance/type_convert.go b/exchanges/binance/type_convert.go index 69db96ef..d03453f1 100644 --- a/exchanges/binance/type_convert.go +++ b/exchanges/binance/type_convert.go @@ -325,28 +325,6 @@ func (a *WebsocketDepthStream) UnmarshalJSON(data []byte) error { return nil } -// UnmarshalJSON deserialises the JSON info, including the timestamp -func (a *wsAccountInfo) UnmarshalJSON(data []byte) error { - type Alias wsAccountInfo - aux := &struct { - Data struct { - EventTime binanceTime `json:"E"` - LastUpdated binanceTime `json:"u"` - *WsAccountInfoData - } `json:"data"` - *Alias - }{ - Alias: (*Alias)(a), - } - if err := json.Unmarshal(data, &aux); err != nil { - return err - } - a.Data = *aux.Data.WsAccountInfoData - a.Data.EventTime = aux.Data.EventTime.Time() - a.Data.LastUpdated = aux.Data.LastUpdated.Time() - return nil -} - // UnmarshalJSON deserialises the JSON info, including the timestamp func (a *wsAccountPosition) UnmarshalJSON(data []byte) error { type Alias wsAccountPosition diff --git a/exchanges/binanceus/binanceus_wrapper.go b/exchanges/binanceus/binanceus_wrapper.go index 3bb71427..e6ae5b74 100644 --- a/exchanges/binanceus/binanceus_wrapper.go +++ b/exchanges/binanceus/binanceus_wrapper.go @@ -124,7 +124,7 @@ func (bi *Binanceus) SetDefaults() { } bi.Requester, err = request.New(bi.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/binanceus/ratelimit.go b/exchanges/binanceus/ratelimit.go index be9e510c..34816a3a 100644 --- a/exchanges/binanceus/ratelimit.go +++ b/exchanges/binanceus/ratelimit.go @@ -1,12 +1,9 @@ package binanceus import ( - "context" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -41,78 +38,30 @@ const ( spotAccountInformationRate ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - SpotRate *rate.Limiter - SpotOrdersRate *rate.Limiter -} - -// Limit executes rate limiting functionality for Binance -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch f { - case spotDefaultRate: - limiter, tokens = r.SpotRate, 1 - case spotOrderbookTickerAllRate, - spotSymbolPriceAllRate: - limiter, tokens = r.SpotRate, 2 - case spotHistoricalTradesRate, - spotOrderbookDepth500Rate: - limiter, tokens = r.SpotRate, 5 - case spotOrderbookDepth1000Rate, - spotAccountInformationRate, - spotExchangeInfo, - spotTradesQueryRate: - limiter, tokens = r.SpotRate, 10 - case spotPriceChangeAllRate: - limiter, tokens = r.SpotRate, 40 - case spotOrderbookDepth5000Rate: - limiter, tokens = r.SpotRate, 50 - case spotOrderRate: - limiter, tokens = r.SpotOrdersRate, 1 - case spotOrderQueryRate, - spotSingleOCOOrderRate: - limiter, tokens = r.SpotOrdersRate, 2 - case spotOpenOrdersSpecificRate: - limiter, tokens = r.SpotOrdersRate, 3 - case spotAllOrdersRate, - spotAllOCOOrdersRate: - limiter, tokens = r.SpotOrdersRate, 10 - case spotOrderRateLimitRate: - limiter, tokens = r.SpotOrdersRate, 20 - case spotOpenOrdersAllRate: - limiter, tokens = r.SpotOrdersRate, 40 - default: - limiter, tokens = r.SpotRate, 1 - } - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - // Consume tokens 1 at a time as this avoids needing burst capacity in the limiter, - // which would otherwise allow the rate limit to be exceeded over short periods - reserves[i] = limiter.Reserve() - finalDelay = reserves[i].Delay() - } - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - // Cancel all potential reservations to free up rate limiter if deadline - // is exceeded. - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - time.Sleep(finalDelay) - return nil -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - SpotRate: request.NewRateLimit(spotInterval, spotRequestRate), - SpotOrdersRate: request.NewRateLimit(spotOrderInterval, spotOrderRequestRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + spotRate := request.NewRateLimit(spotInterval, spotRequestRate) + spotOrdersRate := request.NewRateLimit(spotOrderInterval, spotOrderRequestRate) + return request.RateLimitDefinitions{ + spotDefaultRate: request.GetRateLimiterWithWeight(spotRate, 1), + spotOrderbookTickerAllRate: request.GetRateLimiterWithWeight(spotRate, 2), + spotSymbolPriceAllRate: request.GetRateLimiterWithWeight(spotRate, 2), + spotHistoricalTradesRate: request.GetRateLimiterWithWeight(spotRate, 5), + spotOrderbookDepth500Rate: request.GetRateLimiterWithWeight(spotRate, 5), + spotOrderbookDepth1000Rate: request.GetRateLimiterWithWeight(spotRate, 10), + spotAccountInformationRate: request.GetRateLimiterWithWeight(spotRate, 10), + spotExchangeInfo: request.GetRateLimiterWithWeight(spotRate, 10), + spotTradesQueryRate: request.GetRateLimiterWithWeight(spotRate, 10), + spotPriceChangeAllRate: request.GetRateLimiterWithWeight(spotRate, 40), + spotOrderbookDepth5000Rate: request.GetRateLimiterWithWeight(spotRate, 50), + spotOrderRate: request.GetRateLimiterWithWeight(spotOrdersRate, 1), + spotOrderQueryRate: request.GetRateLimiterWithWeight(spotOrdersRate, 2), + spotSingleOCOOrderRate: request.GetRateLimiterWithWeight(spotOrdersRate, 2), + spotOpenOrdersSpecificRate: request.GetRateLimiterWithWeight(spotOrdersRate, 3), + spotAllOrdersRate: request.GetRateLimiterWithWeight(spotOrdersRate, 10), + spotAllOCOOrdersRate: request.GetRateLimiterWithWeight(spotOrdersRate, 10), + spotOrderRateLimitRate: request.GetRateLimiterWithWeight(spotOrdersRate, 20), + spotOpenOrdersAllRate: request.GetRateLimiterWithWeight(spotOrdersRate, 40), } } diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 86384d01..41e21140 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -163,7 +163,7 @@ func (b *Bitfinex) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/bitfinex/ratelimit.go b/exchanges/bitfinex/ratelimit.go index ff30f9d8..8c6b0876 100644 --- a/exchanges/bitfinex/ratelimit.go +++ b/exchanges/bitfinex/ratelimit.go @@ -1,12 +1,9 @@ package bitfinex import ( - "context" - "errors" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -175,316 +172,84 @@ const ( lends ) -// RateLimit implements the rate.Limiter interface -type RateLimit struct { - PlatformStatus *rate.Limiter - TickerBatch *rate.Limiter - Ticker *rate.Limiter - Trade *rate.Limiter - Orderbook *rate.Limiter - Stats *rate.Limiter - Candle *rate.Limiter - Configs *rate.Limiter - Status *rate.Limiter - Liquid *rate.Limiter - LeaderBoard *rate.Limiter - MarketAveragePrice *rate.Limiter - Fx *rate.Limiter - AccountWalletBalance *rate.Limiter - AccountWalletHistory *rate.Limiter - // Orders - - RetrieveOrder *rate.Limiter - SubmitOrder *rate.Limiter - UpdateOrder *rate.Limiter - CancelOrder *rate.Limiter - OrderBatch *rate.Limiter - CancelBatch *rate.Limiter - OrderHistory *rate.Limiter - GetOrderTrades *rate.Limiter - GetTrades *rate.Limiter - GetLedgers *rate.Limiter - // Positions - - GetAccountMarginInfo *rate.Limiter - GetActivePositions *rate.Limiter - ClaimPosition *rate.Limiter - GetPositionHistory *rate.Limiter - GetPositionAudit *rate.Limiter - UpdateCollateralOnPosition *rate.Limiter - // Margin funding - - GetActiveFundingOffers *rate.Limiter - SubmitFundingOffer *rate.Limiter - CancelFundingOffer *rate.Limiter - CancelAllFundingOffer *rate.Limiter - CloseFunding *rate.Limiter - FundingAutoRenew *rate.Limiter - KeepFunding *rate.Limiter - GetOffersHistory *rate.Limiter - GetFundingLoans *rate.Limiter - GetFundingLoanHistory *rate.Limiter - GetFundingCredits *rate.Limiter - GetFundingCreditsHistory *rate.Limiter - GetFundingTrades *rate.Limiter - GetFundingInfo *rate.Limiter - // Account actions - GetUserInfo *rate.Limiter - TransferBetweenWallets *rate.Limiter - GetDepositAddress *rate.Limiter - Withdrawal *rate.Limiter - GetMovements *rate.Limiter - GetAlertList *rate.Limiter - SetPriceAlert *rate.Limiter - DeletePriceAlert *rate.Limiter - GetBalanceForOrdersOffers *rate.Limiter - UserSettingsWrite *rate.Limiter - UserSettingsRead *rate.Limiter - UserSettingsDelete *rate.Limiter - // Account V1 endpoints - GetAccountFees *rate.Limiter - GetWithdrawalFees *rate.Limiter - GetAccountSummary *rate.Limiter - NewDepositAddress *rate.Limiter - GetKeyPermissions *rate.Limiter - GetMarginInfo *rate.Limiter - GetAccountBalance *rate.Limiter - WalletTransfer *rate.Limiter - WithdrawV1 *rate.Limiter - OrderV1 *rate.Limiter - OrderMulti *rate.Limiter - StatsV1 *rate.Limiter - Fundingbook *rate.Limiter - Lends *rate.Limiter -} - -// Limit limits outbound requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case platformStatus: - return r.PlatformStatus.Wait(ctx) - case tickerBatch: - return r.TickerBatch.Wait(ctx) - case tickerFunction: - return r.Ticker.Wait(ctx) - case tradeRateLimit: - return r.Trade.Wait(ctx) - case orderbookFunction: - return r.Orderbook.Wait(ctx) - case stats: - return r.Stats.Wait(ctx) - case candle: - return r.Candle.Wait(ctx) - case configs: - return r.Configs.Wait(ctx) - case status: - return r.Stats.Wait(ctx) - case liquid: - return r.Liquid.Wait(ctx) - case leaderBoard: - return r.LeaderBoard.Wait(ctx) - case marketAveragePrice: - return r.MarketAveragePrice.Wait(ctx) - case fx: - return r.Fx.Wait(ctx) - case accountWalletBalance: - return r.AccountWalletBalance.Wait(ctx) - case accountWalletHistory: - return r.AccountWalletHistory.Wait(ctx) - case retrieveOrder: - return r.RetrieveOrder.Wait(ctx) - case submitOrder: - return r.SubmitOrder.Wait(ctx) - case updateOrder: - return r.UpdateOrder.Wait(ctx) - case cancelOrder: - return r.CancelOrder.Wait(ctx) - case orderBatch: - return r.OrderBatch.Wait(ctx) - case cancelBatch: - return r.CancelBatch.Wait(ctx) - case orderHistory: - return r.OrderHistory.Wait(ctx) - case getOrderTrades: - return r.GetOrderTrades.Wait(ctx) - case getTrades: - return r.GetTrades.Wait(ctx) - case getLedgers: - return r.GetLedgers.Wait(ctx) - case getAccountMarginInfo: - return r.GetAccountMarginInfo.Wait(ctx) - case getActivePositions: - return r.GetActivePositions.Wait(ctx) - case claimPosition: - return r.ClaimPosition.Wait(ctx) - case getPositionHistory: - return r.GetPositionHistory.Wait(ctx) - case getPositionAudit: - return r.GetPositionAudit.Wait(ctx) - case updateCollateralOnPosition: - return r.UpdateCollateralOnPosition.Wait(ctx) - case getActiveFundingOffers: - return r.GetActiveFundingOffers.Wait(ctx) - case submitFundingOffer: - return r.SubmitFundingOffer.Wait(ctx) - case cancelFundingOffer: - return r.CancelFundingOffer.Wait(ctx) - case cancelAllFundingOffer: - return r.CancelAllFundingOffer.Wait(ctx) - case closeFunding: - return r.CloseFunding.Wait(ctx) - case fundingAutoRenew: - return r.FundingAutoRenew.Wait(ctx) - case keepFunding: - return r.KeepFunding.Wait(ctx) - case getOffersHistory: - return r.GetOffersHistory.Wait(ctx) - case getFundingLoans: - return r.GetFundingLoans.Wait(ctx) - case getFundingLoanHistory: - return r.GetFundingLoanHistory.Wait(ctx) - case getFundingCredits: - return r.GetFundingCredits.Wait(ctx) - case getFundingCreditsHistory: - return r.GetFundingCreditsHistory.Wait(ctx) - case getFundingTrades: - return r.GetFundingTrades.Wait(ctx) - case getFundingInfo: - return r.GetFundingInfo.Wait(ctx) - case getUserInfo: - return r.GetUserInfo.Wait(ctx) - case transferBetweenWallets: - return r.TransferBetweenWallets.Wait(ctx) - case getDepositAddress: - return r.GetDepositAddress.Wait(ctx) - case withdrawal: - return r.Withdrawal.Wait(ctx) - case getMovements: - return r.GetMovements.Wait(ctx) - case getAlertList: - return r.GetAlertList.Wait(ctx) - case setPriceAlert: - return r.SetPriceAlert.Wait(ctx) - case deletePriceAlert: - return r.DeletePriceAlert.Wait(ctx) - case getBalanceForOrdersOffers: - return r.GetBalanceForOrdersOffers.Wait(ctx) - case userSettingsWrite: - return r.UserSettingsWrite.Wait(ctx) - case userSettingsRead: - return r.UserSettingsRead.Wait(ctx) - case userSettingsDelete: - return r.UserSettingsDelete.Wait(ctx) - - // Bitfinex V1 API - case getAccountFees: - return r.GetAccountFees.Wait(ctx) - case getWithdrawalFees: - return r.GetWithdrawalFees.Wait(ctx) - case getAccountSummary: - return r.GetAccountSummary.Wait(ctx) - case newDepositAddress: - return r.NewDepositAddress.Wait(ctx) - case getKeyPermissions: - return r.GetKeyPermissions.Wait(ctx) - case getMarginInfo: - return r.GetMarginInfo.Wait(ctx) - case getAccountBalance: - return r.GetAccountBalance.Wait(ctx) - case walletTransfer: - return r.WalletTransfer.Wait(ctx) - case withdrawV1: - return r.WithdrawV1.Wait(ctx) - case orderV1: - return r.OrderV1.Wait(ctx) - case orderMulti: - return r.OrderMulti.Wait(ctx) - case statsV1: - return r.Stats.Wait(ctx) - case fundingbook: - return r.Fundingbook.Wait(ctx) - case lends: - return r.Lends.Wait(ctx) - default: - return errors.New("endpoint rate limit functionality not found") - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - PlatformStatus: request.NewRateLimit(requestLimitInterval, platformStatusReqRate), - TickerBatch: request.NewRateLimit(requestLimitInterval, tickerBatchReqRate), - Ticker: request.NewRateLimit(requestLimitInterval, tickerReqRate), - Trade: request.NewRateLimit(requestLimitInterval, tradeReqRate), - Orderbook: request.NewRateLimit(requestLimitInterval, orderbookReqRate), - Stats: request.NewRateLimit(requestLimitInterval, statsReqRate), - Candle: request.NewRateLimit(requestLimitInterval, candleReqRate), - Configs: request.NewRateLimit(requestLimitInterval, configsReqRate), - Status: request.NewRateLimit(requestLimitInterval, statusReqRate), - Liquid: request.NewRateLimit(requestLimitInterval, liquidReqRate), - LeaderBoard: request.NewRateLimit(requestLimitInterval, leaderBoardReqRate), - MarketAveragePrice: request.NewRateLimit(requestLimitInterval, marketAveragePriceReqRate), - Fx: request.NewRateLimit(requestLimitInterval, fxReqRate), - AccountWalletBalance: request.NewRateLimit(requestLimitInterval, accountWalletBalanceReqRate), - AccountWalletHistory: request.NewRateLimit(requestLimitInterval, accountWalletHistoryReqRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + platformStatus: request.NewRateLimitWithWeight(requestLimitInterval, platformStatusReqRate, 1), + tickerBatch: request.NewRateLimitWithWeight(requestLimitInterval, tickerBatchReqRate, 1), + tickerFunction: request.NewRateLimitWithWeight(requestLimitInterval, tickerReqRate, 1), + tradeRateLimit: request.NewRateLimitWithWeight(requestLimitInterval, tradeReqRate, 1), + orderbookFunction: request.NewRateLimitWithWeight(requestLimitInterval, orderbookReqRate, 1), + stats: request.NewRateLimitWithWeight(requestLimitInterval, statsReqRate, 1), + candle: request.NewRateLimitWithWeight(requestLimitInterval, candleReqRate, 1), + configs: request.NewRateLimitWithWeight(requestLimitInterval, configsReqRate, 1), + status: request.NewRateLimitWithWeight(requestLimitInterval, statusReqRate, 1), + liquid: request.NewRateLimitWithWeight(requestLimitInterval, liquidReqRate, 1), + leaderBoard: request.NewRateLimitWithWeight(requestLimitInterval, leaderBoardReqRate, 1), + marketAveragePrice: request.NewRateLimitWithWeight(requestLimitInterval, marketAveragePriceReqRate, 1), + fx: request.NewRateLimitWithWeight(requestLimitInterval, fxReqRate, 1), + accountWalletBalance: request.NewRateLimitWithWeight(requestLimitInterval, accountWalletBalanceReqRate, 1), + accountWalletHistory: request.NewRateLimitWithWeight(requestLimitInterval, accountWalletHistoryReqRate, 1), // Orders - - RetrieveOrder: request.NewRateLimit(requestLimitInterval, retrieveOrderReqRate), - SubmitOrder: request.NewRateLimit(requestLimitInterval, submitOrderReqRate), - UpdateOrder: request.NewRateLimit(requestLimitInterval, updateOrderReqRate), - CancelOrder: request.NewRateLimit(requestLimitInterval, cancelOrderReqRate), - OrderBatch: request.NewRateLimit(requestLimitInterval, orderBatchReqRate), - CancelBatch: request.NewRateLimit(requestLimitInterval, cancelBatchReqRate), - OrderHistory: request.NewRateLimit(requestLimitInterval, orderHistoryReqRate), - GetOrderTrades: request.NewRateLimit(requestLimitInterval, getOrderTradesReqRate), - GetTrades: request.NewRateLimit(requestLimitInterval, getTradesReqRate), - GetLedgers: request.NewRateLimit(requestLimitInterval, getLedgersReqRate), + retrieveOrder: request.NewRateLimitWithWeight(requestLimitInterval, retrieveOrderReqRate, 1), + submitOrder: request.NewRateLimitWithWeight(requestLimitInterval, submitOrderReqRate, 1), + updateOrder: request.NewRateLimitWithWeight(requestLimitInterval, updateOrderReqRate, 1), + cancelOrder: request.NewRateLimitWithWeight(requestLimitInterval, cancelOrderReqRate, 1), + orderBatch: request.NewRateLimitWithWeight(requestLimitInterval, orderBatchReqRate, 1), + cancelBatch: request.NewRateLimitWithWeight(requestLimitInterval, cancelBatchReqRate, 1), + orderHistory: request.NewRateLimitWithWeight(requestLimitInterval, orderHistoryReqRate, 1), + getOrderTrades: request.NewRateLimitWithWeight(requestLimitInterval, getOrderTradesReqRate, 1), + getTrades: request.NewRateLimitWithWeight(requestLimitInterval, getTradesReqRate, 1), + getLedgers: request.NewRateLimitWithWeight(requestLimitInterval, getLedgersReqRate, 1), // Positions - - GetAccountMarginInfo: request.NewRateLimit(requestLimitInterval, getAccountMarginInfoReqRate), - GetActivePositions: request.NewRateLimit(requestLimitInterval, getActivePositionsReqRate), - ClaimPosition: request.NewRateLimit(requestLimitInterval, claimPositionReqRate), - GetPositionHistory: request.NewRateLimit(requestLimitInterval, getPositionAuditReqRate), - GetPositionAudit: request.NewRateLimit(requestLimitInterval, getPositionAuditReqRate), - UpdateCollateralOnPosition: request.NewRateLimit(requestLimitInterval, updateCollateralOnPositionReqRate), + getAccountMarginInfo: request.NewRateLimitWithWeight(requestLimitInterval, getAccountMarginInfoReqRate, 1), + getActivePositions: request.NewRateLimitWithWeight(requestLimitInterval, getActivePositionsReqRate, 1), + claimPosition: request.NewRateLimitWithWeight(requestLimitInterval, claimPositionReqRate, 1), + getPositionHistory: request.NewRateLimitWithWeight(requestLimitInterval, getPositionAuditReqRate, 1), + getPositionAudit: request.NewRateLimitWithWeight(requestLimitInterval, getPositionAuditReqRate, 1), + updateCollateralOnPosition: request.NewRateLimitWithWeight(requestLimitInterval, updateCollateralOnPositionReqRate, 1), // Margin funding - - GetActiveFundingOffers: request.NewRateLimit(requestLimitInterval, getActiveFundingOffersReqRate), - SubmitFundingOffer: request.NewRateLimit(requestLimitInterval, submitFundingOfferReqRate), - CancelFundingOffer: request.NewRateLimit(requestLimitInterval, cancelFundingOfferReqRate), - CancelAllFundingOffer: request.NewRateLimit(requestLimitInterval, cancelAllFundingOfferReqRate), - CloseFunding: request.NewRateLimit(requestLimitInterval, closeFundingReqRate), - FundingAutoRenew: request.NewRateLimit(requestLimitInterval, fundingAutoRenewReqRate), - KeepFunding: request.NewRateLimit(requestLimitInterval, keepFundingReqRate), - GetOffersHistory: request.NewRateLimit(requestLimitInterval, getOffersHistoryReqRate), - GetFundingLoans: request.NewRateLimit(requestLimitInterval, getOffersHistoryReqRate), - GetFundingLoanHistory: request.NewRateLimit(requestLimitInterval, getFundingLoanHistoryReqRate), - GetFundingCredits: request.NewRateLimit(requestLimitInterval, getFundingCreditsReqRate), - GetFundingCreditsHistory: request.NewRateLimit(requestLimitInterval, getFundingCreditsHistoryReqRate), - GetFundingTrades: request.NewRateLimit(requestLimitInterval, getFundingTradesReqRate), - GetFundingInfo: request.NewRateLimit(requestLimitInterval, getFundingInfoReqRate), + getActiveFundingOffers: request.NewRateLimitWithWeight(requestLimitInterval, getActiveFundingOffersReqRate, 1), + submitFundingOffer: request.NewRateLimitWithWeight(requestLimitInterval, submitFundingOfferReqRate, 1), + cancelFundingOffer: request.NewRateLimitWithWeight(requestLimitInterval, cancelFundingOfferReqRate, 1), + cancelAllFundingOffer: request.NewRateLimitWithWeight(requestLimitInterval, cancelAllFundingOfferReqRate, 1), + closeFunding: request.NewRateLimitWithWeight(requestLimitInterval, closeFundingReqRate, 1), + fundingAutoRenew: request.NewRateLimitWithWeight(requestLimitInterval, fundingAutoRenewReqRate, 1), + keepFunding: request.NewRateLimitWithWeight(requestLimitInterval, keepFundingReqRate, 1), + getOffersHistory: request.NewRateLimitWithWeight(requestLimitInterval, getOffersHistoryReqRate, 1), + getFundingLoans: request.NewRateLimitWithWeight(requestLimitInterval, getOffersHistoryReqRate, 1), + getFundingLoanHistory: request.NewRateLimitWithWeight(requestLimitInterval, getFundingLoanHistoryReqRate, 1), + getFundingCredits: request.NewRateLimitWithWeight(requestLimitInterval, getFundingCreditsReqRate, 1), + getFundingCreditsHistory: request.NewRateLimitWithWeight(requestLimitInterval, getFundingCreditsHistoryReqRate, 1), + getFundingTrades: request.NewRateLimitWithWeight(requestLimitInterval, getFundingTradesReqRate, 1), + getFundingInfo: request.NewRateLimitWithWeight(requestLimitInterval, getFundingInfoReqRate, 1), // Account actions - GetUserInfo: request.NewRateLimit(requestLimitInterval, getUserInfoReqRate), - TransferBetweenWallets: request.NewRateLimit(requestLimitInterval, transferBetweenWalletsReqRate), - GetDepositAddress: request.NewRateLimit(requestLimitInterval, getDepositAddressReqRate), - Withdrawal: request.NewRateLimit(requestLimitInterval, withdrawalReqRate), - GetMovements: request.NewRateLimit(requestLimitInterval, getMovementsReqRate), - GetAlertList: request.NewRateLimit(requestLimitInterval, getAlertListReqRate), - SetPriceAlert: request.NewRateLimit(requestLimitInterval, setPriceAlertReqRate), - DeletePriceAlert: request.NewRateLimit(requestLimitInterval, deletePriceAlertReqRate), - GetBalanceForOrdersOffers: request.NewRateLimit(requestLimitInterval, getBalanceForOrdersOffersReqRate), - UserSettingsWrite: request.NewRateLimit(requestLimitInterval, userSettingsWriteReqRate), - UserSettingsRead: request.NewRateLimit(requestLimitInterval, userSettingsReadReqRate), - UserSettingsDelete: request.NewRateLimit(requestLimitInterval, userSettingsDeleteReqRate), + getUserInfo: request.NewRateLimitWithWeight(requestLimitInterval, getUserInfoReqRate, 1), + transferBetweenWallets: request.NewRateLimitWithWeight(requestLimitInterval, transferBetweenWalletsReqRate, 1), + getDepositAddress: request.NewRateLimitWithWeight(requestLimitInterval, getDepositAddressReqRate, 1), + withdrawal: request.NewRateLimitWithWeight(requestLimitInterval, withdrawalReqRate, 1), + getMovements: request.NewRateLimitWithWeight(requestLimitInterval, getMovementsReqRate, 1), + getAlertList: request.NewRateLimitWithWeight(requestLimitInterval, getAlertListReqRate, 1), + setPriceAlert: request.NewRateLimitWithWeight(requestLimitInterval, setPriceAlertReqRate, 1), + deletePriceAlert: request.NewRateLimitWithWeight(requestLimitInterval, deletePriceAlertReqRate, 1), + getBalanceForOrdersOffers: request.NewRateLimitWithWeight(requestLimitInterval, getBalanceForOrdersOffersReqRate, 1), + userSettingsWrite: request.NewRateLimitWithWeight(requestLimitInterval, userSettingsWriteReqRate, 1), + userSettingsRead: request.NewRateLimitWithWeight(requestLimitInterval, userSettingsReadReqRate, 1), + userSettingsDelete: request.NewRateLimitWithWeight(requestLimitInterval, userSettingsDeleteReqRate, 1), // Account V1 endpoints - GetAccountFees: request.NewRateLimit(requestLimitInterval, getAccountFeesReqRate), - GetWithdrawalFees: request.NewRateLimit(requestLimitInterval, getWithdrawalFeesReqRate), - GetAccountSummary: request.NewRateLimit(requestLimitInterval, getAccountSummaryReqRate), - NewDepositAddress: request.NewRateLimit(requestLimitInterval, newDepositAddressReqRate), - GetKeyPermissions: request.NewRateLimit(requestLimitInterval, getKeyPermissionsReqRate), - GetMarginInfo: request.NewRateLimit(requestLimitInterval, getMarginInfoReqRate), - GetAccountBalance: request.NewRateLimit(requestLimitInterval, getAccountBalanceReqRate), - WalletTransfer: request.NewRateLimit(requestLimitInterval, walletTransferReqRate), - WithdrawV1: request.NewRateLimit(requestLimitInterval, withdrawV1ReqRate), - OrderV1: request.NewRateLimit(requestLimitInterval, orderV1ReqRate), - OrderMulti: request.NewRateLimit(requestLimitInterval, orderMultiReqRate), - StatsV1: request.NewRateLimit(requestLimitInterval, statsV1ReqRate), - Fundingbook: request.NewRateLimit(requestLimitInterval, fundingbookReqRate), - Lends: request.NewRateLimit(requestLimitInterval, lendsReqRate), + getAccountFees: request.NewRateLimitWithWeight(requestLimitInterval, getAccountFeesReqRate, 1), + getWithdrawalFees: request.NewRateLimitWithWeight(requestLimitInterval, getWithdrawalFeesReqRate, 1), + getAccountSummary: request.NewRateLimitWithWeight(requestLimitInterval, getAccountSummaryReqRate, 1), + newDepositAddress: request.NewRateLimitWithWeight(requestLimitInterval, newDepositAddressReqRate, 1), + getKeyPermissions: request.NewRateLimitWithWeight(requestLimitInterval, getKeyPermissionsReqRate, 1), + getMarginInfo: request.NewRateLimitWithWeight(requestLimitInterval, getMarginInfoReqRate, 1), + getAccountBalance: request.NewRateLimitWithWeight(requestLimitInterval, getAccountBalanceReqRate, 1), + walletTransfer: request.NewRateLimitWithWeight(requestLimitInterval, walletTransferReqRate, 1), + withdrawV1: request.NewRateLimitWithWeight(requestLimitInterval, withdrawV1ReqRate, 1), + orderV1: request.NewRateLimitWithWeight(requestLimitInterval, orderV1ReqRate, 1), + orderMulti: request.NewRateLimitWithWeight(requestLimitInterval, orderMultiReqRate, 1), + statsV1: request.NewRateLimitWithWeight(requestLimitInterval, statsV1ReqRate, 1), + fundingbook: request.NewRateLimitWithWeight(requestLimitInterval, fundingbookReqRate, 1), + lends: request.NewRateLimitWithWeight(requestLimitInterval, lendsReqRate, 1), } } diff --git a/exchanges/bitflyer/bitflyer.go b/exchanges/bitflyer/bitflyer.go index d7e96947..6ad8ae5a 100644 --- a/exchanges/bitflyer/bitflyer.go +++ b/exchanges/bitflyer/bitflyer.go @@ -300,7 +300,7 @@ func (b *Bitflyer) SendHTTPRequest(ctx context.Context, ep exchange.URL, path st HTTPDebugging: b.HTTPDebugging, HTTPRecording: b.HTTPRecording, } - return b.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return b.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) } diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index 150ec88e..767c107b 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -74,7 +74,7 @@ func (b *Bitflyer) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/bitflyer/ratelimit.go b/exchanges/bitflyer/ratelimit.go index 564b5f34..9e4ab01b 100644 --- a/exchanges/bitflyer/ratelimit.go +++ b/exchanges/bitflyer/ratelimit.go @@ -1,11 +1,9 @@ package bitflyer import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Exchange specific rate limit consts @@ -17,50 +15,14 @@ const ( bitflyerPublicRequestRate = 500 ) -// RateLimit implements the rate.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter - - // Send a New Order - // Submit New Parent Order (Special order) - // Cancel All Orders - Order *rate.Limiter - LowVolume *rate.Limiter -} - -// Limit limits outbound requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case request.Auth: - return r.Auth.Wait(ctx) - case orders: - err := r.Auth.Wait(ctx) - if err != nil { - return err - } - return r.Order.Wait(ctx) - case lowVolume: - err := r.LowVolume.Wait(ctx) - if err != nil { - return err - } - err = r.Order.Wait(ctx) - if err != nil { - return err - } - return r.Auth.Wait(ctx) - default: - return r.UnAuth.Wait(ctx) - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(biflyerRateInterval, bitflyerPrivateRequestRate), - UnAuth: request.NewRateLimit(biflyerRateInterval, bitflyerPublicRequestRate), - Order: request.NewRateLimit(biflyerRateInterval, bitflyerPrivateSendOrderRequestRate), - LowVolume: request.NewRateLimit(time.Minute, bitflyerPrivateLowVolumeRequestRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(biflyerRateInterval, bitflyerPrivateRequestRate, 1), + request.UnAuth: request.NewRateLimitWithWeight(biflyerRateInterval, bitflyerPublicRequestRate, 1), + // TODO: Below limits need to also take from auth rate limit. This + // can not yet be tested and verified so is left not done for now. + orders: request.NewRateLimitWithWeight(biflyerRateInterval, bitflyerPrivateSendOrderRequestRate, 1), + lowVolume: request.NewRateLimitWithWeight(time.Minute, bitflyerPrivateLowVolumeRequestRate, 1), } } diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 9c528ce2..4b0dec33 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -114,7 +114,7 @@ func (b *Bithumb) SetDefaults() { } b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/bithumb/ratelimit.go b/exchanges/bithumb/ratelimit.go index fd4316bb..9ef74e17 100644 --- a/exchanges/bithumb/ratelimit.go +++ b/exchanges/bithumb/ratelimit.go @@ -1,11 +1,9 @@ package bithumb import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Exchange specific rate limit consts @@ -15,24 +13,10 @@ const ( bithumbUnauthRate = 95 ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -// Limit limits requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - if f == request.Auth { - return r.Auth.Wait(ctx) - } - return r.UnAuth.Wait(ctx) -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(bithumbRateInterval, bithumbAuthRate), - UnAuth: request.NewRateLimit(bithumbRateInterval, bithumbUnauthRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(bithumbRateInterval, bithumbAuthRate, 1), + request.Unset: request.NewRateLimitWithWeight(bithumbRateInterval, bithumbUnauthRate, 1), } } diff --git a/exchanges/bitmex/bitmex.go b/exchanges/bitmex/bitmex.go index 2a065ca7..73bd5637 100644 --- a/exchanges/bitmex/bitmex.go +++ b/exchanges/bitmex/bitmex.go @@ -860,7 +860,7 @@ func (b *Bitmex) SendHTTPRequest(ctx context.Context, ep exchange.URL, path stri HTTPRecording: b.HTTPRecording, } - err = b.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + err = b.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) if err != nil { diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index b9017625..b5f53e03 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -140,7 +140,7 @@ func (b *Bitmex) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/bitmex/ratelimit.go b/exchanges/bitmex/ratelimit.go index 5207d289..c226d50f 100644 --- a/exchanges/bitmex/ratelimit.go +++ b/exchanges/bitmex/ratelimit.go @@ -1,11 +1,9 @@ package bitmex import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Bitmex rate limits @@ -15,24 +13,10 @@ const ( bitmexAuthRate = 60 ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -// Limit limits outbound calls -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - if f == request.Auth { - return r.Auth.Wait(ctx) - } - return r.UnAuth.Wait(ctx) -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(bitmexRateInterval, bitmexAuthRate), - UnAuth: request.NewRateLimit(bitmexRateInterval, bitmexUnauthRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(bitmexRateInterval, bitmexAuthRate, 1), + request.UnAuth: request.NewRateLimitWithWeight(bitmexRateInterval, bitmexUnauthRate, 1), } } diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index d9c3071b..2ea7f3dc 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -111,7 +111,7 @@ func (b *Bitstamp) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(bitstampRateInterval, bitstampRequestRate))) + request.WithLimiter(request.NewBasicRateLimit(bitstampRateInterval, bitstampRequestRate, 1))) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/btcmarkets/btcmarkets.go b/exchanges/btcmarkets/btcmarkets.go index c1a81c2b..38d91d8d 100644 --- a/exchanges/btcmarkets/btcmarkets.go +++ b/exchanges/btcmarkets/btcmarkets.go @@ -814,7 +814,7 @@ func (b *BTCMarkets) SendHTTPRequest(ctx context.Context, path string, result in HTTPDebugging: b.HTTPDebugging, HTTPRecording: b.HTTPRecording, } - return b.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return b.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) } diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 3fface3e..5981caaf 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -115,7 +115,7 @@ func (b *BTCMarkets) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/btcmarkets/ratelimit.go b/exchanges/btcmarkets/ratelimit.go index a54aa966..289bec98 100644 --- a/exchanges/btcmarkets/ratelimit.go +++ b/exchanges/btcmarkets/ratelimit.go @@ -1,11 +1,9 @@ package btcmarkets import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // BTCMarkets Rate limit consts @@ -25,42 +23,14 @@ const ( newReportFunc ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter - OrderPlacement *rate.Limiter - BatchOrders *rate.Limiter - WithdrawRequest *rate.Limiter - CreateNewReport *rate.Limiter -} - -// Limit limits the outbound requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case request.Auth: - return r.Auth.Wait(ctx) - case orderFunc: - return r.OrderPlacement.Wait(ctx) - case batchFunc: - return r.BatchOrders.Wait(ctx) - case withdrawFunc: - return r.WithdrawRequest.Wait(ctx) - case newReportFunc: - return r.CreateNewReport.Wait(ctx) - default: - return r.UnAuth.Wait(ctx) - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(btcmarketsRateInterval, btcmarketsAuthLimit), - UnAuth: request.NewRateLimit(btcmarketsRateInterval, btcmarketsUnauthLimit), - OrderPlacement: request.NewRateLimit(btcmarketsRateInterval, btcmarketsOrderLimit), - BatchOrders: request.NewRateLimit(btcmarketsRateInterval, btcmarketsBatchOrderLimit), - WithdrawRequest: request.NewRateLimit(btcmarketsRateInterval, btcmarketsWithdrawLimit), - CreateNewReport: request.NewRateLimit(btcmarketsRateInterval, btcmarketsCreateNewReportLimit), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsAuthLimit, 1), + request.UnAuth: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsUnauthLimit, 1), + orderFunc: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsOrderLimit, 1), + batchFunc: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsBatchOrderLimit, 1), + withdrawFunc: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsWithdrawLimit, 1), + newReportFunc: request.NewRateLimitWithWeight(btcmarketsRateInterval, btcmarketsCreateNewReportLimit, 1), } } diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 75251f2b..39b2087b 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -140,7 +140,7 @@ func (b *BTSE) SetDefaults() { b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/btse/ratelimit.go b/exchanges/btse/ratelimit.go index 4d4bece7..0dad19c9 100644 --- a/exchanges/btse/ratelimit.go +++ b/exchanges/btse/ratelimit.go @@ -1,11 +1,9 @@ package btse import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -17,26 +15,10 @@ const ( orderFunc ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Query *rate.Limiter - Orders *rate.Limiter -} - -// Limit executes rate limiting functionality for exchange -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case orderFunc: - return r.Orders.Wait(ctx) - default: - return r.Query.Wait(ctx) - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Orders: request.NewRateLimit(btseRateInterval, btseOrdersLimit), - Query: request.NewRateLimit(btseRateInterval, btseQueryLimit), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + orderFunc: request.NewRateLimitWithWeight(btseRateInterval, btseOrdersLimit, 1), + queryFunc: request.NewRateLimitWithWeight(btseRateInterval, btseQueryLimit, 1), } } diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index f79495ad..b9138e4a 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -178,7 +178,7 @@ func (by *Bybit) SetDefaults() { by.Requester, err = request.New(by.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/bybit/ratelimit.go b/exchanges/bybit/ratelimit.go index 0d2d96b0..1bdf90c3 100644 --- a/exchanges/bybit/ratelimit.go +++ b/exchanges/bybit/ratelimit.go @@ -1,17 +1,9 @@ package bybit import ( - "context" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" -) - -const ( - // See: https://bybit-exchange.github.io/docs/v5/rate-limit - spotInterval = time.Second * 5 ) const ( @@ -76,281 +68,67 @@ const ( spotCrossMarginTradeSwitchEPL ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - SpotRate *rate.Limiter - CreateOrderRate *rate.Limiter - CreateSpotOrderRate *rate.Limiter - AmendOrderRate *rate.Limiter - CancelOrderRate *rate.Limiter - CancelSpotRate *rate.Limiter - CancelAllRate *rate.Limiter - CancelAllSpotRate *rate.Limiter - CreateBatchOrderRate *rate.Limiter - AmendBatchOrderRate *rate.Limiter - CancelBatchOrderRate *rate.Limiter - GetOrderRate *rate.Limiter - GetOrderHistoryRate *rate.Limiter - GetPositionListRate *rate.Limiter - GetExecutionListRate *rate.Limiter - GetPositionClosedPNLRate *rate.Limiter - PostPositionSetLeverageRate *rate.Limiter - SetPositionTPLSModeRate *rate.Limiter - SetPositionRiskLimitRate *rate.Limiter - StopTradingPositionRate *rate.Limiter - GetAccountWalletBalanceRate *rate.Limiter - GetAccountFeeRate *rate.Limiter - GetAssetTransferQueryInfoRate *rate.Limiter - GetAssetTransferQueryTransferCoinListRate *rate.Limiter - GetAssetTransferCoinListRate *rate.Limiter - GetAssetInterTransferListRate *rate.Limiter - GetSubMemberListRate *rate.Limiter - GetAssetUniversalTransferListRate *rate.Limiter - GetAssetAccountCoinBalanceRate *rate.Limiter - GetAssetDepositRecordsRate *rate.Limiter - GetAssetDepositSubMemberRecordsRate *rate.Limiter - GetAssetDepositSubMemberAddressRate *rate.Limiter - GetWithdrawRecordsRate *rate.Limiter - GetAssetCoinInfoRate *rate.Limiter - GetExchangeOrderRecordRate *rate.Limiter - InterTransferRate *rate.Limiter - SaveTransferSubMemberRate *rate.Limiter - UniversalTransferRate *rate.Limiter - CreateWithdrawalRate *rate.Limiter - CancelWithdrawalRate *rate.Limiter - UserCreateSubMemberRate *rate.Limiter - UserCreateSubAPIKeyRate *rate.Limiter - UserFrozenSubMemberRate *rate.Limiter - UserUpdateAPIRate *rate.Limiter - UserUpdateSubAPIRate *rate.Limiter - UserDeleteAPIRate *rate.Limiter - UserDeleteSubAPIRate *rate.Limiter - UserQuerySubMembersRate *rate.Limiter - UserQueryAPIRate *rate.Limiter - GetSpotLeverageTokenOrderRecordsRate *rate.Limiter - SpotLeverageTokenPurchaseRate *rate.Limiter - SpotLeverTokenRedeemRate *rate.Limiter - GetSpotCrossMarginTradeLoanInfoRate *rate.Limiter - GetSpotCrossMarginTradeAccountRate *rate.Limiter - GetSpotCrossMarginTradeOrdersRate *rate.Limiter - GetSpotCrossMarginTradeRepayHistoryRate *rate.Limiter - SpotCrossMarginTradeLoanRate *rate.Limiter - SpotCrossMarginTradeRepayRate *rate.Limiter - SpotCrossMarginTradeSwitchRate *rate.Limiter -} - -// Limit executes rate limiting functionality for Binance -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch f { - case defaultEPL: - limiter, tokens = r.SpotRate, 1 - case createOrderEPL: - limiter, tokens = r.CreateOrderRate, 10 - case createSpotOrderEPL: - limiter, tokens = r.CreateSpotOrderRate, 20 - case amendOrderEPL: - limiter, tokens = r.AmendOrderRate, 10 - case cancelOrderEPL: - limiter, tokens = r.CancelOrderRate, 10 - case cancelSpotEPL: - limiter, tokens = r.CancelSpotRate, 20 - case cancelAllEPL: - limiter, tokens = r.CancelAllRate, 1 - case cancelAllSpotEPL: - limiter, tokens = r.CancelAllSpotRate, 20 - case createBatchOrderEPL: - limiter, tokens = r.CreateBatchOrderRate, 10 - case amendBatchOrderEPL: - limiter, tokens = r.AmendBatchOrderRate, 10 - case cancelBatchOrderEPL: - limiter, tokens = r.CancelBatchOrderRate, 10 - case getOrderEPL: - limiter, tokens = r.GetOrderRate, 10 - case getOrderHistoryEPL: - limiter, tokens = r.GetOrderHistoryRate, 10 - case getPositionListEPL: - limiter, tokens = r.GetPositionListRate, 10 - case getExecutionListEPL: - limiter, tokens = r.GetExecutionListRate, 10 - case getPositionClosedPNLEPL: - limiter, tokens = r.GetPositionClosedPNLRate, 10 - case postPositionSetLeverageEPL: - limiter, tokens = r.PostPositionSetLeverageRate, 10 - case setPositionTPLSModeEPL: - limiter, tokens = r.SetPositionTPLSModeRate, 10 - case setPositionRiskLimitEPL: - limiter, tokens = r.SetPositionRiskLimitRate, 10 - case stopTradingPositionEPL: - limiter, tokens = r.StopTradingPositionRate, 10 - case getAccountWalletBalanceEPL: - limiter, tokens = r.GetAccountWalletBalanceRate, 10 - case getAccountFeeEPL: - limiter, tokens = r.GetAccountFeeRate, 10 - case getAssetTransferQueryInfoEPL: - limiter, tokens = r.GetAssetTransferQueryInfoRate, 1 - case getAssetTransferQueryTransferCoinListEPL: - limiter, tokens = r.GetAssetTransferQueryTransferCoinListRate, 1 - case getAssetTransferCoinListEPL: - limiter, tokens = r.GetAssetTransferCoinListRate, 1 - case getAssetInterTransferListEPL: - limiter, tokens = r.GetAssetInterTransferListRate, 1 - case getSubMemberListEPL: - limiter, tokens = r.GetSubMemberListRate, 1 - case getAssetUniversalTransferListEPL: - limiter, tokens = r.GetAssetUniversalTransferListRate, 2 - case getAssetAccountCoinBalanceEPL: - limiter, tokens = r.GetAssetAccountCoinBalanceRate, 2 - case getAssetDepositRecordsEPL: - limiter, tokens = r.GetAssetDepositRecordsRate, 1 - case getAssetDepositSubMemberRecordsEPL: - limiter, tokens = r.GetAssetDepositSubMemberRecordsRate, 1 - case getAssetDepositSubMemberAddressEPL: - limiter, tokens = r.GetAssetDepositSubMemberAddressRate, 1 - case getWithdrawRecordsEPL: - limiter, tokens = r.GetWithdrawRecordsRate, 1 - case getAssetCoinInfoEPL: - limiter, tokens = r.GetAssetCoinInfoRate, 1 - case getExchangeOrderRecordEPL: - limiter, tokens = r.GetExchangeOrderRecordRate, 1 - case interTransferEPL: - limiter, tokens = r.InterTransferRate, 1 - case saveTransferSubMemberEPL: - limiter, tokens = r.SaveTransferSubMemberRate, 1 - case universalTransferEPL: - limiter, tokens = r.UniversalTransferRate, 5 - case createWithdrawalEPL: - limiter, tokens = r.CreateWithdrawalRate, 1 - case cancelWithdrawalEPL: - limiter, tokens = r.CancelWithdrawalRate, 1 - case userCreateSubMemberEPL: - limiter, tokens = r.UserCreateSubMemberRate, 5 - case userCreateSubAPIKeyEPL: - limiter, tokens = r.UserCreateSubAPIKeyRate, 5 - case userFrozenSubMemberEPL: - limiter, tokens = r.UserFrozenSubMemberRate, 5 - case userUpdateAPIEPL: - limiter, tokens = r.UserUpdateAPIRate, 5 - case userUpdateSubAPIEPL: - limiter, tokens = r.UserUpdateSubAPIRate, 5 - case userDeleteAPIEPL: - limiter, tokens = r.UserDeleteAPIRate, 5 - case userDeleteSubAPIEPL: - limiter, tokens = r.UserDeleteSubAPIRate, 5 - case userQuerySubMembersEPL: - limiter, tokens = r.UserQuerySubMembersRate, 10 - case userQueryAPIEPL: - limiter, tokens = r.UserQueryAPIRate, 10 - case getSpotLeverageTokenOrderRecordsEPL: - limiter, tokens = r.GetSpotLeverageTokenOrderRecordsRate, 50 - case spotLeverageTokenPurchaseEPL: - limiter, tokens = r.SpotLeverageTokenPurchaseRate, 20 - case spotLeverTokenRedeemEPL: - limiter, tokens = r.SpotLeverTokenRedeemRate, 20 - case getSpotCrossMarginTradeLoanInfoEPL: - limiter, tokens = r.GetSpotCrossMarginTradeLoanInfoRate, 50 - case getSpotCrossMarginTradeAccountEPL: - limiter, tokens = r.GetSpotCrossMarginTradeAccountRate, 50 - case getSpotCrossMarginTradeOrdersEPL: - limiter, tokens = r.GetSpotCrossMarginTradeOrdersRate, 50 - case getSpotCrossMarginTradeRepayHistoryEPL: - limiter, tokens = r.GetSpotCrossMarginTradeRepayHistoryRate, 50 - case spotCrossMarginTradeLoanEPL: - limiter, tokens = r.SpotCrossMarginTradeLoanRate, 50 - case spotCrossMarginTradeRepayEPL: - limiter, tokens = r.SpotCrossMarginTradeRepayRate, 50 - case spotCrossMarginTradeSwitchEPL: - limiter, tokens = r.SpotCrossMarginTradeSwitchRate, 50 - default: - limiter, tokens = r.SpotRate, 1 - } - - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - // Consume tokens 1 at a time as this avoids needing burst capacity in the limiter, - // which would otherwise allow the rate limit to be exceeded over short periods - reserves[i] = limiter.Reserve() - finalDelay = limiter.Reserve().Delay() - } - - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - // Cancel all potential reservations to free up rate limiter if deadline - // is exceeded. - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - - time.Sleep(finalDelay) - return nil -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - SpotRate: request.NewRateLimit(spotInterval, 120), - CreateOrderRate: request.NewRateLimit(time.Second, 10), - CreateSpotOrderRate: request.NewRateLimit(time.Second, 20), - AmendOrderRate: request.NewRateLimit(time.Second, 10), - CancelOrderRate: request.NewRateLimit(time.Second, 10), - CancelSpotRate: request.NewRateLimit(time.Second, 20), - CancelAllRate: request.NewRateLimit(time.Second, 1), - CancelAllSpotRate: request.NewRateLimit(time.Second, 20), - CreateBatchOrderRate: request.NewRateLimit(time.Second, 10), - AmendBatchOrderRate: request.NewRateLimit(time.Second, 10), - CancelBatchOrderRate: request.NewRateLimit(time.Second, 10), - GetOrderRate: request.NewRateLimit(time.Second, 10), - GetOrderHistoryRate: request.NewRateLimit(time.Second, 10), - GetPositionListRate: request.NewRateLimit(time.Second, 10), - GetExecutionListRate: request.NewRateLimit(time.Second, 10), - GetPositionClosedPNLRate: request.NewRateLimit(time.Second, 10), - PostPositionSetLeverageRate: request.NewRateLimit(time.Second, 10), - SetPositionTPLSModeRate: request.NewRateLimit(time.Second, 10), - SetPositionRiskLimitRate: request.NewRateLimit(time.Second, 10), - StopTradingPositionRate: request.NewRateLimit(time.Second, 10), - GetAccountWalletBalanceRate: request.NewRateLimit(time.Second, 10), - GetAccountFeeRate: request.NewRateLimit(time.Second, 10), - GetAssetTransferQueryInfoRate: request.NewRateLimit(time.Minute, 60), - GetAssetTransferQueryTransferCoinListRate: request.NewRateLimit(time.Minute, 60), - GetAssetTransferCoinListRate: request.NewRateLimit(time.Minute, 60), - GetAssetInterTransferListRate: request.NewRateLimit(time.Minute, 60), - GetSubMemberListRate: request.NewRateLimit(time.Minute, 60), - GetAssetUniversalTransferListRate: request.NewRateLimit(time.Second, 2), - GetAssetAccountCoinBalanceRate: request.NewRateLimit(time.Second, 2), - GetAssetDepositRecordsRate: request.NewRateLimit(time.Minute, 300), - GetAssetDepositSubMemberRecordsRate: request.NewRateLimit(time.Minute, 300), - GetAssetDepositSubMemberAddressRate: request.NewRateLimit(time.Minute, 300), - GetWithdrawRecordsRate: request.NewRateLimit(time.Minute, 300), - GetAssetCoinInfoRate: request.NewRateLimit(time.Minute, 300), - GetExchangeOrderRecordRate: request.NewRateLimit(time.Minute, 300), - InterTransferRate: request.NewRateLimit(time.Minute, 20), - SaveTransferSubMemberRate: request.NewRateLimit(time.Minute, 20), - UniversalTransferRate: request.NewRateLimit(time.Second, 5), - CreateWithdrawalRate: request.NewRateLimit(time.Second, 1), - CancelWithdrawalRate: request.NewRateLimit(time.Minute, 60), - UserCreateSubMemberRate: request.NewRateLimit(time.Second, 5), - UserCreateSubAPIKeyRate: request.NewRateLimit(time.Second, 5), - UserFrozenSubMemberRate: request.NewRateLimit(time.Second, 5), - UserUpdateAPIRate: request.NewRateLimit(time.Second, 5), - UserUpdateSubAPIRate: request.NewRateLimit(time.Second, 5), - UserDeleteAPIRate: request.NewRateLimit(time.Second, 5), - UserDeleteSubAPIRate: request.NewRateLimit(time.Second, 5), - UserQuerySubMembersRate: request.NewRateLimit(time.Second, 10), - UserQueryAPIRate: request.NewRateLimit(time.Second, 10), - GetSpotLeverageTokenOrderRecordsRate: request.NewRateLimit(time.Second, 50), - SpotLeverageTokenPurchaseRate: request.NewRateLimit(time.Second, 20), - SpotLeverTokenRedeemRate: request.NewRateLimit(time.Second, 20), - GetSpotCrossMarginTradeLoanInfoRate: request.NewRateLimit(time.Second, 50), - GetSpotCrossMarginTradeAccountRate: request.NewRateLimit(time.Second, 50), - GetSpotCrossMarginTradeOrdersRate: request.NewRateLimit(time.Second, 50), - GetSpotCrossMarginTradeRepayHistoryRate: request.NewRateLimit(time.Second, 50), - SpotCrossMarginTradeLoanRate: request.NewRateLimit(time.Second, 20), - SpotCrossMarginTradeRepayRate: request.NewRateLimit(time.Second, 20), - SpotCrossMarginTradeSwitchRate: request.NewRateLimit(time.Second, 20), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + defaultEPL: request.NewRateLimitWithWeight(time.Second*5 /* See: https://bybit-exchange.github.io/docs/v5/rate-limit */, 600, 1), + createOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + createSpotOrderEPL: request.NewRateLimitWithWeight(time.Second, 20, 20), + amendOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + cancelOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + cancelSpotEPL: request.NewRateLimitWithWeight(time.Second, 20, 20), + cancelAllEPL: request.NewRateLimitWithWeight(time.Second, 1, 1), + cancelAllSpotEPL: request.NewRateLimitWithWeight(time.Second, 20, 20), + createBatchOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + amendBatchOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + cancelBatchOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getOrderEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getOrderHistoryEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getPositionListEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getExecutionListEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getPositionClosedPNLEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + postPositionSetLeverageEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + setPositionTPLSModeEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + setPositionRiskLimitEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + stopTradingPositionEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getAccountWalletBalanceEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getAccountFeeEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getAssetTransferQueryInfoEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + getAssetTransferQueryTransferCoinListEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + getAssetTransferCoinListEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + getAssetInterTransferListEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + getSubMemberListEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + getAssetUniversalTransferListEPL: request.NewRateLimitWithWeight(time.Second, 2, 2), + getAssetAccountCoinBalanceEPL: request.NewRateLimitWithWeight(time.Second, 2, 2), + getAssetDepositRecordsEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + getAssetDepositSubMemberRecordsEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + getAssetDepositSubMemberAddressEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + getWithdrawRecordsEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + getAssetCoinInfoEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + getExchangeOrderRecordEPL: request.NewRateLimitWithWeight(time.Minute, 30, 1), + interTransferEPL: request.NewRateLimitWithWeight(time.Minute, 20, 1), + saveTransferSubMemberEPL: request.NewRateLimitWithWeight(time.Minute, 20, 1), + universalTransferEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + createWithdrawalEPL: request.NewRateLimitWithWeight(time.Second, 1, 1), + cancelWithdrawalEPL: request.NewRateLimitWithWeight(time.Minute, 60, 1), + userCreateSubMemberEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userCreateSubAPIKeyEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userFrozenSubMemberEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userUpdateAPIEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userUpdateSubAPIEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userDeleteAPIEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userDeleteSubAPIEPL: request.NewRateLimitWithWeight(time.Second, 5, 5), + userQuerySubMembersEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + userQueryAPIEPL: request.NewRateLimitWithWeight(time.Second, 10, 10), + getSpotLeverageTokenOrderRecordsEPL: request.NewRateLimitWithWeight(time.Second, 50, 50), + spotLeverageTokenPurchaseEPL: request.NewRateLimitWithWeight(time.Second, 20, 20), + spotLeverTokenRedeemEPL: request.NewRateLimitWithWeight(time.Second, 20, 20), + getSpotCrossMarginTradeLoanInfoEPL: request.NewRateLimitWithWeight(time.Second, 50, 50), + getSpotCrossMarginTradeAccountEPL: request.NewRateLimitWithWeight(time.Second, 50, 50), + getSpotCrossMarginTradeOrdersEPL: request.NewRateLimitWithWeight(time.Second, 50, 50), + getSpotCrossMarginTradeRepayHistoryEPL: request.NewRateLimitWithWeight(time.Second, 50, 50), + spotCrossMarginTradeLoanEPL: request.NewRateLimitWithWeight(time.Second, 20, 50), + spotCrossMarginTradeRepayEPL: request.NewRateLimitWithWeight(time.Second, 20, 50), + spotCrossMarginTradeSwitchEPL: request.NewRateLimitWithWeight(time.Second, 20, 50), } } diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index 18ec2f09..31308e77 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -767,7 +767,7 @@ func (c *CoinbasePro) SendHTTPRequest(ctx context.Context, ep exchange.URL, path HTTPRecording: c.HTTPRecording, } - return c.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return c.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) } diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index f334fe5b..14d83728 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -109,7 +109,7 @@ func (c *CoinbasePro) SetDefaults() { c.Requester, err = request.New(c.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/coinbasepro/ratelimit.go b/exchanges/coinbasepro/ratelimit.go index d9c6fa76..e636f666 100644 --- a/exchanges/coinbasepro/ratelimit.go +++ b/exchanges/coinbasepro/ratelimit.go @@ -1,11 +1,9 @@ package coinbasepro import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Coinbasepro rate limit conts @@ -15,24 +13,10 @@ const ( coinbaseproUnauthRate = 2 ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -// Limit limits outbound calls -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - if f == request.Auth { - return r.Auth.Wait(ctx) - } - return r.UnAuth.Wait(ctx) -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(coinbaseproRateInterval, coinbaseproAuthRate), - UnAuth: request.NewRateLimit(coinbaseproRateInterval, coinbaseproUnauthRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(coinbaseproRateInterval, coinbaseproAuthRate, 1), + request.UnAuth: request.NewRateLimitWithWeight(coinbaseproRateInterval, coinbaseproUnauthRate, 1), } } diff --git a/exchanges/deribit/deribit_wrapper.go b/exchanges/deribit/deribit_wrapper.go index 3b3bef96..faa7050a 100644 --- a/exchanges/deribit/deribit_wrapper.go +++ b/exchanges/deribit/deribit_wrapper.go @@ -152,7 +152,7 @@ func (d *Deribit) SetDefaults() { } d.Requester, err = request.New(d.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit()), + request.WithLimiter(GetRateLimits()), ) if err != nil { log.Errorln(log.ExchangeSys, err) diff --git a/exchanges/deribit/ratelimit.go b/exchanges/deribit/ratelimit.go index 563bde1a..642b43b6 100644 --- a/exchanges/deribit/ratelimit.go +++ b/exchanges/deribit/ratelimit.go @@ -1,79 +1,32 @@ package deribit import ( - "context" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( - // request rates per interval + // Request rates per interval minMatchingBurst = 100 nonMatchingRate = 20 - minMatchingRate = 5 portfoliMarginRate = 1 - + // Weightings + matchingWeight = 5 + standardWeight = 1 + // Rate limit keys nonMatchingEPL request.EndpointLimit = iota matchingEPL portfolioMarginEPL privatePortfolioMarginEPL ) -// RateLimiter holds the rate limiter to endpoints -type RateLimiter struct { - NonMatchingEngine *rate.Limiter - MatchingEngine *rate.Limiter - PortfolioMargin *rate.Limiter - PrivatePortfolioMargin *rate.Limiter -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimiter { - return &RateLimiter{ - NonMatchingEngine: request.NewRateLimit(time.Second, nonMatchingRate), - MatchingEngine: request.NewRateLimit(time.Second, minMatchingBurst), - PortfolioMargin: request.NewRateLimit(5*time.Second, portfoliMarginRate), - PrivatePortfolioMargin: request.NewRateLimit(5*time.Second, portfoliMarginRate), +// GetRateLimits returns the rate limit for the exchange +func GetRateLimits() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + nonMatchingEPL: request.GetRateLimiterWithWeight(request.NewRateLimit(time.Second, nonMatchingRate), standardWeight), + matchingEPL: request.GetRateLimiterWithWeight(request.NewRateLimit(time.Second, minMatchingBurst), matchingWeight), + portfolioMarginEPL: request.GetRateLimiterWithWeight(request.NewRateLimit(5*time.Second, portfoliMarginRate), standardWeight), + privatePortfolioMarginEPL: request.GetRateLimiterWithWeight(request.NewRateLimit(5*time.Second, portfoliMarginRate), standardWeight), } } - -// Limit executes rate limiting functionality for Binance -func (r *RateLimiter) Limit(ctx context.Context, f request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch f { - case nonMatchingEPL: - limiter, tokens = r.NonMatchingEngine, 1 - case portfolioMarginEPL: - limiter, tokens = r.PortfolioMargin, portfoliMarginRate - case privatePortfolioMarginEPL: - limiter, tokens = r.PrivatePortfolioMargin, portfoliMarginRate - default: - limiter, tokens = r.MatchingEngine, minMatchingRate - } - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - // Consume tokens 1 at a time as this avoids needing burst capacity in the limiter, - // which would otherwise allow the rate limit to be exceeded over short periods - reserves[i] = limiter.Reserve() - finalDelay = reserves[i].Delay() - } - - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - // Cancel all potential reservations to free up rate limiter if deadline - // is exceeded. - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - - time.Sleep(finalDelay) - return nil -} diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index d6d6c3e9..dbb8f723 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -90,7 +90,7 @@ func (e *EXMO) SetDefaults() { e.Requester, err = request.New(e.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(exmoRateInterval, exmoRequestRate))) + request.WithLimiter(request.NewBasicRateLimit(exmoRateInterval, exmoRequestRate, 1))) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index a3e364e0..bb62857b 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -142,7 +142,7 @@ func (g *Gateio) SetDefaults() { } g.Requester, err = request.New(g.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit()), + request.WithLimiter(GetRateLimit()), ) if err != nil { log.Errorln(log.ExchangeSys, err) diff --git a/exchanges/gateio/ratelimiter.go b/exchanges/gateio/ratelimiter.go index 0d024095..2c554b38 100644 --- a/exchanges/gateio/ratelimiter.go +++ b/exchanges/gateio/ratelimiter.go @@ -1,12 +1,9 @@ package gateio import ( - "context" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // GateIO endpoints limits. @@ -40,79 +37,18 @@ const ( threeSecondsInterval = time.Second * 3 ) -// RateLimitter represents a rate limiter structure for gateIO endpoints. -type RateLimitter struct { - SpotDefault *rate.Limiter - SpotPrivate *rate.Limiter - SpotPlaceOrders *rate.Limiter - SpotCancelOrders *rate.Limiter - PerpetualSwapDefault *rate.Limiter - PerpetualSwapPlaceOrders *rate.Limiter - PerpetualSwapPrivate *rate.Limiter - PerpetualSwapCancelOrders *rate.Limiter - Wallet *rate.Limiter - Withdrawal *rate.Limiter -} - -// Limit executes rate limiting functionality -// implements the request.Limiter interface -func (r *RateLimitter) Limit(ctx context.Context, epl request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch epl { - case spotDefaultEPL: - limiter, tokens = r.SpotDefault, 1 - case spotPrivateEPL: - return r.SpotPrivate.Wait(ctx) - case spotPlaceOrdersEPL: - return r.SpotPlaceOrders.Wait(ctx) - case spotCancelOrdersEPL: - return r.SpotCancelOrders.Wait(ctx) - case perpetualSwapDefaultEPL: - limiter, tokens = r.PerpetualSwapDefault, 1 - case perpetualSwapPlaceOrdersEPL: - return r.PerpetualSwapPlaceOrders.Wait(ctx) - case perpetualSwapPrivateEPL: - return r.PerpetualSwapPrivate.Wait(ctx) - case perpetualSwapCancelOrdersEPL: - return r.PerpetualSwapCancelOrders.Wait(ctx) - case walletEPL: - return r.Wallet.Wait(ctx) - case withdrawalEPL: - return r.Withdrawal.Wait(ctx) - default: - } - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - reserves[i] = limiter.Reserve() - finalDelay = reserves[i].Delay() - } - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - - time.Sleep(finalDelay) - return nil -} - -// SetRateLimit returns the rate limiter for the exchange -func SetRateLimit() *RateLimitter { - return &RateLimitter{ - SpotDefault: request.NewRateLimit(oneSecondInterval, spotPublicRate), - SpotPrivate: request.NewRateLimit(oneSecondInterval, spotPrivateRate), - SpotPlaceOrders: request.NewRateLimit(oneSecondInterval, spotPlaceOrdersRate), - SpotCancelOrders: request.NewRateLimit(oneSecondInterval, spotCancelOrdersRate), - PerpetualSwapDefault: request.NewRateLimit(oneSecondInterval, perpetualSwapPublicRate), - PerpetualSwapPlaceOrders: request.NewRateLimit(oneSecondInterval, perpetualSwapPlaceOrdersRate), - PerpetualSwapPrivate: request.NewRateLimit(oneSecondInterval, perpetualSwapPrivateRate), - PerpetualSwapCancelOrders: request.NewRateLimit(oneSecondInterval, perpetualSwapCancelOrdersRate), - Wallet: request.NewRateLimit(oneSecondInterval, walletRate), - Withdrawal: request.NewRateLimit(threeSecondsInterval, withdrawalRate), +// GetRateLimit returns the rate limiter for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + spotDefaultEPL: request.NewRateLimitWithWeight(oneSecondInterval, spotPublicRate, 1), + spotPrivateEPL: request.NewRateLimitWithWeight(oneSecondInterval, spotPrivateRate, 1), + spotPlaceOrdersEPL: request.NewRateLimitWithWeight(oneSecondInterval, spotPlaceOrdersRate, 1), + spotCancelOrdersEPL: request.NewRateLimitWithWeight(oneSecondInterval, spotCancelOrdersRate, 1), + perpetualSwapDefaultEPL: request.NewRateLimitWithWeight(oneSecondInterval, perpetualSwapPublicRate, 1), + perpetualSwapPlaceOrdersEPL: request.NewRateLimitWithWeight(oneSecondInterval, perpetualSwapPlaceOrdersRate, 1), + perpetualSwapPrivateEPL: request.NewRateLimitWithWeight(oneSecondInterval, perpetualSwapPrivateRate, 1), + perpetualSwapCancelOrdersEPL: request.NewRateLimitWithWeight(oneSecondInterval, perpetualSwapCancelOrdersRate, 1), + walletEPL: request.NewRateLimitWithWeight(oneSecondInterval, walletRate, 1), + withdrawalEPL: request.NewRateLimitWithWeight(threeSecondsInterval, withdrawalRate, 1), } } diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index fb23666b..e6cce565 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -402,7 +402,7 @@ func (g *Gemini) SendHTTPRequest(ctx context.Context, ep exchange.URL, path stri HTTPRecording: g.HTTPRecording, } - return g.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return g.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) } diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index 424e08ac..ed9b0f8f 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -93,7 +93,7 @@ func (g *Gemini) SetDefaults() { g.Requester, err = request.New(g.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/gemini/ratelimit.go b/exchanges/gemini/ratelimit.go index d9afe873..f64d42a5 100644 --- a/exchanges/gemini/ratelimit.go +++ b/exchanges/gemini/ratelimit.go @@ -1,11 +1,9 @@ package gemini import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -15,24 +13,10 @@ const ( geminiUnauthRate = 120 ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -// Limit limits the endpoint functionality -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - if f == request.Auth { - return r.Auth.Wait(ctx) - } - return r.UnAuth.Wait(ctx) -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(geminiRateInterval, geminiAuthRate), - UnAuth: request.NewRateLimit(geminiRateInterval, geminiUnauthRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(geminiRateInterval, geminiAuthRate, 1), + request.UnAuth: request.NewRateLimitWithWeight(geminiRateInterval, geminiUnauthRate, 1), } } diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index ae597137..83030b89 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -112,7 +112,7 @@ func (h *HitBTC) SetDefaults() { h.Requester, err = request.New(h.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/hitbtc/ratelimit.go b/exchanges/hitbtc/ratelimit.go index 9ae58f5b..bd0b6d54 100644 --- a/exchanges/hitbtc/ratelimit.go +++ b/exchanges/hitbtc/ratelimit.go @@ -1,12 +1,9 @@ package hitbtc import ( - "context" - "errors" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -20,32 +17,11 @@ const ( otherRequests ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - MarketData *rate.Limiter - Trading *rate.Limiter - Other *rate.Limiter -} - -// Limit limits outbound requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case marketRequests: - return r.MarketData.Wait(ctx) - case tradingRequests: - return r.Trading.Wait(ctx) - case otherRequests: - return r.Other.Wait(ctx) - default: - return errors.New("functionality not found") - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - MarketData: request.NewRateLimit(hitbtcRateInterval, hitbtcMarketDataReqRate), - Trading: request.NewRateLimit(hitbtcRateInterval, hitbtcTradingReqRate), - Other: request.NewRateLimit(hitbtcRateInterval, hitbtcAllOthers), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + marketRequests: request.NewRateLimitWithWeight(hitbtcRateInterval, hitbtcMarketDataReqRate, 1), + tradingRequests: request.NewRateLimitWithWeight(hitbtcRateInterval, hitbtcTradingReqRate, 1), + otherRequests: request.NewRateLimitWithWeight(hitbtcRateInterval, hitbtcAllOthers, 1), } } diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 93391c1a..a9c34628 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -165,7 +165,7 @@ func (h *HUOBI) SetDefaults() { h.Requester, err = request.New(h.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/huobi/ratelimit.go b/exchanges/huobi/ratelimit.go index 55866fe2..6c828f63 100644 --- a/exchanges/huobi/ratelimit.go +++ b/exchanges/huobi/ratelimit.go @@ -1,11 +1,9 @@ package huobi import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -28,47 +26,17 @@ const ( huobiFuturesUnAuth huobiFuturesTransfer huobiSwapAuth - huobiSwapUnauth + huobiSwapUnAuth ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Spot *rate.Limiter - FuturesAuth *rate.Limiter - FuturesUnauth *rate.Limiter - SwapAuth *rate.Limiter - SwapUnauth *rate.Limiter - FuturesXfer *rate.Limiter -} - -// Limit limits outbound requests -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - // TODO: Add futures and swap functionality - case huobiFuturesAuth: - return r.FuturesAuth.Wait(ctx) - case huobiFuturesUnAuth: - return r.FuturesUnauth.Wait(ctx) - case huobiFuturesTransfer: - return r.FuturesXfer.Wait(ctx) - case huobiSwapAuth: - return r.SwapAuth.Wait(ctx) - case huobiSwapUnauth: - return r.SwapUnauth.Wait(ctx) - default: - // Spot calls - return r.Spot.Wait(ctx) - } -} - -// SetRateLimit returns the rate limit for the exchange -func SetRateLimit() *RateLimit { - return &RateLimit{ - Spot: request.NewRateLimit(huobiSpotRateInterval, huobiSpotRequestRate), - FuturesAuth: request.NewRateLimit(huobiFuturesRateInterval, huobiFuturesAuthRequestRate), - FuturesUnauth: request.NewRateLimit(huobiFuturesRateInterval, huobiFuturesUnAuthRequestRate), - SwapAuth: request.NewRateLimit(huobiSwapRateInterval, huobiSwapAuthRequestRate), - SwapUnauth: request.NewRateLimit(huobiSwapRateInterval, huobiSwapUnauthRequestRate), - FuturesXfer: request.NewRateLimit(huobiFuturesTransferRateInterval, huobiFuturesTransferReqRate), +// GetRateLimit returns the rate limit for the exchange +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Unset: request.NewRateLimitWithWeight(huobiSpotRateInterval, huobiSpotRequestRate, 1), + huobiFuturesAuth: request.NewRateLimitWithWeight(huobiFuturesRateInterval, huobiFuturesAuthRequestRate, 1), + huobiFuturesUnAuth: request.NewRateLimitWithWeight(huobiFuturesRateInterval, huobiFuturesUnAuthRequestRate, 1), + huobiSwapAuth: request.NewRateLimitWithWeight(huobiSwapRateInterval, huobiSwapAuthRequestRate, 1), + huobiSwapUnAuth: request.NewRateLimitWithWeight(huobiSwapRateInterval, huobiSwapUnauthRequestRate, 1), + huobiFuturesTransfer: request.NewRateLimitWithWeight(huobiFuturesTransferRateInterval, huobiFuturesTransferReqRate, 1), } } diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 64e459cf..05bede1b 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -172,7 +172,7 @@ func (k *Kraken) SetDefaults() { k.Requester, err = request.New(k.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(request.NewBasicRateLimit(krakenRateInterval, krakenRequestRate))) + request.WithLimiter(request.NewBasicRateLimit(krakenRateInterval, krakenRequestRate, 1))) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/kucoin/kucoin_ratelimit.go b/exchanges/kucoin/kucoin_ratelimit.go index 7f8a52b4..62140ee7 100644 --- a/exchanges/kucoin/kucoin_ratelimit.go +++ b/exchanges/kucoin/kucoin_ratelimit.go @@ -1,13 +1,9 @@ package kucoin import ( - "context" - "errors" - "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -15,39 +11,6 @@ const ( oneMinuteInterval = time.Minute ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - RetrieveAccountLedger *rate.Limiter - MasterSubUserTransfer *rate.Limiter - RetrieveDepositList *rate.Limiter - RetrieveV1HistoricalDepositList *rate.Limiter - RetrieveWithdrawalList *rate.Limiter - RetrieveV1HistoricalWithdrawalList *rate.Limiter - PlaceOrder *rate.Limiter - PlaceMarginOrders *rate.Limiter - PlaceBulkOrders *rate.Limiter - CancelOrder *rate.Limiter - CancelAllOrders *rate.Limiter - ListOrders *rate.Limiter - ListFills *rate.Limiter - RetrieveFullOrderbook *rate.Limiter - RetrieveMarginAccount *rate.Limiter - SpotRate *rate.Limiter - FuturesRate *rate.Limiter - - FRetrieveAccountOverviewRate *rate.Limiter - FRetrieveTransactionHistoryRate *rate.Limiter - FPlaceOrderRate *rate.Limiter - FCancelAnOrderRate *rate.Limiter - FLimitOrderMassCancelationRate *rate.Limiter - FRetrieveOrderListRate *rate.Limiter - FRetrieveFillsRate *rate.Limiter - FRecentFillsRate *rate.Limiter - FRetrievePositionListRate *rate.Limiter - FRetrieveFundingHistoryRate *rate.Limiter - FRetrieveFullOrderbookLevel2Rate *rate.Limiter -} - // rate of request per interval const ( retrieveAccountLedgerRate = 18 @@ -116,129 +79,41 @@ const ( defaultFuturesEPL ) -// Limit executes rate limiting functionality for Kucoin -func (r *RateLimit) Limit(ctx context.Context, epl request.EndpointLimit) error { - var limiter *rate.Limiter - var tokens int - switch epl { - case retrieveAccountLedgerEPL: - return r.RetrieveAccountLedger.Wait(ctx) - case masterSubUserTransferEPL: - return r.MasterSubUserTransfer.Wait(ctx) - case retrieveDepositListEPL: - return r.RetrieveDepositList.Wait(ctx) - case retrieveV1HistoricalDepositListEPL: - return r.RetrieveV1HistoricalDepositList.Wait(ctx) - case retrieveWithdrawalListEPL: - return r.RetrieveWithdrawalList.Wait(ctx) - case retrieveV1HistoricalWithdrawalListEPL: - return r.RetrieveV1HistoricalWithdrawalList.Wait(ctx) - case placeOrderEPL: - return r.PlaceOrder.Wait(ctx) - case placeMarginOrdersEPL: - return r.PlaceMarginOrders.Wait(ctx) - case placeBulkOrdersEPL: - return r.PlaceBulkOrders.Wait(ctx) - case cancelOrderEPL: - return r.CancelOrder.Wait(ctx) - case cancelAllOrdersEPL: - return r.CancelAllOrders.Wait(ctx) - case listOrdersEPL: - return r.ListOrders.Wait(ctx) - case listFillsEPL: - return r.ListFills.Wait(ctx) - case retrieveFullOrderbookEPL: - return r.RetrieveFullOrderbook.Wait(ctx) - case retrieveMarginAccountEPL: - return r.RetrieveMarginAccount.Wait(ctx) - case futuresRetrieveAccountOverviewEPL: - return r.FRetrieveAccountOverviewRate.Wait(ctx) - case futuresRetrieveTransactionHistoryEPL: - return r.FRetrieveTransactionHistoryRate.Wait(ctx) - case futuresPlaceOrderEPL: - return r.FPlaceOrderRate.Wait(ctx) - case futuresCancelAnOrderEPL: - return r.FCancelAnOrderRate.Wait(ctx) - case futuresLimitOrderMassCancelationEPL: - return r.FLimitOrderMassCancelationRate.Wait(ctx) - case futuresRetrieveOrderListEPL: - return r.FRetrieveOrderListRate.Wait(ctx) - case futuresRetrieveFillsEPL: - return r.FRetrieveFillsRate.Wait(ctx) - case futuresRecentFillsEPL: - return r.FRecentFillsRate.Wait(ctx) - case futuresRetrievePositionListEPL: - return r.FRetrievePositionListRate.Wait(ctx) - case futuresRetrieveFundingHistoryEPL: - return r.FRetrieveFundingHistoryRate.Wait(ctx) - case futuresRetrieveFullOrderbookLevel2EPL: - return r.FRetrieveFullOrderbookLevel2Rate.Wait(ctx) - case defaultSpotEPL: - limiter, tokens = r.SpotRate, 1 - case defaultFuturesEPL: - limiter, tokens = r.FuturesRate, 1 - default: - return errors.New("endpoint rate limit functionality not found") - } - var finalDelay time.Duration - var reserves = make([]*rate.Reservation, tokens) - for i := 0; i < tokens; i++ { - // Consume tokens 1 at a time as this avoids needing burst capacity in the limiter, - // which would otherwise allow the rate limit to be exceeded over short periods - reserves[i] = limiter.Reserve() - finalDelay = reserves[i].Delay() - } - - if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { - // Cancel all potential reservations to free up rate limiter if deadline - // is exceeded. - for x := range reserves { - reserves[x].Cancel() - } - return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", - finalDelay, - context.DeadlineExceeded) - } - - time.Sleep(finalDelay) - return nil -} - -// SetRateLimit returns a RateLimit instance, which implements the request.Limiter interface. -func SetRateLimit() *RateLimit { - return &RateLimit{ +// GetRateLimit returns a RateLimit instance, which implements the request.Limiter interface. +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ // spot specific rate limiters - RetrieveAccountLedger: request.NewRateLimit(threeSecondsInterval, retrieveAccountLedgerRate), - MasterSubUserTransfer: request.NewRateLimit(threeSecondsInterval, masterSubUserTransferRate), - RetrieveDepositList: request.NewRateLimit(threeSecondsInterval, retrieveDepositListRate), - RetrieveV1HistoricalDepositList: request.NewRateLimit(threeSecondsInterval, retrieveV1HistoricalDepositListRate), - RetrieveWithdrawalList: request.NewRateLimit(threeSecondsInterval, retrieveWithdrawalListRate), - RetrieveV1HistoricalWithdrawalList: request.NewRateLimit(threeSecondsInterval, retrieveV1HistoricalWithdrawalListRate), - PlaceOrder: request.NewRateLimit(threeSecondsInterval, placeOrderRate), - PlaceMarginOrders: request.NewRateLimit(threeSecondsInterval, placeMarginOrdersRate), - PlaceBulkOrders: request.NewRateLimit(threeSecondsInterval, placeBulkOrdersRate), - CancelOrder: request.NewRateLimit(threeSecondsInterval, cancelOrderRate), - CancelAllOrders: request.NewRateLimit(threeSecondsInterval, cancelAllOrdersRate), - ListOrders: request.NewRateLimit(threeSecondsInterval, listOrdersRate), - ListFills: request.NewRateLimit(threeSecondsInterval, listFillsRate), - RetrieveFullOrderbook: request.NewRateLimit(threeSecondsInterval, retrieveFullOrderbookRate), - RetrieveMarginAccount: request.NewRateLimit(threeSecondsInterval, retrieveMarginAccountRate), + retrieveAccountLedgerEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveAccountLedgerRate, 1), + masterSubUserTransferEPL: request.NewRateLimitWithWeight(threeSecondsInterval, masterSubUserTransferRate, 1), + retrieveDepositListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveDepositListRate, 1), + retrieveV1HistoricalDepositListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveV1HistoricalDepositListRate, 1), + retrieveWithdrawalListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveWithdrawalListRate, 1), + retrieveV1HistoricalWithdrawalListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveV1HistoricalWithdrawalListRate, 1), + placeOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeOrderRate, 1), + placeMarginOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeMarginOrdersRate, 1), + placeBulkOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, placeBulkOrdersRate, 1), + cancelOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, cancelOrderRate, 1), + cancelAllOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, cancelAllOrdersRate, 1), + listOrdersEPL: request.NewRateLimitWithWeight(threeSecondsInterval, listOrdersRate, 1), + listFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, listFillsRate, 1), + retrieveFullOrderbookEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveFullOrderbookRate, 1), + retrieveMarginAccountEPL: request.NewRateLimitWithWeight(threeSecondsInterval, retrieveMarginAccountRate, 1), // default spot and futures rates - SpotRate: request.NewRateLimit(oneMinuteInterval, defaultSpotRate), - FuturesRate: request.NewRateLimit(oneMinuteInterval, defaultFuturesRate), + defaultSpotEPL: request.NewRateLimitWithWeight(oneMinuteInterval, defaultSpotRate, 1), + defaultFuturesEPL: request.NewRateLimitWithWeight(oneMinuteInterval, defaultFuturesRate, 1), // futures specific rate limiters - FRetrieveAccountOverviewRate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveAccountOverviewRate), - FRetrieveTransactionHistoryRate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveTransactionHistoryRate), - FPlaceOrderRate: request.NewRateLimit(threeSecondsInterval, futuresPlaceOrderRate), - FCancelAnOrderRate: request.NewRateLimit(threeSecondsInterval, futuresCancelAnOrderRate), - FLimitOrderMassCancelationRate: request.NewRateLimit(threeSecondsInterval, futuresLimitOrderMassCancelationRate), - FRetrieveOrderListRate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveOrderListRate), - FRetrieveFillsRate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveFillsRate), - FRecentFillsRate: request.NewRateLimit(threeSecondsInterval, futuresRecentFillsRate), - FRetrievePositionListRate: request.NewRateLimit(threeSecondsInterval, futuresRetrievePositionListRate), - FRetrieveFundingHistoryRate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveFundingHistoryRate), - FRetrieveFullOrderbookLevel2Rate: request.NewRateLimit(threeSecondsInterval, futuresRetrieveFullOrderbookLevel2Rate), + futuresRetrieveAccountOverviewEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveAccountOverviewRate, 1), + futuresRetrieveTransactionHistoryEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveTransactionHistoryRate, 1), + futuresPlaceOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresPlaceOrderRate, 1), + futuresCancelAnOrderEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresCancelAnOrderRate, 1), + futuresLimitOrderMassCancelationEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresLimitOrderMassCancelationRate, 1), + futuresRetrieveOrderListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveOrderListRate, 1), + futuresRetrieveFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFillsRate, 1), + futuresRecentFillsEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRecentFillsRate, 1), + futuresRetrievePositionListEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrievePositionListRate, 1), + futuresRetrieveFundingHistoryEPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFundingHistoryRate, 1), + futuresRetrieveFullOrderbookLevel2EPL: request.NewRateLimitWithWeight(threeSecondsInterval, futuresRetrieveFullOrderbookLevel2Rate, 1), } } diff --git a/exchanges/kucoin/kucoin_wrapper.go b/exchanges/kucoin/kucoin_wrapper.go index 49773b17..cc6849ae 100644 --- a/exchanges/kucoin/kucoin_wrapper.go +++ b/exchanges/kucoin/kucoin_wrapper.go @@ -159,7 +159,7 @@ func (ku *Kucoin) SetDefaults() { } ku.Requester, err = request.New(ku.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/okcoin/okcoin_ratelimit.go b/exchanges/okcoin/okcoin_ratelimit.go index 00bfa9b7..965ab768 100644 --- a/exchanges/okcoin/okcoin_ratelimit.go +++ b/exchanges/okcoin/okcoin_ratelimit.go @@ -1,12 +1,9 @@ package okcoin import ( - "context" - "errors" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Interval instances @@ -16,79 +13,6 @@ const ( fiveSecondsInterval = time.Second * 5 ) -// RateLimit implementa a rate Limiter -type RateLimit struct { - PlaceTradeOrder *rate.Limiter - PlaceTradeMultipleOrders *rate.Limiter - CancelTradeOrder *rate.Limiter - CancelMultipleOrder *rate.Limiter - AmendTradeOrder *rate.Limiter - AmendMultipleOrders *rate.Limiter - GetOrderDetails *rate.Limiter - GetOrderList *rate.Limiter - GetOrderHistory *rate.Limiter - GetOrderhistory3Months *rate.Limiter - GetTransactionDetails3Days *rate.Limiter - GetTransactionDetails3Months *rate.Limiter - PlaceAlgoOrder *rate.Limiter - CancelAlgoOrder *rate.Limiter - CancelAdvancedAlgoOrder *rate.Limiter - GetAlgoOrderList *rate.Limiter - GetAlgoOrderHistory *rate.Limiter - GetFundingCurrencies *rate.Limiter - GetFundingAccountBalance *rate.Limiter - GetAccountAssetValuation *rate.Limiter - FundingTransfer *rate.Limiter - GetFundsTransferState *rate.Limiter - AssetBillsDetail *rate.Limiter - LightningDeposits *rate.Limiter - GetAssetDepositAddress *rate.Limiter - GetDepositHistory *rate.Limiter - PostWithdrawal *rate.Limiter - PostLightningWithdrawal *rate.Limiter - CancelWithdrawal *rate.Limiter - GetAssetWithdrawalHistory *rate.Limiter - GetAccountBalance *rate.Limiter - GetBillsDetailLast3Month *rate.Limiter - GetBillsDetail *rate.Limiter - GetAccountConfiguration *rate.Limiter - GetMaxBuySellAmountOpenAmount *rate.Limiter - GetMaxAvailableTradableAmount *rate.Limiter - GetFeeRates *rate.Limiter - GetMaxWithdrawals *rate.Limiter - GetAvailablePairs *rate.Limiter - RequestQuotes *rate.Limiter - PlaceRFQOrder *rate.Limiter - GetRFQTradeOrderDetails *rate.Limiter - GetRFQTradeOrderHistory *rate.Limiter - FiatDepositRate *rate.Limiter - FiatCancelDepositRate *rate.Limiter - FiatDepositHistoryRate *rate.Limiter - FiatWithdrawalRate *rate.Limiter - FiatCancelWithdrawalRate *rate.Limiter - FiatGetWithdrawalsRate *rate.Limiter - FiatGetChannelInfoRate *rate.Limiter - SubAccountsList *rate.Limiter - GetAPIKeyOfASubAccount *rate.Limiter - GetSubAccountTradingBalance *rate.Limiter - GetSubAccountFundingBalance *rate.Limiter - SubAccountTransferHistory *rate.Limiter - MasterAccountsManageTransfersBetweenSubaccount *rate.Limiter - GetTickers *rate.Limiter - GetTicker *rate.Limiter - GetOrderbook *rate.Limiter - GetCandlesticks *rate.Limiter - GetCandlestickHistory *rate.Limiter - GetPublicTrades *rate.Limiter - GetPublicTradeHistrory *rate.Limiter - Get24HourTradingVolume *rate.Limiter - GetOracle *rate.Limiter - GetExchangeRate *rate.Limiter - GetInstrumentsRate *rate.Limiter - GetSystemTimeRate *rate.Limiter - GetSystemStatusRate *rate.Limiter -} - // Rate of requests per interval for each end point const ( placeTradeOrderRate = 60 @@ -239,223 +163,77 @@ const ( getSystemStatusEPL ) -// Limit implements an endpoint limit. -func (r *RateLimit) Limit(ctx context.Context, ep request.EndpointLimit) error { - switch ep { - case placeTradeOrderEPL: - return r.PlaceTradeOrder.Wait(ctx) - case placeTradeMultipleOrdersEPL: - return r.PlaceTradeMultipleOrders.Wait(ctx) - case cancelTradeOrderEPL: - return r.CancelTradeOrder.Wait(ctx) - case cancelMultipleOrderEPL: - return r.CancelMultipleOrder.Wait(ctx) - case amendTradeOrderEPL: - return r.AmendTradeOrder.Wait(ctx) - case amendMultipleOrdersEPL: - return r.AmendMultipleOrders.Wait(ctx) - case getOrderDetailsEPL: - return r.GetOrderDetails.Wait(ctx) - case getOrderListEPL: - return r.GetOrderList.Wait(ctx) - case getOrderHistoryEPL: - return r.GetOrderHistory.Wait(ctx) - case getOrderhistory3MonthsEPL: - return r.GetOrderhistory3Months.Wait(ctx) - case getTransactionDetails3DaysEPL: - return r.GetTransactionDetails3Days.Wait(ctx) - case getTransactionDetails3MonthsEPL: - return r.GetTransactionDetails3Months.Wait(ctx) - case placeAlgoOrderEPL: - return r.PlaceAlgoOrder.Wait(ctx) - case cancelAlgoOrderEPL: - return r.CancelAlgoOrder.Wait(ctx) - case cancelAdvancedAlgoOrderEPL: - return r.CancelAdvancedAlgoOrder.Wait(ctx) - case getAlgoOrderListEPL: - return r.GetAlgoOrderList.Wait(ctx) - case getAlgoOrderHistoryEPL: - return r.GetAlgoOrderHistory.Wait(ctx) - case getFundingCurrenciesEPL: - return r.GetFundingCurrencies.Wait(ctx) - case getFundingAccountBalanceEPL: - return r.GetFundingAccountBalance.Wait(ctx) - case getAccountAssetValuationEPL: - return r.GetAccountAssetValuation.Wait(ctx) - case fundingTransferEPL: - return r.FundingTransfer.Wait(ctx) - case getFundsTransferStateEPL: - return r.GetFundsTransferState.Wait(ctx) - case assetBillsDetailEPL: - return r.AssetBillsDetail.Wait(ctx) - case lightningDepositsEPL: - return r.LightningDeposits.Wait(ctx) - case getAssetDepositAddressEPL: - return r.GetAssetDepositAddress.Wait(ctx) - case getDepositHistoryEPL: - return r.GetDepositHistory.Wait(ctx) - case postWithdrawalEPL: - return r.PostWithdrawal.Wait(ctx) - case postLightningWithdrawalEPL: - return r.PostLightningWithdrawal.Wait(ctx) - case cancelWithdrawalEPL: - return r.CancelWithdrawal.Wait(ctx) - case getAssetWithdrawalHistoryEPL: - return r.GetAssetWithdrawalHistory.Wait(ctx) - case getAccountBalanceEPL: - return r.GetAccountBalance.Wait(ctx) - case getBillsDetailLast3MonthEPL: - return r.GetBillsDetailLast3Month.Wait(ctx) - case getBillsDetailEPL: - return r.GetBillsDetail.Wait(ctx) - case getAccountConfigurationEPL: - return r.GetAccountConfiguration.Wait(ctx) - case getMaxBuySellAmountOpenAmountEPL: - return r.GetMaxBuySellAmountOpenAmount.Wait(ctx) - case getMaxAvailableTradableAmountEPL: - return r.GetMaxAvailableTradableAmount.Wait(ctx) - case getFeeRatesEPL: - return r.GetFeeRates.Wait(ctx) - case getMaxWithdrawalsEPL: - return r.GetMaxWithdrawals.Wait(ctx) - case getAvailablePairsEPL: - return r.GetAvailablePairs.Wait(ctx) - case requestQuotesEPL: - return r.RequestQuotes.Wait(ctx) - case placeRFQOrderEPL: - return r.PlaceRFQOrder.Wait(ctx) - case getRFQTradeOrderDetailsEPL: - return r.GetRFQTradeOrderDetails.Wait(ctx) - case getRFQTradeOrderHistoryEPL: - return r.GetRFQTradeOrderHistory.Wait(ctx) - case fiatDepositEPL: - return r.FiatDepositRate.Wait(ctx) - case fiatCancelDepositEPL: - return r.FiatCancelDepositRate.Wait(ctx) - case fiatDepositHistoryEPL: - return r.FiatDepositHistoryRate.Wait(ctx) - case fiatWithdrawalEPL: - return r.FiatWithdrawalRate.Wait(ctx) - case fiatCancelWithdrawalEPL: - return r.FiatCancelWithdrawalRate.Wait(ctx) - case fiatGetWithdrawalsEPL: - return r.FiatGetWithdrawalsRate.Wait(ctx) - case fiatGetChannelInfoEPL: - return r.FiatGetChannelInfoRate.Wait(ctx) - case subAccountsListEPL: - return r.SubAccountsList.Wait(ctx) - case getAPIKeyOfASubAccountEPL: - return r.GetAPIKeyOfASubAccount.Wait(ctx) - case getSubAccountTradingBalanceEPL: - return r.GetSubAccountTradingBalance.Wait(ctx) - case getSubAccountFundingBalanceEPL: - return r.GetSubAccountFundingBalance.Wait(ctx) - case subAccountTransferHistoryEPL: - return r.SubAccountTransferHistory.Wait(ctx) - case masterAccountsManageTransfersBetweenSubaccountEPL: - return r.MasterAccountsManageTransfersBetweenSubaccount.Wait(ctx) - case getTickersEPL: - return r.GetTickers.Wait(ctx) - case getTickerEPL: - return r.GetTicker.Wait(ctx) - case getOrderbookEPL: - return r.GetOrderbook.Wait(ctx) - case getCandlesticksEPL: - return r.GetCandlesticks.Wait(ctx) - case getCandlestickHistoryEPL: - return r.GetCandlestickHistory.Wait(ctx) - case getPublicTradesEPL: - return r.GetPublicTrades.Wait(ctx) - case getPublicTradeHistroryEPL: - return r.GetPublicTradeHistrory.Wait(ctx) - case get24HourTradingVolumeEPL: - return r.Get24HourTradingVolume.Wait(ctx) - case getOracleEPL: - return r.GetOracle.Wait(ctx) - case getExchangeRateEPL: - return r.GetExchangeRate.Wait(ctx) - case getInstrumentsEPL: - return r.GetInstrumentsRate.Wait(ctx) - case getSystemTimeEPL: - return r.GetSystemTimeRate.Wait(ctx) - case getSystemStatusEPL: - return r.GetSystemStatusRate.Wait(ctx) - default: - return errors.New("unknown endpoint limit") - } -} - -// SetRateLimit returns a new RateLimit instance which implements request.Limiter interface. -func SetRateLimit() *RateLimit { - return &RateLimit{ - PlaceTradeOrder: request.NewRateLimit(twoSecondsInterval, placeTradeOrderRate), - PlaceTradeMultipleOrders: request.NewRateLimit(twoSecondsInterval, placeTradeMultipleOrdersRate), - CancelTradeOrder: request.NewRateLimit(twoSecondsInterval, cancelTradeOrderRate), - CancelMultipleOrder: request.NewRateLimit(twoSecondsInterval, cancelMultipleOrderRate), - AmendTradeOrder: request.NewRateLimit(twoSecondsInterval, amendTradeOrderRate), - AmendMultipleOrders: request.NewRateLimit(twoSecondsInterval, amendMultipleOrdersRate), - GetOrderDetails: request.NewRateLimit(twoSecondsInterval, getOrderDetailsRate), - GetOrderList: request.NewRateLimit(twoSecondsInterval, getOrderListRate), - GetOrderHistory: request.NewRateLimit(twoSecondsInterval, getOrderHistoryRate), - GetOrderhistory3Months: request.NewRateLimit(twoSecondsInterval, getOrderhistory3MonthsRate), - GetTransactionDetails3Days: request.NewRateLimit(twoSecondsInterval, getTransactionDetails3DaysRate), - GetTransactionDetails3Months: request.NewRateLimit(twoSecondsInterval, getTransactionDetails3MonthsRate), - PlaceAlgoOrder: request.NewRateLimit(twoSecondsInterval, placeAlgoOrderRate), - CancelAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAlgoOrderRate), - CancelAdvancedAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAdvancedAlgoOrderRate), - GetAlgoOrderList: request.NewRateLimit(twoSecondsInterval, getAlgoOrderListRate), - GetAlgoOrderHistory: request.NewRateLimit(twoSecondsInterval, getAlgoOrderHistoryRate), - GetFundingCurrencies: request.NewRateLimit(oneSecondInterval, getFundingCurrenciesRate), - GetFundingAccountBalance: request.NewRateLimit(oneSecondInterval, getFundingAccountBalanceRate), - GetAccountAssetValuation: request.NewRateLimit(twoSecondsInterval, getAccountAssetValuationRate), - FundingTransfer: request.NewRateLimit(oneSecondInterval, fundingTransferRate), - GetFundsTransferState: request.NewRateLimit(oneSecondInterval, getFundsTransferStateRate), - AssetBillsDetail: request.NewRateLimit(oneSecondInterval, assetBillsDetailRate), - LightningDeposits: request.NewRateLimit(oneSecondInterval, lightningDepositsRate), - GetAssetDepositAddress: request.NewRateLimit(oneSecondInterval, getAssetDepositAddressRate), - GetDepositHistory: request.NewRateLimit(oneSecondInterval, getDepositHistoryRate), - PostWithdrawal: request.NewRateLimit(oneSecondInterval, postWithdrawalRate), - PostLightningWithdrawal: request.NewRateLimit(oneSecondInterval, postLightningWithdrawalRate), - CancelWithdrawal: request.NewRateLimit(oneSecondInterval, cancelWithdrawalRate), - GetAssetWithdrawalHistory: request.NewRateLimit(oneSecondInterval, getAssetWithdrawalHistoryRate), - GetAccountBalance: request.NewRateLimit(twoSecondsInterval, getAccountBalanceRate), - GetBillsDetailLast3Month: request.NewRateLimit(oneSecondInterval, getBillsDetailLast3MonthRate), - GetBillsDetail: request.NewRateLimit(oneSecondInterval, getBillsDetailRate), - GetAccountConfiguration: request.NewRateLimit(twoSecondsInterval, getAccountConfigurationRate), - GetMaxBuySellAmountOpenAmount: request.NewRateLimit(twoSecondsInterval, getMaxBuySellAmountOpenAmountRate), - GetMaxAvailableTradableAmount: request.NewRateLimit(twoSecondsInterval, getMaxAvailableTradableAmountRate), - GetFeeRates: request.NewRateLimit(twoSecondsInterval, getFeeRatesRate), - GetMaxWithdrawals: request.NewRateLimit(twoSecondsInterval, getMaxWithdrawalsRate), - GetAvailablePairs: request.NewRateLimit(oneSecondInterval, getAvailablePairsRate), - RequestQuotes: request.NewRateLimit(oneSecondInterval, requestQuotesRate), - PlaceRFQOrder: request.NewRateLimit(oneSecondInterval, placeRFQOrderRate), - GetRFQTradeOrderDetails: request.NewRateLimit(oneSecondInterval, getRFQTradeOrderDetailsRate), - GetRFQTradeOrderHistory: request.NewRateLimit(oneSecondInterval, getRFQTradeOrderHistoryRate), - FiatDepositRate: request.NewRateLimit(oneSecondInterval, fiatDepositRate), - FiatCancelDepositRate: request.NewRateLimit(twoSecondsInterval, fiatCancelDepositRate), - FiatDepositHistoryRate: request.NewRateLimit(oneSecondInterval, fiatDepositHistoryRate), - FiatWithdrawalRate: request.NewRateLimit(oneSecondInterval, fiatWithdrawalRate), - FiatCancelWithdrawalRate: request.NewRateLimit(twoSecondsInterval, fiatCancelWithdrawalRate), - FiatGetWithdrawalsRate: request.NewRateLimit(oneSecondInterval, fiatGetWithdrawalsRate), - FiatGetChannelInfoRate: request.NewRateLimit(oneSecondInterval, fiatGetChannelInfoRate), - SubAccountsList: request.NewRateLimit(twoSecondsInterval, subAccountsListRate), - GetAPIKeyOfASubAccount: request.NewRateLimit(oneSecondInterval, getAPIKeyOfASubAccountRate), - GetSubAccountTradingBalance: request.NewRateLimit(twoSecondsInterval, getSubAccountTradingBalanceRate), - GetSubAccountFundingBalance: request.NewRateLimit(twoSecondsInterval, getSubAccountFundingBalanceRate), - SubAccountTransferHistory: request.NewRateLimit(oneSecondInterval, subAccountTransferHistoryRate), - MasterAccountsManageTransfersBetweenSubaccount: request.NewRateLimit(oneSecondInterval, masterAccountsManageTransfersBetweenSubaccountRate), - GetTickers: request.NewRateLimit(twoSecondsInterval, getTickersRate), - GetTicker: request.NewRateLimit(twoSecondsInterval, getTickerRate), - GetOrderbook: request.NewRateLimit(twoSecondsInterval, getOrderbookRate), - GetCandlesticks: request.NewRateLimit(twoSecondsInterval, getCandlesticksRate), - GetCandlestickHistory: request.NewRateLimit(twoSecondsInterval, getCandlestickHistoryRate), - GetPublicTrades: request.NewRateLimit(twoSecondsInterval, getPublicTradesRate), - GetPublicTradeHistrory: request.NewRateLimit(twoSecondsInterval, getPublicTradeHistroryRate), - Get24HourTradingVolume: request.NewRateLimit(twoSecondsInterval, get24HourTradingVolumeRate), - GetOracle: request.NewRateLimit(fiveSecondsInterval, getOracleRate), - GetExchangeRate: request.NewRateLimit(twoSecondsInterval, getExchangeRateRate), - GetInstrumentsRate: request.NewRateLimit(twoSecondsInterval, getInstrumentsRate), - GetSystemTimeRate: request.NewRateLimit(twoSecondsInterval, getSystemTimeRate), - GetSystemStatusRate: request.NewRateLimit(fiveSecondsInterval, getSystemStatusRate), +// GetRateLimit returns a new RateLimit instance which implements request.Limiter interface. +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + placeTradeOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeTradeOrderRate, 1), + placeTradeMultipleOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeTradeMultipleOrdersRate, 1), + cancelTradeOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelTradeOrderRate, 1), + cancelMultipleOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelMultipleOrderRate, 1), + amendTradeOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, amendTradeOrderRate, 1), + amendMultipleOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, amendMultipleOrdersRate, 1), + getOrderDetailsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderDetailsRate, 1), + getOrderListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderListRate, 1), + getOrderHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderHistoryRate, 1), + getOrderhistory3MonthsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderhistory3MonthsRate, 1), + getTransactionDetails3DaysEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTransactionDetails3DaysRate, 1), + getTransactionDetails3MonthsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTransactionDetails3MonthsRate, 1), + placeAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeAlgoOrderRate, 1), + cancelAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAlgoOrderRate, 1), + cancelAdvancedAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAdvancedAlgoOrderRate, 1), + getAlgoOrderListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAlgoOrderListRate, 1), + getAlgoOrderHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAlgoOrderHistoryRate, 1), + getFundingCurrenciesEPL: request.NewRateLimitWithWeight(oneSecondInterval, getFundingCurrenciesRate, 1), + getFundingAccountBalanceEPL: request.NewRateLimitWithWeight(oneSecondInterval, getFundingAccountBalanceRate, 1), + getAccountAssetValuationEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountAssetValuationRate, 1), + fundingTransferEPL: request.NewRateLimitWithWeight(oneSecondInterval, fundingTransferRate, 1), + getFundsTransferStateEPL: request.NewRateLimitWithWeight(oneSecondInterval, getFundsTransferStateRate, 1), + assetBillsDetailEPL: request.NewRateLimitWithWeight(oneSecondInterval, assetBillsDetailRate, 1), + lightningDepositsEPL: request.NewRateLimitWithWeight(oneSecondInterval, lightningDepositsRate, 1), + getAssetDepositAddressEPL: request.NewRateLimitWithWeight(oneSecondInterval, getAssetDepositAddressRate, 1), + getDepositHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getDepositHistoryRate, 1), + postWithdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, postWithdrawalRate, 1), + postLightningWithdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, postLightningWithdrawalRate, 1), + cancelWithdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, cancelWithdrawalRate, 1), + getAssetWithdrawalHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getAssetWithdrawalHistoryRate, 1), + getAccountBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountBalanceRate, 1), + getBillsDetailLast3MonthEPL: request.NewRateLimitWithWeight(oneSecondInterval, getBillsDetailLast3MonthRate, 1), + getBillsDetailEPL: request.NewRateLimitWithWeight(oneSecondInterval, getBillsDetailRate, 1), + getAccountConfigurationEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountConfigurationRate, 1), + getMaxBuySellAmountOpenAmountEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaxBuySellAmountOpenAmountRate, 1), + getMaxAvailableTradableAmountEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaxAvailableTradableAmountRate, 1), + getFeeRatesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getFeeRatesRate, 1), + getMaxWithdrawalsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaxWithdrawalsRate, 1), + getAvailablePairsEPL: request.NewRateLimitWithWeight(oneSecondInterval, getAvailablePairsRate, 1), + requestQuotesEPL: request.NewRateLimitWithWeight(oneSecondInterval, requestQuotesRate, 1), + placeRFQOrderEPL: request.NewRateLimitWithWeight(oneSecondInterval, placeRFQOrderRate, 1), + getRFQTradeOrderDetailsEPL: request.NewRateLimitWithWeight(oneSecondInterval, getRFQTradeOrderDetailsRate, 1), + getRFQTradeOrderHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getRFQTradeOrderHistoryRate, 1), + fiatDepositEPL: request.NewRateLimitWithWeight(oneSecondInterval, fiatDepositRate, 1), + fiatCancelDepositEPL: request.NewRateLimitWithWeight(twoSecondsInterval, fiatCancelDepositRate, 1), + fiatDepositHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, fiatDepositHistoryRate, 1), + fiatWithdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, fiatWithdrawalRate, 1), + fiatCancelWithdrawalEPL: request.NewRateLimitWithWeight(twoSecondsInterval, fiatCancelWithdrawalRate, 1), + fiatGetWithdrawalsEPL: request.NewRateLimitWithWeight(oneSecondInterval, fiatGetWithdrawalsRate, 1), + fiatGetChannelInfoEPL: request.NewRateLimitWithWeight(oneSecondInterval, fiatGetChannelInfoRate, 1), + subAccountsListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, subAccountsListRate, 1), + getAPIKeyOfASubAccountEPL: request.NewRateLimitWithWeight(oneSecondInterval, getAPIKeyOfASubAccountRate, 1), + getSubAccountTradingBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSubAccountTradingBalanceRate, 1), + getSubAccountFundingBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSubAccountFundingBalanceRate, 1), + subAccountTransferHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, subAccountTransferHistoryRate, 1), + masterAccountsManageTransfersBetweenSubaccountEPL: request.NewRateLimitWithWeight(oneSecondInterval, masterAccountsManageTransfersBetweenSubaccountRate, 1), + getTickersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTickersRate, 1), + getTickerEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTickerRate, 1), + getOrderbookEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderbookRate, 1), + getCandlesticksEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getCandlesticksRate, 1), + getCandlestickHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getCandlestickHistoryRate, 1), + getPublicTradesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPublicTradesRate, 1), + getPublicTradeHistroryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPublicTradeHistroryRate, 1), + get24HourTradingVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, get24HourTradingVolumeRate, 1), + getOracleEPL: request.NewRateLimitWithWeight(fiveSecondsInterval, getOracleRate, 1), + getExchangeRateEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getExchangeRateRate, 1), + getInstrumentsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInstrumentsRate, 1), + getSystemTimeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSystemTimeRate, 1), + getSystemStatusEPL: request.NewRateLimitWithWeight(fiveSecondsInterval, getSystemStatusRate, 1), } } diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index bda68cf2..a86b88f5 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -116,7 +116,7 @@ func (o *Okcoin) SetDefaults() { } o.Requester, err = request.New(o.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit()), + request.WithLimiter(GetRateLimit()), ) if err != nil { log.Errorln(log.ExchangeSys, err) diff --git a/exchanges/okx/okx.go b/exchanges/okx/okx.go index 2e951367..af782f4d 100644 --- a/exchanges/okx/okx.go +++ b/exchanges/okx/okx.go @@ -3140,7 +3140,7 @@ func (ok *Okx) GetIntervalEnum(interval kline.Interval, appendUTC bool) string { // GetCandlesticks Retrieve the candlestick charts. This endpoint can retrieve the latest 1,440 data entries. Charts are returned in groups based on the requested bar. func (ok *Okx) GetCandlesticks(ctx context.Context, instrumentID string, interval kline.Interval, before, after time.Time, limit int64) ([]CandleStick, error) { - return ok.GetCandlestickData(ctx, instrumentID, interval, before, after, limit, marketCandles, getCandlesticksEPL) + return ok.GetCandlestickData(ctx, instrumentID, interval, before, after, limit, marketCandles, getCandlestickEPL) } // GetCandlesticksHistory Retrieve history candlestick charts from recent years. @@ -3151,7 +3151,7 @@ func (ok *Okx) GetCandlesticksHistory(ctx context.Context, instrumentID string, // GetIndexCandlesticks Retrieve the candlestick charts of the index. This endpoint can retrieve the latest 1,440 data entries. Charts are returned in groups based on the requested bar. // the response is a list of Candlestick data. func (ok *Okx) GetIndexCandlesticks(ctx context.Context, instrumentID string, interval kline.Interval, before, after time.Time, limit int64) ([]CandleStick, error) { - return ok.GetCandlestickData(ctx, instrumentID, interval, before, after, limit, marketCandlesIndex, getIndexCandlesticksEPL) + return ok.GetCandlestickData(ctx, instrumentID, interval, before, after, limit, marketCandlesIndex, getIndexCandlestickEPL) } // GetMarkPriceCandlesticks Retrieve the candlestick charts of mark price. This endpoint can retrieve the latest 1,440 data entries. Charts are returned in groups based on the requested bar. @@ -3488,7 +3488,7 @@ func (ok *Okx) GetEstimatedDeliveryPrice(ctx context.Context, instrumentID strin return nil, errMissingRequiredParamInstID } params.Set("instId", instrumentID) - return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getEstimatedDeliveryPriceEPL, http.MethodGet, common.EncodeURLValues(publicEstimatedPrice, params), nil, &resp, false) + return resp, ok.SendHTTPRequest(ctx, exchange.RestSpot, getEstimatedDeliveryExercisePriceEPL, http.MethodGet, common.EncodeURLValues(publicEstimatedPrice, params), nil, &resp, false) } // GetDiscountRateAndInterestFreeQuota retrieves discount rate level and interest-free quota. diff --git a/exchanges/okx/okx_test.go b/exchanges/okx/okx_test.go index 37812082..20b05cd6 100644 --- a/exchanges/okx/okx_test.go +++ b/exchanges/okx/okx_test.go @@ -989,7 +989,7 @@ func TestCancelAllQuotes(t *testing.T) { switch { case err != nil: t.Error("Okx CancelAllQuotes() error", err) - case err == nil && time.IsZero(): + case time.IsZero(): t.Error("Okx CancelAllQuotes() zero timestamp message ") } } @@ -2237,7 +2237,7 @@ func TestGetOrderHistory(t *testing.T) { _, err := ok.GetOrderHistory(contextGenerate(), &getOrdersRequest) if err == nil { t.Errorf("Okx GetOrderHistory() Expected: %v. received nil", err) - } else if err != nil && !errors.Is(err, errMissingAtLeast1CurrencyPair) { + } else if !errors.Is(err, errMissingAtLeast1CurrencyPair) { t.Errorf("Okx GetOrderHistory() Expected: %v, but found %v", errMissingAtLeast1CurrencyPair, err) } getOrdersRequest.Pairs = []currency.Pair{ diff --git a/exchanges/okx/okx_websocket.go b/exchanges/okx/okx_websocket.go index 29f5435a..3b5a9d2e 100644 --- a/exchanges/okx/okx_websocket.go +++ b/exchanges/okx/okx_websocket.go @@ -1829,9 +1829,6 @@ func (ok *Okx) wsChannelSubscription(operation, channel string, assetType asset. return errIncompleteCurrencyPair } instrumentID = format.Format(pair) - if err != nil { - instrumentID = "" - } } input := &SubscriptionOperationInput{ Operation: operation, @@ -1885,9 +1882,6 @@ func (ok *Okx) wsAuthChannelSubscription(operation, channel string, assetType as return errIncompleteCurrencyPair } instrumentID = format.Format(pair) - if err != nil { - instrumentID = "" - } } if params.Currency { if !pair.IsEmpty() { diff --git a/exchanges/okx/okx_wrapper.go b/exchanges/okx/okx_wrapper.go index d454e30d..9b1f80d1 100644 --- a/exchanges/okx/okx_wrapper.go +++ b/exchanges/okx/okx_wrapper.go @@ -154,7 +154,7 @@ func (ok *Okx) SetDefaults() { } ok.Requester, err = request.New(ok.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } @@ -820,12 +820,8 @@ func (ok *Okx) ModifyOrder(ctx context.Context, action *order.Modify) (*order.Mo if action.Pair.IsEmpty() { return nil, currency.ErrCurrencyPairEmpty } - instrumentID := pairFormat.Format(action.Pair) - if err != nil { - return nil, err - } amendRequest := AmendOrderRequestParams{ - InstrumentID: instrumentID, + InstrumentID: pairFormat.Format(action.Pair), NewQuantity: action.Amount, OrderID: action.OrderID, ClientOrderID: action.ClientOrderID, @@ -888,8 +884,6 @@ func (ok *Okx) CancelBatchOrders(ctx context.Context, o []order.Cancel) (*order. if !ok.SupportsAsset(ord.AssetType) { return nil, fmt.Errorf("%w: %v", asset.ErrNotSupported, ord.AssetType) } - - var instrumentID string var pairFormat currency.PairFormat pairFormat, err = ok.GetPairFormat(ord.AssetType, true) if err != nil { @@ -898,12 +892,8 @@ func (ok *Okx) CancelBatchOrders(ctx context.Context, o []order.Cancel) (*order. if !ord.Pair.IsPopulated() { return nil, errIncompleteCurrencyPair } - instrumentID = pairFormat.Format(ord.Pair) - if err != nil { - return nil, err - } cancelOrderParams[x] = CancelOrderRequestParam{ - InstrumentID: instrumentID, + InstrumentID: pairFormat.Format(ord.Pair), OrderID: ord.OrderID, ClientOrderID: ord.ClientOrderID, } diff --git a/exchanges/okx/ratelimit.go b/exchanges/okx/ratelimit.go index 6ccb0b4f..bc1fd23d 100644 --- a/exchanges/okx/ratelimit.go +++ b/exchanges/okx/ratelimit.go @@ -1,12 +1,9 @@ package okx import ( - "context" - "errors" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) // Ratelimit intervals. @@ -18,182 +15,6 @@ const ( tenSecondsInterval = 10 * time.Second ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - // Trade Endpoints - PlaceOrder *rate.Limiter - PlaceMultipleOrders *rate.Limiter - CancelOrder *rate.Limiter - CancelMultipleOrders *rate.Limiter - AmendOrder *rate.Limiter - AmendMultipleOrders *rate.Limiter - CloseDeposit *rate.Limiter - GetOrderDetails *rate.Limiter - GetOrderList *rate.Limiter - GetOrderHistory7Days *rate.Limiter - GetOrderHistory3Months *rate.Limiter - GetTransactionDetail3Days *rate.Limiter - GetTransactionDetail3Months *rate.Limiter - PlaceAlgoOrder *rate.Limiter - CancelAlgoOrder *rate.Limiter - CancelAdvanceAlgoOrder *rate.Limiter - GetAlgoOrderList *rate.Limiter - GetAlgoOrderHistory *rate.Limiter - GetEasyConvertCurrencyList *rate.Limiter - PlaceEasyConvert *rate.Limiter - GetEasyConvertHistory *rate.Limiter - GetOneClickRepayHistory *rate.Limiter - OneClickRepayCurrencyList *rate.Limiter - TradeOneClickRepay *rate.Limiter - // Block Trading endpoints - GetCounterparties *rate.Limiter - CreateRfq *rate.Limiter - CancelRfq *rate.Limiter - CancelMultipleRfq *rate.Limiter - CancelAllRfqs *rate.Limiter - ExecuteQuote *rate.Limiter - SetQuoteProducts *rate.Limiter - RestMMPStatus *rate.Limiter - CreateQuote *rate.Limiter - CancelQuote *rate.Limiter - CancelMultipleQuotes *rate.Limiter - CancelAllQuotes *rate.Limiter - GetRfqs *rate.Limiter - GetQuotes *rate.Limiter - GetTrades *rate.Limiter - GetTradesHistory *rate.Limiter - GetPublicTrades *rate.Limiter - // Funding - GetCurrencies *rate.Limiter - GetBalance *rate.Limiter - GetAccountAssetValuation *rate.Limiter - FundsTransfer *rate.Limiter - GetFundsTransferState *rate.Limiter - AssetBillsDetails *rate.Limiter - LightningDeposits *rate.Limiter - GetDepositAddress *rate.Limiter - GetDepositHistory *rate.Limiter - Withdrawal *rate.Limiter - LightningWithdrawals *rate.Limiter - CancelWithdrawal *rate.Limiter - GetWithdrawalHistory *rate.Limiter - SmallAssetsConvert *rate.Limiter - // Savings - GetSavingBalance *rate.Limiter - SavingsPurchaseRedempt *rate.Limiter - SetLendingRate *rate.Limiter - GetLendingHistory *rate.Limiter - GetPublicBorrowInfo *rate.Limiter - GetPublicBorrowHistory *rate.Limiter - // Convert - GetConvertCurrencies *rate.Limiter - GetConvertCurrencyPair *rate.Limiter - EstimateQuote *rate.Limiter - ConvertTrade *rate.Limiter - GetConvertHistory *rate.Limiter - // Account - GetAccountBalance *rate.Limiter - GetPositions *rate.Limiter - GetPositionsHistory *rate.Limiter - GetAccountAndPositionRisk *rate.Limiter - GetBillsDetails *rate.Limiter - GetAccountConfiguration *rate.Limiter - SetPositionMode *rate.Limiter - SetLeverage *rate.Limiter - GetMaximumBuyOrSellAmount *rate.Limiter - GetMaximumAvailableTradableAmount *rate.Limiter - IncreaseOrDecreaseMargin *rate.Limiter - GetLeverage *rate.Limiter - GetTheMaximumLoanOfInstrument *rate.Limiter - GetFeeRates *rate.Limiter - GetInterestAccruedData *rate.Limiter - GetInterestRate *rate.Limiter - SetGreeks *rate.Limiter - IsolatedMarginTradingSettings *rate.Limiter - GetMaximumWithdrawals *rate.Limiter - GetAccountRiskState *rate.Limiter - VipLoansBorrowAnsRepay *rate.Limiter - GetBorrowAnsRepayHistoryHistory *rate.Limiter - GetBorrowInterestAndLimit *rate.Limiter - PositionBuilder *rate.Limiter - GetGreeks *rate.Limiter - GetPMLimitation *rate.Limiter - // Sub Account Endpoints - ViewSubaccountList *rate.Limiter - ResetSubAccountAPIKey *rate.Limiter - GetSubaccountTradingBalance *rate.Limiter - GetSubaccountFundingBalance *rate.Limiter - HistoryOfSubaccountTransfer *rate.Limiter - MasterAccountsManageTransfersBetweenSubaccount *rate.Limiter - SetPermissionOfTransferOut *rate.Limiter - GetCustodyTradingSubaccountList *rate.Limiter - GridTrading *rate.Limiter - AmendGridAlgoOrder *rate.Limiter - StopGridAlgoOrder *rate.Limiter - GetGridAlgoOrderList *rate.Limiter - GetGridAlgoOrderHistory *rate.Limiter - GetGridAlgoOrderDetails *rate.Limiter - GetGridAlgoSubOrders *rate.Limiter - GetGridAlgoOrderPositions *rate.Limiter - SpotGridWithdrawIncome *rate.Limiter - ComputeMarginBalance *rate.Limiter - AdjustMarginBalance *rate.Limiter - GetGridAIParameter *rate.Limiter - // Earn - GetOffer *rate.Limiter - Purchase *rate.Limiter - Redeem *rate.Limiter - CancelPurchaseOrRedemption *rate.Limiter - GetEarnActiveOrders *rate.Limiter - GetFundingOrderHistory *rate.Limiter - // Market Data - GetTickers *rate.Limiter - GetIndexTickers *rate.Limiter - GetOrderBook *rate.Limiter - GetCandlesticks *rate.Limiter - GetCandlesticksHistory *rate.Limiter - GetIndexCandlesticks *rate.Limiter - GetMarkPriceCandlesticks *rate.Limiter - GetTradesRequest *rate.Limiter - Get24HTotalVolume *rate.Limiter - GetOracle *rate.Limiter - GetExchangeRateRequest *rate.Limiter - GetIndexComponents *rate.Limiter - GetBlockTickers *rate.Limiter - GetBlockTrades *rate.Limiter - // Public Data Endpoints - GetInstruments *rate.Limiter - GetDeliveryExerciseHistory *rate.Limiter - GetOpenInterest *rate.Limiter - GetFunding *rate.Limiter - GetFundingRateHistory *rate.Limiter - GetLimitPrice *rate.Limiter - GetOptionMarketDate *rate.Limiter - GetEstimatedDeliveryExercisePrice *rate.Limiter - GetDiscountRateAndInterestFreeQuota *rate.Limiter - GetSystemTime *rate.Limiter - GetLiquidationOrders *rate.Limiter - GetMarkPrice *rate.Limiter - GetPositionTiers *rate.Limiter - GetInterestRateAndLoanQuota *rate.Limiter - GetInterestRateAndLoanQuoteForVIPLoans *rate.Limiter - GetUnderlying *rate.Limiter - GetInsuranceFund *rate.Limiter - UnitConvert *rate.Limiter - // Trading Data Endpoints - GetSupportCoin *rate.Limiter - GetTakerVolume *rate.Limiter - GetMarginLendingRatio *rate.Limiter - GetLongShortRatio *rate.Limiter - GetContractsOpenInterestAndVolume *rate.Limiter - GetOptionsOpenInterestAndVolume *rate.Limiter - GetPutCallRatio *rate.Limiter - GetOpenInterestAndVolume *rate.Limiter - GetTakerFlow *rate.Limiter - // Status Endpoints - GetEventStatus *rate.Limiter -} - const ( // Trade Endpoints placeOrderRate = 60 @@ -202,7 +23,7 @@ const ( cancelMultipleOrdersRate = 300 amendOrderRate = 60 amendMultipleOrdersRate = 300 - closeDepositions = 20 + closePositionsRate = 20 getOrderDetails = 60 getOrderListRate = 60 getOrderHistory7DaysRate = 40 @@ -502,7 +323,7 @@ const ( getTickersEPL getIndexTickersEPL getOrderBookEPL - getCandlesticksEPL + getCandlestickEPL getTradesRequestEPL get24HTotalVolumeEPL getOracleEPL @@ -517,7 +338,7 @@ const ( getFundingRateHistoryEPL getLimitPriceEPL getOptionMarketDateEPL - getEstimatedDeliveryPriceEPL + getEstimatedDeliveryExercisePriceEPL getDiscountRateAndInterestFreeQuotaEPL getSystemTimeEPL getLiquidationOrdersEPL @@ -539,519 +360,192 @@ const ( getTakerFlowEPL getEventStatusEPL getCandlestickHistoryEPL - getIndexCandlesticksEPL + getIndexCandlestickEPL ) -// Limit executes rate limiting for Okx exchange given the context and EndpointLimit -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - switch f { - case placeOrderEPL: - return r.PlaceOrder.Wait(ctx) - case placeMultipleOrdersEPL: - return r.PlaceMultipleOrders.Wait(ctx) - case cancelOrderEPL: - return r.CancelOrder.Wait(ctx) - case cancelMultipleOrdersEPL: - return r.CancelMultipleOrders.Wait(ctx) - case amendOrderEPL: - return r.AmendOrder.Wait(ctx) - case amendMultipleOrdersEPL: - return r.AmendMultipleOrders.Wait(ctx) - case closePositionEPL: - return r.CloseDeposit.Wait(ctx) - case getOrderDetEPL: - return r.GetOrderDetails.Wait(ctx) - case getOrderListEPL: - return r.GetOrderList.Wait(ctx) - case getOrderHistory7DaysEPL: - return r.GetOrderHistory7Days.Wait(ctx) - case getOrderHistory3MonthsEPL: - return r.GetOrderHistory3Months.Wait(ctx) - case getTransactionDetail3DaysEPL: - return r.GetTransactionDetail3Days.Wait(ctx) - case getTransactionDetail3MonthsEPL: - return r.GetTransactionDetail3Months.Wait(ctx) - case placeAlgoOrderEPL: - return r.PlaceAlgoOrder.Wait(ctx) - case cancelAlgoOrderEPL: - return r.CancelAlgoOrder.Wait(ctx) - case cancelAdvanceAlgoOrderEPL: - return r.CancelAdvanceAlgoOrder.Wait(ctx) - case getAlgoOrderListEPL: - return r.GetAlgoOrderList.Wait(ctx) - case getAlgoOrderHistoryEPL: - return r.GetAlgoOrderHistory.Wait(ctx) - case getEasyConvertCurrencyListEPL: - return r.GetEasyConvertCurrencyList.Wait(ctx) - case placeEasyConvertEPL: - return r.PlaceEasyConvert.Wait(ctx) - case getEasyConvertHistoryEPL: - return r.GetEasyConvertHistory.Wait(ctx) - case getOneClickRepayHistoryEPL: - return r.GetOneClickRepayHistory.Wait(ctx) - case oneClickRepayCurrencyListEPL: - return r.OneClickRepayCurrencyList.Wait(ctx) - case tradeOneClickRepayEPL: - return r.TradeOneClickRepay.Wait(ctx) - case getCounterpartiesEPL: - return r.GetCounterparties.Wait(ctx) - case createRfqEPL: - return r.CreateRfq.Wait(ctx) - case cancelRfqEPL: - return r.CancelRfq.Wait(ctx) - case cancelMultipleRfqEPL: - return r.CancelMultipleRfq.Wait(ctx) - case cancelAllRfqsEPL: - return r.CancelAllRfqs.Wait(ctx) - case executeQuoteEPL: - return r.ExecuteQuote.Wait(ctx) - case setQuoteProductsEPL: - return r.SetQuoteProducts.Wait(ctx) - case restMMPStatusEPL: - return r.RestMMPStatus.Wait(ctx) - case createQuoteEPL: - return r.CreateQuote.Wait(ctx) - case cancelQuoteEPL: - return r.CancelQuote.Wait(ctx) - case cancelMultipleQuotesEPL: - return r.CancelMultipleQuotes.Wait(ctx) - case cancelAllQuotesEPL: - return r.CancelAllQuotes.Wait(ctx) - case getRfqsEPL: - return r.GetRfqs.Wait(ctx) - case getQuotesEPL: - return r.GetQuotes.Wait(ctx) - case getTradesEPL: - return r.GetTrades.Wait(ctx) - case getTradesHistoryEPL: - return r.GetTradesHistory.Wait(ctx) - case getPublicTradesEPL: - return r.GetPublicTrades.Wait(ctx) - case getCurrenciesEPL: - return r.GetCurrencies.Wait(ctx) - case getBalanceEPL: - return r.GetBalance.Wait(ctx) - case getAccountAssetValuationEPL: - return r.GetAccountAssetValuation.Wait(ctx) - case fundsTransferEPL: - return r.FundsTransfer.Wait(ctx) - case getFundsTransferStateEPL: - return r.GetFundsTransferState.Wait(ctx) - case assetBillsDetailsEPL: - return r.AssetBillsDetails.Wait(ctx) - case lightningDepositsEPL: - return r.LightningDeposits.Wait(ctx) - case getDepositAddressEPL: - return r.GetDepositAddress.Wait(ctx) - case getDepositHistoryEPL: - return r.GetDepositHistory.Wait(ctx) - case withdrawalEPL: - return r.Withdrawal.Wait(ctx) - case lightningWithdrawalsEPL: - return r.LightningWithdrawals.Wait(ctx) - case cancelWithdrawalEPL: - return r.CancelWithdrawal.Wait(ctx) - case getWithdrawalHistoryEPL: - return r.GetWithdrawalHistory.Wait(ctx) - case smallAssetsConvertEPL: - return r.SmallAssetsConvert.Wait(ctx) - case getSavingBalanceEPL: - return r.GetSavingBalance.Wait(ctx) - case savingsPurchaseRedemptionEPL: - return r.SavingsPurchaseRedempt.Wait(ctx) - case setLendingRateEPL: - return r.SetLendingRate.Wait(ctx) - case getLendingHistoryEPL: - return r.GetLendingHistory.Wait(ctx) - case getPublicBorrowInfoEPL: - return r.GetPublicBorrowInfo.Wait(ctx) - case getPublicBorrowHistoryEPL: - return r.GetPublicBorrowHistory.Wait(ctx) - case getConvertCurrenciesEPL: - return r.GetConvertCurrencies.Wait(ctx) - case getConvertCurrencyPairEPL: - return r.GetConvertCurrencyPair.Wait(ctx) - case estimateQuoteEPL: - return r.EstimateQuote.Wait(ctx) - case convertTradeEPL: - return r.ConvertTrade.Wait(ctx) - case getConvertHistoryEPL: - return r.GetConvertHistory.Wait(ctx) - case getAccountBalanceEPL: - return r.GetAccountBalance.Wait(ctx) - case getPositionsEPL: - return r.GetPositions.Wait(ctx) - case getPositionsHistoryEPL: - return r.GetPositionsHistory.Wait(ctx) - case getAccountAndPositionRiskEPL: - return r.GetAccountAndPositionRisk.Wait(ctx) - case getBillsDetailsEPL: - return r.GetBillsDetails.Wait(ctx) - case getAccountConfigurationEPL: - return r.GetAccountConfiguration.Wait(ctx) - case setPositionModeEPL: - return r.SetPositionMode.Wait(ctx) - case setLeverageEPL: - return r.SetLeverage.Wait(ctx) - case getMaximumBuyOrSellAmountEPL: - return r.GetMaximumBuyOrSellAmount.Wait(ctx) - case getMaximumAvailableTradableAmountEPL: - return r.GetMaximumAvailableTradableAmount.Wait(ctx) - case increaseOrDecreaseMarginEPL: - return r.IncreaseOrDecreaseMargin.Wait(ctx) - case getLeverageEPL: - return r.GetLeverage.Wait(ctx) - case getTheMaximumLoanOfInstrumentEPL: - return r.GetTheMaximumLoanOfInstrument.Wait(ctx) - case getFeeRatesEPL: - return r.GetFeeRates.Wait(ctx) - case getInterestAccruedDataEPL: - return r.GetInterestAccruedData.Wait(ctx) - case getInterestRateEPL: - return r.GetInterestRate.Wait(ctx) - case setGreeksEPL: - return r.SetGreeks.Wait(ctx) - case isolatedMarginTradingSettingsEPL: - return r.IsolatedMarginTradingSettings.Wait(ctx) - case getMaximumWithdrawalsEPL: - return r.GetMaximumWithdrawals.Wait(ctx) - case getAccountRiskStateEPL: - return r.GetAccountRiskState.Wait(ctx) - case vipLoansBorrowAnsRepayEPL: - return r.VipLoansBorrowAnsRepay.Wait(ctx) - case getBorrowAnsRepayHistoryHistoryEPL: - return r.GetBorrowAnsRepayHistoryHistory.Wait(ctx) - case getBorrowInterestAndLimitEPL: - return r.GetBorrowInterestAndLimit.Wait(ctx) - case positionBuilderEPL: - return r.PositionBuilder.Wait(ctx) - case getGreeksEPL: - return r.GetGreeks.Wait(ctx) - case getPMLimitationEPL: - return r.GetPMLimitation.Wait(ctx) - case viewSubaccountListEPL: - return r.ViewSubaccountList.Wait(ctx) - case resetSubAccountAPIKeyEPL: - return r.ResetSubAccountAPIKey.Wait(ctx) - case getSubaccountTradingBalanceEPL: - return r.GetSubaccountTradingBalance.Wait(ctx) - case getSubaccountFundingBalanceEPL: - return r.GetSubaccountFundingBalance.Wait(ctx) - case historyOfSubaccountTransferEPL: - return r.HistoryOfSubaccountTransfer.Wait(ctx) - case masterAccountsManageTransfersBetweenSubaccountEPL: - return r.MasterAccountsManageTransfersBetweenSubaccount.Wait(ctx) - case setPermissionOfTransferOutEPL: - return r.SetPermissionOfTransferOut.Wait(ctx) - case getCustodyTradingSubaccountListEPL: - return r.GetCustodyTradingSubaccountList.Wait(ctx) - case gridTradingEPL: - return r.GridTrading.Wait(ctx) - case amendGridAlgoOrderEPL: - return r.AmendGridAlgoOrder.Wait(ctx) - case stopGridAlgoOrderEPL: - return r.StopGridAlgoOrder.Wait(ctx) - case getGridAlgoOrderListEPL: - return r.GetGridAlgoOrderList.Wait(ctx) - case getGridAlgoOrderHistoryEPL: - return r.GetGridAlgoOrderHistory.Wait(ctx) - case getGridAlgoOrderDetailsEPL: - return r.GetGridAlgoOrderDetails.Wait(ctx) - case getGridAlgoSubOrdersEPL: - return r.GetGridAlgoSubOrders.Wait(ctx) - case getGridAlgoOrderPositionsEPL: - return r.GetGridAlgoOrderPositions.Wait(ctx) - case spotGridWithdrawIncomeEPL: - return r.SpotGridWithdrawIncome.Wait(ctx) - case computeMarginBalanceEPL: - return r.ComputeMarginBalance.Wait(ctx) - case adjustMarginBalanceEPL: - return r.AdjustMarginBalance.Wait(ctx) - case getGridAIParameterEPL: - return r.GetGridAIParameter.Wait(ctx) - case getOfferEPL: - return r.GetOffer.Wait(ctx) - case purchaseEPL: - return r.Purchase.Wait(ctx) - case redeemEPL: - return r.Redeem.Wait(ctx) - case cancelPurchaseOrRedemptionEPL: - return r.CancelPurchaseOrRedemption.Wait(ctx) - case getEarnActiveOrdersEPL: - return r.GetEarnActiveOrders.Wait(ctx) - case getFundingOrderHistoryEPL: - return r.GetFundingOrderHistory.Wait(ctx) - case getTickersEPL: - return r.GetTickers.Wait(ctx) - case getIndexTickersEPL: - return r.GetIndexTickers.Wait(ctx) - case getOrderBookEPL: - return r.GetOrderBook.Wait(ctx) - case getCandlesticksEPL: - return r.GetCandlesticks.Wait(ctx) - case getCandlestickHistoryEPL: - return r.GetCandlesticksHistory.Wait(ctx) - case getIndexCandlesticksEPL: - return r.GetIndexCandlesticks.Wait(ctx) - case getTradesRequestEPL: - return r.GetTradesRequest.Wait(ctx) - case get24HTotalVolumeEPL: - return r.Get24HTotalVolume.Wait(ctx) - case getOracleEPL: - return r.GetOracle.Wait(ctx) - case getExchangeRateRequestEPL: - return r.GetExchangeRateRequest.Wait(ctx) - case getIndexComponentsEPL: - return r.GetIndexComponents.Wait(ctx) - case getBlockTickersEPL: - return r.GetBlockTickers.Wait(ctx) - case getBlockTradesEPL: - return r.GetBlockTrades.Wait(ctx) - case getInstrumentsEPL: - return r.GetInstruments.Wait(ctx) - case getDeliveryExerciseHistoryEPL: - return r.GetDeliveryExerciseHistory.Wait(ctx) - case getOpenInterestEPL: - return r.GetOpenInterest.Wait(ctx) - case getFundingEPL: - return r.GetFunding.Wait(ctx) - case getFundingRateHistoryEPL: - return r.GetFundingRateHistory.Wait(ctx) - case getLimitPriceEPL: - return r.GetLimitPrice.Wait(ctx) - case getOptionMarketDateEPL: - return r.GetOptionMarketDate.Wait(ctx) - case getEstimatedDeliveryPriceEPL: - return r.GetEstimatedDeliveryExercisePrice.Wait(ctx) - case getDiscountRateAndInterestFreeQuotaEPL: - return r.GetDiscountRateAndInterestFreeQuota.Wait(ctx) - case getSystemTimeEPL: - return r.GetSystemTime.Wait(ctx) - case getLiquidationOrdersEPL: - return r.GetLiquidationOrders.Wait(ctx) - case getMarkPriceEPL: - return r.GetMarkPrice.Wait(ctx) - case getPositionTiersEPL: - return r.GetPositionTiers.Wait(ctx) - case getInterestRateAndLoanQuotaEPL: - return r.GetInterestRateAndLoanQuota.Wait(ctx) - case getInterestRateAndLoanQuoteForVIPLoansEPL: - return r.GetInterestRateAndLoanQuoteForVIPLoans.Wait(ctx) - case getUnderlyingEPL: - return r.GetUnderlying.Wait(ctx) - case getInsuranceFundEPL: - return r.GetInsuranceFund.Wait(ctx) - case unitConvertEPL: - return r.UnitConvert.Wait(ctx) - case getSupportCoinEPL: - return r.GetSupportCoin.Wait(ctx) - case getTakerVolumeEPL: - return r.GetTakerVolume.Wait(ctx) - case getMarginLendingRatioEPL: - return r.GetMarginLendingRatio.Wait(ctx) - case getLongShortRatioEPL: - return r.GetLongShortRatio.Wait(ctx) - case getContractsOpenInterestAndVolumeEPL: - return r.GetContractsOpenInterestAndVolume.Wait(ctx) - case getOptionsOpenInterestAndVolumeEPL: - return r.GetOptionsOpenInterestAndVolume.Wait(ctx) - case getPutCallRatioEPL: - return r.GetPutCallRatio.Wait(ctx) - case getOpenInterestAndVolumeEPL: - return r.GetOpenInterestAndVolume.Wait(ctx) - case getTakerFlowEPL: - return r.GetTakerFlow.Wait(ctx) - case getEventStatusEPL: - return r.GetEventStatus.Wait(ctx) - default: - return errors.New("endpoint rate limit functionality not found") - } -} - -// SetRateLimit returns a RateLimit instance, which implements the request.Limiter interface. -func SetRateLimit() *RateLimit { - return &RateLimit{ +// GetRateLimit returns a RateLimit instance, which implements the request.Limiter interface. +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ // Trade Endpoints - PlaceOrder: request.NewRateLimit(twoSecondsInterval, placeOrderRate), - PlaceMultipleOrders: request.NewRateLimit(twoSecondsInterval, placeMultipleOrdersRate), - CancelOrder: request.NewRateLimit(twoSecondsInterval, cancelOrderRate), - CancelMultipleOrders: request.NewRateLimit(twoSecondsInterval, cancelMultipleOrdersRate), - AmendOrder: request.NewRateLimit(twoSecondsInterval, amendOrderRate), - AmendMultipleOrders: request.NewRateLimit(twoSecondsInterval, amendMultipleOrdersRate), - CloseDeposit: request.NewRateLimit(twoSecondsInterval, closeDepositions), - GetOrderDetails: request.NewRateLimit(twoSecondsInterval, getOrderDetails), - GetOrderList: request.NewRateLimit(twoSecondsInterval, getOrderListRate), - GetOrderHistory7Days: request.NewRateLimit(twoSecondsInterval, getOrderHistory7DaysRate), - GetOrderHistory3Months: request.NewRateLimit(twoSecondsInterval, getOrderHistory3MonthsRate), - GetTransactionDetail3Days: request.NewRateLimit(twoSecondsInterval, getTransactionDetail3DaysRate), - GetTransactionDetail3Months: request.NewRateLimit(twoSecondsInterval, getTransactionDetail3MonthsRate), - PlaceAlgoOrder: request.NewRateLimit(twoSecondsInterval, placeAlgoOrderRate), - CancelAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAlgoOrderRate), - CancelAdvanceAlgoOrder: request.NewRateLimit(twoSecondsInterval, cancelAdvanceAlgoOrderRate), - GetAlgoOrderList: request.NewRateLimit(twoSecondsInterval, getAlgoOrderListRate), - GetAlgoOrderHistory: request.NewRateLimit(twoSecondsInterval, getAlgoOrderHistoryRate), - GetEasyConvertCurrencyList: request.NewRateLimit(twoSecondsInterval, getEasyConvertCurrencyListRate), - PlaceEasyConvert: request.NewRateLimit(twoSecondsInterval, placeEasyConvert), - GetEasyConvertHistory: request.NewRateLimit(twoSecondsInterval, getEasyConvertHistory), - GetOneClickRepayHistory: request.NewRateLimit(twoSecondsInterval, getOneClickRepayHistory), - OneClickRepayCurrencyList: request.NewRateLimit(twoSecondsInterval, oneClickRepayCurrencyList), - TradeOneClickRepay: request.NewRateLimit(twoSecondsInterval, tradeOneClickRepay), + placeOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeOrderRate, 1), + placeMultipleOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeMultipleOrdersRate, 1), + cancelOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelOrderRate, 1), + cancelMultipleOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelMultipleOrdersRate, 1), + amendOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, amendOrderRate, 1), + amendMultipleOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, amendMultipleOrdersRate, 1), + closePositionEPL: request.NewRateLimitWithWeight(twoSecondsInterval, closePositionsRate, 1), + getOrderDetEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderDetails, 1), + getOrderListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderListRate, 1), + getOrderHistory7DaysEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderHistory7DaysRate, 1), + getOrderHistory3MonthsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderHistory3MonthsRate, 1), + getTransactionDetail3DaysEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTransactionDetail3DaysRate, 1), + getTransactionDetail3MonthsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTransactionDetail3MonthsRate, 1), + placeAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeAlgoOrderRate, 1), + cancelAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAlgoOrderRate, 1), + cancelAdvanceAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAdvanceAlgoOrderRate, 1), + getAlgoOrderListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAlgoOrderListRate, 1), + getAlgoOrderHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAlgoOrderHistoryRate, 1), + getEasyConvertCurrencyListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getEasyConvertCurrencyListRate, 1), + placeEasyConvertEPL: request.NewRateLimitWithWeight(twoSecondsInterval, placeEasyConvert, 1), + getEasyConvertHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getEasyConvertHistory, 1), + getOneClickRepayHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOneClickRepayHistory, 1), + oneClickRepayCurrencyListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, oneClickRepayCurrencyList, 1), + tradeOneClickRepayEPL: request.NewRateLimitWithWeight(twoSecondsInterval, tradeOneClickRepay, 1), // Block Trading endpoints - GetCounterparties: request.NewRateLimit(twoSecondsInterval, getCounterpartiesRate), - CreateRfq: request.NewRateLimit(twoSecondsInterval, createRfqRate), - CancelRfq: request.NewRateLimit(twoSecondsInterval, cancelRfqRate), - CancelMultipleRfq: request.NewRateLimit(twoSecondsInterval, cancelMultipleRfqRate), - CancelAllRfqs: request.NewRateLimit(twoSecondsInterval, cancelAllRfqsRate), - ExecuteQuote: request.NewRateLimit(threeSecondsInterval, executeQuoteRate), - SetQuoteProducts: request.NewRateLimit(twoSecondsInterval, setQuoteProducts), - RestMMPStatus: request.NewRateLimit(twoSecondsInterval, restMMPStatus), - CreateQuote: request.NewRateLimit(twoSecondsInterval, createQuoteRate), - CancelQuote: request.NewRateLimit(twoSecondsInterval, cancelQuoteRate), - CancelMultipleQuotes: request.NewRateLimit(twoSecondsInterval, cancelMultipleQuotesRate), - CancelAllQuotes: request.NewRateLimit(twoSecondsInterval, cancelAllQuotes), - GetRfqs: request.NewRateLimit(twoSecondsInterval, getRfqsRate), - GetQuotes: request.NewRateLimit(twoSecondsInterval, getQuotesRate), - GetTrades: request.NewRateLimit(twoSecondsInterval, getTradesRate), - GetTradesHistory: request.NewRateLimit(twoSecondsInterval, getTradesHistoryRate), - GetPublicTrades: request.NewRateLimit(twoSecondsInterval, getPublicTradesRate), + getCounterpartiesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getCounterpartiesRate, 1), + createRfqEPL: request.NewRateLimitWithWeight(twoSecondsInterval, createRfqRate, 1), + cancelRfqEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelRfqRate, 1), + cancelMultipleRfqEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelMultipleRfqRate, 1), + cancelAllRfqsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAllRfqsRate, 1), + executeQuoteEPL: request.NewRateLimitWithWeight(threeSecondsInterval, executeQuoteRate, 1), + setQuoteProductsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, setQuoteProducts, 1), + restMMPStatusEPL: request.NewRateLimitWithWeight(twoSecondsInterval, restMMPStatus, 1), + createQuoteEPL: request.NewRateLimitWithWeight(twoSecondsInterval, createQuoteRate, 1), + cancelQuoteEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelQuoteRate, 1), + cancelMultipleQuotesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelMultipleQuotesRate, 1), + cancelAllQuotesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, cancelAllQuotes, 1), + getRfqsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getRfqsRate, 1), + getQuotesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getQuotesRate, 1), + getTradesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTradesRate, 1), + getTradesHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTradesHistoryRate, 1), + getPublicTradesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPublicTradesRate, 1), // Funding - GetCurrencies: request.NewRateLimit(oneSecondInterval, getCurrenciesRate), - GetBalance: request.NewRateLimit(oneSecondInterval, getBalanceRate), - GetAccountAssetValuation: request.NewRateLimit(twoSecondsInterval, getAccountAssetValuationRate), - FundsTransfer: request.NewRateLimit(oneSecondInterval, fundsTransferRate), - GetFundsTransferState: request.NewRateLimit(oneSecondInterval, getFundsTransferStateRate), - AssetBillsDetails: request.NewRateLimit(oneSecondInterval, assetBillsDetailsRate), - LightningDeposits: request.NewRateLimit(oneSecondInterval, lightningDepositsRate), - GetDepositAddress: request.NewRateLimit(oneSecondInterval, getDepositAddressRate), - GetDepositHistory: request.NewRateLimit(oneSecondInterval, getDepositHistoryRate), - Withdrawal: request.NewRateLimit(oneSecondInterval, withdrawalRate), - LightningWithdrawals: request.NewRateLimit(oneSecondInterval, lightningWithdrawalsRate), - CancelWithdrawal: request.NewRateLimit(oneSecondInterval, cancelWithdrawalRate), - GetWithdrawalHistory: request.NewRateLimit(oneSecondInterval, getWithdrawalHistoryRate), - SmallAssetsConvert: request.NewRateLimit(oneSecondInterval, smallAssetsConvertRate), - GetSavingBalance: request.NewRateLimit(oneSecondInterval, getSavingBalanceRate), - SavingsPurchaseRedempt: request.NewRateLimit(oneSecondInterval, savingsPurchaseRedemptionRate), - SetLendingRate: request.NewRateLimit(oneSecondInterval, setLendingRateRate), - GetLendingHistory: request.NewRateLimit(oneSecondInterval, getLendingHistoryRate), - GetPublicBorrowInfo: request.NewRateLimit(oneSecondInterval, getPublicBorrowInfoRate), - GetPublicBorrowHistory: request.NewRateLimit(oneSecondInterval, getPublicBorrowHistoryRate), + getCurrenciesEPL: request.NewRateLimitWithWeight(oneSecondInterval, getCurrenciesRate, 1), + getBalanceEPL: request.NewRateLimitWithWeight(oneSecondInterval, getBalanceRate, 1), + getAccountAssetValuationEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountAssetValuationRate, 1), + fundsTransferEPL: request.NewRateLimitWithWeight(oneSecondInterval, fundsTransferRate, 1), + getFundsTransferStateEPL: request.NewRateLimitWithWeight(oneSecondInterval, getFundsTransferStateRate, 1), + assetBillsDetailsEPL: request.NewRateLimitWithWeight(oneSecondInterval, assetBillsDetailsRate, 1), + lightningDepositsEPL: request.NewRateLimitWithWeight(oneSecondInterval, lightningDepositsRate, 1), + getDepositAddressEPL: request.NewRateLimitWithWeight(oneSecondInterval, getDepositAddressRate, 1), + getDepositHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getDepositHistoryRate, 1), + withdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, withdrawalRate, 1), + lightningWithdrawalsEPL: request.NewRateLimitWithWeight(oneSecondInterval, lightningWithdrawalsRate, 1), + cancelWithdrawalEPL: request.NewRateLimitWithWeight(oneSecondInterval, cancelWithdrawalRate, 1), + getWithdrawalHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getWithdrawalHistoryRate, 1), + smallAssetsConvertEPL: request.NewRateLimitWithWeight(oneSecondInterval, smallAssetsConvertRate, 1), + getSavingBalanceEPL: request.NewRateLimitWithWeight(oneSecondInterval, getSavingBalanceRate, 1), + savingsPurchaseRedemptionEPL: request.NewRateLimitWithWeight(oneSecondInterval, savingsPurchaseRedemptionRate, 1), + setLendingRateEPL: request.NewRateLimitWithWeight(oneSecondInterval, setLendingRateRate, 1), + getLendingHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getLendingHistoryRate, 1), + getPublicBorrowInfoEPL: request.NewRateLimitWithWeight(oneSecondInterval, getPublicBorrowInfoRate, 1), + getPublicBorrowHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getPublicBorrowHistoryRate, 1), // Convert - GetConvertCurrencies: request.NewRateLimit(oneSecondInterval, getConvertCurrenciesRate), - GetConvertCurrencyPair: request.NewRateLimit(oneSecondInterval, getConvertCurrencyPairRate), - EstimateQuote: request.NewRateLimit(oneSecondInterval, estimateQuoteRate), - ConvertTrade: request.NewRateLimit(oneSecondInterval, convertTradeRate), - GetConvertHistory: request.NewRateLimit(oneSecondInterval, getConvertHistoryRate), + getConvertCurrenciesEPL: request.NewRateLimitWithWeight(oneSecondInterval, getConvertCurrenciesRate, 1), + getConvertCurrencyPairEPL: request.NewRateLimitWithWeight(oneSecondInterval, getConvertCurrencyPairRate, 1), + estimateQuoteEPL: request.NewRateLimitWithWeight(oneSecondInterval, estimateQuoteRate, 1), + convertTradeEPL: request.NewRateLimitWithWeight(oneSecondInterval, convertTradeRate, 1), + getConvertHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getConvertHistoryRate, 1), // Account - GetAccountBalance: request.NewRateLimit(twoSecondsInterval, getAccountBalanceRate), - GetPositions: request.NewRateLimit(twoSecondsInterval, getPositionsRate), - GetPositionsHistory: request.NewRateLimit(tenSecondsInterval, getPositionsHistoryRate), - GetAccountAndPositionRisk: request.NewRateLimit(twoSecondsInterval, getAccountAndPositionRiskRate), - GetBillsDetails: request.NewRateLimit(oneSecondInterval, getBillsDetailsRate), - GetAccountConfiguration: request.NewRateLimit(twoSecondsInterval, getAccountConfigurationRate), - SetPositionMode: request.NewRateLimit(twoSecondsInterval, setPositionModeRate), - SetLeverage: request.NewRateLimit(twoSecondsInterval, setLeverageRate), - GetMaximumBuyOrSellAmount: request.NewRateLimit(twoSecondsInterval, getMaximumBuyOrSellAmountRate), - GetMaximumAvailableTradableAmount: request.NewRateLimit(twoSecondsInterval, getMaximumAvailableTradableAmountRate), - IncreaseOrDecreaseMargin: request.NewRateLimit(twoSecondsInterval, increaseOrDecreaseMarginRate), - GetLeverage: request.NewRateLimit(twoSecondsInterval, getLeverageRate), - GetTheMaximumLoanOfInstrument: request.NewRateLimit(twoSecondsInterval, getTheMaximumLoanOfInstrumentRate), - GetFeeRates: request.NewRateLimit(twoSecondsInterval, getFeeRatesRate), - GetInterestAccruedData: request.NewRateLimit(twoSecondsInterval, getInterestAccruedDataRate), - GetInterestRate: request.NewRateLimit(twoSecondsInterval, getInterestRateRate), - SetGreeks: request.NewRateLimit(twoSecondsInterval, setGreeksRate), - IsolatedMarginTradingSettings: request.NewRateLimit(twoSecondsInterval, isolatedMarginTradingSettingsRate), - GetMaximumWithdrawals: request.NewRateLimit(twoSecondsInterval, getMaximumWithdrawalsRate), - GetAccountRiskState: request.NewRateLimit(twoSecondsInterval, getAccountRiskStateRate), - VipLoansBorrowAnsRepay: request.NewRateLimit(oneSecondInterval, vipLoansBorrowAndRepayRate), - GetBorrowAnsRepayHistoryHistory: request.NewRateLimit(twoSecondsInterval, getBorrowAnsRepayHistoryHistoryRate), - GetBorrowInterestAndLimit: request.NewRateLimit(twoSecondsInterval, getBorrowInterestAndLimitRate), - PositionBuilder: request.NewRateLimit(twoSecondsInterval, positionBuilderRate), - GetGreeks: request.NewRateLimit(twoSecondsInterval, getGreeksRate), - GetPMLimitation: request.NewRateLimit(twoSecondsInterval, getPMLimitation), + getAccountBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountBalanceRate, 1), + getPositionsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPositionsRate, 1), + getPositionsHistoryEPL: request.NewRateLimitWithWeight(tenSecondsInterval, getPositionsHistoryRate, 1), + getAccountAndPositionRiskEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountAndPositionRiskRate, 1), + getBillsDetailsEPL: request.NewRateLimitWithWeight(oneSecondInterval, getBillsDetailsRate, 1), + getAccountConfigurationEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountConfigurationRate, 1), + setPositionModeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, setPositionModeRate, 1), + setLeverageEPL: request.NewRateLimitWithWeight(twoSecondsInterval, setLeverageRate, 1), + getMaximumBuyOrSellAmountEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaximumBuyOrSellAmountRate, 1), + getMaximumAvailableTradableAmountEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaximumAvailableTradableAmountRate, 1), + increaseOrDecreaseMarginEPL: request.NewRateLimitWithWeight(twoSecondsInterval, increaseOrDecreaseMarginRate, 1), + getLeverageEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getLeverageRate, 1), + getTheMaximumLoanOfInstrumentEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTheMaximumLoanOfInstrumentRate, 1), + getFeeRatesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getFeeRatesRate, 1), + getInterestAccruedDataEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInterestAccruedDataRate, 1), + getInterestRateEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInterestRateRate, 1), + setGreeksEPL: request.NewRateLimitWithWeight(twoSecondsInterval, setGreeksRate, 1), + isolatedMarginTradingSettingsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, isolatedMarginTradingSettingsRate, 1), + getMaximumWithdrawalsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMaximumWithdrawalsRate, 1), + getAccountRiskStateEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getAccountRiskStateRate, 1), + vipLoansBorrowAnsRepayEPL: request.NewRateLimitWithWeight(oneSecondInterval, vipLoansBorrowAndRepayRate, 1), + getBorrowAnsRepayHistoryHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getBorrowAnsRepayHistoryHistoryRate, 1), + getBorrowInterestAndLimitEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getBorrowInterestAndLimitRate, 1), + positionBuilderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, positionBuilderRate, 1), + getGreeksEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGreeksRate, 1), + getPMLimitationEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPMLimitation, 1), // Sub Account Endpoints - ViewSubaccountList: request.NewRateLimit(twoSecondsInterval, viewSubaccountListRate), - ResetSubAccountAPIKey: request.NewRateLimit(oneSecondInterval, resetSubAccountAPIKey), - GetSubaccountTradingBalance: request.NewRateLimit(twoSecondsInterval, getSubaccountTradingBalanceRate), - GetSubaccountFundingBalance: request.NewRateLimit(twoSecondsInterval, getSubaccountFundingBalanceRate), - HistoryOfSubaccountTransfer: request.NewRateLimit(oneSecondInterval, historyOfSubaccountTransferRate), - MasterAccountsManageTransfersBetweenSubaccount: request.NewRateLimit(oneSecondInterval, masterAccountsManageTransfersBetweenSubaccountRate), - SetPermissionOfTransferOut: request.NewRateLimit(oneSecondInterval, setPermissionOfTransferOutRate), - GetCustodyTradingSubaccountList: request.NewRateLimit(oneSecondInterval, getCustodyTradingSubaccountListRate), + viewSubaccountListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, viewSubaccountListRate, 1), + resetSubAccountAPIKeyEPL: request.NewRateLimitWithWeight(oneSecondInterval, resetSubAccountAPIKey, 1), + getSubaccountTradingBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSubaccountTradingBalanceRate, 1), + getSubaccountFundingBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSubaccountFundingBalanceRate, 1), + historyOfSubaccountTransferEPL: request.NewRateLimitWithWeight(oneSecondInterval, historyOfSubaccountTransferRate, 1), + masterAccountsManageTransfersBetweenSubaccountEPL: request.NewRateLimitWithWeight(oneSecondInterval, masterAccountsManageTransfersBetweenSubaccountRate, 1), + setPermissionOfTransferOutEPL: request.NewRateLimitWithWeight(oneSecondInterval, setPermissionOfTransferOutRate, 1), + getCustodyTradingSubaccountListEPL: request.NewRateLimitWithWeight(oneSecondInterval, getCustodyTradingSubaccountListRate, 1), // Grid Trading Endpoints - GridTrading: request.NewRateLimit(twoSecondsInterval, gridTradingRate), - AmendGridAlgoOrder: request.NewRateLimit(twoSecondsInterval, amendGridAlgoOrderRate), - StopGridAlgoOrder: request.NewRateLimit(twoSecondsInterval, stopGridAlgoOrderRate), - GetGridAlgoOrderList: request.NewRateLimit(twoSecondsInterval, getGridAlgoOrderListRate), - GetGridAlgoOrderHistory: request.NewRateLimit(twoSecondsInterval, getGridAlgoOrderHistoryRate), - GetGridAlgoOrderDetails: request.NewRateLimit(twoSecondsInterval, getGridAlgoOrderDetailsRate), - GetGridAlgoSubOrders: request.NewRateLimit(twoSecondsInterval, getGridAlgoSubOrdersRate), - GetGridAlgoOrderPositions: request.NewRateLimit(twoSecondsInterval, getGridAlgoOrderPositionsRate), - SpotGridWithdrawIncome: request.NewRateLimit(twoSecondsInterval, spotGridWithdrawIncomeRate), - ComputeMarginBalance: request.NewRateLimit(twoSecondsInterval, computeMarginBalance), - AdjustMarginBalance: request.NewRateLimit(twoSecondsInterval, adjustMarginBalance), - GetGridAIParameter: request.NewRateLimit(twoSecondsInterval, getGridAIParameter), + gridTradingEPL: request.NewRateLimitWithWeight(twoSecondsInterval, gridTradingRate, 1), + amendGridAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, amendGridAlgoOrderRate, 1), + stopGridAlgoOrderEPL: request.NewRateLimitWithWeight(twoSecondsInterval, stopGridAlgoOrderRate, 1), + getGridAlgoOrderListEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAlgoOrderListRate, 1), + getGridAlgoOrderHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAlgoOrderHistoryRate, 1), + getGridAlgoOrderDetailsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAlgoOrderDetailsRate, 1), + getGridAlgoSubOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAlgoSubOrdersRate, 1), + getGridAlgoOrderPositionsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAlgoOrderPositionsRate, 1), + spotGridWithdrawIncomeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, spotGridWithdrawIncomeRate, 1), + computeMarginBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, computeMarginBalance, 1), + adjustMarginBalanceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, adjustMarginBalance, 1), + getGridAIParameterEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getGridAIParameter, 1), // Earn - GetOffer: request.NewRateLimit(oneSecondInterval, getOffer), - Purchase: request.NewRateLimit(oneSecondInterval, purchase), - Redeem: request.NewRateLimit(oneSecondInterval, redeem), - CancelPurchaseOrRedemption: request.NewRateLimit(oneSecondInterval, cancelPurchaseOrRedemption), - GetEarnActiveOrders: request.NewRateLimit(oneSecondInterval, getEarnActiveOrders), - GetFundingOrderHistory: request.NewRateLimit(oneSecondInterval, getFundingOrderHistory), + getOfferEPL: request.NewRateLimitWithWeight(oneSecondInterval, getOffer, 1), + purchaseEPL: request.NewRateLimitWithWeight(oneSecondInterval, purchase, 1), + redeemEPL: request.NewRateLimitWithWeight(oneSecondInterval, redeem, 1), + cancelPurchaseOrRedemptionEPL: request.NewRateLimitWithWeight(oneSecondInterval, cancelPurchaseOrRedemption, 1), + getEarnActiveOrdersEPL: request.NewRateLimitWithWeight(oneSecondInterval, getEarnActiveOrders, 1), + getFundingOrderHistoryEPL: request.NewRateLimitWithWeight(oneSecondInterval, getFundingOrderHistory, 1), // Market Data - GetTickers: request.NewRateLimit(twoSecondsInterval, getTickersRate), - GetIndexTickers: request.NewRateLimit(twoSecondsInterval, getIndexTickersRate), - GetOrderBook: request.NewRateLimit(twoSecondsInterval, getOrderBookRate), - GetCandlesticks: request.NewRateLimit(twoSecondsInterval, getCandlesticksRate), - GetCandlesticksHistory: request.NewRateLimit(twoSecondsInterval, getCandlesticksHistoryRate), - GetIndexCandlesticks: request.NewRateLimit(twoSecondsInterval, getIndexCandlesticksRate), - GetMarkPriceCandlesticks: request.NewRateLimit(twoSecondsInterval, getMarkPriceCandlesticksRate), - GetTradesRequest: request.NewRateLimit(twoSecondsInterval, getTradesRequestRate), - Get24HTotalVolume: request.NewRateLimit(twoSecondsInterval, get24HTotalVolumeRate), - GetOracle: request.NewRateLimit(fiveSecondsInterval, getOracleRate), - GetExchangeRateRequest: request.NewRateLimit(twoSecondsInterval, getExchangeRateRequestRate), - GetIndexComponents: request.NewRateLimit(twoSecondsInterval, getIndexComponentsRate), - GetBlockTickers: request.NewRateLimit(twoSecondsInterval, getBlockTickersRate), - GetBlockTrades: request.NewRateLimit(twoSecondsInterval, getBlockTradesRate), + getTickersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTickersRate, 1), + getIndexTickersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getIndexTickersRate, 1), + getOrderBookEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOrderBookRate, 1), + getCandlestickEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getCandlesticksRate, 1), + getCandlestickHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getCandlesticksHistoryRate, 1), + getIndexCandlestickEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getIndexCandlesticksRate, 1), + getTradesRequestEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTradesRequestRate, 1), + get24HTotalVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, get24HTotalVolumeRate, 1), + getOracleEPL: request.NewRateLimitWithWeight(fiveSecondsInterval, getOracleRate, 1), + getExchangeRateRequestEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getExchangeRateRequestRate, 1), + getIndexComponentsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getIndexComponentsRate, 1), + getBlockTickersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getBlockTickersRate, 1), + getBlockTradesEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getBlockTradesRate, 1), // Public Data Endpoints - GetInstruments: request.NewRateLimit(twoSecondsInterval, getInstrumentsRate), - GetDeliveryExerciseHistory: request.NewRateLimit(twoSecondsInterval, getDeliveryExerciseHistoryRate), - GetOpenInterest: request.NewRateLimit(twoSecondsInterval, getOpenInterestRate), - GetFunding: request.NewRateLimit(twoSecondsInterval, getFundingRate), - GetFundingRateHistory: request.NewRateLimit(twoSecondsInterval, getFundingRateHistoryRate), - GetLimitPrice: request.NewRateLimit(twoSecondsInterval, getLimitPriceRate), - GetOptionMarketDate: request.NewRateLimit(twoSecondsInterval, getOptionMarketDateRate), - GetEstimatedDeliveryExercisePrice: request.NewRateLimit(twoSecondsInterval, getEstimatedDeliveryExercisePriceRate), - GetDiscountRateAndInterestFreeQuota: request.NewRateLimit(twoSecondsInterval, getDiscountRateAndInterestFreeQuotaRate), - GetSystemTime: request.NewRateLimit(twoSecondsInterval, getSystemTimeRate), - GetLiquidationOrders: request.NewRateLimit(twoSecondsInterval, getLiquidationOrdersRate), - GetMarkPrice: request.NewRateLimit(twoSecondsInterval, getMarkPriceRate), - GetPositionTiers: request.NewRateLimit(twoSecondsInterval, getPositionTiersRate), - GetInterestRateAndLoanQuota: request.NewRateLimit(twoSecondsInterval, getInterestRateAndLoanQuotaRate), - GetInterestRateAndLoanQuoteForVIPLoans: request.NewRateLimit(twoSecondsInterval, getInterestRateAndLoanQuoteForVIPLoansRate), - GetUnderlying: request.NewRateLimit(twoSecondsInterval, getUnderlyingRate), - GetInsuranceFund: request.NewRateLimit(twoSecondsInterval, getInsuranceFundRate), - UnitConvert: request.NewRateLimit(twoSecondsInterval, unitConvertRate), + getInstrumentsEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInstrumentsRate, 1), + getDeliveryExerciseHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getDeliveryExerciseHistoryRate, 1), + getOpenInterestEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOpenInterestRate, 1), + getFundingEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getFundingRate, 1), + getFundingRateHistoryEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getFundingRateHistoryRate, 1), + getLimitPriceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getLimitPriceRate, 1), + getOptionMarketDateEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOptionMarketDateRate, 1), + getEstimatedDeliveryExercisePriceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getEstimatedDeliveryExercisePriceRate, 1), + getDiscountRateAndInterestFreeQuotaEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getDiscountRateAndInterestFreeQuotaRate, 1), + getSystemTimeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSystemTimeRate, 1), + getLiquidationOrdersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getLiquidationOrdersRate, 1), + getMarkPriceEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMarkPriceRate, 1), + getPositionTiersEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPositionTiersRate, 1), + getInterestRateAndLoanQuotaEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInterestRateAndLoanQuotaRate, 1), + getInterestRateAndLoanQuoteForVIPLoansEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInterestRateAndLoanQuoteForVIPLoansRate, 1), + getUnderlyingEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getUnderlyingRate, 1), + getInsuranceFundEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getInsuranceFundRate, 1), + unitConvertEPL: request.NewRateLimitWithWeight(twoSecondsInterval, unitConvertRate, 1), // Trading Data Endpoints - GetSupportCoin: request.NewRateLimit(twoSecondsInterval, getSupportCoinRate), - GetTakerVolume: request.NewRateLimit(twoSecondsInterval, getTakerVolumeRate), - GetMarginLendingRatio: request.NewRateLimit(twoSecondsInterval, getMarginLendingRatioRate), - GetLongShortRatio: request.NewRateLimit(twoSecondsInterval, getLongShortRatioRate), - GetContractsOpenInterestAndVolume: request.NewRateLimit(twoSecondsInterval, getContractsOpenInterestAndVolumeRate), - GetOptionsOpenInterestAndVolume: request.NewRateLimit(twoSecondsInterval, getOptionsOpenInterestAndVolumeRate), - GetPutCallRatio: request.NewRateLimit(twoSecondsInterval, getPutCallRatioRate), - GetOpenInterestAndVolume: request.NewRateLimit(twoSecondsInterval, getOpenInterestAndVolumeRate), - GetTakerFlow: request.NewRateLimit(twoSecondsInterval, getTakerFlowRate), + getSupportCoinEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getSupportCoinRate, 1), + getTakerVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTakerVolumeRate, 1), + getMarginLendingRatioEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getMarginLendingRatioRate, 1), + getLongShortRatioEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getLongShortRatioRate, 1), + getContractsOpenInterestAndVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getContractsOpenInterestAndVolumeRate, 1), + getOptionsOpenInterestAndVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOptionsOpenInterestAndVolumeRate, 1), + getPutCallRatioEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getPutCallRatioRate, 1), + getOpenInterestAndVolumeEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getOpenInterestAndVolumeRate, 1), + getTakerFlowEPL: request.NewRateLimitWithWeight(twoSecondsInterval, getTakerFlowRate, 1), // Status Endpoints - GetEventStatus: request.NewRateLimit(fiveSecondsInterval, getEventStatusRate), + getEventStatusEPL: request.NewRateLimitWithWeight(fiveSecondsInterval, getEventStatusRate, 1), } } diff --git a/exchanges/poloniex/poloniex.go b/exchanges/poloniex/poloniex.go index 4ef6ff0b..4f95e53d 100644 --- a/exchanges/poloniex/poloniex.go +++ b/exchanges/poloniex/poloniex.go @@ -934,7 +934,7 @@ func (p *Poloniex) SendHTTPRequest(ctx context.Context, ep exchange.URL, path st HTTPRecording: p.HTTPRecording, } - return p.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return p.SendPayload(ctx, request.UnAuth, func() (*request.Item, error) { return item, nil }, request.UnauthenticatedRequest) } @@ -950,7 +950,7 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange return err } - return p.SendPayload(ctx, request.Unset, func() (*request.Item, error) { + return p.SendPayload(ctx, request.Auth, func() (*request.Item, error) { headers := make(map[string]string) headers["Content-Type"] = "application/x-www-form-urlencoded" headers["Key"] = creds.Key diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index 5fe3526a..5118ae63 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -123,7 +123,7 @@ func (p *Poloniex) SetDefaults() { p.Requester, err = request.New(p.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), - request.WithLimiter(SetRateLimit())) + request.WithLimiter(GetRateLimit())) if err != nil { log.Errorln(log.ExchangeSys, err) } diff --git a/exchanges/poloniex/ratelimit.go b/exchanges/poloniex/ratelimit.go index 69c2d243..71c2ec66 100644 --- a/exchanges/poloniex/ratelimit.go +++ b/exchanges/poloniex/ratelimit.go @@ -1,11 +1,9 @@ package poloniex import ( - "context" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "golang.org/x/time/rate" ) const ( @@ -14,28 +12,14 @@ const ( poloniexUnauthRate = 6 ) -// RateLimit implements the request.Limiter interface -type RateLimit struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -// Limit limits outbound calls -func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error { - if f == request.Auth { - return r.Auth.Wait(ctx) - } - return r.UnAuth.Wait(ctx) -} - -// SetRateLimit returns the rate limit for the exchange +// GetRateLimit returns the rate limit for the exchange // If your account's volume is over $5 million in 30 day volume, // you may be eligible for an API rate limit increase. // Please email poloniex@circle.com. // As per https://docs.poloniex.com/#http-api -func SetRateLimit() *RateLimit { - return &RateLimit{ - Auth: request.NewRateLimit(poloniexRateInterval, poloniexAuthRate), - UnAuth: request.NewRateLimit(poloniexRateInterval, poloniexUnauthRate), +func GetRateLimit() request.RateLimitDefinitions { + return request.RateLimitDefinitions{ + request.Auth: request.NewRateLimitWithWeight(poloniexRateInterval, poloniexAuthRate, 1), + request.UnAuth: request.NewRateLimitWithWeight(poloniexRateInterval, poloniexUnauthRate, 1), } } diff --git a/exchanges/request/limit.go b/exchanges/request/limit.go index e2179399..cc0f193f 100644 --- a/exchanges/request/limit.go +++ b/exchanges/request/limit.go @@ -14,6 +14,10 @@ import ( var ( ErrRateLimiterAlreadyDisabled = errors.New("rate limiter already disabled") ErrRateLimiterAlreadyEnabled = errors.New("rate limiter already enabled") + + errLimiterSystemIsNil = errors.New("limiter system is nil") + errInvalidWeightCount = errors.New("invalid weight count must equal or greater than 1") + errSpecificRateLimiterIsNil = errors.New("specific rate limiter is nil") ) // Const here define individual functionality sub types for rate limiting @@ -23,26 +27,35 @@ const ( UnAuth ) -// BasicLimit denotes basic rate limit that implements the Limiter interface -// does not need to set endpoint functionality. -type BasicLimit struct { - r *rate.Limiter -} - -// Limit executes a single rate limit set by NewRateLimit -func (b *BasicLimit) Limit(ctx context.Context, _ EndpointLimit) error { - return b.r.Wait(ctx) -} - // EndpointLimit defines individual endpoint rate limits that are set when // New is called. -type EndpointLimit int +type EndpointLimit uint16 -// Limiter interface groups rate limit functionality defined in the REST -// wrapper for extended rate limiting configuration i.e. Shells of rate -// limits with a global rate for sub rates. -type Limiter interface { - Limit(context.Context, EndpointLimit) error +// Weight defines the number of reservations to be used. This is a generalised +// weight for rate limiting. e.g. n weight = n request. i.e. 50 Weight = 50 +// requests. +type Weight uint8 + +// RateLimitDefinitions is a map of endpoint limits to rate limiters +type RateLimitDefinitions map[interface{}]*RateLimiterWithWeight + +// RateLimiterWithWeight is a rate limiter coupled with a weight count which +// refers to the number or weighting of the request. This is used to define +// the rate limit for a specific endpoint. +type RateLimiterWithWeight struct { + *rate.Limiter + Weight +} + +// Reservations is a slice of rate reservations +type Reservations []*rate.Reservation + +// CancelAll cancels all potential reservations to free up rate limiter for +// context cancellations and deadline exceeded cases. +func (r Reservations) CancelAll() { + for x := range r { + r[x].Cancel() + } } // NewRateLimit creates a new RateLimit based of time interval and how many @@ -59,10 +72,25 @@ func NewRateLimit(interval time.Duration, actions int) *rate.Limiter { return rate.NewLimiter(rate.Limit(rps), 1) } +// NewRateLimitWithWeight creates a new RateLimit based of time interval and how +// many actions allowed. This also has a weight count which refers to the number +// or weighting of the request. This is used to define the rate limit for a +// specific endpoint. +func NewRateLimitWithWeight(interval time.Duration, actions int, weight Weight) *RateLimiterWithWeight { + return GetRateLimiterWithWeight(NewRateLimit(interval, actions), weight) +} + +// GetRateLimiterWithWeight couples a rate limiter with a weight count into an +// accepted defined rate limiter with weight struct +func GetRateLimiterWithWeight(l *rate.Limiter, weight Weight) *RateLimiterWithWeight { + return &RateLimiterWithWeight{l, weight} +} + // NewBasicRateLimit returns an object that implements the limiter interface // for basic rate limit -func NewBasicRateLimit(interval time.Duration, actions int) Limiter { - return &BasicLimit{NewRateLimit(interval, actions)} +func NewBasicRateLimit(interval time.Duration, actions int, weight Weight) RateLimitDefinitions { + rl := NewRateLimitWithWeight(interval, actions, weight) + return RateLimitDefinitions{Unset: rl, Auth: rl, UnAuth: rl} } // InitiateRateLimit sleeps for designated end point rate limits @@ -73,12 +101,46 @@ func (r *Requester) InitiateRateLimit(ctx context.Context, e EndpointLimit) erro if atomic.LoadInt32(&r.disableRateLimiter) == 1 { return nil } - - if r.limiter != nil { - return r.limiter.Limit(ctx, e) + if r.limiter == nil { + return fmt.Errorf("cannot rate limit request %w", errLimiterSystemIsNil) } - return nil + rateLimiter := r.limiter[e] + + if rateLimiter == nil { + return fmt.Errorf("cannot rate limit request %w for endpoint %d", errSpecificRateLimiterIsNil, e) + } + + if rateLimiter.Weight <= 0 { + return fmt.Errorf("cannot rate limit request %w for endpoint %d", errInvalidWeightCount, e) + } + + var finalDelay time.Duration + var reservations = make(Reservations, rateLimiter.Weight) + for i := Weight(0); i < rateLimiter.Weight; i++ { + // Consume 1 weight at a time as this avoids needing burst capacity in the limiter, + // which would otherwise allow the rate limit to be exceeded over short periods + reservations[i] = rateLimiter.Reserve() + finalDelay = reservations[i].Delay() + } + + if dl, ok := ctx.Deadline(); ok && dl.Before(time.Now().Add(finalDelay)) { + reservations.CancelAll() + return fmt.Errorf("rate limit delay of %s will exceed deadline: %w", + finalDelay, + context.DeadlineExceeded) + } + + tick := time.NewTimer(finalDelay) + select { + case <-tick.C: + return nil + case <-ctx.Done(): + tick.Stop() + reservations.CancelAll() + return ctx.Err() + } + // TODO: Shutdown case } // DisableRateLimiter disables the rate limiting system for the exchange diff --git a/exchanges/request/options.go b/exchanges/request/options.go index 51f16735..29ce0612 100644 --- a/exchanges/request/options.go +++ b/exchanges/request/options.go @@ -8,9 +8,9 @@ func WithBackoff(b Backoff) RequesterOption { } // WithLimiter configures the rate limiter for a Requester. -func WithLimiter(l Limiter) RequesterOption { +func WithLimiter(def RateLimitDefinitions) RequesterOption { return func(r *Requester) { - r.limiter = l + r.limiter = def } } diff --git a/exchanges/request/request.go b/exchanges/request/request.go index 6b07d583..9c0b5c86 100644 --- a/exchanges/request/request.go +++ b/exchanges/request/request.go @@ -149,10 +149,12 @@ func (r *Requester) doRequest(ctx context.Context, endpoint EndpointLimit, newRe default: } - // Initiate a rate limit reservation and sleep on requested endpoint - err := r.InitiateRateLimit(ctx, endpoint) - if err != nil { - return fmt.Errorf("failed to rate limit HTTP request: %w", err) + if r.limiter != nil { + // Initiate a rate limit reservation and sleep on requested endpoint + err := r.InitiateRateLimit(ctx, endpoint) + if err != nil { + return fmt.Errorf("failed to rate limit HTTP request: %w", err) + } } p, err := newRequest() @@ -231,7 +233,15 @@ func (r *Requester) doRequest(ctx context.Context, endpoint EndpointLimit, newRe log.Errorf(log.RequestSys, "%s request has failed. Retrying request in %s, attempt %d", r.name, delay, attempt) } - time.Sleep(delay) + if delay > 0 { + // Allow for context cancellation while delaying the retry. + select { + case <-time.After(delay): + case <-ctx.Done(): + return ctx.Err() + } + } + continue } diff --git a/exchanges/request/request_test.go b/exchanges/request/request_test.go index 4d0398b4..c083b989 100644 --- a/exchanges/request/request_test.go +++ b/exchanges/request/request_test.go @@ -3,7 +3,6 @@ package request import ( "context" "errors" - "fmt" "io" "log" "math" @@ -28,12 +27,12 @@ import ( const unexpected = "unexpected values" var testURL string -var serverLimit *rate.Limiter +var serverLimit *RateLimiterWithWeight func TestMain(m *testing.M) { serverLimitInterval := time.Millisecond * 500 - serverLimit = NewRateLimit(serverLimitInterval, 1) - serverLimitRetry := NewRateLimit(serverLimitInterval, 1) + serverLimit = NewRateLimitWithWeight(serverLimitInterval, 1, 1) + serverLimitRetry := NewRateLimitWithWeight(serverLimitInterval, 1, 1) sm := http.NewServeMux() sm.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -102,26 +101,26 @@ func TestMain(m *testing.M) { os.Exit(issues) } -func TestNewRateLimit(t *testing.T) { +func TestNewRateLimitWithWeight(t *testing.T) { t.Parallel() - r := NewRateLimit(time.Second*10, 5) + r := NewRateLimitWithWeight(time.Second*10, 5, 1) if r.Limit() != 0.5 { t.Fatal(unexpected) } // Ensures rate limiting factor is the same - r = NewRateLimit(time.Second*2, 1) + r = NewRateLimitWithWeight(time.Second*2, 1, 1) if r.Limit() != 0.5 { t.Fatal(unexpected) } // Test for open rate limit - r = NewRateLimit(time.Second*2, 0) + r = NewRateLimitWithWeight(time.Second*2, 0, 1) if r.Limit() != rate.Inf { t.Fatal(unexpected) } - r = NewRateLimit(0, 69) + r = NewRateLimitWithWeight(0, 69, 1) if r.Limit() != rate.Inf { t.Fatal(unexpected) } @@ -201,39 +200,13 @@ func TestCheckRequest(t *testing.T) { } } -type GlobalLimitTest struct { - Auth *rate.Limiter - UnAuth *rate.Limiter -} - -var errEndpointLimitNotFound = errors.New("endpoint limit not found") - -func (g *GlobalLimitTest) Limit(ctx context.Context, e EndpointLimit) error { - switch e { - case Auth: - if g.Auth == nil { - return errors.New("auth rate not set") - } - return g.Auth.Wait(ctx) - case UnAuth: - if g.UnAuth == nil { - return errors.New("unauth rate not set") - } - return g.UnAuth.Wait(ctx) - default: - return fmt.Errorf("cannot execute functionality: %d %w", - e, - errEndpointLimitNotFound) - } -} - -var globalshell = GlobalLimitTest{ - Auth: NewRateLimit(time.Millisecond*600, 1), - UnAuth: NewRateLimit(time.Second*1, 100)} +var globalshell = RateLimitDefinitions{ + Auth: NewRateLimitWithWeight(time.Millisecond*600, 1, 1), + UnAuth: NewRateLimitWithWeight(time.Second*1, 100, 1)} func TestDoRequest(t *testing.T) { t.Parallel() - r, err := New("test", new(http.Client), WithLimiter(&globalshell)) + r, err := New("test", new(http.Client), WithLimiter(globalshell)) if err != nil { t.Fatal(err) } @@ -270,13 +243,9 @@ func TestDoRequest(t *testing.T) { } // Invalid/missing endpoint limit - err = r.SendPayload(ctx, Unset, func() (*Item, error) { - return &Item{ - Path: testURL, - }, nil - }, UnauthenticatedRequest) - if !errors.Is(err, errEndpointLimitNotFound) { - t.Fatalf("expected: %v but received: %v", errEndpointLimitNotFound, err) + err = r.SendPayload(ctx, Unset, func() (*Item, error) { return &Item{Path: testURL}, nil }, UnauthenticatedRequest) + if !errors.Is(err, errSpecificRateLimiterIsNil) { + t.Fatalf("expected: %v but received: %v", errSpecificRateLimiterIsNil, err) } // Force debug @@ -497,7 +466,7 @@ func TestDoRequest_NotRetryable(t *testing.T) { func TestGetNonce(t *testing.T) { t.Parallel() - r, err := New("test", new(http.Client), WithLimiter(&globalshell)) + r, err := New("test", new(http.Client), WithLimiter(globalshell)) require.NoError(t, err) n1 := r.GetNonce(nonce.Unix) assert.NotZero(t, n1) @@ -505,7 +474,7 @@ func TestGetNonce(t *testing.T) { assert.NotZero(t, n2) assert.NotEqual(t, n1, n2) - r2, err := New("test", new(http.Client), WithLimiter(&globalshell)) + r2, err := New("test", new(http.Client), WithLimiter(globalshell)) require.NoError(t, err) n3 := r2.GetNonce(nonce.UnixNano) assert.NotZero(t, n3) @@ -520,7 +489,7 @@ func TestGetNonce(t *testing.T) { // 40532461 30.29 ns/op 0 B/op 0 allocs/op (prev) // 45329203 26.53 ns/op 0 B/op 0 allocs/op func BenchmarkGetNonce(b *testing.B) { - r, err := New("test", new(http.Client), WithLimiter(&globalshell)) + r, err := New("test", new(http.Client), WithLimiter(globalshell)) require.NoError(b, err) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -536,9 +505,7 @@ func TestSetProxy(t *testing.T) { if !errors.Is(err, ErrRequestSystemIsNil) { t.Fatalf("received: '%v', but expected: '%v'", err, ErrRequestSystemIsNil) } - r, err = New("test", - &http.Client{Transport: new(http.Transport)}, - WithLimiter(&globalshell)) + r, err = New("test", &http.Client{Transport: new(http.Transport)}, WithLimiter(globalshell)) if err != nil { t.Fatal(err) } @@ -561,16 +528,11 @@ func TestSetProxy(t *testing.T) { } func TestBasicLimiter(t *testing.T) { - r, err := New("test", - new(http.Client), - WithLimiter(NewBasicRateLimit(time.Second, 1))) + r, err := New("test", new(http.Client), WithLimiter(NewBasicRateLimit(time.Second, 1, 1))) if err != nil { t.Fatal(err) } - i := Item{ - Path: "http://www.google.com", - Method: http.MethodGet, - } + i := Item{Path: "http://www.google.com", Method: http.MethodGet} ctx := context.Background() tn := time.Now() @@ -595,9 +557,7 @@ func TestBasicLimiter(t *testing.T) { } func TestEnableDisableRateLimit(t *testing.T) { - r, err := New("TestRequest", - new(http.Client), - WithLimiter(NewBasicRateLimit(time.Minute, 1))) + r, err := New("TestRequest", new(http.Client), WithLimiter(NewBasicRateLimit(time.Minute, 1, 1))) if err != nil { t.Fatal(err) } diff --git a/exchanges/request/request_types.go b/exchanges/request/request_types.go index 8213bdbb..bf1c258f 100644 --- a/exchanges/request/request_types.go +++ b/exchanges/request/request_types.go @@ -27,7 +27,7 @@ var ( // Requester struct for the request client type Requester struct { _HTTPClient *client - limiter Limiter + limiter RateLimitDefinitions reporter Reporter name string userAgent string diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 00b9a341..58447754 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -77,7 +77,7 @@ func (y *Yobit) SetDefaults() { y.Requester, err = request.New(y.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), // Server responses are cached every 2 seconds. - request.WithLimiter(request.NewBasicRateLimit(time.Second, 1))) + request.WithLimiter(request.NewBasicRateLimit(time.Second, 1, 1))) if err != nil { log.Errorln(log.ExchangeSys, err) }