From 913601be1ae7be867c59a66f6d11027755d5d63c Mon Sep 17 00:00:00 2001 From: Samuel Reid <43227667+cranktakular@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:26:41 +1000 Subject: [PATCH] Alas Bitget continues --- cmd/exchange_wrapper_issues/main.go | 18 -- .../exchange_wrapper_standards_test.go | 1 - exchanges/binance/binance_test.go | 2 +- exchanges/bitget/bitget.go | 20 +-- exchanges/bitget/bitget_test.go | 42 ++++- exchanges/bitget/bitget_wrapper.go | 165 +++++++++++++++++- exchanges/exchange.go | 5 - exchanges/exchange_test.go | 8 - exchanges/futures/futures.go | 3 - exchanges/interfaces.go | 1 - exchanges/okx/okx_test.go | 2 +- 11 files changed, 213 insertions(+), 54 deletions(-) diff --git a/cmd/exchange_wrapper_issues/main.go b/cmd/exchange_wrapper_issues/main.go index 0e1aa3aa350..b5ddb8feab8 100644 --- a/cmd/exchange_wrapper_issues/main.go +++ b/cmd/exchange_wrapper_issues/main.go @@ -919,24 +919,6 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config) Response: marginRateHistoryResponse, }) - positionSummaryRequest := &futures.PositionSummaryRequest{ - Asset: assetTypes[i], - Pair: p, - } - var positionSummaryResponse *futures.PositionSummary - positionSummaryResponse, err = e.GetPositionSummary(context.TODO(), positionSummaryRequest) - msg = "" - if err != nil { - msg = err.Error() - responseContainer.ErrorCount++ - } - responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{ - SentParams: jsonifyInterface([]interface{}{positionSummaryRequest}), - Function: "GetFuturesPositionSummary", - Error: msg, - Response: jsonifyInterface([]interface{}{positionSummaryResponse}), - }) - calculatePNLRequest := &futures.PNLCalculatorRequest{ Pair: p, Underlying: p.Base, diff --git a/cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go b/cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go index 7d6b5f4b657..d1eedce4dec 100644 --- a/cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go +++ b/cmd/exchange_wrapper_standards/exchange_wrapper_standards_test.go @@ -579,7 +579,6 @@ var excludedMethodNames = map[string]struct{}{ "CalculatePNL": {}, "CalculateTotalCollateral": {}, "ScaleCollateral": {}, - "GetPositionSummary": {}, "GetFuturesPositionSummary": {}, "GetFuturesPositionOrders": {}, "SetCollateralMode": {}, diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index f589a41723b..8fdb5876f54 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -3053,7 +3053,7 @@ func TestChangePositionMargin(t *testing.T) { } } -func TestGetPositionSummary(t *testing.T) { +func TestGetFuturesPositionSummary(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, b) diff --git a/exchanges/bitget/bitget.go b/exchanges/bitget/bitget.go index d1fdacbf53a..5f9231a3d47 100644 --- a/exchanges/bitget/bitget.go +++ b/exchanges/bitget/bitget.go @@ -441,7 +441,6 @@ func (bi *Bitget) GetMerchantP2POrders(ctx context.Context, startTime, endTime t params.Values.Set("status", status) params.Values.Set("side", side) params.Values.Set("coin", cryptoCurrency) - // params.Values.Set("language", "en-US") params.Values.Set("fiat", fiatCurrency) var resp *P2POrdersResp return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, @@ -467,7 +466,6 @@ func (bi *Bitget) GetMerchantAdvertisementList(ctx context.Context, startTime, e params.Values.Set("status", status) params.Values.Set("side", side) params.Values.Set("coin", cryptoCurrency) - // params.Values.Set("language", "en-US") params.Values.Set("fiat", fiatCurrency) params.Values.Set("orderBy", orderBy) params.Values.Set("sourceType", sourceType) @@ -686,7 +684,7 @@ func (bi *Bitget) GetVirtualSubaccounts(ctx context.Context, limit, pagination i vals.Set("status", status) path := bitgetUser + bitgetVirtualSubaccount + "-" + bitgetList var resp *GetVirSubResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate2, http.MethodGet, path, vals, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, path, vals, nil, &resp) } @@ -751,7 +749,7 @@ func (bi *Bitget) GetAPIKeys(ctx context.Context, subaccountID string) (*GetAPIK vals.Set("subAccountUid", subaccountID) path := bitgetUser + bitgetVirtualSubaccount + "-" + bitgetAPIKey + "-" + bitgetList var resp *GetAPIKeyResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, path, vals, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate5, http.MethodGet, path, vals, nil, &resp) } @@ -780,7 +778,7 @@ func (bi *Bitget) GetBotAccountAssets(ctx context.Context, accountType string) ( // GetAssetOverview returns an overview of the user's assets across various account types func (bi *Bitget) GetAssetOverview(ctx context.Context) (*AssetOverviewResp, error) { var resp *AssetOverviewResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate1, http.MethodGet, bitgetAccount+bitgetAllAccountBalance, nil, nil, &resp) } @@ -1395,7 +1393,7 @@ func (bi *Bitget) BatchCancelSpotPlanOrders(ctx context.Context, pairs []string) } path := bitgetSpot + bitgetTrade + bitgetBatchCancelPlanOrder var resp *BatchOrderResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodPost, path, nil, req, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate5, http.MethodPost, path, nil, req, &resp) } @@ -1651,7 +1649,7 @@ func (bi *Bitget) SwitchBGBDeductionStatus(ctx context.Context, deduct bool) (*B } path := bitgetSpot + bitgetAccount + bitgetSwitchDeduct var resp *BoolData - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodPost, path, nil, req, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate1, http.MethodPost, path, nil, req, &resp) } @@ -1691,7 +1689,7 @@ func (bi *Bitget) GetSubaccountDepositAddress(ctx context.Context, subaccountID, func (bi *Bitget) GetBGBDeductionStatus(ctx context.Context) (*BGBDeductResp, error) { path := bitgetSpot + bitgetAccount + bitgetDeductInfo var resp *BGBDeductResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, path, nil, nil, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate5, http.MethodGet, path, nil, nil, &resp) } @@ -2055,7 +2053,7 @@ func (bi *Bitget) GetFuturesSubaccountAssets(ctx context.Context, productType st vals.Set("productType", productType) path := bitgetMix + bitgetAccount + bitgetSubaccountAssets2 var resp *SubaccountFuturesResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate10, http.MethodGet, path, vals, nil, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate1, http.MethodGet, path, vals, nil, &resp) } @@ -2295,7 +2293,7 @@ func (bi *Bitget) GetHistoricalPositions(ctx context.Context, pair, productType } path := bitgetMix + bitgetPosition + bitgetHistoryPosition var resp *HistPositionResp - return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate5, http.MethodGet, path, params.Values, + return resp, bi.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, Rate20, http.MethodGet, path, params.Values, nil, &resp) } @@ -2428,7 +2426,7 @@ func (bi *Bitget) BatchPlaceFuturesOrders(ctx context.Context, pair, productType "orderList": orders, } path := bitgetMix + bitgetOrder + bitgetBatchPlaceOrder - rLim := Rate10 + rLim := Rate5 if isCopyTradeLeader { rLim = Rate1 } diff --git a/exchanges/bitget/bitget_test.go b/exchanges/bitget/bitget_test.go index ad674e169e7..812786b56cd 100644 --- a/exchanges/bitget/bitget_test.go +++ b/exchanges/bitget/bitget_test.go @@ -73,12 +73,12 @@ const ( errAPIKeyLimitPartial = `Bitget unsuccessful HTTP status code: 400 raw response: {"code":"40063","msg":"API exceeds the maximum limit added","requestTime":` errCurrentlyHoldingPositionPartial = `Bitget unsuccessful HTTP status code: 400 raw response: {"code":"45117","msg":"Currently holding positions or orders, the margin mode cannot be adjusted","requestTime":` - errFakePairDoesNotExistPartial = `Bitget unsuccessful HTTP status code: 400 raw response: {"code":"40034","msg":"Parameter FAKEPAIRNOTREALMEOWMEOW does not exist","requestTime"` ) // Developer-defined variables to aid testing var ( - fakePair = currency.NewPair(currency.NewCode("FAKEPAIRNOT"), currency.NewCode("REALMEOWMEOW")) + fakeCurrency = currency.NewCode("FAKECURRENCYNOT") + fakePair = currency.NewPair(fakeCurrency, currency.NewCode("REALMEOWMEOW")) ) var bi = &Bitget{} @@ -2778,12 +2778,46 @@ func TestUpdateOrderExecutionLimits(t *testing.T) { assert.NoError(t, err) } +func TestUpdateCurrencyStates(t *testing.T) { + t.Parallel() + err := bi.UpdateCurrencyStates(context.Background(), asset.Spot) + assert.NoError(t, err) +} + func TestGetAvailableTransferChains(t *testing.T) { t.Parallel() testGetOneArg(t, bi.GetAvailableTransferChains, currency.EMPTYCODE, testCrypto, errCurrencyEmpty, false, false, true) - _, err := bi.GetAvailableTransferChains(context.Background(), currency.NewCode("fakecurrencynotrealmeowmeow")) + _, err := bi.GetAvailableTransferChains(context.Background(), fakeCurrency) + assert.Error(t, err) +} + +func TestCalculatePNL(t *testing.T) { + bi.Verbose = true + _, err := bi.CalculatePNL(context.Background(), nil) + assert.NoError(t, err) +} + +func TestGetFuturesPositionSummary(t *testing.T) { + t.Parallel() + _, err := bi.GetFuturesPositionSummary(context.Background(), nil) + assert.ErrorIs(t, err, common.ErrNilPointer) + sharedtestvalues.SkipTestIfCredentialsUnset(t, bi) + _, err = bi.GetFuturesPositionSummary(context.Background(), &futures.PositionSummaryRequest{}) + assert.ErrorIs(t, err, errPairEmpty) + _, err = bi.GetFuturesPositionSummary(context.Background(), &futures.PositionSummaryRequest{Pair: testPair}) + assert.NoError(t, err) +} + +func TestGetFuturesPositions(t *testing.T) { + t.Parallel() + _, err := bi.GetFuturesPositions(context.Background(), nil) + assert.ErrorIs(t, err, common.ErrNilPointer) + sharedtestvalues.SkipTestIfCredentialsUnset(t, bi) + req := &futures.PositionsRequest{ + Pairs: currency.Pairs{testPair, currency.NewPair(currency.BTC, currency.ETH)}, + } + _, err = bi.GetFuturesPositions(context.Background(), req) assert.NoError(t, err) - // See if there's an established fake currency you can use instead of reinventing this one } // The following 3 tests aren't parallel due to collisions with each other, and some other plan order-related tests diff --git a/exchanges/bitget/bitget_wrapper.go b/exchanges/bitget/bitget_wrapper.go index 4458bc7e84d..95669411cad 100644 --- a/exchanges/bitget/bitget_wrapper.go +++ b/exchanges/bitget/bitget_wrapper.go @@ -15,6 +15,8 @@ import ( exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/account" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" + "github.com/thrasher-corp/gocryptotrader/exchanges/collateral" + "github.com/thrasher-corp/gocryptotrader/exchanges/currencystate" "github.com/thrasher-corp/gocryptotrader/exchanges/deposit" "github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate" "github.com/thrasher-corp/gocryptotrader/exchanges/futures" @@ -1639,6 +1641,9 @@ func (bi *Bitget) GetFuturesContractDetails(ctx context.Context, _ asset.Item) ( // GetLatestFundingRates returns the latest funding rates data func (bi *Bitget) GetLatestFundingRates(ctx context.Context, req *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) { + if req == nil { + return nil, fmt.Errorf("%T %w", req, common.ErrNilPointer) + } curRate, err := bi.GetFundingCurrent(ctx, req.Pair.String(), getProductType(req.Pair)) if err != nil { return nil, err @@ -1727,7 +1732,33 @@ func (bi *Bitget) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) // UpdateCurrencyStates updates currency states func (bi *Bitget) UpdateCurrencyStates(ctx context.Context, a asset.Item) error { - return common.ErrNotYetImplemented + payload := make(map[currency.Code]currencystate.Options) + resp, err := bi.GetCoinInfo(ctx, "") + if err != nil { + return err + } + for i := range resp.Data { + var withdraw bool + var deposit bool + var trade bool + for j := range resp.Data[i].Chains { + if resp.Data[i].Chains[j].Withdrawable { + withdraw = true + } + if resp.Data[i].Chains[j].Rechargeable { + deposit = true + } + } + if withdraw && deposit { + trade = true + } + payload[currency.NewCode(resp.Data[i].Coin)] = currencystate.Options{ + Withdraw: &withdraw, + Deposit: &deposit, + Trade: &trade, + } + } + return bi.States.UpdateAll(a, payload) } // GetAvailableTransferChains returns a list of supported transfer chains based @@ -1750,6 +1781,138 @@ func (bi *Bitget) GetAvailableTransferChains(ctx context.Context, cur currency.C return chains, nil } +// CalculatePNL is an overridable function to allow PNL to be calculated on an +// open position +// It will also determine whether the position is considered to be liquidated +// For live trading, an overriding function may wish to confirm the liquidation by +// requesting the status of the asset +func (bi *Bitget) CalculatePNL(ctx context.Context, req *futures.PNLCalculatorRequest) (*futures.PNLResult, error) { + if req == nil { + return nil, fmt.Errorf("%T %w", req, common.ErrNilPointer) + } + + // Putting this on ice until later, I could copy the code for calculating it offline from futures.go but that seems + // bad. Also unsure whether I could call i.e. GetSinglePosition when CalculateOffline is false + return nil, common.ErrNotYetImplemented +} + +// ScaleCollateral is an overridable function to determine how much +// collateral is usable in futures positions +func (bi *Bitget) ScaleCollateral(context.Context, *futures.CollateralCalculator) (*collateral.ByCurrency, error) { + // Skipping until I learn how to calculate collateral + return nil, common.ErrNotYetImplemented +} + +// CalculateTotalCollateral takes in n collateral calculators to determine an overall +// standing in a singular currency +func (bi *Bitget) CalculateTotalCollateral(_ context.Context, _ *futures.TotalCollateralCalculator) (*futures.TotalCollateralResponse, error) { + // Skipping until I learn how to calculate collateral + return nil, common.ErrNotYetImplemented +} + +// GetCollateralCurrencyForContract returns the collateral currency for an asset and contract pair +func (bi *Bitget) GetCollateralCurrencyForContract(a asset.Item, p currency.Pair) (currency.Code, asset.Item, error) { + // Due to the lack of a context, I can't get this to work unless I deduce the currency from the pair, which + // seems like a real waste of a function + return currency.Code{}, asset.Empty, common.ErrNotYetImplemented +} + +// GetCurrencyForRealisedPNL returns where to put realised PNL +// example 1: Bybit universal margin PNL is paid out in USD to your spot wallet +// example 2: Binance coin margined futures pays returns using the same currency eg BTC +func (bi *Bitget) GetCurrencyForRealisedPNL(_ asset.Item, _ currency.Pair) (currency.Code, asset.Item, error) { + // Skipped since I'm not sure where to get this information from + return currency.Code{}, asset.Empty, common.ErrNotYetImplemented +} + +// GetMarginRatesHistory returns the margin rate history for the supplied currency +func (bi *Bitget) GetMarginRatesHistory(context.Context, *margin.RateHistoryRequest) (*margin.RateHistoryResponse, error) { + // Skipped since I'm not fully sure waht this means, or where to get it from + return nil, common.ErrNotYetImplemented +} + +// GetFuturesPositionSummary returns stats for a future position +func (bi *Bitget) GetFuturesPositionSummary(ctx context.Context, req *futures.PositionSummaryRequest) (*futures.PositionSummary, error) { + if req == nil { + return nil, fmt.Errorf("%T %w", req, common.ErrNilPointer) + } + resp, err := bi.GetSinglePosition(ctx, getProductType(req.Pair), req.Pair.String(), req.Pair.Quote.String()) + if err != nil { + return nil, err + } + if len(resp.Data) != 1 { + // I'm not sure that it should actually return one data point in this case, replace this with a properly + // formatted error message once certain + return nil, fmt.Errorf("expected 1 position, received %v", len(resp.Data)) + } + summary := &futures.PositionSummary{ + Pair: req.Pair, + Asset: req.Asset, + // OpenDelegateSize is "Amount to be filled of the current order", would this be AvailableEquity? + // What is MarginSize? + AvailableEquity: decimal.NewFromFloat(resp.Data[0].Available), + FrozenBalance: decimal.NewFromFloat(resp.Data[0].Locked), + Leverage: decimal.NewFromFloat(resp.Data[0].Leverage), + RealisedPNL: decimal.NewFromFloat(resp.Data[0].AchievedProfits), + AverageOpenPrice: decimal.NewFromFloat(resp.Data[0].OpenPriceAverage), + UnrealisedPNL: decimal.NewFromFloat(resp.Data[0].UnrealizedPL), + // Not sure if these are actually equivalent + MaintenanceMarginRequirement: decimal.NewFromFloat(resp.Data[0].KeepMarginRate), + MarkPrice: decimal.NewFromFloat(resp.Data[0].MarkPrice), + StartDate: resp.Data[0].CreationTime.Time(), + } + + // Okay so the only two exchanges which invoke CalculateOffline use it to print a warning that they can't do that + // Why have it then? + // EstimatePosition isn't used at all either + return summary, nil +} + +// GetFuturesPositions returns futures positions for all currencies +func (bi *Bitget) GetFuturesPositions(ctx context.Context, req *futures.PositionsRequest) ([]futures.PositionDetails, error) { + if req == nil { + return nil, fmt.Errorf("%T %w", req, common.ErrNilPointer) + } + var resp []futures.PositionDetails + // This exchange essentially needs these listed, since a MarginCoin has to be provided + for i := range req.Pairs { + temp, err := bi.GetAllPositions(ctx, getProductType(req.Pairs[i]), req.Pairs[i].Quote.String()) + if err != nil { + return nil, err + } + for x := range temp.Data { + pair, err := pairFromStringHelper(temp.Data[x].Symbol) + if err != nil { + return nil, err + } + ord := []order.Detail{ + { + Exchange: bi.Name, + AssetType: req.Asset, + Pair: pair, + Side: sideDecoder(temp.Data[x].HoldSide), + RemainingAmount: temp.Data[x].OpenDelegateSize, + // Is this accurate? If so, ExecutedAmount should = Locked, which sounds weird + Amount: temp.Data[x].Total, + Leverage: temp.Data[x].Leverage, + AverageExecutedPrice: temp.Data[x].OpenPriceAverage, + MarginType: marginDecoder(temp.Data[x].MarginMode), + // Not 100% certain about this one + Price: temp.Data[x].MarkPrice, + Date: temp.Data[x].CreationTime.Time(), + }, + } + resp = append(resp, futures.PositionDetails{ + Exchange: bi.Name, + Pair: pair, + Asset: req.Asset, + Orders: ord, + }) + } + } + return resp, nil +} + // GetProductType is a helper function that returns the appropriate product type for a given currency pair func getProductType(p currency.Pair) string { var prodType string diff --git a/exchanges/exchange.go b/exchanges/exchange.go index bb67b9844a5..e663975171f 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -1506,11 +1506,6 @@ func (b *Base) HasAssetTypeAccountSegregation() bool { return b.Features.Supports.RESTCapabilities.HasAssetTypeAccountSegregation } -// GetPositionSummary returns stats for a future position -func (b *Base) GetPositionSummary(context.Context, *futures.PositionSummaryRequest) (*futures.PositionSummary, error) { - return nil, common.ErrNotYetImplemented -} - // GetKlineRequest returns a helper for the fetching of candle/kline data for // a single request within a pre-determined time window. func (b *Base) GetKlineRequest(pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time, fixedAPICandleLength bool) (*kline.Request, error) { diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index 76d2d4a5d9d..c8a0dfd9397 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -2069,14 +2069,6 @@ func TestGetMarginRateHistory(t *testing.T) { } } -func TestGetPositionSummary(t *testing.T) { - t.Parallel() - var b Base - if _, err := b.GetFuturesPositionSummary(context.Background(), nil); !errors.Is(err, common.ErrNotYetImplemented) { - t.Errorf("received: %v, expected: %v", err, common.ErrNotYetImplemented) - } -} - func TestGetFuturesPositions(t *testing.T) { t.Parallel() var b Base diff --git a/exchanges/futures/futures.go b/exchanges/futures/futures.go index 76cb8cf358f..a9d4da9e0e8 100644 --- a/exchanges/futures/futures.go +++ b/exchanges/futures/futures.go @@ -781,9 +781,6 @@ func (p *PositionTracker) TrackNewOrder(d *order.Detail, isInitialOrder bool) er // adding a new position to something that is already closed return fmt.Errorf("%w cannot process new order %v", ErrPositionClosed, d.OrderID) } - if d == nil { - return order.ErrSubmissionIsNil - } if !p.contractPair.Equal(d.Pair) { return fmt.Errorf("%w pair '%v' received: '%v'", errOrderNotEqualToTracker, d.Pair, p.contractPair) diff --git a/exchanges/interfaces.go b/exchanges/interfaces.go index e76f9268f30..c972c7f7393 100644 --- a/exchanges/interfaces.go +++ b/exchanges/interfaces.go @@ -164,7 +164,6 @@ type FunctionalityChecker interface { type FuturesManagement interface { GetOpenInterest(context.Context, ...key.PairAsset) ([]futures.OpenInterest, error) ScaleCollateral(ctx context.Context, calculator *futures.CollateralCalculator) (*collateral.ByCurrency, error) - GetPositionSummary(context.Context, *futures.PositionSummaryRequest) (*futures.PositionSummary, error) CalculateTotalCollateral(context.Context, *futures.TotalCollateralCalculator) (*futures.TotalCollateralResponse, error) GetFuturesPositions(context.Context, *futures.PositionsRequest) ([]futures.PositionDetails, error) GetHistoricalFundingRates(context.Context, *fundingrate.HistoricalRatesRequest) (*fundingrate.HistoricalRates, error) diff --git a/exchanges/okx/okx_test.go b/exchanges/okx/okx_test.go index 20b05cd6987..092a4f87ec1 100644 --- a/exchanges/okx/okx_test.go +++ b/exchanges/okx/okx_test.go @@ -3509,7 +3509,7 @@ func TestSetCollateralMode(t *testing.T) { } } -func TestGetPositionSummary(t *testing.T) { +func TestGetFuturesPositionSummary(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, ok) pp, err := ok.CurrencyPairs.GetPairs(asset.PerpetualSwap, true)