package bybit import ( "context" "fmt" "time" "github.com/thrasher-corp/gocryptotrader/exchanges/request" "golang.org/x/time/rate" ) const ( spotInterval = time.Second spotRequestRate = 70 futuresPublicInterval = time.Second futuresRequestRate = 50 spotPrivateRequestRate = 20 futuresInterval = time.Minute futuresDefaultRateCount = 100 futuresOrderRate = 100 futuresOrderListRate = 600 futuresExecutionRate = 120 futuresPositionRateCount = 75 futuresPositionListRate = 120 futuresFundingRate = 120 futuresWalletRate = 120 futuresAccountRate = 600 usdcPerpetualPublicRate = 50 usdcPerpetualCancelAllRate = 1 usdcPerpetualPrivateRate = 5 usdcPerpetualInterval = time.Second ) const ( publicSpotRate request.EndpointLimit = iota publicFuturesRate privateSpotRate cFuturesDefaultRate cFuturesCancelActiveOrderRate cFuturesCancelAllActiveOrderRate cFuturesCreateConditionalOrderRate cFuturesCancelConditionalOrderRate cFuturesReplaceActiveOrderRate cFuturesReplaceConditionalOrderRate cFuturesCreateOrderRate cFuturesCancelAllConditionalOrderRate cFuturesGetActiveOrderRate cFuturesGetConditionalOrderRate cFuturesGetRealtimeOrderRate cFuturesTradeRate cFuturesSetLeverageRate cFuturesUpdateMarginRate cFuturesSetTradingRate cFuturesSwitchPositionRate cFuturesGetTradingFeeRate cFuturesPositionRate cFuturesWalletBalanceRate cFuturesLastFundingFeeRate cFuturesPredictFundingRate cFuturesWalletFundRecordRate cFuturesWalletWithdrawalRate cFuturesAPIKeyInfoRate uFuturesDefaultRate uFuturesCreateOrderRate uFuturesCancelOrderRate uFuturesCancelAllOrderRate uFuturesCreateConditionalOrderRate uFuturesCancelConditionalOrderRate uFuturesCancelAllConditionalOrderRate uFuturesSetLeverageRate uFuturesSwitchMargin uFuturesSwitchPosition uFuturesSetMarginRate uFuturesSetTradingStopRate uFuturesUpdateMarginRate uFuturesPositionRate uFuturesGetClosedTradesRate uFuturesGetTradesRate uFuturesGetActiveOrderRate uFuturesGetActiveRealtimeOrderRate uFuturesGetConditionalOrderRate uFuturesGetConditionalRealtimeOrderRate uFuturesGetMyLastFundingFeeRate uFuturesPredictFundingRate futuresDefaultRate futuresCancelOrderRate futuresCreateOrderRate futuresReplaceOrderRate futuresCancelAllOrderRate futuresCancelAllConditionalOrderRate futuresReplaceConditionalOrderRate futuresCancelConditionalOrderRate futuresCreateConditionalOrderRate futuresGetActiveOrderRate futuresGetConditionalOrderRate futuresGetActiveRealtimeOrderRate futuresGetConditionalRealtimeOrderRate futuresGetTradeRate futuresSetLeverageRate futuresUpdateMarginRate futuresSetTradingStopRate futuresSwitchPositionModeRate futuresSwitchMarginRate futuresSwitchPositionRate futuresPositionRate usdcPublicRate usdcCancelAllOrderRate usdcPlaceOrderRate usdcModifyOrderRate usdcCancelOrderRate usdcGetOrderRate usdcGetOrderHistoryRate usdcGetTradeHistoryRate usdcGetTransactionRate usdcGetWalletRate usdcGetAssetRate usdcGetMarginRate usdcGetPositionRate usdcSetLeverageRate usdcGetSettlementRate usdcSetRiskRate usdcGetPredictedFundingRate ) // RateLimit implements the request.Limiter interface type RateLimit struct { SpotRate *rate.Limiter FuturesRate *rate.Limiter PrivateSpotRate *rate.Limiter CMFuturesDefaultRate *rate.Limiter CMFuturesOrderRate *rate.Limiter CMFuturesOrderListRate *rate.Limiter CMFuturesExecutionRate *rate.Limiter CMFuturesPositionRate *rate.Limiter CMFuturesPositionListRate *rate.Limiter CMFuturesFundingRate *rate.Limiter CMFuturesWalletRate *rate.Limiter CMFuturesAccountRate *rate.Limiter UFuturesDefaultRate *rate.Limiter UFuturesOrderRate *rate.Limiter UFuturesPositionRate *rate.Limiter UFuturesPositionListRate *rate.Limiter UFuturesOrderListRate *rate.Limiter UFuturesFundingRate *rate.Limiter FuturesDefaultRate *rate.Limiter FuturesOrderRate *rate.Limiter FuturesOrderListRate *rate.Limiter FuturesExecutionRate *rate.Limiter FuturesPositionRate *rate.Limiter FuturesPositionListRate *rate.Limiter USDCPublic *rate.Limiter USDCPlaceOrderRate *rate.Limiter USDCModifyOrderRate *rate.Limiter USDCCancelOrderRate *rate.Limiter USDCCancelAllOrderRate *rate.Limiter USDCGetOrderRate *rate.Limiter USDCGetOrderHistoryRate *rate.Limiter USDCGetTradeHistoryRate *rate.Limiter USDCGetTransactionRate *rate.Limiter USDCGetWalletRate *rate.Limiter USDCGetAssetRate *rate.Limiter USDCGetMarginRate *rate.Limiter USDCGetPositionRate *rate.Limiter USDCSetLeverageRate *rate.Limiter USDCGetSettlementRate *rate.Limiter USDCSetRiskRate *rate.Limiter USDCGetPredictedFundingRate *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 publicSpotRate: limiter, tokens = r.SpotRate, 1 case privateSpotRate: limiter, tokens = r.PrivateSpotRate, 1 case cFuturesDefaultRate: limiter, tokens = r.CMFuturesDefaultRate, 1 case cFuturesCancelActiveOrderRate, cFuturesCreateConditionalOrderRate, cFuturesCancelConditionalOrderRate, cFuturesReplaceActiveOrderRate, cFuturesReplaceConditionalOrderRate, cFuturesCreateOrderRate: limiter, tokens = r.CMFuturesOrderRate, 1 case cFuturesCancelAllActiveOrderRate, cFuturesCancelAllConditionalOrderRate: limiter, tokens = r.CMFuturesOrderRate, 10 case cFuturesGetActiveOrderRate, cFuturesGetConditionalOrderRate, cFuturesGetRealtimeOrderRate: limiter, tokens = r.CMFuturesOrderListRate, 1 case cFuturesTradeRate: limiter, tokens = r.CMFuturesExecutionRate, 1 case cFuturesSetLeverageRate, cFuturesUpdateMarginRate, cFuturesSetTradingRate, cFuturesSwitchPositionRate, cFuturesGetTradingFeeRate: limiter, tokens = r.CMFuturesPositionRate, 1 case cFuturesPositionRate, cFuturesWalletBalanceRate: limiter, tokens = r.CMFuturesPositionListRate, 1 case cFuturesLastFundingFeeRate, cFuturesPredictFundingRate: limiter, tokens = r.CMFuturesFundingRate, 1 case cFuturesWalletFundRecordRate, cFuturesWalletWithdrawalRate: limiter, tokens = r.CMFuturesWalletRate, 1 case cFuturesAPIKeyInfoRate: limiter, tokens = r.CMFuturesAccountRate, 1 case uFuturesDefaultRate: limiter, tokens = r.UFuturesDefaultRate, 1 case uFuturesCreateOrderRate, uFuturesCancelOrderRate, uFuturesCreateConditionalOrderRate, uFuturesCancelConditionalOrderRate: limiter, tokens = r.UFuturesOrderRate, 1 case uFuturesCancelAllOrderRate, uFuturesCancelAllConditionalOrderRate: limiter, tokens = r.UFuturesOrderRate, 10 case uFuturesSetLeverageRate, uFuturesSwitchMargin, uFuturesSwitchPosition, uFuturesSetMarginRate, uFuturesSetTradingStopRate, uFuturesUpdateMarginRate: limiter, tokens = r.UFuturesPositionRate, 1 case uFuturesPositionRate, uFuturesGetClosedTradesRate, uFuturesGetTradesRate: limiter, tokens = r.UFuturesPositionListRate, 1 case uFuturesGetActiveOrderRate, uFuturesGetActiveRealtimeOrderRate, uFuturesGetConditionalOrderRate, uFuturesGetConditionalRealtimeOrderRate: limiter, tokens = r.UFuturesOrderListRate, 1 case uFuturesGetMyLastFundingFeeRate, uFuturesPredictFundingRate: limiter, tokens = r.UFuturesFundingRate, 1 case futuresDefaultRate: limiter, tokens = r.FuturesDefaultRate, 1 case futuresCancelOrderRate, futuresCreateOrderRate, futuresReplaceOrderRate, futuresReplaceConditionalOrderRate, futuresCancelConditionalOrderRate, futuresCreateConditionalOrderRate: limiter, tokens = r.FuturesOrderRate, 1 case futuresCancelAllOrderRate, futuresCancelAllConditionalOrderRate: limiter, tokens = r.FuturesOrderRate, 10 case futuresGetActiveOrderRate, futuresGetConditionalOrderRate, futuresGetActiveRealtimeOrderRate, futuresGetConditionalRealtimeOrderRate: limiter, tokens = r.FuturesOrderListRate, 1 case futuresGetTradeRate: limiter, tokens = r.FuturesExecutionRate, 1 case futuresSetLeverageRate, futuresUpdateMarginRate, futuresSetTradingStopRate, futuresSwitchPositionModeRate, futuresSwitchMarginRate, futuresSwitchPositionRate: limiter, tokens = r.FuturesPositionRate, 1 case futuresPositionRate: limiter, tokens = r.FuturesPositionListRate, 1 case usdcPublicRate: limiter, tokens = r.USDCPublic, 1 case usdcCancelAllOrderRate: limiter, tokens = r.USDCCancelAllOrderRate, 1 case usdcPlaceOrderRate: limiter, tokens = r.USDCPlaceOrderRate, 1 case usdcModifyOrderRate: limiter, tokens = r.USDCModifyOrderRate, 1 case usdcCancelOrderRate: limiter, tokens = r.USDCCancelOrderRate, 1 case usdcGetOrderRate: limiter, tokens = r.USDCGetOrderRate, 1 case usdcGetOrderHistoryRate: limiter, tokens = r.USDCGetOrderHistoryRate, 1 case usdcGetTradeHistoryRate: limiter, tokens = r.USDCGetTradeHistoryRate, 1 case usdcGetTransactionRate: limiter, tokens = r.USDCGetTransactionRate, 1 case usdcGetWalletRate: limiter, tokens = r.USDCGetWalletRate, 1 case usdcGetAssetRate: limiter, tokens = r.USDCGetAssetRate, 1 case usdcGetMarginRate: limiter, tokens = r.USDCGetMarginRate, 1 case usdcGetPositionRate: limiter, tokens = r.USDCGetPositionRate, 1 case usdcSetLeverageRate: limiter, tokens = r.USDCSetLeverageRate, 1 case usdcGetSettlementRate: limiter, tokens = r.USDCGetSettlementRate, 1 case usdcSetRiskRate: limiter, tokens = r.USDCSetRiskRate, 1 case usdcGetPredictedFundingRate: limiter, tokens = r.USDCGetPredictedFundingRate, 1 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, spotRequestRate), FuturesRate: request.NewRateLimit(futuresPublicInterval, futuresRequestRate), PrivateSpotRate: request.NewRateLimit(spotInterval, spotPrivateRequestRate), CMFuturesDefaultRate: request.NewRateLimit(futuresInterval, futuresDefaultRateCount), CMFuturesOrderRate: request.NewRateLimit(futuresInterval, futuresOrderRate), CMFuturesOrderListRate: request.NewRateLimit(futuresInterval, futuresOrderListRate), CMFuturesExecutionRate: request.NewRateLimit(futuresInterval, futuresExecutionRate), CMFuturesPositionRate: request.NewRateLimit(futuresInterval, futuresPositionRateCount), CMFuturesPositionListRate: request.NewRateLimit(futuresInterval, futuresPositionListRate), CMFuturesFundingRate: request.NewRateLimit(futuresInterval, futuresFundingRate), CMFuturesWalletRate: request.NewRateLimit(futuresInterval, futuresWalletRate), CMFuturesAccountRate: request.NewRateLimit(futuresInterval, futuresAccountRate), UFuturesDefaultRate: request.NewRateLimit(futuresInterval, futuresDefaultRateCount), UFuturesOrderRate: request.NewRateLimit(futuresInterval, futuresOrderRate), UFuturesPositionRate: request.NewRateLimit(futuresInterval, futuresPositionRateCount), UFuturesPositionListRate: request.NewRateLimit(futuresInterval, futuresPositionListRate), UFuturesOrderListRate: request.NewRateLimit(futuresInterval, futuresOrderListRate), UFuturesFundingRate: request.NewRateLimit(futuresInterval, futuresFundingRate), FuturesDefaultRate: request.NewRateLimit(futuresInterval, futuresDefaultRateCount), FuturesOrderRate: request.NewRateLimit(futuresInterval, futuresOrderRate), FuturesOrderListRate: request.NewRateLimit(futuresInterval, futuresOrderListRate), FuturesExecutionRate: request.NewRateLimit(futuresInterval, futuresExecutionRate), FuturesPositionRate: request.NewRateLimit(futuresInterval, futuresPositionRateCount), FuturesPositionListRate: request.NewRateLimit(futuresInterval, futuresPositionListRate), USDCPublic: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPublicRate), USDCPlaceOrderRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCModifyOrderRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCCancelOrderRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCCancelAllOrderRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualCancelAllRate), USDCGetOrderRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetOrderHistoryRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetTradeHistoryRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetTransactionRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetWalletRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetAssetRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetMarginRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetPositionRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCSetLeverageRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetSettlementRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCSetRiskRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), USDCGetPredictedFundingRate: request.NewRateLimit(usdcPerpetualInterval, usdcPerpetualPrivateRate), } }