package okx import ( "context" "errors" "fmt" "log" "os" "slices" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/common/key" "github.com/thrasher-corp/gocryptotrader/core" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/encoding/json" "github.com/thrasher-corp/gocryptotrader/exchange/order/limits" "github.com/thrasher-corp/gocryptotrader/exchange/websocket" exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/collateral" "github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate" "github.com/thrasher-corp/gocryptotrader/exchanges/futures" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" "github.com/thrasher-corp/gocryptotrader/exchanges/margin" "github.com/thrasher-corp/gocryptotrader/exchanges/order" "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" "github.com/thrasher-corp/gocryptotrader/exchanges/request" "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" "github.com/thrasher-corp/gocryptotrader/exchanges/subscription" "github.com/thrasher-corp/gocryptotrader/exchanges/trade" testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange" testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions" "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" ) // Please supply your own keys here to do authenticated endpoint testing const ( apiKey = "" apiSecret = "" passphrase = "" canManipulateRealOrders = false useTestNet = false ) var ( e *Exchange leadTraderUniqueID string loadLeadTraderOnce sync.Once errSyncLeadTrader error mainPair = currency.NewPairWithDelimiter("BTC", "USDT", "-") // Is used for spot, margin symbols and underlying contracts optionsPair = currency.NewPairWithDelimiter("BTC", "USD", "-") perpetualSwapPair = currency.NewPairWithDelimiter("BTC", "USDT-SWAP", "-") spreadPair = currency.NewPairWithDelimiter("BTC-USDT", "BTC-USDT-SWAP", "_") ) func TestMain(m *testing.M) { e = new(Exchange) if err := testexch.Setup(e); err != nil { log.Fatalf("Okx Setup error: %s", err) } if apiKey != "" && apiSecret != "" && passphrase != "" { e.API.AuthenticatedSupport = true e.API.AuthenticatedWebsocketSupport = true e.SetCredentials(apiKey, apiSecret, passphrase, "", "", "") e.Websocket.SetCanUseAuthenticatedEndpoints(true) } os.Exit(m.Run()) } func syncLeadTraderUniqueID(t *testing.T) error { t.Helper() if useTestNet { t.Skip("Testnet does not support lead trader API") } loadLeadTraderOnce.Do(func() { result, err := e.GetLeadTradersRanks(contextGenerate(), &LeadTraderRanksRequest{ InstrumentType: instTypeSwap, SortType: "pnl_ratio", HasVacancy: true, Limit: 10, }) if err != nil { errSyncLeadTrader = fmt.Errorf("GetLeadTradersRanks failed: %s", err) return } if len(result) == 0 { errSyncLeadTrader = errors.New("no lead trader found") return } if len(result[0].Ranks) == 0 { errSyncLeadTrader = errors.New("could not load lead traders ranks") return } leadTraderUniqueID = result[0].Ranks[0].UniqueCode }) return errSyncLeadTrader } // contextGenerate sends an optional value to allow test requests // named this way, so it shows up in auto-complete and reminds you to use it func contextGenerate() context.Context { return context.WithValue(context.Background(), testNetVal, useTestNet) } func TestGetTickers(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) pairs, err := e.GetAvailablePairs(asset.Options) require.NoError(t, err, "GetAvailablePairs must not error") require.NotEmpty(t, pairs, "GetAvailablePairs must not return empty pairs") instFamily, err := e.instrumentFamilyFromInstID(instTypeOption, pairs[0].String()) require.NoError(t, err, "instrumentFamilyFromInstID must not error") _, err = e.GetTickers(contextGenerate(), "", "", instFamily) require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetTickers(contextGenerate(), instTypeOption, "", instFamily) require.NoError(t, err) assert.NotNil(t, result) } func TestGetIndexTicker(t *testing.T) { t.Parallel() _, err := e.GetIndexTickers(contextGenerate(), currency.EMPTYCODE, "") require.ErrorIs(t, err, errEitherInstIDOrCcyIsRequired) result, err := e.GetIndexTickers(contextGenerate(), currency.USDT, "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetTicker(t *testing.T) { t.Parallel() _, err := e.GetTicker(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetTicker(contextGenerate(), perpetualSwapPair.String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPremiumHistory(t *testing.T) { t.Parallel() _, err := e.GetPremiumHistory(contextGenerate(), "", time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetPremiumHistory(contextGenerate(), perpetualSwapPair.String(), time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOrderBookDepth(t *testing.T) { t.Parallel() _, err := e.GetOrderBookDepth(contextGenerate(), "", 400) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetOrderBookDepth(contextGenerate(), mainPair.String(), 400) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCandlesticks(t *testing.T) { t.Parallel() _, err := e.GetCandlesticks(contextGenerate(), "", kline.OneHour, time.Now().Add(-time.Minute*2), time.Now(), 2) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetCandlesticks(contextGenerate(), mainPair.String(), kline.OneHour, time.Now().Add(-time.Hour), time.Now(), 2) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCandlesticksHistory(t *testing.T) { t.Parallel() _, err := e.GetCandlesticksHistory(contextGenerate(), "", kline.OneHour, time.Unix(time.Now().Unix()-int64(time.Minute), 3), time.Now(), 3) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetCandlesticksHistory(contextGenerate(), mainPair.String(), kline.OneHour, time.Unix(time.Now().Unix()-int64(time.Minute), 3), time.Now(), 3) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTrades(t *testing.T) { t.Parallel() _, err := e.GetTrades(contextGenerate(), "", 3) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetTrades(contextGenerate(), mainPair.String(), 3) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTradeHistory(t *testing.T) { t.Parallel() _, err := e.GetTradesHistory(contextGenerate(), "", "", "", 2) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetTradesHistory(contextGenerate(), mainPair.String(), "", "", 2) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOptionTradesByInstrumentFamily(t *testing.T) { t.Parallel() _, err := e.GetOptionTradesByInstrumentFamily(contextGenerate(), "") require.ErrorIs(t, err, errInstrumentFamilyRequired) result, err := e.GetOptionTradesByInstrumentFamily(contextGenerate(), optionsPair.String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOptionTrades(t *testing.T) { t.Parallel() _, err := e.GetOptionTrades(contextGenerate(), "", "", "C") require.ErrorIs(t, err, errInstrumentIDorFamilyRequired) result, err := e.GetOptionTrades(contextGenerate(), "", optionsPair.String(), "C") require.NoError(t, err) assert.NotNil(t, result) } func TestGet24HTotalVolume(t *testing.T) { t.Parallel() result, err := e.Get24HTotalVolume(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOracle(t *testing.T) { t.Parallel() t.Skip("Skipping test: The server endpoint has a rate-limiting issue that needs to be fixed.") result, err := e.GetOracle(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetExchangeRate(t *testing.T) { t.Parallel() result, err := e.GetExchangeRate(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetIndexComponents(t *testing.T) { t.Parallel() _, err := e.GetIndexComponents(contextGenerate(), "") require.ErrorIs(t, err, errIndexComponentNotFound) result, err := e.GetIndexComponents(contextGenerate(), mainPair.String()) require.NoError(t, err) require.NotNil(t, result) assert.NotEmpty(t, result.Index, "Index should not be empty") assert.NotEmpty(t, result.Components, "Components should not be empty") } func TestGetBlockTickers(t *testing.T) { t.Parallel() _, err := e.GetBlockTickers(contextGenerate(), "", "") require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetBlockTickers(contextGenerate(), "SWAP", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetBlockTicker(t *testing.T) { t.Parallel() _, err := e.GetBlockTicker(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetBlockTicker(contextGenerate(), mainPair.String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBlockTrade(t *testing.T) { t.Parallel() _, err := e.GetPublicBlockTrades(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) trades, err := e.GetPublicBlockTrades(contextGenerate(), mainPair.String()) require.NoError(t, err) if assert.NotEmpty(t, trades, "Should get some block trades") { blockTrade := trades[0] assert.Equal(t, mainPair.String(), blockTrade.InstrumentID, "InstrumentID should have correct value") assert.NotEmpty(t, blockTrade.TradeID, "TradeID should not be empty") assert.Positive(t, blockTrade.Price.Float64(), "Price should have a positive value") assert.Positive(t, blockTrade.Size.Float64(), "Size should have a positive value") assert.Contains(t, []order.Side{order.Buy, order.Sell}, blockTrade.Side, "Side should be a side") assert.WithinRange(t, blockTrade.Timestamp.Time(), time.Now().Add(time.Hour*-24*90), time.Now(), "Timestamp should be within last 90 days") } testexch.UpdatePairsOnce(t, e) pairs, err := e.GetAvailablePairs(asset.Options) require.NoError(t, err) require.NotEmpty(t, pairs) publicTrades, err := e.GetPublicRFQTrades(contextGenerate(), "", "", 100) require.NoError(t, err) tested := false LOOP: for _, trade := range publicTrades { for _, leg := range trade.Legs { p, err := e.MatchSymbolWithAvailablePairs(leg.InstrumentID, asset.Options, true) if err != nil { continue } trades, err = e.GetPublicBlockTrades(contextGenerate(), p.String()) require.NoError(t, err, "GetBlockTrades must not error on Options") for _, trade := range trades { assert.Equal(t, p.String(), trade.InstrumentID, "InstrumentID should have correct value") assert.NotEmpty(t, trade.TradeID, "TradeID should not be empty") assert.Positive(t, trade.Price.Float64(), "Price should have a positive value") assert.Positive(t, trade.Size.Float64(), "Size should have a positive value") assert.Contains(t, []order.Side{order.Buy, order.Sell}, trade.Side, "Side should be a side") assert.GreaterOrEqual(t, trade.FillVolatility.Float64(), float64(0), "FillVolatility should not be negative") assert.Positive(t, trade.ForwardPrice.Float64(), "ForwardPrice should have a positive value") assert.Positive(t, trade.IndexPrice.Float64(), "IndexPrice should have a positive value") assert.Positive(t, trade.MarkPrice.Float64(), "MarkPrice should have a positive value") assert.NotEmpty(t, trade.Timestamp, "Timestamp should not be empty") tested = true break LOOP } } } assert.True(t, tested, "Should find at least one BlockTrade somewhere") } func TestGetInstrument(t *testing.T) { t.Parallel() _, err := e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{Underlying: mainPair.String()}) assert.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{ InstrumentType: instTypeOption, Underlying: "", }) assert.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) resp, err := e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{ InstrumentType: instTypeFutures, Underlying: "SOL-USD", }) require.NoError(t, err) assert.Empty(t, resp, "Should get back no instruments for SOL-USD futures") result, err := e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{ InstrumentType: instTypeSpot, }) require.NoError(t, err) assert.NotNil(t, result) _, err = e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{ InstrumentType: instTypeSwap, Underlying: mainPair.String(), }) assert.NoError(t, err) assert.NotNil(t, result) } func TestGetDeliveryHistory(t *testing.T) { t.Parallel() _, err := e.GetDeliveryHistory(contextGenerate(), "", mainPair.String(), "", time.Time{}, time.Time{}, 3) require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetDeliveryHistory(contextGenerate(), instTypeFutures, "", "", time.Time{}, time.Time{}, 3) require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) _, err = e.GetDeliveryHistory(contextGenerate(), instTypeFutures, mainPair.String(), "", time.Time{}, time.Time{}, 345) require.ErrorIs(t, err, errLimitValueExceedsMaxOf100) result, err := e.GetDeliveryHistory(contextGenerate(), instTypeFutures, mainPair.String(), "", time.Time{}, time.Time{}, 3) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOpenInterestData(t *testing.T) { t.Parallel() _, err := e.GetOpenInterestData(contextGenerate(), "", mainPair.String(), "", "") require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetOpenInterestData(contextGenerate(), instTypeOption, "", "", "") require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) testexch.UpdatePairsOnce(t, e) p, err := e.GetAvailablePairs(asset.Options) require.NoError(t, err, "GetAvailablePairs must not error") require.NotEmpty(t, p, "GetAvailablePairs must not return empty pairs") uly, err := e.underlyingFromInstID(instTypeOption, p[0].String()) require.NoError(t, err) result, err := e.GetOpenInterestData(contextGenerate(), instTypeOption, uly, optionsPair.String(), p[0].String()) require.NoError(t, err) assert.NotNil(t, result) } // Only being used for testing purposes and unexported func (e *Exchange) underlyingFromInstID(instrumentType, instID string) (string, error) { e.instrumentsInfoMapLock.Lock() defer e.instrumentsInfoMapLock.Unlock() if instrumentType != "" { insts, okay := e.instrumentsInfoMap[instrumentType] if !okay { return "", errInvalidInstrumentType } for a := range insts { if insts[a].InstrumentID.String() == instID { return insts[a].Underlying, nil } } } else { for _, insts := range e.instrumentsInfoMap { for a := range insts { if insts[a].InstrumentID.String() == instID { return insts[a].Underlying, nil } } } } return "", fmt.Errorf("underlying not found for instrument %s", instID) } func TestGetSingleFundingRate(t *testing.T) { t.Parallel() _, err := e.GetSingleFundingRate(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetSingleFundingRate(contextGenerate(), perpetualSwapPair.String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFundingRateHistory(t *testing.T) { t.Parallel() _, err := e.GetFundingRateHistory(contextGenerate(), "", time.Time{}, time.Time{}, 2) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetFundingRateHistory(contextGenerate(), perpetualSwapPair.String(), time.Time{}, time.Time{}, 2) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLimitPrice(t *testing.T) { t.Parallel() _, err := e.GetLimitPrice(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetLimitPrice(contextGenerate(), perpetualSwapPair.String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOptionMarketData(t *testing.T) { t.Parallel() _, err := e.GetOptionMarketData(contextGenerate(), "", "", time.Time{}) require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) result, err := e.GetOptionMarketData(contextGenerate(), "BTC-USD", "", time.Time{}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetEstimatedDeliveryPrice(t *testing.T) { t.Parallel() _, err := e.GetEstimatedDeliveryPrice(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) testexch.UpdatePairsOnce(t, e) p, err := e.GetAvailablePairs(asset.Futures) require.NoError(t, err, "GetAvailablePairs must not error") require.NotEmpty(t, p, "GetAvailablePairs must not return empty pairs") result, err := e.GetEstimatedDeliveryPrice(contextGenerate(), p[0].String()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetDiscountRateAndInterestFreeQuota(t *testing.T) { t.Parallel() result, err := e.GetDiscountRateAndInterestFreeQuota(contextGenerate(), currency.EMPTYCODE, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSystemTime(t *testing.T) { t.Parallel() result, err := e.GetSystemTime(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) assert.False(t, result.Time().IsZero(), "GetSystemTime should not return a zero time") } func TestGetLiquidationOrders(t *testing.T) { t.Parallel() result, err := e.GetLiquidationOrders(contextGenerate(), &LiquidationOrderRequestParams{ InstrumentType: instTypeMargin, Underlying: mainPair.String(), Currency: currency.BTC, Limit: 2, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMarkPrice(t *testing.T) { t.Parallel() _, err := e.GetMarkPrice(contextGenerate(), "", "", "", mainPair.String()) require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetMarkPrice(contextGenerate(), "MARGIN", "", "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetPositionTiers(t *testing.T) { t.Parallel() _, err := e.GetPositionTiers(contextGenerate(), "", "cross", mainPair.String(), "", "", "", currency.ETH) require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetPositionTiers(contextGenerate(), instTypeFutures, "", mainPair.String(), "", "", "", currency.ETH) require.ErrorIs(t, err, errInvalidTradeMode) _, err = e.GetPositionTiers(contextGenerate(), instTypeFutures, "cross", "", "", "", "", currency.EMPTYCODE) require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) _, err = e.GetPositionTiers(contextGenerate(), instTypeFutures, "cross", mainPair.String(), "", "", "", currency.EMPTYCODE) require.ErrorIs(t, err, errEitherInstIDOrCcyIsRequired) result, err := e.GetPositionTiers(contextGenerate(), instTypeFutures, "cross", mainPair.String(), "", "", "", currency.ETH) require.NoError(t, err) assert.NotNil(t, result) } func TestGetInterestRateAndLoanQuota(t *testing.T) { t.Parallel() result, err := e.GetInterestRateAndLoanQuota(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetInterestRateAndLoanQuotaForVIPLoans(t *testing.T) { t.Parallel() result, err := e.GetInterestRateAndLoanQuotaForVIPLoans(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicUnderlyings(t *testing.T) { t.Parallel() _, err := e.GetPublicUnderlyings(contextGenerate(), "") require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetPublicUnderlyings(contextGenerate(), instTypeFutures) require.NoError(t, err) require.NotNil(t, result) assert.NotEmpty(t, result) } func TestGetInsuranceFundInformation(t *testing.T) { t.Parallel() _, err := e.GetInsuranceFundInformation(contextGenerate(), &InsuranceFundInformationRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &InsuranceFundInformationRequestParams{Limit: 2} _, err = e.GetInsuranceFundInformation(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidInstrumentType) arg.InstrumentType = instTypeSwap _, err = e.GetInsuranceFundInformation(contextGenerate(), arg) require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) arg.Underlying = mainPair.String() r, err := e.GetInsuranceFundInformation(contextGenerate(), arg) require.NoError(t, err) assert.Positive(t, r.Total, "Total should be positive") assert.NotEmpty(t, r.Details, "Should have some details") for _, d := range r.Details { assert.Positive(t, d.Balance, "Balance should be positive") assert.NotEmpty(t, d.InsuranceType, "Type should not be empty") assert.Positive(t, d.Timestamp, "Timestamp should be positive") } r, err = e.GetInsuranceFundInformation(contextGenerate(), &InsuranceFundInformationRequestParams{ InstrumentType: instTypeFutures, Underlying: mainPair.String(), Limit: 2, }) require.NoError(t, err) assert.Positive(t, r.Total, "Total should be positive") assert.NotEmpty(t, r.Details, "Should have some details") for _, d := range r.Details { assert.Positive(t, d.Balance, "Balance should be positive") assert.NotEmpty(t, d.InsuranceType, "Type should not be empty") assert.Positive(t, d.Timestamp, "Timestamp should be positive") } } func TestCurrencyUnitConvert(t *testing.T) { t.Parallel() _, err := e.CurrencyUnitConvert(contextGenerate(), "", 1, 3500, 1, currency.EMPTYCODE, false) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.CurrencyUnitConvert(contextGenerate(), perpetualSwapPair.String(), 0, 3500, 1, currency.EMPTYCODE, false) require.ErrorIs(t, err, errMissingQuantity) result, err := e.CurrencyUnitConvert(contextGenerate(), perpetualSwapPair.String(), 1, 3500, 1, currency.EMPTYCODE, false) require.NoError(t, err) assert.NotNil(t, result) } // Trading related endpoints test functions. func TestGetSupportCoins(t *testing.T) { t.Parallel() result, err := e.GetSupportCoins(contextGenerate()) require.NoError(t, err) require.NotNil(t, result) assert.NotEmpty(t, result.Spot, "SupportedCoins Spot should not be empty") } func TestGetTakerVolume(t *testing.T) { t.Parallel() _, err := e.GetTakerVolume(contextGenerate(), currency.BTC, "", "", time.Time{}, time.Time{}, kline.OneDay) require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetTakerVolume(contextGenerate(), currency.BTC, instTypeSpot, "", time.Time{}, time.Time{}, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMarginLendingRatio(t *testing.T) { t.Parallel() result, err := e.GetMarginLendingRatio(contextGenerate(), currency.BTC, time.Time{}, time.Time{}, kline.FiveMin) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLongShortRatio(t *testing.T) { t.Parallel() result, err := e.GetLongShortRatio(contextGenerate(), currency.BTC, time.Time{}, time.Time{}, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetContractsOpenInterestAndVolume(t *testing.T) { t.Parallel() result, err := e.GetContractsOpenInterestAndVolume(contextGenerate(), currency.BTC, time.Time{}, time.Time{}, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOptionsOpenInterestAndVolume(t *testing.T) { t.Parallel() result, err := e.GetOptionsOpenInterestAndVolume(contextGenerate(), currency.BTC, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPutCallRatio(t *testing.T) { t.Parallel() result, err := e.GetPutCallRatio(contextGenerate(), currency.BTC, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOpenInterestAndVolumeExpiry(t *testing.T) { t.Parallel() result, err := e.GetOpenInterestAndVolumeExpiry(contextGenerate(), currency.BTC, kline.OneDay) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOpenInterestAndVolumeStrike(t *testing.T) { t.Parallel() _, err := e.GetOpenInterestAndVolumeStrike(contextGenerate(), currency.BTC, time.Time{}, kline.OneDay) require.ErrorIs(t, err, errMissingExpiryTimeParameter) instruments, err := e.GetInstruments(contextGenerate(), &InstrumentsFetchParams{ InstrumentType: instTypeOption, Underlying: optionsPair.String(), }) require.NoErrorf(t, err, "GetInstruments for options (underlying: %s) must not error", optionsPair) require.NotEmptyf(t, instruments, "GetInstruments for options (underlying: %s) must return at least one instrument", optionsPair) var selectedExpTime time.Time for _, inst := range instruments { if inst.ExpTime.Time().IsZero() { continue } selectedExpTime = inst.ExpTime.Time() break } require.NotZero(t, selectedExpTime, "GetInstruments must return an instrument with a non-zero expiry time") result, err := e.GetOpenInterestAndVolumeStrike(contextGenerate(), currency.BTC, selectedExpTime, kline.OneDay) require.NoErrorf(t, err, "GetOpenInterestAndVolumeStrike with expiry %s for currency %s must not error", selectedExpTime, currency.BTC) assert.NotNilf(t, result, "GetOpenInterestAndVolumeStrike with expiry %s for currency %s should return a non-nil result", selectedExpTime, currency.BTC) } func TestGetTakerFlow(t *testing.T) { t.Parallel() result, err := e.GetTakerFlow(contextGenerate(), currency.BTC, kline.OneDay) require.NoError(t, err) require.NotNil(t, result) assert.False(t, result.Timestamp.Time().IsZero(), "Timestamp should not be zero") } func TestPlaceOrder(t *testing.T) { t.Parallel() _, err := e.PlaceOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) arg := &PlaceOrderRequestParam{ ReduceOnly: true, AssetType: asset.Margin, } _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Buy.Lower() arg.TradeMode = "abc" _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = "cross" _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = order.Limit.String() _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.AssetType = asset.Futures _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.PositionSide = "long" _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Amount = 1 arg.TargetCurrency = "abcd" _, err = e.PlaceOrder(contextGenerate(), arg) require.ErrorIs(t, err, errCurrencyQuantityTypeRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceOrder(contextGenerate(), &PlaceOrderRequestParam{ InstrumentID: "BTC-USDC", TradeMode: "cross", Side: order.Buy.String(), OrderType: "limit", Amount: 2.6, Price: 2.1, Currency: "BTC", AssetType: asset.Margin, }) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.PlaceOrder(contextGenerate(), &PlaceOrderRequestParam{ InstrumentID: "BTC-USDC", TradeMode: "cross", Side: order.Buy.Lower(), PositionSide: "long", OrderType: "limit", Amount: 2.6, Price: 2.1, Currency: "BTC", AssetType: asset.Futures, }) require.NoError(t, err) assert.NotNil(t, result) } const ( instrumentJSON = `{"alias":"","baseCcy":"","category":"1","ctMult":"1","ctType":"linear","ctVal":"0.0001","ctValCcy":"BTC","expTime":"","instFamily":"BTC-USDC","instId":"BTC-USDC-SWAP","instType":"SWAP","lever":"125","listTime":"1666076190000","lotSz":"1","maxIcebergSz":"100000000.0000000000000000","maxLmtSz":"100000000","maxMktSz":"85000","maxStopSz":"85000","maxTriggerSz":"100000000.0000000000000000","maxTwapSz":"","minSz":"1","optType":"","quoteCcy":"","settleCcy":"USDC","state":"live","stk":"","tickSz":"0.1","uly":"BTC-USDC"}` placeOrderArgs = `[{"side": "buy","instId": "BTC-USDT","tdMode": "cash","ordType": "market","sz": "100"},{"side": "buy","instId": "LTC-USDT","tdMode": "cash","ordType": "market","sz": "1"}]` calculateOrderbookChecksumUpdateOrderbookJSON = `{"Bids":[{"Amount":56,"Price":0.07014,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":608,"Price":0.07011,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":110,"Price":0.07009,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1264,"Price":0.07006,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":2347,"Price":0.07004,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":279,"Price":0.07003,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":52,"Price":0.07001,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":91,"Price":0.06997,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":4242,"Price":0.06996,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":486,"Price":0.06995,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":161,"Price":0.06992,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":63,"Price":0.06991,"ID":0,"Period":0,"LiquidationOrders":0, "OrderCount":0},{"Amount":7518,"Price":0.06988,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":186,"Price":0.06976,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":71,"Price":0.06975,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1086,"Price":0.06973,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":513,"Price":0.06961,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":4603,"Price":0.06959,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":186,"Price":0.0695,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":3043,"Price":0.06946,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":103,"Price":0.06939,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5053,"Price":0.0693,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5039,"Price":0.06909,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5037,"Price":0.06888,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1526,"Price":0.06886,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5008,"Price":0.06867,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5065,"Price":0.06846,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1572,"Price":0.06826,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1565,"Price":0.06801,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":67,"Price":0.06748,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":111,"Price":0.0674,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":10038,"Price":0.0672,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.06652,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1526,"Price":0.06625,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":10924,"Price":0.06619,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.05986,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.05387,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.04848,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.04363,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0}],"Asks":[{"Amount":5,"Price":0.07026,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":765,"Price":0.07027,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":110,"Price":0.07028,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1264,"Price":0.0703,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":280,"Price":0.07034,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":2255,"Price":0.07035,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":28,"Price":0.07036,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":63,"Price":0.07037,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":137,"Price":0.07039,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":48,"Price":0.0704,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":32,"Price":0.07041,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":3985,"Price":0.07043,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":257,"Price":0.07057,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":7870,"Price":0.07058,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":161,"Price":0.07059,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":4539,"Price":0.07061,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1438,"Price":0.07068,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":3162,"Price":0.07088,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":99,"Price":0.07104,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5018,"Price":0.07108,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1540,"Price":0.07115,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5080,"Price":0.07129,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1512,"Price":0.07145,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5016,"Price":0.0715,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5026,"Price":0.07171,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":5062,"Price":0.07192,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1517,"Price":0.07197,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1511,"Price":0.0726,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":10376,"Price":0.07314,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.07354,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":10277,"Price":0.07466,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":269,"Price":0.07626,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":269,"Price":0.07636,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.0809,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.08899,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.09789,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0},{"Amount":1,"Price":0.10768,"ID":0,"Period":0,"LiquidationOrders":0,"OrderCount":0}],"Exchange":"Okx","Pair":"BTC-USDT","Asset":"spot","LastUpdated":"0001-01-01T00:00:00Z","LastUpdateID":0,"PriceDuplication":false,"IsFundingRate":false,"RestSnapshot":false,"IDAlignment":false}` placeMultipleOrderParamsJSON = `[{"instId":"BTC-USDT","tdMode":"cash","clOrdId":"b159","side":"buy","ordType":"limit","px":"2.15","sz":"2"},{"instId":"BTC-USDT","tdMode":"cash","clOrdId":"b15","side":"buy","ordType":"limit","px":"2.15","sz":"2"}]` ) func TestPlaceMultipleOrders(t *testing.T) { t.Parallel() var params []PlaceOrderRequestParam err := json.Unmarshal([]byte(placeMultipleOrderParamsJSON), ¶ms) assert.NoError(t, err) _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{}) require.ErrorIs(t, err, order.ErrSubmissionIsNil) arg := PlaceOrderRequestParam{ ReduceOnly: true, } _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = "buy" arg.TradeMode = "abc" _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = "cross" _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = orderLimit _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.AssetType = asset.Futures _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.PositionSide = "long" _, err = e.PlaceMultipleOrders(contextGenerate(), []PlaceOrderRequestParam{arg}) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceMultipleOrders(contextGenerate(), params) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelSingleOrder(t *testing.T) { t.Parallel() _, err := e.CancelSingleOrder(contextGenerate(), &CancelOrderRequestParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CancelSingleOrder(contextGenerate(), &CancelOrderRequestParam{OrderID: "12321312312"}) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.CancelSingleOrder(contextGenerate(), &CancelOrderRequestParam{InstrumentID: mainPair.String()}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelSingleOrder(contextGenerate(), &CancelOrderRequestParam{ InstrumentID: mainPair.String(), OrderID: "2510789768709120", }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelMultipleOrders(t *testing.T) { t.Parallel() _, err := e.CancelMultipleOrders(contextGenerate(), []CancelOrderRequestParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := CancelOrderRequestParam{} _, err = e.CancelMultipleOrders(contextGenerate(), []CancelOrderRequestParam{arg}) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.CancelMultipleOrders(contextGenerate(), []CancelOrderRequestParam{arg}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelMultipleOrders(contextGenerate(), []CancelOrderRequestParam{ { InstrumentID: mainPair.String(), OrderID: "2510789768709120", }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendOrder(t *testing.T) { t.Parallel() _, err := e.AmendOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) arg := &AmendOrderRequestParams{} _, err = e.AmendOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.AmendOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrOrderIDNotSet) arg.OrderID = "1234" _, err = e.AmendOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidNewSizeOrPriceInformation) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendOrder(contextGenerate(), &AmendOrderRequestParams{ InstrumentID: mainPair.String(), OrderID: "2510789768709120", NewPrice: 1233324.332, }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendMultipleOrders(t *testing.T) { t.Parallel() _, err := e.AmendMultipleOrders(contextGenerate(), []AmendOrderRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := AmendOrderRequestParams{ NewPriceInUSD: 1233, } _, err = e.AmendMultipleOrders(contextGenerate(), []AmendOrderRequestParams{arg}) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.AmendMultipleOrders(contextGenerate(), []AmendOrderRequestParams{arg}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) arg.ClientOrderID = "123212" _, err = e.AmendMultipleOrders(contextGenerate(), []AmendOrderRequestParams{arg}) require.ErrorIs(t, err, errInvalidNewSizeOrPriceInformation) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendMultipleOrders(contextGenerate(), []AmendOrderRequestParams{{ InstrumentID: mainPair.String(), OrderID: "2510789768709120", NewPrice: 1233324.332, }}) require.NoError(t, err) assert.NotNil(t, result) } func TestClosePositions(t *testing.T) { t.Parallel() _, err := e.ClosePositions(contextGenerate(), &ClosePositionsRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.ClosePositions(contextGenerate(), &ClosePositionsRequestParams{MarginMode: "cross"}) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.ClosePositions(contextGenerate(), &ClosePositionsRequestParams{InstrumentID: mainPair.String(), MarginMode: "abc"}) require.ErrorIs(t, err, margin.ErrMarginTypeUnsupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ClosePositions(contextGenerate(), &ClosePositionsRequestParams{ InstrumentID: mainPair.String(), MarginMode: "cross", Currency: "BTC", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOrderDetail(t *testing.T) { t.Parallel() _, err := e.GetOrderDetail(contextGenerate(), &OrderDetailRequestParam{}) assert.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.GetOrderDetail(contextGenerate(), &OrderDetailRequestParam{OrderID: "1234"}) assert.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetOrderDetail(contextGenerate(), &OrderDetailRequestParam{InstrumentID: mainPair.String()}) assert.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOrderDetail(contextGenerate(), &OrderDetailRequestParam{InstrumentID: "SUI-USDT", OrderID: "1974857619964870656"}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOrderList(t *testing.T) { t.Parallel() _, err := e.GetOrderList(contextGenerate(), &OrderListRequestParams{}) assert.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOrderList(contextGenerate(), &OrderListRequestParams{Limit: 1}) require.NoError(t, err) assert.NotNil(t, result) } func TestGet7DayOrderHistory(t *testing.T) { t.Parallel() _, err := e.getOrderHistory(contextGenerate(), &OrderHistoryRequestParams{}, "", request.UnAuth) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.getOrderHistory(contextGenerate(), &OrderHistoryRequestParams{Category: "abc"}, "", request.UnAuth) require.ErrorIs(t, err, errInvalidInstrumentType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.Get7DayOrderHistory(contextGenerate(), &OrderHistoryRequestParams{OrderListRequestParams: OrderListRequestParams{InstrumentType: "MARGIN"}}) require.NoError(t, err) require.NotNil(t, result) } func TestGet3MonthOrderHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.Get3MonthOrderHistory(contextGenerate(), &OrderHistoryRequestParams{OrderListRequestParams: OrderListRequestParams{InstrumentType: "MARGIN"}}) require.NoError(t, err) assert.NotNil(t, result) } func TestTransactionHistory(t *testing.T) { t.Parallel() _, err := e.getTransactionDetails(contextGenerate(), &TransactionDetailRequestParams{}, "", request.UnAuth) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.getTransactionDetails(contextGenerate(), &TransactionDetailRequestParams{Limit: 10}, "", request.UnAuth) require.ErrorIs(t, err, errInvalidInstrumentType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetTransactionDetailsLast3Days(contextGenerate(), &TransactionDetailRequestParams{InstrumentType: "MARGIN", Limit: 1}) require.NoError(t, err) require.NotNil(t, result) } func TestGetTransactionDetailsLast3Months(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetTransactionDetailsLast3Months(contextGenerate(), &TransactionDetailRequestParams{InstrumentType: "MARGIN"}) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceAlgoOrder(t *testing.T) { t.Parallel() _, err := e.PlaceAlgoOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &AlgoOrderParams{ ReduceOnly: true, } arg.OrderType = "conditional" _, err = e.PlaceAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = TradeModeCross _, err = e.PlaceAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Sell.Lower() arg.OrderType = "" _, err = e.PlaceAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = "limit" _, err = e.PlaceAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) } func TestStopOrder(t *testing.T) { t.Parallel() _, err := e.PlaceStopOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &AlgoOrderParams{ ReduceOnly: true, } arg.OrderType = "conditional" _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.TakeProfitTriggerPrice = 123 _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrUnknownPriceType) arg.TakeProfitTriggerPriceType = "last_price" arg.AlgoClientOrderID = "12345" _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = TradeModeCross _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Sell.Lower() arg.OrderType = "" _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = "limit" _, err = e.PlaceStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceStopOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", TakeProfitTriggerPriceType: "index", InstrumentID: mainPair.String(), OrderType: "conditional", Side: order.Sell.Lower(), TradeMode: "isolated", Size: 12, TakeProfitTriggerPrice: 12335, TakeProfitOrderPrice: 1234, }) assert.NoError(t, err) assert.NotNil(t, result) } func TestPlaceIcebergOrder(t *testing.T) { t.Parallel() _, err := e.PlaceIcebergOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.PlaceIcebergOrder(contextGenerate(), &AlgoOrderParams{ReduceOnly: true}) require.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.PlaceIcebergOrder(contextGenerate(), &AlgoOrderParams{OrderType: "iceberg"}) require.ErrorIs(t, err, errMissingSizeLimit) _, err = e.PlaceIcebergOrder(contextGenerate(), &AlgoOrderParams{OrderType: "iceberg", SizeLimit: 123}) require.ErrorIs(t, err, errInvalidPriceLimit) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceIcebergOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", LimitPrice: 100.22, SizeLimit: 9999.9, PriceSpread: 0.04, InstrumentID: mainPair.String(), OrderType: "iceberg", Side: order.Buy.Lower(), TradeMode: "isolated", Size: 6, }) assert.NoError(t, err) assert.NotNil(t, result) } func TestPlaceTWAPOrder(t *testing.T) { t.Parallel() _, err := e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{ReduceOnly: true}) require.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{OrderType: "twap"}) require.ErrorIs(t, err, errMissingSizeLimit) _, err = e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{SizeLimit: 2, OrderType: "twap"}) require.ErrorIs(t, err, errInvalidPriceLimit) _, err = e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{SizeLimit: 2, OrderType: "twap", LimitPrice: 1234.5}) require.ErrorIs(t, err, errMissingIntervalValue) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceTWAPOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", InstrumentID: mainPair.String(), LimitPrice: 100.22, SizeLimit: 9999.9, OrderType: "twap", PriceSpread: 0.4, TradeMode: "cross", Side: order.Sell.Lower(), Size: 6, TimeInterval: kline.ThreeDay, }) assert.NoError(t, err) assert.NotNil(t, result) } func TestPlaceTakeProfitStopLossOrder(t *testing.T) { t.Parallel() _, err := e.PlaceTakeProfitStopLossOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.PlaceTakeProfitStopLossOrder(contextGenerate(), &AlgoOrderParams{ReduceOnly: true}) require.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.PlaceTakeProfitStopLossOrder(contextGenerate(), &AlgoOrderParams{OrderType: "conditional"}) require.ErrorIs(t, err, limits.ErrPriceBelowMin) _, err = e.PlaceTakeProfitStopLossOrder(contextGenerate(), &AlgoOrderParams{ OrderType: "conditional", StopLossTriggerPrice: 1234, StopLossTriggerPriceType: "abcd", }) require.ErrorIs(t, err, order.ErrUnknownPriceType) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceTakeProfitStopLossOrder(contextGenerate(), &AlgoOrderParams{ OrderType: "conditional", StopLossTriggerPrice: 1234, StopLossTriggerPriceType: "last", AlgoClientOrderID: "681096944655273984", InstrumentID: mainPair.String(), LimitPrice: 100.22, SizeLimit: 9999.9, PriceSpread: 0.4, TradeMode: "cross", Side: order.Sell.Lower(), Size: 6, TimeInterval: kline.ThreeDay, }) assert.NoError(t, err) assert.NotNil(t, result) } func TestPlaceChaseAlgoOrder(t *testing.T) { t.Parallel() _, err := e.PlaceChaseAlgoOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &AlgoOrderParams{ ReduceOnly: true, } _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = orderChase arg.MaxChaseType = "percentage" _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errPriceTrackingNotSet) arg.MaxChaseType = "percentage" arg.MaxChaseValue = .5 _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = "cross" _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Sell.Lower() _, err = e.PlaceChaseAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceChaseAlgoOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", InstrumentID: mainPair.String(), LimitPrice: 100.22, OrderType: orderChase, TradeMode: "cross", Side: order.Sell.Lower(), MaxChaseType: "distance", MaxChaseValue: .5, Size: 6, }) require.NoError(t, err) assert.NotNil(t, result) } func TestTriggerAlgoOrder(t *testing.T) { t.Parallel() _, err := e.PlaceTriggerAlgoOrder(contextGenerate(), &AlgoOrderParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.PlaceTriggerAlgoOrder(contextGenerate(), &AlgoOrderParams{AlgoClientOrderID: "1234"}) require.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.PlaceTriggerAlgoOrder(contextGenerate(), &AlgoOrderParams{AlgoClientOrderID: "1234", OrderType: "trigger"}) require.ErrorIs(t, err, limits.ErrPriceBelowMin) _, err = e.PlaceTriggerAlgoOrder(contextGenerate(), &AlgoOrderParams{AlgoClientOrderID: "1234", OrderType: "trigger", TriggerPrice: 123., TriggerPriceType: "abcd"}) require.ErrorIs(t, err, order.ErrUnknownPriceType) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceTriggerAlgoOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", TriggerPriceType: "mark", TriggerPrice: 1234, InstrumentID: mainPair.String(), OrderType: "trigger", Side: order.Buy.Lower(), TradeMode: "cross", Size: 5, }) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceTrailingStopOrder(t *testing.T) { t.Parallel() _, err := e.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{}) assert.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{Size: 2}) assert.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{Size: 2, OrderType: orderMoveOrderStop}) assert.ErrorIs(t, err, errPriceTrackingNotSet) // Offline error handling unit tests for the base function PlaceAlgoOrder are already covered within unit test TestPlaceAlgoOrder. sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceTrailingStopOrder(contextGenerate(), &AlgoOrderParams{ AlgoClientOrderID: "681096944655273984", CallbackRatio: 0.01, InstrumentID: mainPair.String(), OrderType: orderMoveOrderStop, Side: order.Buy.Lower(), TradeMode: "isolated", Size: 2, ActivePrice: 1234, }) assert.NoError(t, err) assert.NotNil(t, result) } func TestCancelAlgoOrder(t *testing.T) { t.Parallel() arg := AlgoOrderCancelParams{} _, err := e.CancelAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{arg}) require.ErrorIs(t, err, common.ErrEmptyParams) arg.AlgoOrderID = "90994943" _, err = e.CancelAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{arg}) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() arg.AlgoOrderID = "" _, err = e.CancelAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{arg}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{ { InstrumentID: mainPair.String(), AlgoOrderID: "90994943", }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAdvanceAlgoOrder(t *testing.T) { t.Parallel() _, err := e.CancelAdvanceAlgoOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CancelAdvanceAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{{}}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CancelAdvanceAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{{InstrumentID: "90994943"}}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.CancelAdvanceAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{{AlgoOrderID: "90994943"}}) require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAdvanceAlgoOrder(contextGenerate(), []AlgoOrderCancelParams{{ InstrumentID: mainPair.String(), AlgoOrderID: "90994943", }}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAlgoOrderList(t *testing.T) { t.Parallel() _, err := e.GetAlgoOrderList(contextGenerate(), "", "", "", "", "", time.Time{}, time.Time{}, 1) require.ErrorIs(t, err, order.ErrTypeIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAlgoOrderList(contextGenerate(), "conditional", "", "", "", "", time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAlgoOrderHistory(t *testing.T) { t.Parallel() _, err := e.GetAlgoOrderHistory(contextGenerate(), "", "effective", "", "", "", time.Time{}, time.Time{}, 1) require.ErrorIs(t, err, order.ErrTypeIsInvalid) _, err = e.GetAlgoOrderHistory(contextGenerate(), "conditional", "", "", "", "", time.Time{}, time.Time{}, 1) require.ErrorIs(t, err, errMissingEitherAlgoIDOrState) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAlgoOrderHistory(contextGenerate(), "conditional", "effective", "", "", "", time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetEasyConvertCurrencyList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetEasyConvertCurrencyList(contextGenerate(), "1") require.NoError(t, err) assert.NotNil(t, result) } func TestGetOneClickRepayCurrencyList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOneClickRepayCurrencyList(contextGenerate(), "cross") require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceEasyConvert(t *testing.T) { t.Parallel() _, err := e.PlaceEasyConvert(contextGenerate(), PlaceEasyConvertParam{}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.PlaceEasyConvert(contextGenerate(), PlaceEasyConvertParam{FromCurrency: []string{"BTC"}}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceEasyConvert(contextGenerate(), PlaceEasyConvertParam{FromCurrency: []string{"BTC"}, ToCurrency: "USDT"}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetEasyConvertHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetEasyConvertHistory(contextGenerate(), time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOneClickRepayHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOneClickRepayHistory(contextGenerate(), time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestTradeOneClickRepay(t *testing.T) { t.Parallel() _, err := e.TradeOneClickRepay(contextGenerate(), TradeOneClickRepayParam{DebtCurrency: []string{}, RepayCurrency: "USDT"}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.TradeOneClickRepay(contextGenerate(), TradeOneClickRepayParam{DebtCurrency: []string{"BTC"}, RepayCurrency: ""}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.TradeOneClickRepay(contextGenerate(), TradeOneClickRepayParam{ DebtCurrency: []string{"BTC"}, RepayCurrency: "USDT", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCounterparties(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCounterparties(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } const createRFQInputJSON = `{"anonymous": true,"counterparties":["Trader1","Trader2"],"clRfqId":"rfq01","legs":[{"sz":"25","side":"buy","instId":"BTCUSD-221208-100000-C"},{"sz":"150","side":"buy","instId":"BTC-USDT","tgtCcy":"base_ccy"}]}` func TestCreateRFQ(t *testing.T) { t.Parallel() var input *CreateRFQInput err := json.Unmarshal([]byte(createRFQInputJSON), &input) require.NoError(t, err) _, err = e.CreateRFQ(contextGenerate(), &CreateRFQInput{CounterParties: []string{}}) require.ErrorIs(t, err, errInvalidCounterParties) _, err = e.CreateRFQ(contextGenerate(), &CreateRFQInput{CounterParties: []string{"Trader1"}}) require.ErrorIs(t, err, errMissingLegs) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CreateRFQ(contextGenerate(), input) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelRFQ(t *testing.T) { t.Parallel() _, err := e.CancelRFQ(contextGenerate(), "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelRFQ(contextGenerate(), "", "somersdjskfjsdkfjxvxv") require.NoError(t, err) assert.NotNil(t, result) } func TestMultipleCancelRFQ(t *testing.T) { t.Parallel() _, err := e.CancelMultipleRFQs(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) _, err = e.CancelMultipleRFQs(contextGenerate(), &CancelRFQRequestsParam{}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.CancelMultipleRFQs(contextGenerate(), &CancelRFQRequestsParam{RFQIDs: make([]string, 100), ClientRFQIDs: make([]string, 100)}) require.ErrorIs(t, err, errMaxRFQOrdersToCancel) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelMultipleRFQs(contextGenerate(), &CancelRFQRequestsParam{ClientRFQIDs: []string{"somersdjskfjsdkfjxvxv"}}) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllRFQs(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllRFQs(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestExecuteQuote(t *testing.T) { t.Parallel() _, err := e.ExecuteQuote(contextGenerate(), "", "") assert.ErrorIs(t, err, errMissingRFQIDOrQuoteID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ExecuteQuote(contextGenerate(), "22540", "84073") require.NoError(t, err) assert.NotNil(t, result) } func TestGetQuoteProducts(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetQuoteProducts(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestSetQuoteProducts(t *testing.T) { t.Parallel() _, err := e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{{InstrumentType: "ABC"}}) require.ErrorIs(t, err, errInvalidInstrumentType) arg := SetQuoteProductParam{InstrumentType: "SWAP"} _, err = e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{arg}) require.ErrorIs(t, err, errMissingMakerInstrumentSettings) data := MakerInstrumentSetting{MaxBlockSize: 10000, MakerPriceBand: 5} arg.Data = []MakerInstrumentSetting{data} _, err = e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{arg}) require.ErrorIs(t, err, errInvalidUnderlying) arg.InstrumentType = "SPOT" data = MakerInstrumentSetting{Underlying: "BTC-USD", MaxBlockSize: 10000, MakerPriceBand: 5} arg.Data = []MakerInstrumentSetting{data} _, err = e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{arg}) require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetQuoteProducts(contextGenerate(), []SetQuoteProductParam{ { InstrumentType: "SWAP", Data: []MakerInstrumentSetting{ { Underlying: "BTC-USD", MaxBlockSize: 10000, MakerPriceBand: 5, }, { Underlying: mainPair.String(), }, }, }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestResetRFQMMPStatus(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ResetRFQMMPStatus(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestCreateQuote(t *testing.T) { t.Parallel() _, err := e.CreateQuote(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) arg := &CreateQuoteParams{} _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, errMissingRFQID) arg.RFQID = "123456789" _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.QuoteSide = "sell" _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, errMissingLegs) subArg := QuoteLeg{} arg.Legs = []QuoteLeg{subArg} _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) subArg.InstrumentID = "SOL-USD-220909" arg.Legs = []QuoteLeg{subArg} _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, errMissingSizeOfQuote) subArg.SizeOfQuoteLeg = 2 arg.Legs = []QuoteLeg{subArg} _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, errMissingLegsQuotePrice) subArg.Price = 1234 arg.Legs = []QuoteLeg{subArg} _, err = e.CreateQuote(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CreateQuote(contextGenerate(), &CreateQuoteParams{ RFQID: "12345", QuoteSide: order.Buy.Lower(), Legs: []QuoteLeg{ { Price: 1234, SizeOfQuoteLeg: 2, InstrumentID: "SOL-USD-220909", Side: order.Sell, }, { Price: 1234, SizeOfQuoteLeg: 1, InstrumentID: "SOL-USD-220909", Side: order.Buy, }, }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelQuote(t *testing.T) { t.Parallel() _, err := e.CancelQuote(contextGenerate(), "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelQuote(contextGenerate(), "1234", "") require.NoError(t, err) require.NotNil(t, result) result, err = e.CancelQuote(contextGenerate(), "", "1234") require.NoError(t, err) assert.NotNil(t, result) } func TestCancelMultipleQuote(t *testing.T) { t.Parallel() _, err := e.CancelMultipleQuote(contextGenerate(), CancelQuotesRequestParams{}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelMultipleQuote(contextGenerate(), CancelQuotesRequestParams{ QuoteIDs: []string{"1150", "1151", "1152"}, // Block trades require a minimum of $100,000 in assets in your trading account }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllRFQQuotes(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) tt, err := e.CancelAllRFQQuotes(contextGenerate()) require.NoError(t, err) assert.NotEmpty(t, tt) } func TestGetRFQs(t *testing.T) { t.Parallel() _, err := e.GetRFQs(contextGenerate(), &RFQRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRFQs(contextGenerate(), &RFQRequestParams{ Limit: 1, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetQuotes(t *testing.T) { t.Parallel() _, err := e.GetQuotes(contextGenerate(), &QuoteRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetQuotes(contextGenerate(), &QuoteRequestParams{ Limit: 3, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetRFQTrades(t *testing.T) { t.Parallel() _, err := e.GetRFQTrades(contextGenerate(), &RFQTradesRequestParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRFQTrades(contextGenerate(), &RFQTradesRequestParams{Limit: 1}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicRFQTrades(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetPublicRFQTrades(contextGenerate(), "", "", 3) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFundingCurrencies(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFundingCurrencies(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBalance(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBalance(contextGenerate(), currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestGetNonTradableAssets(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetNonTradableAssets(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountAssetValuation(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountAssetValuation(contextGenerate(), currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestFundingTransfer(t *testing.T) { t.Parallel() _, err := e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{}) assert.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{ BeneficiaryAccountType: "6", RemittingAccountType: "18", Currency: currency.BTC, }) assert.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{ Amount: 12.000, BeneficiaryAccountType: "6", RemittingAccountType: "18", Currency: currency.EMPTYCODE, }) assert.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{ Amount: 12.000, BeneficiaryAccountType: "2", RemittingAccountType: "3", Currency: currency.BTC, }) assert.ErrorIs(t, err, errAddressRequired) _, err = e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{ Amount: 12.000, BeneficiaryAccountType: "2", RemittingAccountType: "18", Currency: currency.BTC, }) assert.ErrorIs(t, err, errAddressRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.FundingTransfer(contextGenerate(), &FundingTransferRequestInput{ Amount: 12.000, BeneficiaryAccountType: "6", RemittingAccountType: "18", Currency: currency.BTC, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFundsTransferState(t *testing.T) { t.Parallel() _, err := e.GetFundsTransferState(contextGenerate(), "", "", 1) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFundsTransferState(contextGenerate(), "754147", "1232", 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAssetBillsDetails(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAssetBillsDetails(contextGenerate(), currency.EMPTYCODE, "", time.Time{}, time.Time{}, 0, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLightningDeposits(t *testing.T) { t.Parallel() _, err := e.GetLightningDeposits(contextGenerate(), currency.EMPTYCODE, 1.00, 0) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.GetLightningDeposits(contextGenerate(), currency.BTC, 0, 0) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLightningDeposits(contextGenerate(), currency.BTC, 1.00, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCurrencyDepositAddress(t *testing.T) { t.Parallel() _, err := e.GetCurrencyDepositAddress(contextGenerate(), currency.EMPTYCODE) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCurrencyDepositAddress(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCurrencyDepositHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCurrencyDepositHistory(contextGenerate(), currency.BTC, "", "", "", "271", time.Time{}, time.Time{}, 0, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestWithdrawal(t *testing.T) { t.Parallel() _, err := e.Withdrawal(contextGenerate(), &WithdrawalInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.Withdrawal(contextGenerate(), &WithdrawalInput{Amount: 0.1, TransactionFee: 0.00005, Currency: currency.EMPTYCODE, WithdrawalDestination: "4", ToAddress: core.BitcoinDonationAddress}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.Withdrawal(contextGenerate(), &WithdrawalInput{TransactionFee: 0.00005, Currency: currency.BTC, WithdrawalDestination: "4", ToAddress: core.BitcoinDonationAddress}) require.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.Withdrawal(contextGenerate(), &WithdrawalInput{Amount: 0.1, TransactionFee: 0.00005, Currency: currency.BTC, ToAddress: core.BitcoinDonationAddress}) require.ErrorIs(t, err, errAddressRequired) _, err = e.Withdrawal(contextGenerate(), &WithdrawalInput{Amount: 0.1, TransactionFee: 0.00005, Currency: currency.BTC, WithdrawalDestination: "4"}) require.ErrorIs(t, err, errAddressRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.Withdrawal(contextGenerate(), &WithdrawalInput{Amount: 0.1, TransactionFee: 0.00005, Currency: currency.BTC, WithdrawalDestination: "4", ToAddress: core.BitcoinDonationAddress}) require.NoError(t, err) assert.NotNil(t, result) result, err = e.Withdrawal(contextGenerate(), &WithdrawalInput{ Amount: 0.1, WithdrawalDestination: "4", TransactionFee: 0.00005, Currency: currency.BTC, ChainName: "BTC-Bitcoin", ToAddress: core.BitcoinDonationAddress, RecipientInformation: &WithdrawalRecipientInformation{ WalletType: "exchange", ExchangeID: "did:ethr:0xfeb4f99829a9acdf52979abee87e83addf22a7e1", ReceiverFirstName: "Bruce", ReceiverLastName: "Wayne", }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestLightningWithdrawal(t *testing.T) { t.Parallel() _, err := e.LightningWithdrawal(contextGenerate(), &LightningWithdrawalRequestInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.LightningWithdrawal(contextGenerate(), &LightningWithdrawalRequestInput{ Invoice: "lnbc100u1psnnvhtpp5yq2x3q5hhrzsuxpwx7ptphwzc4k4wk0j3stp0099968m44cyjg9sdqqcqzpgxqzjcsp5hz", Currency: currency.EMPTYCODE, }) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.LightningWithdrawal(contextGenerate(), &LightningWithdrawalRequestInput{Invoice: "", Currency: currency.BTC}) require.ErrorIs(t, err, errInvoiceTextMissing) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.LightningWithdrawal(contextGenerate(), &LightningWithdrawalRequestInput{ Currency: currency.BTC, Invoice: "lnbc100u1psnnvhtpp5yq2x3q5hhrzsuxpwx7ptphwzc4k4wk0j3stp0099968m44cyjg9sdqqcqzpgxqzjcsp5hz", }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelWithdrawal(t *testing.T) { t.Parallel() _, err := e.CancelWithdrawal(contextGenerate(), "") require.ErrorIs(t, err, errMissingValidWithdrawalID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelWithdrawal(contextGenerate(), "fjasdfkjasdk") require.NoError(t, err) assert.NotNil(t, result) } func TestGetWithdrawalHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetWithdrawalHistory(contextGenerate(), currency.BTC, "", "", "", "", time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestSmallAssetsConvert(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SmallAssetsConvert(contextGenerate(), []string{"BTC", "USDT"}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSavingBalance(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSavingBalance(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestSavingsPurchase(t *testing.T) { t.Parallel() _, err := e.SavingsPurchaseOrRedemption(contextGenerate(), &SavingsPurchaseRedemptionInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &SavingsPurchaseRedemptionInput{Rate: 1} _, err = e.SavingsPurchaseOrRedemption(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.Currency = currency.BTC _, err = e.SavingsPurchaseOrRedemption(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Amount = 123.4 _, err = e.SavingsPurchaseOrRedemption(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Rate = 0.001 arg.ActionType = "purchase" _, err = e.SavingsPurchaseOrRedemption(contextGenerate(), arg) require.ErrorIs(t, err, errRateRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SavingsPurchaseOrRedemption(contextGenerate(), &SavingsPurchaseRedemptionInput{ Amount: 123.4, Currency: currency.BTC, Rate: 1, ActionType: "purchase", }) require.NoError(t, err) require.NotNil(t, result) result, err = e.SavingsPurchaseOrRedemption(contextGenerate(), &SavingsPurchaseRedemptionInput{ Amount: 123.4, Currency: currency.BTC, Rate: 1, ActionType: "redempt", }) require.NoError(t, err) assert.NotNil(t, result) } func TestSetLendingRate(t *testing.T) { t.Parallel() _, err := e.SetLendingRate(contextGenerate(), &LendingRate{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetLendingRate(contextGenerate(), &LendingRate{Currency: currency.EMPTYCODE, Rate: 2}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.SetLendingRate(contextGenerate(), &LendingRate{Currency: currency.BTC}) require.ErrorIs(t, err, errRateRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetLendingRate(contextGenerate(), &LendingRate{Currency: currency.BTC, Rate: 2}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLendingHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLendingHistory(contextGenerate(), currency.USDT, time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicBorrowInfo(t *testing.T) { t.Parallel() result, err := e.GetPublicBorrowInfo(contextGenerate(), currency.EMPTYCODE) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.GetPublicBorrowInfo(contextGenerate(), currency.USDT) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicBorrowHistory(t *testing.T) { t.Parallel() result, err := e.GetPublicBorrowHistory(contextGenerate(), currency.USDT, time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMonthlyStatement(t *testing.T) { t.Parallel() _, err := e.GetMonthlyStatement(contextGenerate(), "") require.ErrorIs(t, err, errMonthNameRequired) _, err = e.GetMonthlyStatement(contextGenerate(), "") require.ErrorIs(t, err, errMonthNameRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMonthlyStatement(contextGenerate(), "Jan") require.NoError(t, err) assert.NotNil(t, result) } func TestApplyForMonthlyStatement(t *testing.T) { t.Parallel() _, err := e.ApplyForMonthlyStatement(contextGenerate(), "") require.ErrorIs(t, err, errMonthNameRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ApplyForMonthlyStatement(contextGenerate(), "Jan") require.NoError(t, err) assert.NotNil(t, result) } func TestGetConvertCurrencies(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetConvertCurrencies(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetConvertCurrencyPair(t *testing.T) { t.Parallel() _, err := e.GetConvertCurrencyPair(contextGenerate(), currency.EMPTYCODE, currency.BTC) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.GetConvertCurrencyPair(contextGenerate(), currency.USDT, currency.EMPTYCODE) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetConvertCurrencyPair(contextGenerate(), currency.USDT, currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestEstimateQuote(t *testing.T) { t.Parallel() _, err := e.EstimateQuote(contextGenerate(), &EstimateQuoteRequestInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &EstimateQuoteRequestInput{Tag: "abcd"} _, err = e.EstimateQuote(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.BaseCurrency = currency.BTC _, err = e.EstimateQuote(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.QuoteCurrency = currency.BTC _, err = e.EstimateQuote(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Sell.Lower() _, err = e.EstimateQuote(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.RFQAmount = 30 _, err = e.EstimateQuote(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.EstimateQuote(contextGenerate(), &EstimateQuoteRequestInput{ BaseCurrency: currency.BTC, QuoteCurrency: currency.USDT, Side: order.Sell.Lower(), RFQAmount: 30, RFQSzCurrency: "USDT", }) require.NoError(t, err) assert.NotNil(t, result) } func TestConvertTrade(t *testing.T) { t.Parallel() _, err := e.ConvertTrade(contextGenerate(), &ConvertTradeInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &ConvertTradeInput{Tag: "123"} _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.BaseCurrency = "BTC" _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.QuoteCurrency = "USDT" _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = order.Buy.Lower() _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Size = 2 _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.SizeCurrency = currency.USDT _, err = e.ConvertTrade(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ConvertTrade(contextGenerate(), &ConvertTradeInput{ BaseCurrency: "BTC", QuoteCurrency: "USDT", Side: order.Buy.Lower(), Size: 2, SizeCurrency: currency.USDT, QuoteID: "16461885104612381", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetConvertHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetConvertHistory(contextGenerate(), time.Time{}, time.Time{}, 1, "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetNonZeroAccountBalance(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.AccountBalance(contextGenerate(), currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPositions(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetPositions(contextGenerate(), "", "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetPositionsHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetPositionsHistory(contextGenerate(), "", "", "", "1234213123", 0, 1, time.Time{}, time.Time{}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountAndPositionRisk(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountAndPositionRisk(contextGenerate(), "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetBillsDetail(t *testing.T) { t.Parallel() _, err := e.GetBillsDetailLast7Days(contextGenerate(), &BillsDetailQueryParameter{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBillsDetailLast7Days(contextGenerate(), &BillsDetailQueryParameter{ Limit: 3, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBillsDetail3Months(t *testing.T) { t.Parallel() _, err := e.GetBillsDetail3Months(contextGenerate(), &BillsDetailQueryParameter{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBillsDetail3Months(contextGenerate(), &BillsDetailQueryParameter{Limit: 3}) require.NoError(t, err) assert.NotNil(t, result) } func TestApplyBillDetails(t *testing.T) { t.Parallel() _, err := e.ApplyBillDetails(contextGenerate(), "", "Q2") require.ErrorIs(t, err, errYearRequired) _, err = e.ApplyBillDetails(contextGenerate(), "2023", "") require.ErrorIs(t, err, errQuarterValueRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.ApplyBillDetails(contextGenerate(), "2023", "Q2") require.NoError(t, err) assert.NotNil(t, result) } func TestGetBillsHistoryArchive(t *testing.T) { t.Parallel() _, err := e.GetBillsHistoryArchive(contextGenerate(), "", "Q2") require.ErrorIs(t, err, errYearRequired) _, err = e.GetBillsHistoryArchive(contextGenerate(), "2023", "") require.ErrorIs(t, err, errQuarterValueRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBillsHistoryArchive(contextGenerate(), "2023", "Q2") require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountConfiguration(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountConfiguration(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestSetPositionMode(t *testing.T) { t.Parallel() _, err := e.SetPositionMode(contextGenerate(), "") require.ErrorIs(t, err, errInvalidPositionMode) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.SetPositionMode(contextGenerate(), "net_mode") require.NoError(t, err) assert.NotNil(t, result) } func TestSetLeverageRate(t *testing.T) { t.Parallel() _, err := e.SetLeverageRate(contextGenerate(), &SetLeverageInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetLeverageRate(contextGenerate(), &SetLeverageInput{Leverage: 5, MarginMode: "isolated", AssetType: asset.PerpetualSwap}) require.ErrorIs(t, err, errEitherInstIDOrCcyIsRequired) _, err = e.SetLeverageRate(contextGenerate(), &SetLeverageInput{ Currency: currency.USDT, Leverage: 5, MarginMode: "isolated", InstrumentID: perpetualSwapPair.String(), AssetType: asset.PerpetualSwap, }) require.ErrorIs(t, err, order.ErrSideIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) _, err = e.SetLeverageRate(contextGenerate(), &SetLeverageInput{ Currency: currency.USDT, Leverage: 5, MarginMode: "cross", InstrumentID: perpetualSwapPair.String(), }) assert.Truef(t, err == nil || errors.Is(err, common.ErrNoResponse), "SetLeverageRate should not error: %s", err) } func TestGetMaximumBuySellAmountOROpenAmount(t *testing.T) { t.Parallel() _, err := e.GetMaximumBuySellAmountOROpenAmount(contextGenerate(), currency.BTC, "", "cross", "", 5, true) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetMaximumBuySellAmountOROpenAmount(contextGenerate(), currency.BTC, mainPair.String(), "", "", 5, true) require.ErrorIs(t, err, errInvalidTradeModeValue) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMaximumBuySellAmountOROpenAmount(contextGenerate(), currency.BTC, mainPair.String(), "cross", "", 5, true) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMaximumAvailableTradableAmount(t *testing.T) { t.Parallel() _, err := e.GetMaximumAvailableTradableAmount(contextGenerate(), currency.BTC, "", "cross", "", true, false, 123) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetMaximumAvailableTradableAmount(contextGenerate(), currency.BTC, mainPair.String(), "", "", true, false, 123) require.ErrorIs(t, err, errInvalidTradeModeValue) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMaximumAvailableTradableAmount(contextGenerate(), currency.BTC, mainPair.String(), "cross", "", true, false, 123) require.NoError(t, err) assert.NotNil(t, result) } func TestIncreaseDecreaseMargin(t *testing.T) { t.Parallel() _, err := e.IncreaseDecreaseMargin(contextGenerate(), &IncreaseDecreaseMarginInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &IncreaseDecreaseMarginInput{Currency: "USD"} _, err = e.IncreaseDecreaseMargin(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.IncreaseDecreaseMargin(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.PositionSide = "long" _, err = e.IncreaseDecreaseMargin(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.MarginBalanceType = "reduce" _, err = e.IncreaseDecreaseMargin(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.IncreaseDecreaseMargin(contextGenerate(), &IncreaseDecreaseMarginInput{ InstrumentID: mainPair.String(), PositionSide: "long", MarginBalanceType: "add", Amount: 1000, Currency: "USD", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeverageRate(t *testing.T) { t.Parallel() _, err := e.GetLeverageRate(contextGenerate(), "", "cross", currency.EMPTYCODE) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetLeverageRate(contextGenerate(), mainPair.String(), "", currency.EMPTYCODE) require.ErrorIs(t, err, margin.ErrMarginTypeUnsupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLeverageRate(contextGenerate(), mainPair.String(), "cross", currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMaximumLoanOfInstrument(t *testing.T) { t.Parallel() _, err := e.GetMaximumLoanOfInstrument(contextGenerate(), "", "isolated", currency.ZRX) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetMaximumLoanOfInstrument(contextGenerate(), "ZRX-BTC", "", currency.ZRX) require.ErrorIs(t, err, margin.ErrInvalidMarginType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMaximumLoanOfInstrument(contextGenerate(), mainPair.String(), "isolated", currency.ZRX) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTradeFee(t *testing.T) { t.Parallel() _, err := e.GetTradeFee(contextGenerate(), "", "", "", "", "") require.ErrorIs(t, err, errInvalidInstrumentType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetTradeFee(contextGenerate(), instTypeSpot, "", "", "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetInterestAccruedData(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetInterestAccruedData(contextGenerate(), 0, 1, currency.EMPTYCODE, "", "", time.Time{}, time.Time{}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetInterestRate(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetInterestRate(contextGenerate(), currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestSetGreeks(t *testing.T) { t.Parallel() _, err := e.SetGreeks(contextGenerate(), "") require.ErrorIs(t, err, errMissingValidGreeksType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetGreeks(contextGenerate(), "PA") require.NoError(t, err) assert.NotNil(t, result) } func TestIsolatedMarginTradingSettings(t *testing.T) { t.Parallel() _, err := e.IsolatedMarginTradingSettings(contextGenerate(), &IsolatedMode{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.IsolatedMarginTradingSettings(contextGenerate(), &IsolatedMode{IsoMode: "", InstrumentType: "MARGIN"}) require.ErrorIs(t, err, errMissingIsolatedMarginTradingSetting) _, err = e.IsolatedMarginTradingSettings(contextGenerate(), &IsolatedMode{IsoMode: "autonomy", InstrumentType: ""}) require.ErrorIs(t, err, errInvalidInstrumentType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.IsolatedMarginTradingSettings(contextGenerate(), &IsolatedMode{IsoMode: "autonomy", InstrumentType: "MARGIN"}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMaximumWithdrawals(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMaximumWithdrawals(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountRiskState(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountRiskState(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestVIPLoansBorrowAndRepay(t *testing.T) { t.Parallel() _, err := e.VIPLoansBorrowAndRepay(contextGenerate(), &LoanBorrowAndReplayInput{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.VIPLoansBorrowAndRepay(contextGenerate(), &LoanBorrowAndReplayInput{Currency: currency.EMPTYCODE, Side: "borrow", Amount: 12}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.VIPLoansBorrowAndRepay(contextGenerate(), &LoanBorrowAndReplayInput{Currency: currency.BTC, Side: "", Amount: 12}) require.ErrorIs(t, err, order.ErrSideIsInvalid) _, err = e.VIPLoansBorrowAndRepay(contextGenerate(), &LoanBorrowAndReplayInput{Currency: currency.BTC, Side: "borrow", Amount: 0}) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.VIPLoansBorrowAndRepay(contextGenerate(), &LoanBorrowAndReplayInput{Currency: currency.BTC, Side: "borrow", Amount: 12}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBorrowAndRepayHistoryForVIPLoans(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBorrowAndRepayHistoryForVIPLoans(contextGenerate(), currency.EMPTYCODE, time.Time{}, time.Time{}, 3) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBorrowInterestAndLimit(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBorrowInterestAndLimit(contextGenerate(), 1, currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFixedLoanBorrowLimit(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFixedLoanBorrowLimit(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFixedLoanBorrowQuote(t *testing.T) { t.Parallel() _, err := e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "", "30D", "123423423", 1, .4) require.ErrorIs(t, err, errBorrowTypeRequired) _, err = e.GetFixedLoanBorrowQuote(contextGenerate(), currency.EMPTYCODE, "normal", "30D", "123423423", 1, .4) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "normal", "30D", "", 0, .4) require.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "normal", "30D", "123423423", 1, 0) require.ErrorIs(t, err, errMaxRateRequired) _, err = e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "normal", "", "123423423", 1, .4) require.ErrorIs(t, err, errLendingTermIsRequired) _, err = e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "reborrow", "30D", "", 1, .4) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFixedLoanBorrowQuote(contextGenerate(), currency.USDT, "normal", "30D", "123423423", 1, .4) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceFixedLoanBorrowingOrder(t *testing.T) { t.Parallel() _, err := e.PlaceFixedLoanBorrowingOrder(contextGenerate(), currency.EMPTYCODE, 1, .3, .2, "30D", false) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.PlaceFixedLoanBorrowingOrder(contextGenerate(), currency.USDT, 0, .3, .2, "30D", false) require.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.PlaceFixedLoanBorrowingOrder(contextGenerate(), currency.USDT, 1, 0, .2, "30D", false) require.ErrorIs(t, err, errMaxRateRequired) _, err = e.PlaceFixedLoanBorrowingOrder(contextGenerate(), currency.USDT, 1, .3, .2, "", false) require.ErrorIs(t, err, errLendingTermIsRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceFixedLoanBorrowingOrder(contextGenerate(), currency.USDT, 1, .3, .2, "30D", false) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendFixedLoanBorrowingOrder(t *testing.T) { t.Parallel() _, err := e.AmendFixedLoanBorrowingOrder(contextGenerate(), "", false, .4) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendFixedLoanBorrowingOrder(contextGenerate(), "12312312", false, .4) require.NoError(t, err) assert.NotNil(t, result) } func TestManualRenewFixedLoanBorrowingOrder(t *testing.T) { t.Parallel() _, err := e.ManualRenewFixedLoanBorrowingOrder(contextGenerate(), "", .3) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.ManualRenewFixedLoanBorrowingOrder(contextGenerate(), "12312312", 0) require.ErrorIs(t, err, errMaxRateRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ManualRenewFixedLoanBorrowingOrder(contextGenerate(), "12312312", .3) require.NoError(t, err) assert.NotNil(t, result) } func TestRepayFixedLoanBorrowingOrder(t *testing.T) { t.Parallel() _, err := e.RepayFixedLoanBorrowingOrder(contextGenerate(), "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.RepayFixedLoanBorrowingOrder(contextGenerate(), "12321") require.NoError(t, err) assert.NotNil(t, result) } func TestConvertFixedLoanToMarketLoan(t *testing.T) { t.Parallel() _, err := e.ConvertFixedLoanToMarketLoan(contextGenerate(), "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ConvertFixedLoanToMarketLoan(contextGenerate(), "12321") require.NoError(t, err) assert.NotNil(t, result) } func TestReduceLiabilitiesForFixedLoan(t *testing.T) { t.Parallel() _, err := e.ReduceLiabilitiesForFixedLoan(contextGenerate(), "", false) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ReduceLiabilitiesForFixedLoan(contextGenerate(), "123123", false) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFixedLoanBorrowOrderList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFixedLoanBorrowOrderList(contextGenerate(), currency.USDT, "1231231", "8", "30D", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestManualBorrowOrRepay(t *testing.T) { t.Parallel() _, err := e.ManualBorrowOrRepay(contextGenerate(), currency.EMPTYCODE, "borrow", 1) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.ManualBorrowOrRepay(contextGenerate(), currency.USDT, "", 1) require.ErrorIs(t, err, errLendingSideRequired) _, err = e.ManualBorrowOrRepay(contextGenerate(), currency.USDT, "borrow", 0) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ManualBorrowOrRepay(contextGenerate(), currency.USDT, "borrow", 1) require.NoError(t, err) assert.NotNil(t, result) } func TestSetAutoRepay(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetAutoRepay(contextGenerate(), true) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBorrowRepayHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBorrowRepayHistory(contextGenerate(), currency.ETH, "auto_borrow", time.Time{}, time.Time{}, 100) require.NoError(t, err) assert.NotNil(t, result) } func TestNewPositionBuilder(t *testing.T) { t.Parallel() _, err := e.NewPositionBuilder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.NewPositionBuilder(contextGenerate(), &PositionBuilderParam{ InclRealPosAndEq: false, SimPos: []SimulatedPosition{ { Position: "-10", InstrumentID: "BTC-USDT-SWAP", }, { Position: "10", InstrumentID: "LTC-USDT-SWAP", }, }, SimAsset: []SimulatedAsset{ { Currency: "USDT", Amount: 100, }, }, SpotOffsetType: "1", GreeksType: "CASH", }) require.NoError(t, err) assert.NotNil(t, result) } func TestSetRiskOffsetAmount(t *testing.T) { t.Parallel() _, err := e.SetRiskOffsetAmount(contextGenerate(), currency.EMPTYCODE, 123) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.SetRiskOffsetAmount(contextGenerate(), currency.USDT, 0) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.SetRiskOffsetAmount(contextGenerate(), currency.USDT, 123) require.NoError(t, err) assert.NotNil(t, result) } func TestGetGreeks(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) _, err := e.GetGreeks(contextGenerate(), currency.EMPTYCODE) assert.NoError(t, err) } func TestGetPMLimitation(t *testing.T) { t.Parallel() _, err := e.GetPMPositionLimitation(contextGenerate(), "", mainPair.String(), "") require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetPMPositionLimitation(contextGenerate(), "SWAP", "", "") require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetPMPositionLimitation(contextGenerate(), "SWAP", mainPair.String(), "") require.NoError(t, err) assert.NotNil(t, result) } func TestViewSubaccountList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.ViewSubAccountList(contextGenerate(), false, "", time.Time{}, time.Time{}, 2) require.NoError(t, err) assert.NotNil(t, result) } func TestResetSubAccountAPIKey(t *testing.T) { t.Parallel() _, err := e.ResetSubAccountAPIKey(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) _, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{APIKey: apiKey, APIKeyPermission: "trade"}) require.ErrorIs(t, err, errInvalidSubAccountName) _, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{SubAccountName: "sam", APIKey: "", APIKeyPermission: "trade"}) require.ErrorIs(t, err, errInvalidAPIKey) _, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{IP: "1.2.3.", SubAccountName: "sam", APIKeyPermission: "trade", APIKey: "sample-api-key"}) require.ErrorIs(t, err, errInvalidIPAddress) _, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{APIKeyPermission: "abc", APIKey: "sample-api-key", SubAccountName: "sam"}) require.ErrorIs(t, err, errInvalidAPIKeyPermission) _, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{ Permissions: []string{"abc"}, SubAccountName: "sam", APIKey: "sample-api-key", }) require.ErrorIs(t, err, errInvalidAPIKeyPermission) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{ SubAccountName: "sam", APIKey: apiKey, APIKeyPermission: "trade", }) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.ResetSubAccountAPIKey(contextGenerate(), &SubAccountAPIKeyParam{ SubAccountName: "sam", APIKey: apiKey, Permissions: []string{"trade", "read"}, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSubaccountTradingBalance(t *testing.T) { t.Parallel() _, err := e.GetSubaccountTradingBalance(contextGenerate(), "") assert.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSubaccountTradingBalance(contextGenerate(), "test1") require.NoError(t, err) assert.NotNil(t, result) } func TestGetSubaccountFundingBalance(t *testing.T) { t.Parallel() _, err := e.GetSubaccountFundingBalance(contextGenerate(), "", currency.EMPTYCODE) require.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSubaccountFundingBalance(contextGenerate(), "test1", currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSubAccountMaximumWithdrawal(t *testing.T) { t.Parallel() _, err := e.GetSubAccountMaximumWithdrawal(contextGenerate(), "", currency.BTC) require.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSubAccountMaximumWithdrawal(contextGenerate(), "test1", currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestHistoryOfSubaccountTransfer(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.HistoryOfSubaccountTransfer(contextGenerate(), currency.EMPTYCODE, "0", "", time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetHistoryOfManagedSubAccountTransfer(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetHistoryOfManagedSubAccountTransfer(contextGenerate(), currency.BTC, "", "", "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestMasterAccountsManageTransfersBetweenSubaccounts(t *testing.T) { t.Parallel() _, err := e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), &SubAccountAssetTransferParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &SubAccountAssetTransferParams{LoanTransfer: true} _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.Currency = currency.BTC _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Amount = 1234 _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidSubaccount) arg.From = 1 _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidSubaccount) arg.To = 7 _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidSubaccount) arg.To = 6 _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidSubAccountName) arg.FromSubAccount = "sami" _, err = e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.MasterAccountsManageTransfersBetweenSubaccounts(contextGenerate(), &SubAccountAssetTransferParams{Currency: currency.BTC, Amount: 1200, From: 6, To: 6, FromSubAccount: "test1", ToSubAccount: "test2", LoanTransfer: true}) require.NoError(t, err) assert.NotNil(t, result) } func TestSetPermissionOfTransferOut(t *testing.T) { t.Parallel() _, err := e.SetPermissionOfTransferOut(contextGenerate(), &PermissionOfTransfer{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetPermissionOfTransferOut(contextGenerate(), &PermissionOfTransfer{CanTransOut: true}) require.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.SetPermissionOfTransferOut(contextGenerate(), &PermissionOfTransfer{SubAcct: "Test1"}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCustodyTradingSubaccountList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCustodyTradingSubaccountList(contextGenerate(), "") require.NoError(t, err) assert.NotNil(t, result) } func TestSetSubAccountVIPLoanAllocation(t *testing.T) { t.Parallel() _, err := e.SetSubAccountVIPLoanAllocation(contextGenerate(), &SubAccountLoanAllocationParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := subAccountVIPLoanAllocationInfo{} _, err = e.SetSubAccountVIPLoanAllocation(contextGenerate(), &SubAccountLoanAllocationParam{Alloc: []subAccountVIPLoanAllocationInfo{arg}}) require.ErrorIs(t, err, common.ErrEmptyParams) arg.LoanAlloc = 123 _, err = e.SetSubAccountVIPLoanAllocation(contextGenerate(), &SubAccountLoanAllocationParam{Alloc: []subAccountVIPLoanAllocationInfo{arg}}) require.ErrorIs(t, err, errInvalidSubAccountName) arg.LoanAlloc = -1 arg.SubAcct = "sams" _, err = e.SetSubAccountVIPLoanAllocation(contextGenerate(), &SubAccountLoanAllocationParam{Alloc: []subAccountVIPLoanAllocationInfo{arg}}) require.ErrorIs(t, err, errInvalidLoanAllocationValue) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetSubAccountVIPLoanAllocation(contextGenerate(), &SubAccountLoanAllocationParam{ Enable: true, Alloc: []subAccountVIPLoanAllocationInfo{ { SubAcct: "subAcct1", LoanAlloc: 20.01, }, }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSubAccountBorrowInterestAndLimit(t *testing.T) { t.Parallel() _, err := e.GetSubAccountBorrowInterestAndLimit(contextGenerate(), "", currency.ETH) require.ErrorIs(t, err, errInvalidSubAccountName) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSubAccountBorrowInterestAndLimit(contextGenerate(), "123456", currency.ETH) require.NoError(t, err) assert.NotNil(t, result) } // ETH Staking func TestGetProductInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetProductInfo(contextGenerate()) require.NoError(t, err) assert.NotEmpty(t, result) } func TestPurcahseETHStaking(t *testing.T) { t.Parallel() err := e.PurchaseETHStaking(contextGenerate(), 0) assert.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) err = e.PurchaseETHStaking(contextGenerate(), 100) assert.NoError(t, err) } // RedeemETHStaking func TestRedeemETHStaking(t *testing.T) { t.Parallel() err := e.RedeemETHStaking(contextGenerate(), 0) assert.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) err = e.RedeemETHStaking(contextGenerate(), 100) assert.NoError(t, err) } func TestGetBETHAssetsBalance(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBETHAssetsBalance(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPurchaseAndRedeemHistory(t *testing.T) { t.Parallel() _, err := e.GetPurchaseAndRedeemHistory(contextGenerate(), "", "pending", time.Time{}, time.Now(), 10) require.ErrorIs(t, err, errLendingTermIsRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetPurchaseAndRedeemHistory(contextGenerate(), "purchase", "pending", time.Time{}, time.Now(), 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAPYHistory(t *testing.T) { t.Parallel() result, err := e.GetAPYHistory(contextGenerate(), 34) require.NoError(t, err) assert.NotNil(t, result) } const gridTradingPlaceOrder = `{"instId": "BTC-USD-SWAP","algoOrdType": "contract_grid","maxPx": "5000","minPx": "400","gridNum": "10","runType": "1","sz": "200", "direction": "long","lever": "2"}` func TestPlaceGridAlgoOrder(t *testing.T) { t.Parallel() var input GridAlgoOrder err := json.Unmarshal([]byte(gridTradingPlaceOrder), &input) require.NoError(t, err) _, err = e.PlaceGridAlgoOrder(contextGenerate(), &GridAlgoOrder{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &GridAlgoOrder{BasePosition: true} _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingAlgoOrderType) arg.AlgoOrdType = "contract_grid" _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.MaxPrice = 1000 _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.MinPrice = 1200 arg.GridQuantity = -1 _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidGridQuantity) arg.GridQuantity = 123 _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrAmountMustBeSet) arg.Size = 123 _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingRequiredArgumentDirection) arg.Direction = positionSideLong _, err = e.PlaceGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidLeverage) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceGridAlgoOrder(contextGenerate(), &input) require.NoError(t, err) assert.NotNil(t, result) } const gridOrderAmendAlgo = `{ "algoId":"448965992920907776", "instId":"BTC-USDT", "slTriggerPx":"1200", "tpTriggerPx":"" }` func TestAmendGridAlgoOrder(t *testing.T) { t.Parallel() var input *GridAlgoOrderAmend err := json.Unmarshal([]byte(gridOrderAmendAlgo), &input) require.NoError(t, err) arg := &GridAlgoOrderAmend{} _, err = e.AmendGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, common.ErrEmptyParams) arg.TakeProfitTriggerPrice = 1234.5 _, err = e.AmendGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errAlgoIDRequired) arg.AlgoID = "560472804207104000" _, err = e.AmendGridAlgoOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendGridAlgoOrder(contextGenerate(), input) require.NoError(t, err) assert.NotNil(t, result) } const stopGridAlgoOrderJSON = `{"algoId":"198273485", "instId":"BTC-USDT", "stopType":"1", "algoOrdType":"grid"}` func TestStopGridAlgoOrder(t *testing.T) { t.Parallel() var resp StopGridAlgoOrderRequest err := json.Unmarshal([]byte(stopGridAlgoOrderJSON), &resp) require.NoError(t, err) _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := StopGridAlgoOrderRequest{} _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{arg}) require.ErrorIs(t, err, common.ErrEmptyParams) arg.StopType = 20 _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{arg}) require.ErrorIs(t, err, errAlgoIDRequired) arg.AlgoID = "algo_id" _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{arg}) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{arg}) require.ErrorIs(t, err, errMissingAlgoOrderType) arg.AlgoOrderType = AlgoOrdTypeGrid _, err = e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{arg}) require.ErrorIs(t, err, errMissingValidStopType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.StopGridAlgoOrder(contextGenerate(), []StopGridAlgoOrderRequest{resp}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetGridAlgoOrdersList(t *testing.T) { t.Parallel() _, err := e.GetGridAlgoOrdersList(contextGenerate(), "abc", "", "", "", "", "", 1) require.ErrorIs(t, err, errMissingAlgoOrderType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetGridAlgoOrdersList(contextGenerate(), "grid", "", "", "", "", "", 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetGridAlgoOrderHistory(t *testing.T) { t.Parallel() _, err := e.GetGridAlgoOrderHistory(contextGenerate(), "abc", "", "", "", "", "", 1) require.ErrorIs(t, err, errMissingAlgoOrderType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetGridAlgoOrderHistory(contextGenerate(), "contract_grid", "", "", "", "", "", 1) require.NoError(t, err) assert.NotNil(t, result) } func TestGetGridAlgoOrderDetails(t *testing.T) { t.Parallel() _, err := e.GetGridAlgoOrderDetails(contextGenerate(), "grid", "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetGridAlgoOrderDetails(contextGenerate(), "grid", "7878") require.NoError(t, err) assert.NotNil(t, result) } func TestGetGridAlgoSubOrders(t *testing.T) { t.Parallel() _, err := e.GetGridAlgoSubOrders(contextGenerate(), "", "", "", "", "", "", 2) require.ErrorIs(t, err, errMissingAlgoOrderType) _, err = e.GetGridAlgoSubOrders(contextGenerate(), "grid", "", "", "", "", "", 2) require.ErrorIs(t, err, errAlgoIDRequired) _, err = e.GetGridAlgoSubOrders(contextGenerate(), "grid", "1234", "", "", "", "", 2) require.ErrorIs(t, err, errMissingSubOrderType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetGridAlgoSubOrders(contextGenerate(), "grid", "1234", "live", "", "", "", 2) require.NoError(t, err) assert.NotNil(t, result) } const spotGridAlgoOrderPosition = `{"adl": "1","algoId": "449327675342323712","avgPx": "29215.0142857142857149","cTime": "1653400065917","ccy": "USDT","imr": "2045.386","instId": "BTC-USDT-SWAP","instType": "SWAP","last": "29206.7","lever": "5","liqPx": "661.1684795867162","markPx": "29213.9","mgnMode": "cross","mgnRatio": "217.19370606167573","mmr": "40.907720000000005","notionalUsd": "10216.70307","pos": "35","posSide": "net","uTime": "1653400066938","upl": "1.674999999999818","uplRatio": "0.0008190504784478"}` func TestGetGridAlgoOrderPositions(t *testing.T) { t.Parallel() var resp AlgoOrderPosition err := json.Unmarshal([]byte(spotGridAlgoOrderPosition), &resp) require.NoError(t, err) _, err = e.GetGridAlgoOrderPositions(contextGenerate(), "", "") require.ErrorIs(t, err, errInvalidAlgoOrderType) _, err = e.GetGridAlgoOrderPositions(contextGenerate(), "contract_grid", "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetGridAlgoOrderPositions(contextGenerate(), "contract_grid", "448965992920907776") require.NoError(t, err) assert.NotNil(t, result) } func TestSpotGridWithdrawProfit(t *testing.T) { t.Parallel() _, err := e.SpotGridWithdrawProfit(contextGenerate(), "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SpotGridWithdrawProfit(contextGenerate(), "1234") require.NoError(t, err) assert.NotNil(t, result) } func TestComputeMarginBalance(t *testing.T) { t.Parallel() _, err := e.ComputeMarginBalance(contextGenerate(), MarginBalanceParam{AlgoID: "123456", AdjustMarginBalanceType: "other"}) require.ErrorIs(t, err, errInvalidMarginTypeAdjust) _, err = e.ComputeMarginBalance(contextGenerate(), MarginBalanceParam{AdjustMarginBalanceType: "other"}) require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.ComputeMarginBalance(contextGenerate(), MarginBalanceParam{ AlgoID: "123456", AdjustMarginBalanceType: "reduce", }) require.NoError(t, err) assert.NotNil(t, result) } func TestAdjustMarginBalance(t *testing.T) { t.Parallel() arg := &MarginBalanceParam{} _, err := e.AdjustMarginBalance(contextGenerate(), arg) require.ErrorIs(t, err, common.ErrEmptyParams) arg.Amount = 12345 _, err = e.AdjustMarginBalance(contextGenerate(), arg) require.ErrorIs(t, err, errAlgoIDRequired) arg.AlgoID = "1234" _, err = e.AdjustMarginBalance(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidMarginTypeAdjust) arg.AdjustMarginBalanceType = "reduce" arg.Amount = 0 _, err = e.AdjustMarginBalance(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrAmountIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AdjustMarginBalance(contextGenerate(), &MarginBalanceParam{ AlgoID: "1234", AdjustMarginBalanceType: "reduce", Amount: 12345, }) require.NoError(t, err) assert.NotNil(t, result) } const gridAIParamJSON = `{"algoOrdType": "grid","annualizedRate": "1.5849","ccy": "USDT","direction": "", "duration": "7D","gridNum": "5","instId": "BTC-USDT","lever": "0","maxPx": "21373.3","minInvestment": "0.89557758", "minPx": "15544.2", "perMaxProfitRate": "0.0733865364573281","perMinProfitRate": "0.0561101403446263","runType": "1"}` func TestGetGridAIParameter(t *testing.T) { t.Parallel() var response GridAIParameterResponse err := json.Unmarshal([]byte(gridAIParamJSON), &response) require.NoError(t, err) _, err = e.GetGridAIParameter(contextGenerate(), "", mainPair.String(), "", "") require.ErrorIs(t, err, errInvalidAlgoOrderType) _, err = e.GetGridAIParameter(contextGenerate(), "grid", "", "", "") require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.GetGridAIParameter(contextGenerate(), "contract_grid", mainPair.String(), "", "") require.ErrorIs(t, err, errMissingRequiredArgumentDirection) _, err = e.GetGridAIParameter(contextGenerate(), "grid", mainPair.String(), "", "12M") require.ErrorIs(t, err, errInvalidDuration) result, err := e.GetGridAIParameter(contextGenerate(), "grid", mainPair.String(), "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetOffers(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOffers(contextGenerate(), "", "", currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestPurchase(t *testing.T) { t.Parallel() _, err := e.Purchase(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) _, err = e.Purchase(contextGenerate(), &PurchaseRequestParam{Term: 2}) require.ErrorIs(t, err, errMissingRequiredParameter) _, err = e.Purchase(contextGenerate(), &PurchaseRequestParam{ProductID: "1234", Term: 2, InvestData: []PurchaseInvestDataItem{{Amount: 1}}}) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.Purchase(contextGenerate(), &PurchaseRequestParam{ProductID: "1234", Term: 2, InvestData: []PurchaseInvestDataItem{{Currency: currency.USDT}}}) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.Purchase(contextGenerate(), &PurchaseRequestParam{ ProductID: "1234", InvestData: []PurchaseInvestDataItem{ { Currency: currency.BTC, Amount: 100, }, { Currency: currency.ETH, Amount: 100, }, }, Term: 30, }) require.NoError(t, err) assert.NotNil(t, result) } func TestRedeem(t *testing.T) { t.Parallel() _, err := e.Redeem(contextGenerate(), &RedeemRequestParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.Redeem(contextGenerate(), &RedeemRequestParam{AllowEarlyRedeem: true}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.Redeem(contextGenerate(), &RedeemRequestParam{OrderID: "754147"}) require.ErrorIs(t, err, errInvalidProtocolType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.Redeem(contextGenerate(), &RedeemRequestParam{ OrderID: "754147", ProtocolType: "defi", AllowEarlyRedeem: true, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelPurchaseOrRedemption(t *testing.T) { t.Parallel() _, err := e.CancelPurchaseOrRedemption(contextGenerate(), &CancelFundingParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CancelPurchaseOrRedemption(contextGenerate(), &CancelFundingParam{ProtocolType: "defi"}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.CancelPurchaseOrRedemption(contextGenerate(), &CancelFundingParam{OrderID: "754147"}) require.ErrorIs(t, err, errInvalidProtocolType) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelPurchaseOrRedemption(contextGenerate(), &CancelFundingParam{ OrderID: "754147", ProtocolType: "defi", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetEarnActiveOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetEarnActiveOrders(contextGenerate(), "", "", "", currency.EMPTYCODE) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFundingOrderHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFundingOrderHistory(contextGenerate(), "", "", currency.EMPTYCODE, time.Time{}, time.Time{}, 1) require.NoError(t, err) assert.NotNil(t, result) } func TestSystemStatusResponse(t *testing.T) { t.Parallel() result, err := e.SystemStatusResponse(contextGenerate(), "completed") require.NoError(t, err) assert.NotNil(t, result) } var instrumentTypeToAssetTypeMap = map[string]struct { AssetType asset.Item Error error }{ instTypeSwap: {AssetType: asset.PerpetualSwap}, instTypeContract: {AssetType: asset.PerpetualSwap}, instTypeSpot: {AssetType: asset.Spot}, instTypeMargin: {AssetType: asset.Margin}, instTypeFutures: {AssetType: asset.Futures}, instTypeOption: {AssetType: asset.Options}, "": {AssetType: asset.Empty}, "lol": {AssetType: asset.Empty, Error: asset.ErrNotSupported}, } func TestAssetTypeFromInstrumentType(t *testing.T) { t.Parallel() for k, v := range instrumentTypeToAssetTypeMap { assetItem, err := assetTypeFromInstrumentType(k) require.ErrorIs(t, err, v.Error) assert.Equal(t, v.AssetType, assetItem) } } /********************************** Wrapper Functions **************************************/ func TestFetchTradablePairs(t *testing.T) { t.Parallel() for _, a := range []asset.Item{asset.Options, asset.PerpetualSwap, asset.Futures, asset.Spot, asset.Spread} { result, err := e.FetchTradablePairs(contextGenerate(), a) assert.NoError(t, err) assert.NotNil(t, result) } } func TestUpdateTradablePairs(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) } func TestUpdateOrderExecutionLimits(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { t.Run(a.String(), func(t *testing.T) { t.Parallel() require.NoError(t, e.UpdateOrderExecutionLimits(t.Context(), a), "UpdateOrderExecutionLimits must not error") pairs, err := e.CurrencyPairs.GetPairs(a, true) require.NoError(t, err, "GetPairs must not error") l, err := e.GetOrderExecutionLimits(a, pairs[0]) require.NoError(t, err, "GetOrderExecutionLimits must not error") assert.Positive(t, l.PriceStepIncrementSize, "PriceStepIncrementSize should be positive") assert.Positive(t, l.MinimumBaseAmount, "MinimumBaseAmount should be positive") }) } } func TestUpdateTicker(t *testing.T) { t.Parallel() _, err := e.UpdateTicker(contextGenerate(), currency.Pair{}, asset.Binary) require.ErrorIs(t, err, asset.ErrNotSupported) testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { p, err := e.GetAvailablePairs(a) require.NoErrorf(t, err, "GetAvailablePairs for asset %s must not error", a) require.NotEmptyf(t, p, "GetAvailablePairs for asset %s must not return empty pairs", a) result, err := e.UpdateTicker(contextGenerate(), p[0], a) require.NoErrorf(t, err, "UpdateTicker for asset %s and pair %s must not error", a, p[0]) assert.NotNilf(t, result, "UpdateTicker for asset %s and pair %s should not return nil", a, p[0]) } } func TestUpdateTickers(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { err := e.UpdateTickers(contextGenerate(), a) require.NoErrorf(t, err, "UpdateTickers for asset %s must not error", a) } } func TestUpdateOrderbook(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { p, err := e.GetAvailablePairs(a) require.NoErrorf(t, err, "GetAvailablePairs for asset %s must not error", a) require.NotEmptyf(t, p, "GetAvailablePairs for asset %s must not return empty pairs", a) result, err := e.UpdateOrderbook(contextGenerate(), p[0], a) require.NoErrorf(t, err, "UpdateOrderbook for asset %s and pair %s must not error", a, p[0]) assert.NotNilf(t, result, "UpdateOrderbook for asset %s and pair %s should not return nil", a, p[0]) } } func TestUpdateAccountBalances(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.UpdateAccountBalances(contextGenerate(), asset.Spot) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountFundingHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountFundingHistory(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetWithdrawalsHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetWithdrawalsHistory(contextGenerate(), currency.BTC, asset.Spot) require.NoError(t, err) assert.NotNil(t, result) } func TestGetRecentTrades(t *testing.T) { t.Parallel() result, err := e.GetRecentTrades(contextGenerate(), mainPair, asset.PerpetualSwap) require.NoError(t, err) require.NotNil(t, result) result, err = e.GetRecentTrades(contextGenerate(), mainPair, asset.Spread) require.NoError(t, err) assert.NotNil(t, result) } func TestSubmitOrder(t *testing.T) { t.Parallel() var resp []PlaceOrderRequestParam err := json.Unmarshal([]byte(placeOrderArgs), &resp) require.NoError(t, err) arg := &order.Submit{ Exchange: e.Name, Side: order.Buy, Type: order.Limit, Price: 1, ClientID: "yeneOrder", AssetType: asset.Binary, } _, err = e.SubmitOrder(contextGenerate(), arg) require.ErrorIs(t, err, asset.ErrNotSupported) arg.AssetType = asset.Spot _, err = e.SubmitOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Amount = 1000000000 _, err = e.SubmitOrder(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) arg.Pair = mainPair arg.AssetType = asset.Futures arg.Leverage = -1 _, err = e.SubmitOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSubmitLeverageNotSupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) arg = &order.Submit{ Pair: currency.Pair{ Base: currency.LTC, Quote: currency.BTC, }, Exchange: e.Name, Side: order.Sell, Type: order.Limit, Price: 120000, Amount: 1000000000, ClientID: "yeneOrder", AssetType: asset.Spot, } result, err := e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.Trigger arg.TriggerPrice = 11999 arg.TriggerPriceType = order.LastPrice result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.ConditionalStop arg.TriggerPrice = 11999 arg.TriggerPriceType = order.IndexPrice result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.Chase _, err = e.SubmitOrder(contextGenerate(), arg) assert.ErrorIs(t, err, order.ErrUnknownTrackingMode) arg.TrackingMode = order.Percentage _, err = e.SubmitOrder(contextGenerate(), arg) assert.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.TrackingValue = .5 result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.TWAP result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.TrailingStop result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.OCO _, err = e.SubmitOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.RiskManagementModes = order.RiskManagementModes{ TakeProfit: order.RiskManagement{ Price: 11999, LimitPrice: 12000, }, StopLoss: order.RiskManagement{ Price: 10999, LimitPrice: 11000, }, } result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) cp, err := currency.NewPairFromString("BTC-USDT-230630") require.NoError(t, err) arg = &order.Submit{ Pair: cp, Exchange: e.Name, Side: order.Long, Type: order.Market, Amount: 1, ClientID: "hellomoto", AssetType: asset.Futures, MarginType: margin.Multi, } result, err = e.SubmitOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) pair, err := currency.NewPairFromString("BTC-USDT-SWAP_BTC-USDT-250328") require.NoError(t, err) result, err = e.SubmitOrder(contextGenerate(), &order.Submit{ Pair: pair, Exchange: e.Name, Side: order.Sell, Type: order.Limit, Price: 120000, Amount: 1, ClientID: "hellomoto", AssetType: asset.Spread, MarginType: margin.Multi, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelOrder(t *testing.T) { t.Parallel() arg := &order.Cancel{ AccountID: "1", AssetType: asset.Binary, } err := e.CancelOrder(contextGenerate(), arg) require.ErrorIs(t, err, asset.ErrNotSupported) arg.AssetType = asset.Spot err = e.CancelOrder(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) arg.Pair = mainPair err = e.CancelOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) err = e.CancelOrder(contextGenerate(), &order.Cancel{ OrderID: "1", AccountID: "1", Pair: mainPair, AssetType: asset.Spot, }) assert.NoError(t, err) err = e.CancelOrder(contextGenerate(), &order.Cancel{ Type: order.OCO, OrderID: "1", AccountID: "1", Pair: mainPair, AssetType: asset.Spot, }) assert.NoError(t, err) err = e.CancelOrder(contextGenerate(), &order.Cancel{ OrderID: "1", AccountID: "1", Pair: spreadPair, AssetType: asset.Spread, }) assert.NoError(t, err) } func TestCancelBatchOrders(t *testing.T) { t.Parallel() _, err := e.CancelBatchOrders(contextGenerate(), make([]order.Cancel, 21)) require.ErrorIs(t, err, errExceedLimit) _, err = e.CancelBatchOrders(contextGenerate(), nil) require.ErrorIs(t, err, order.ErrCancelOrderIsNil) arg := order.Cancel{ AccountID: "1", AssetType: asset.Binary, } _, err = e.CancelBatchOrders(contextGenerate(), []order.Cancel{arg}) require.ErrorIs(t, err, asset.ErrNotSupported) arg.AssetType = asset.Spot _, err = e.CancelBatchOrders(contextGenerate(), []order.Cancel{arg}) require.ErrorIs(t, err, currency.ErrCurrencyPairsEmpty) arg.Pair = mainPair arg.Type = order.Liquidation _, err = e.CancelBatchOrders(contextGenerate(), []order.Cancel{arg}) require.ErrorIs(t, err, order.ErrUnsupportedOrderType) arg.Type = order.Trigger _, err = e.CancelBatchOrders(contextGenerate(), []order.Cancel{arg}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) arg.Type = order.Limit _, err = e.CancelBatchOrders(contextGenerate(), []order.Cancel{arg}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) orderCancellationParams := []order.Cancel{ { OrderID: "1", AccountID: "1", Pair: mainPair, AssetType: asset.Spot, }, { OrderID: "1", AccountID: "1", Pair: perpetualSwapPair, AssetType: asset.PerpetualSwap, }, { OrderID: "1", AccountID: "1", Type: order.Trigger, Pair: mainPair, AssetType: asset.Spot, }, } result, err := e.CancelBatchOrders(contextGenerate(), orderCancellationParams) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllOrders(t *testing.T) { t.Parallel() _, err := e.CancelAllOrders(contextGenerate(), &order.Cancel{AssetType: asset.Binary}) require.ErrorIs(t, err, asset.ErrNotSupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllOrders(contextGenerate(), &order.Cancel{AssetType: asset.Spread}) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.CancelAllOrders(contextGenerate(), &order.Cancel{AssetType: asset.Futures}) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.CancelAllOrders(contextGenerate(), &order.Cancel{AssetType: asset.Spot}) assert.NoError(t, err) assert.NotNil(t, result) } func TestModifyOrder(t *testing.T) { t.Parallel() _, err := e.ModifyOrder(contextGenerate(), nil) require.ErrorIs(t, err, order.ErrModifyOrderIsNil) arg := &order.Modify{} _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrPairIsEmpty) arg.Pair = mainPair _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrAssetNotSet) arg.AssetType = asset.Spot _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrOrderIDNotSet) arg.OrderID = "1234" arg.Type = order.Liquidation _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrUnsupportedOrderType) arg.Type = order.Limit _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidNewSizeOrPriceInformation) arg.Type = order.Trigger _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.Type = order.OCO _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) arg = &order.Modify{ AssetType: asset.Spot, Pair: mainPair, OrderID: "1234", Price: 123456.44, Amount: 123, } result, err := e.ModifyOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.Limit result, err = e.ModifyOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.Trigger _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.TriggerPrice = 12345678 _, err = e.ModifyOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) arg.Type = order.OCO _, err = e.ModifyOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.RiskManagementModes = order.RiskManagementModes{ TakeProfit: order.RiskManagement{Price: 12345677}, StopLoss: order.RiskManagement{Price: 12345667}, } result, err = e.ModifyOrder(contextGenerate(), arg) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.ModifyOrder(contextGenerate(), &order.Modify{ AssetType: asset.Spread, Pair: spreadPair, OrderID: "1234", Price: 123456.44, Amount: 123, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetOrderInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetOrderInfo(contextGenerate(), "123", perpetualSwapPair, asset.PerpetualSwap) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.GetOrderInfo(contextGenerate(), "123", spreadPair, asset.Spread) require.NoError(t, err) assert.NotNil(t, result) } func TestGetDepositAddress(t *testing.T) { t.Parallel() _, err := e.GetDepositAddress(contextGenerate(), currency.EMPTYCODE, "", "") require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetDepositAddress(contextGenerate(), currency.BTC, core.BitcoinDonationAddress, "") require.NoError(t, err) assert.NotNil(t, result) } func TestWithdraw(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) withdrawCryptoRequest := withdraw.Request{ Exchange: e.Name, Amount: 0.00000000001, Currency: currency.BTC, Crypto: withdraw.CryptoRequest{ Address: core.BitcoinDonationAddress, }, } result, err := e.WithdrawCryptocurrencyFunds(contextGenerate(), &withdrawCryptoRequest) require.NoError(t, err) assert.NotNil(t, result) } func TestGetPairFromInstrumentID(t *testing.T) { t.Parallel() instruments := []string{ mainPair.String(), perpetualSwapPair.String(), "BTC-USDT-ER33234", } dPair, err := e.GetPairFromInstrumentID(instruments[0]) require.NoError(t, err) require.NotNil(t, dPair) dPair, err = e.GetPairFromInstrumentID(instruments[1]) require.NoError(t, err) require.NotNil(t, dPair) dPair, err = e.GetPairFromInstrumentID(instruments[2]) require.NoError(t, err) assert.NotNil(t, dPair) } func TestGetActiveOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) for _, a := range []asset.Item{asset.Spot, asset.Spread} { pairs := []currency.Pair{currency.NewPair(currency.LTC, currency.USDT), mainPair} if a == asset.Spread { pairs = []currency.Pair{spreadPair} } result, err := e.GetActiveOrders(contextGenerate(), &order.MultiOrderRequest{ Type: order.Limit, Pairs: pairs, AssetType: asset.Spot, Side: order.Buy, }) require.NoErrorf(t, err, "GetActiveOrders for asset %s and pair %s must not error", a, pairs[0]) assert.NotNil(t, result) } } func TestGetOrderHistory(t *testing.T) { t.Parallel() getOrdersRequest := order.MultiOrderRequest{ Type: order.AnyType, AssetType: asset.Spot, Side: order.Buy, } _, err := e.GetOrderHistory(contextGenerate(), &getOrdersRequest) require.ErrorIs(t, err, currency.ErrCurrencyPairsEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) getOrdersRequest.Pairs = []currency.Pair{currency.NewPair(currency.LTC, currency.BTC)} result, err := e.GetOrderHistory(contextGenerate(), &getOrdersRequest) assert.NoError(t, err) assert.NotNil(t, result) getOrdersRequest.AssetType = asset.Spread getOrdersRequest.Type = order.Market result, err = e.GetOrderHistory(contextGenerate(), &getOrdersRequest) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFeeByType(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFeeByType(contextGenerate(), &exchange.FeeBuilder{ Amount: 1, FeeType: exchange.CryptocurrencyTradeFee, Pair: currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "-"), PurchasePrice: 1, FiatCurrency: currency.USD, BankTransactionType: exchange.WireTransfer, }) require.NoError(t, err) assert.NotNil(t, result) } func TestValidateAPICredentials(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) err := e.ValidateAPICredentials(contextGenerate(), asset.Spot) assert.NoError(t, err) } func TestGetHistoricCandles(t *testing.T) { t.Parallel() _, err := e.GetHistoricCandles(contextGenerate(), currency.Pair{}, asset.Binary, kline.OneDay, time.Now(), time.Now()) require.ErrorIs(t, err, asset.ErrNotSupported) startTime := time.Date(2021, 2, 1, 0, 0, 0, 0, time.UTC) endTime := startTime.AddDate(0, 0, 100) _, err = e.GetHistoricCandles(contextGenerate(), mainPair, asset.Spot, kline.Interval(time.Hour*4), startTime, endTime) require.ErrorIs(t, err, kline.ErrRequestExceedsExchangeLimits) testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { pairs, err := e.GetEnabledPairs(a) require.NoErrorf(t, err, "GetEnabledPairs for asset %s must not error", a) require.NotEmptyf(t, pairs, "GetEnabledPairs for asset %s must not return empty pairs", a) result, err := e.GetHistoricCandles(contextGenerate(), pairs[0], a, kline.OneMin, time.Now().Add(-time.Hour), time.Now()) if (a == asset.Spread || a == asset.Options) && err != nil { // Options and spread candles sometimes returns no data continue } require.NoErrorf(t, err, "GetHistoricCandles for asset %s and pair %s must not error", a, pairs[0]) assert.NotNilf(t, result, "GetHistoricCandles for asset %s and pair %s should not return nil", a, pairs[0]) } } func TestGetHistoricCandlesExtended(t *testing.T) { t.Parallel() result, err := e.GetHistoricCandlesExtended(contextGenerate(), mainPair, asset.Spot, kline.OneMin, time.Now().Add(-time.Hour), time.Now()) require.NoError(t, err) assert.NotNil(t, result) } func TestGenerateOrderbookChecksum(t *testing.T) { t.Parallel() var orderbookBase orderbook.Book err := json.Unmarshal([]byte(calculateOrderbookChecksumUpdateOrderbookJSON), &orderbookBase) require.NoError(t, err) require.Equal(t, uint32(2832680552), generateOrderbookChecksum(&orderbookBase)) } func TestOrderPushData(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Test instance Setup must not error") testexch.FixtureToDataHandler(t, "testdata/wsOrders.json", e.WsHandleData) close(e.Websocket.DataHandler) require.Len(t, e.Websocket.DataHandler, 4, "Should see 4 orders") for resp := range e.Websocket.DataHandler { switch v := resp.(type) { case *order.Detail: switch len(e.Websocket.DataHandler) { case 3: assert.Equal(t, "452197707845865472", v.OrderID, "OrderID") assert.Equal(t, "HamsterParty14", v.ClientOrderID, "ClientOrderID") assert.Equal(t, asset.Spot, v.AssetType, "AssetType") assert.Equal(t, order.Sell, v.Side, "Side") assert.Equal(t, order.Filled, v.Status, "Status") assert.Equal(t, order.Limit, v.Type, "Type") assert.Equal(t, currency.NewPairWithDelimiter("BTC", "USDT", "-"), v.Pair, "Pair") assert.Equal(t, 31527.1, v.AverageExecutedPrice, "AverageExecutedPrice") assert.Equal(t, time.UnixMilli(1654084334977), v.Date, "Date") assert.Equal(t, time.UnixMilli(1654084353263), v.CloseTime, "CloseTime") assert.Equal(t, 0.001, v.Amount, "Amount") assert.Equal(t, 0.001, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 0.000, v.RemainingAmount, "RemainingAmount") assert.Equal(t, 31527.1, v.Price, "Price") assert.Equal(t, 0.02522168, v.Fee, "Fee") assert.Equal(t, currency.USDT, v.FeeAsset, "FeeAsset") case 2: assert.Equal(t, "620258920632008725", v.OrderID, "OrderID") assert.Equal(t, asset.Spot, v.AssetType, "AssetType") assert.Equal(t, order.Market, v.Type, "Type") assert.Equal(t, order.Sell, v.Side, "Side") assert.Equal(t, order.Active, v.Status, "Status") assert.Equal(t, 0.0, v.Amount, "Amount should be 0 for a market sell") assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount") case 1: assert.Equal(t, "620258920632008725", v.OrderID, "OrderID") assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount") assert.Equal(t, 0.00038127046945832905, v.Amount, "Amount") assert.Equal(t, 0.010000249968, v.Fee, "Fee") assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount") assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, order.PartiallyFilled, v.Status, "Status") case 0: assert.Equal(t, "620258920632008725", v.OrderID, "OrderID") assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount") assert.Equal(t, 0.010000249968, v.Fee, "Fee") assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount") assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 0.00038128, v.Amount, "Amount should be derived because order filled") assert.Equal(t, order.Filled, v.Status, "Status") } case error: t.Error(v) default: t.Errorf("Got unexpected data: %T %v", v, v) } } } var pushDataMap = map[string]string{ "Algo Orders": `{"arg": {"channel": "orders-algo","uid": "77982378738415879","instType": "FUTURES","instId": "BTC-USD-200329"},"data": [{"instType": "FUTURES","instId": "BTC-USD-200329","ordId": "312269865356374016","ccy": "BTC","algoId": "1234","px": "999","sz": "3","tdMode": "cross","tgtCcy": "","notionalUsd": "","ordType": "trigger","side": "buy","posSide": "long","state": "live","lever": "20","tpTriggerPx": "","tpTriggerPxType": "","tpOrdPx": "","slTriggerPx": "","slTriggerPxType": "","triggerPx": "99","triggerPxType": "last","ordPx": "12","actualSz": "","actualPx": "","tag": "adadadadad","actualSide": "","triggerTime": "1597026383085","cTime": "1597026383000"}]}`, "Advanced Algo Order": `{"arg": {"channel":"algo-advance","uid": "77982378738415879","instType":"SPOT","instId":"BTC-USDT"},"data":[{"actualPx":"","actualSide":"","actualSz":"0","algoId":"355056228680335360","cTime":"1630924001545","ccy":"","count":"1","instId":"BTC-USDT","instType":"SPOT","lever":"0","notionalUsd":"","ordPx":"","ordType":"iceberg","pTime":"1630924295204","posSide":"net","pxLimit":"10","pxSpread":"1","pxVar":"","side":"buy","slOrdPx":"","slTriggerPx":"","state":"pause","sz":"0.1","szLimit":"0.1","tdMode":"cash","timeInterval":"","tpOrdPx":"","tpTriggerPx":"","tag": "adadadadad","triggerPx":"","triggerTime":"","callbackRatio":"","callbackSpread":"","activePx":"","moveTriggerPx":""}]}`, "Position Risk": `{"arg": {"channel": "liquidation-warning","uid": "77982378738415879","instType": "FUTURES"},"data": [{"adl":"1","availPos":"1","avgPx":"2566.31","cTime":"1619507758793","ccy":"ETH","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","imr":"","instId":"ETH-USD-210430","instType":"FUTURES","interest":"0","last":"2566.22","lever":"10","liab":"","liabCcy":"","liqPx":"2352.8496681818233","markPx":"2353.849","margin":"0.0003896645377994","mgnMode":"isolated","mgnRatio":"11.731726509588816","mmr":"0.0000311811092368","notionalUsd":"2276.2546609009605","optVal":"","pTime":"1619507761462","pos":"1","posCcy":"","posId":"307173036051017730","posSide":"long","thetaBS":"","thetaPA":"","tradeId":"109844","uTime":"1619507761462","upl":"-0.0000009932766034","uplRatio":"-0.0025490556801078","vegaBS":"","vegaPA":""}, {"adl":"1","availPos":"1","avgPx":"2566.31","cTime":"1619507758793","ccy":"ETH","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","imr":"","instId":"ETH-USD-SWAP","instType":"SWAP","interest":"0","last":"2566.22","lever":"10","liab":"","liabCcy":"","liqPx":"2352.8496681818233","markPx":"2353.849","margin":"0.0003896645377994","mgnMode":"isolated","mgnRatio":"11.731726509588816","mmr":"0.0000311811092368","notionalUsd":"2276.2546609009605","optVal":"","pTime":"1619507761462","pos":"1","posCcy":"","posId":"307173036051017730","posSide":"long","thetaBS":"","thetaPA":"","tradeId":"109844","uTime":"1619507761462","upl":"-0.0000009932766034","uplRatio":"-0.0025490556801078","vegaBS":"","vegaPA":""}]}`, "Account Greeks": `{"arg": {"channel": "account-greeks","ccy": "BTC"},"data": [{"thetaBS": "","thetaPA":"","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","vegaBS":"","vegaPA":"","ccy":"BTC","ts":"1620282889345"}]}`, "RFQs": `{"arg": {"channel": "account-greeks","ccy": "BTC"},"data": [{"thetaBS": "","thetaPA":"","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","vegaBS":"","vegaPA":"","ccy":"BTC","ts":"1620282889345"}]}`, "Accounts": `{"arg": {"channel": "account","ccy": "BTC","uid": "77982378738415879"}, "data": [{"uTime": "1597026383085","totalEq": "41624.32","isoEq": "3624.32","adjEq": "41624.32","ordFroz": "0","imr": "4162.33","mmr": "4","notionalUsd": "","mgnRatio": "41624.32","details": [{"availBal": "","availEq": "1","ccy": "BTC","cashBal": "1","uTime": "1617279471503","disEq": "50559.01","eq": "1","eqUsd": "45078.3790756226851775","frozenBal": "0","interest": "0","isoEq": "0","liab": "0","maxLoan": "","mgnRatio": "","notionalLever": "0.0022195262185864","ordFrozen": "0","upl": "0","uplLiab": "0","crossLiab": "0","isoLiab": "0","coinUsdPrice": "60000","stgyEq":"0","spotInUseAmt":"","isoUpl":""}]}]}`, "Quotes": `{"arg": {"channel":"quotes"},"data":[{"validUntil":"1608997227854","uTime":"1608267227834","cTime":"1608267227834","legs":[{"px":"0.0023","sz":"25.0","instId":"BTC-USD-220114-25000-C","side":"sell","tgtCcy":""},{"px":"0.0045","sz":"25","instId":"BTC-USD-220114-35000-C","side":"buy","tgtCcy":""}],"quoteId":"25092","rfqId":"18753","traderCode":"SATS","quoteSide":"sell","state":"canceled","clQuoteId":""}]}`, "Structure Block Trades": `{"arg": {"channel":"struc-block-trades"},"data":[{"cTime":"1608267227834","rfqId":"18753","clRfqId":"","quoteId":"25092","clQuoteId":"","blockTdId":"180184","tTraderCode":"ANAND","mTraderCode":"WAGMI","legs":[{"px":"0.0023","sz":"25.0","instId":"BTC-USD-20220630-60000-C","side":"sell","fee":"0.1001","feeCcy":"BTC","tradeId":"10211","tgtCcy":""},{"px":"0.0033","sz":"25","instId":"BTC-USD-20220630-50000-C","side":"buy","fee":"0.1001","feeCcy":"BTC","tradeId":"10212","tgtCcy":""}]}]}`, "Spot Grid Algo Orders": `{"arg": {"channel": "grid-orders-spot","instType": "ANY"},"data": [{"algoId": "448965992920907776","algoOrdType": "grid","annualizedRate": "0","arbitrageNum": "0","baseSz": "0","cTime": "1653313834104","cancelType": "0","curBaseSz": "0.001776289214","curQuoteSz": "46.801755866","floatProfit": "-0.4953878967772","gridNum": "6","gridProfit": "0","instId": "BTC-USDC","instType": "SPOT","investment": "100","maxPx": "33444.8","minPx": "24323.5","pTime": "1653476023742","perMaxProfitRate": "0.060375293181491054543","perMinProfitRate": "0.0455275366818586","pnlRatio": "0","quoteSz": "100","runPx": "30478.1","runType": "1","singleAmt": "0.00059261","slTriggerPx": "","state": "running","stopResult": "0","stopType": "0","totalAnnualizedRate": "-0.9643551057262827","totalPnl": "-0.4953878967772","tpTriggerPx": "","tradeNum": "3","triggerTime": "1653378736894","uTime": "1653378736894"}]}`, "Contract Grid Algo Orders": `{"arg": {"channel": "grid-orders-contract","instType": "ANY"},"data": [{"actualLever": "1.02","algoId": "449327675342323712","algoOrdType": "contract_grid","annualizedRate": "0.7572437878956523","arbitrageNum": "1","basePos": true,"cTime": "1653400065912","cancelType": "0","direction": "long","eq": "10129.419829834853","floatProfit": "109.537858234853","gridNum": "50","gridProfit": "19.8819716","instId": "BTC-USDT-SWAP","instType": "SWAP","investment": "10000","lever": "5","liqPx": "603.2149534767834","maxPx": "100000","minPx": "10","pTime": "1653484573918","perMaxProfitRate": "995.7080916791230692","perMinProfitRate": "0.0946277854875634","pnlRatio": "0.0129419829834853","runPx": "29216.3","runType": "1","singleAmt": "1","slTriggerPx": "","state": "running","stopType": "0","sz": "10000","tag": "","totalAnnualizedRate": "4.929207431970923","totalPnl": "129.419829834853","tpTriggerPx": "","tradeNum": "37","triggerTime": "1653400066940","uTime": "1653484573589","uly": "BTC-USDT"}]}`, "Grid Positions": `{"arg": {"channel": "grid-positions","uid": "44705892343619584","algoId": "449327675342323712"},"data": [{"adl": "1","algoId": "449327675342323712","avgPx": "29181.4638888888888895","cTime": "1653400065917","ccy": "USDT","imr": "2089.2690000000002","instId": "BTC-USDT-SWAP","instType": "SWAP","last": "29852.7","lever": "5","liqPx": "604.7617536513744","markPx": "29849.7","mgnMode": "cross","mgnRatio": "217.71740878394456","mmr": "41.78538","notionalUsd": "10435.794191550001","pTime": "1653536068723","pos": "35","posSide": "net","uTime": "1653445498682","upl": "232.83263888888962","uplRatio": "0.1139826489932205"}]}`, "Grid Sub Orders": `{"arg": {"channel": "grid-sub-orders","uid": "44705892343619584","algoId": "449327675342323712"},"data": [{"accFillSz": "0","algoId": "449327675342323712","algoOrdType": "contract_grid","avgPx": "0","cTime": "1653445498664","ctVal": "0.01","fee": "0","feeCcy": "USDT","groupId": "-1","instId": "BTC-USDT-SWAP","instType": "SWAP","lever": "5","ordId": "449518234142904321","ordType": "limit","pTime": "1653486524502","pnl": "","posSide": "net","px": "28007.2","side": "buy","state": "live","sz": "1","tag":"","tdMode": "cross","uTime": "1653445498674"}]}`, "Instrument": `{"arg": {"channel": "instruments","instType": "FUTURES"},"data": [{"instType": "FUTURES","instId": "BTC-USD-191115","uly": "BTC-USD","category": "1","baseCcy": "","quoteCcy": "","settleCcy": "BTC","ctVal": "10","ctMult": "1","ctValCcy": "USD","optType": "","stk": "","listTime": "","expTime": "","tickSz": "0.01","lotSz": "1","minSz": "1","ctType": "linear","alias": "this_week","state": "live","maxLmtSz":"10000","maxMktSz":"99999","maxTwapSz":"99999","maxIcebergSz":"99999","maxTriggerSz":"9999","maxStopSz":"9999"}]}`, "Open Interest": `{"arg": {"channel": "open-interest","instId": "LTC-USD-SWAP"},"data": [{"instType": "SWAP","instId": "LTC-USD-SWAP","oi": "5000","oiCcy": "555.55","ts": "1597026383085"}]}`, "Trade": `{"arg": {"channel": "trades","instId": "BTC-USDT"},"data": [{"instId": "BTC-USDT","tradeId": "130639474","px": "42219.9","sz": "0.12060306","side": "buy","ts": "1630048897897"}]}`, "Estimated Delivery And Exercise Price": `{"arg": {"args": "estimated-price","instType": "FUTURES","uly": "BTC-USD"},"data": [{"instType": "FUTURES","instId": "BTC-USD-170310","settlePx": "200","ts": "1597026383085"}]}`, "Mark Price": `{"arg": {"channel": "mark-price","instId": "LTC-USD-190628"},"data": [{"instType": "FUTURES","instId": "LTC-USD-190628","markPx": "0.1","ts": "1597026383085"}]}`, "Mark Price Candlestick": `{"arg": {"channel": "mark-price-candle1D","instId": "BTC-USD-190628"},"data": [["1597026383085", "3.721", "3.743", "3.677", "3.708"],["1597026383085", "3.731", "3.799", "3.494", "3.72"]]}`, "Price Limit": `{"arg": {"channel": "price-limit","instId": "LTC-USD-190628"},"data": [{"instId": "LTC-USD-190628","buyLmt": "200","sellLmt": "300","ts": "1597026383085"}]}`, "Test Snapshot Orderbook": `{"arg": {"channel":"books","instId":"BTC-USDT"},"action":"snapshot","data":[{"asks":[["0.07026","5","0","1"],["0.07027","765","0","3"],["0.07028","110","0","1"],["0.0703","1264","0","1"],["0.07034","280","0","1"],["0.07035","2255","0","1"],["0.07036","28","0","1"],["0.07037","63","0","1"],["0.07039","137","0","2"],["0.0704","48","0","1"],["0.07041","32","0","1"],["0.07043","3985","0","1"],["0.07057","257","0","1"],["0.07058","7870","0","1"],["0.07059","161","0","1"],["0.07061","4539","0","1"],["0.07068","1438","0","3"],["0.07088","3162","0","1"],["0.07104","99","0","1"],["0.07108","5018","0","1"],["0.07115","1540","0","1"],["0.07129","5080","0","1"],["0.07145","1512","0","1"],["0.0715","5016","0","1"],["0.07171","5026","0","1"],["0.07192","5062","0","1"],["0.07197","1517","0","1"],["0.0726","1511","0","1"],["0.07314","10376","0","1"],["0.07354","1","0","1"],["0.07466","10277","0","1"],["0.07626","269","0","1"],["0.07636","269","0","1"],["0.0809","1","0","1"],["0.08899","1","0","1"],["0.09789","1","0","1"],["0.10768","1","0","1"]],"bids":[["0.07014","56","0","2"],["0.07011","608","0","1"],["0.07009","110","0","1"],["0.07006","1264","0","1"],["0.07004","2347","0","3"],["0.07003","279","0","1"],["0.07001","52","0","1"],["0.06997","91","0","1"],["0.06996","4242","0","2"],["0.06995","486","0","1"],["0.06992","161","0","1"],["0.06991","63","0","1"],["0.06988","7518","0","1"],["0.06976","186","0","1"],["0.06975","71","0","1"],["0.06973","1086","0","1"],["0.06961","513","0","2"],["0.06959","4603","0","1"],["0.0695","186","0","1"],["0.06946","3043","0","1"],["0.06939","103","0","1"],["0.0693","5053","0","1"],["0.06909","5039","0","1"],["0.06888","5037","0","1"],["0.06886","1526","0","1"],["0.06867","5008","0","1"],["0.06846","5065","0","1"],["0.06826","1572","0","1"],["0.06801","1565","0","1"],["0.06748","67","0","1"],["0.0674","111","0","1"],["0.0672","10038","0","1"],["0.06652","1","0","1"],["0.06625","1526","0","1"],["0.06619","10924","0","1"],["0.05986","1","0","1"],["0.05387","1","0","1"],["0.04848","1","0","1"],["0.04363","1","0","1"]],"ts":"1659792392540","checksum":-1462286744}]}`, "Options Trades": `{"arg": {"channel": "option-trades", "instType": "OPTION", "instFamily": "BTC-USD" }, "data": [ { "fillVol": "0.5066007836914062", "fwdPx": "16469.69928595038", "idxPx": "16537.2", "instFamily": "BTC-USD", "instId": "BTC-USD-230224-18000-C", "markPx": "0.04690107010619562", "optType": "C", "px": "0.045", "side": "sell", "sz": "2", "tradeId": "38", "ts": "1672286551080" } ] }`, "Public Block Trades": `{"arg": {"channel":"public-block-trades", "instId":"BTC-USD-231020-5000-P" }, "data":[ { "fillVol":"5", "fwdPx":"26808.16", "idxPx":"27222.5", "instId":"BTC-USD-231020-5000-P", "markPx":"0.0022406326071111", "px":"0.0048", "side":"buy", "sz":"1", "tradeId":"633971452580106242", "ts":"1697422572972"}]}`, "Option Summary": `{"arg": {"channel": "opt-summary","uly": "BTC-USD"},"data": [{"instType": "OPTION","instId": "BTC-USD-200103-5500-C","uly": "BTC-USD","delta": "0.7494223636","gamma": "-0.6765419039","theta": "-0.0000809873","vega": "0.0000077307","deltaBS": "0.7494223636","gammaBS": "-0.6765419039","thetaBS": "-0.0000809873","vegaBS": "0.0000077307","realVol": "0","bidVol": "","askVol": "1.5625","markVol": "0.9987","lever": "4.0342","fwdPx": "39016.8143629068452065","ts": "1597026383085"}]}`, "Funding Rate": `{"arg": {"channel": "funding-rate","instId": "BTC-USD-SWAP"},"data": [{"instType": "SWAP","instId": "BTC-USD-SWAP","fundingRate": "0.018","nextFundingRate": "","fundingTime": "1597026383085"}]}`, "Index Candlestick": `{"arg": {"channel": "index-candle30m","instId": "BTC-USDT"},"data": [["1597026383085", "3811.31", "3811.31", "3811.31", "3811.31"]]}`, "Index Ticker": `{"arg": {"channel": "index-tickers","instId": "BTC-USDT"},"data": [{"instId": "BTC-USDT","idxPx": "0.1","high24h": "0.5","low24h": "0.1","open24h": "0.1","sodUtc0": "0.1","sodUtc8": "0.1","ts": "1597026383085"}]}`, "Status": `{"arg": {"channel": "status"},"data": [{"title": "Spot System Upgrade","state": "scheduled","begin": "1610019546","href": "","end": "1610019546","serviceType": "1","system": "classic","scheDesc": "","ts": "1597026383085"}]}`, "Public Struct Block Trades": `{"arg": {"channel":"public-struc-block-trades"},"data":[{"cTime":"1608267227834","blockTdId":"1802896","legs":[{"px":"0.323","sz":"25.0","instId":"BTC-USD-20220114-13250-C","side":"sell","tradeId":"15102"},{"px":"0.666","sz":"25","instId":"BTC-USD-20220114-21125-C","side":"buy","tradeId":"15103"}]}]}`, "Block Ticker": `{"arg": {"channel": "block-tickers"},"data": [{"instType": "SWAP","instId": "LTC-USD-SWAP","volCcy24h": "0","vol24h": "0","ts": "1597026383085"}]}`, "Account": `{"arg": {"channel": "block-tickers"},"data": [{"instType": "SWAP","instId": "LTC-USD-SWAP","volCcy24h": "0","vol24h": "0","ts": "1597026383085"}]}`, "Position": `{"arg": {"channel":"positions","instType":"FUTURES"},"data":[{"adl":"1","availPos":"1","avgPx":"2566.31","cTime":"1619507758793","ccy":"ETH","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","imr":"","instId":"ETH-USD-210430","instType":"FUTURES","interest":"0","last":"2566.22","lever":"10","liab":"","liabCcy":"","liqPx":"2352.8496681818233","markPx":"2353.849","margin":"0.0003896645377994","mgnMode":"isolated","mgnRatio":"11.731726509588816","mmr":"0.0000311811092368","notionalUsd":"2276.2546609009605","optVal":"","pTime":"1619507761462","pos":"1","posCcy":"","posId":"307173036051017730","posSide":"long","thetaBS":"","thetaPA":"","tradeId":"109844","uTime":"1619507761462","upl":"-0.0000009932766034","uplRatio":"-0.0025490556801078","vegaBS":"","vegaPA":""}]}`, "Position Data With Underlying": `{"arg": {"channel": "positions","uid": "77982378738415879","instType": "FUTURES"},"data": [{"adl":"1","availPos":"1","avgPx":"2566.31","cTime":"1619507758793","ccy":"ETH","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","imr":"","instId":"ETH-USD-210430","instType":"FUTURES","interest":"0","last":"2566.22","usdPx":"","lever":"10","liab":"","liabCcy":"","liqPx":"2352.8496681818233","markPx":"2353.849","margin":"0.0003896645377994","mgnMode":"isolated","mgnRatio":"11.731726509588816","mmr":"0.0000311811092368","notionalUsd":"2276.2546609009605","optVal":"","pTime":"1619507761462","pos":"1","posCcy":"","posId":"307173036051017730","posSide":"long","thetaBS":"","thetaPA":"","tradeId":"109844","uTime":"1619507761462","upl":"-0.0000009932766034","uplRatio":"-0.0025490556801078","vegaBS":"","vegaPA":""}, {"adl":"1","availPos":"1","avgPx":"2566.31","cTime":"1619507758793","ccy":"ETH","deltaBS":"","deltaPA":"","gammaBS":"","gammaPA":"","imr":"","instId":"ETH-USD-SWAP","instType":"SWAP","interest":"0","last":"2566.22","usdPx":"","lever":"10","liab":"","liabCcy":"","liqPx":"2352.8496681818233","markPx":"2353.849","margin":"0.0003896645377994","mgnMode":"isolated","mgnRatio":"11.731726509588816","mmr":"0.0000311811092368","notionalUsd":"2276.2546609009605","optVal":"","pTime":"1619507761462","pos":"1","posCcy":"","posId":"307173036051017730","posSide":"long","thetaBS":"","thetaPA":"","tradeId":"109844","uTime":"1619507761462","upl":"-0.0000009932766034","uplRatio":"-0.0025490556801078","vegaBS":"","vegaPA":""}]}`, "Balance And Position": `{"arg": {"channel": "balance_and_position","uid": "77982378738415879"},"data": [{"pTime": "1597026383085","eventType": "snapshot","balData": [{"ccy": "BTC","cashBal": "1","uTime": "1597026383085"}],"posData": [{"posId": "1111111111","tradeId": "2","instId": "BTC-USD-191018","instType": "FUTURES","mgnMode": "cross","posSide": "long","pos": "10","ccy": "BTC","posCcy": "","avgPx": "3320","uTIme": "1597026383085"}]}]}`, "Deposit Info Details": `{"arg": {"channel": "deposit-info", "uid": "289320****60975104" }, "data": [{ "actualDepBlkConfirm": "0", "amt": "1", "areaCodeFrom": "", "ccy": "USDT", "chain": "USDT-TRC20", "depId": "88165462", "from": "", "fromWdId": "", "pTime": "1674103661147", "state": "0", "subAcct": "test", "to": "TEhFAqpuHa3LY*****8ByNoGnrmexeGMw", "ts": "1674103661123", "txId": "bc5376817*****************dbb0d729f6b", "uid": "289320****60975104" }] }`, "Withdrawal Info Details": `{"arg": {"channel": "deposit-info", "uid": "289320****60975104" }, "data": [{ "actualDepBlkConfirm": "0", "amt": "1", "areaCodeFrom": "", "ccy": "USDT", "chain": "USDT-TRC20", "depId": "88165462", "from": "", "fromWdId": "", "pTime": "1674103661147", "state": "0", "subAcct": "test", "to": "TEhFAqpuHa3LY*****8ByNoGnrmexeGMw", "ts": "1674103661123", "txId": "bc5376817*****************dbb0d729f6b", "uid": "289320****60975104" }] }`, "Recurring Buy Order": `{"arg": {"channel": "algo-recurring-buy", "instType": "SPOT", "uid": "447*******584" }, "data": [{ "algoClOrdId": "", "algoId": "644497312047435776", "algoOrdType": "recurring", "amt": "100", "cTime": "1699932133373", "cycles": "0", "instType": "SPOT", "investmentAmt": "0", "investmentCcy": "USDC", "mktCap": "0", "nextInvestTime": "1699934415300", "pTime": "1699933314691", "period": "hourly", "pnlRatio": "0", "recurringDay": "", "recurringHour": "1", "recurringList": [{ "avgPx": "0", "ccy": "BTC", "profit": "0", "px": "36482", "ratio": "0.2", "totalAmt": "0" }, { "avgPx": "0", "ccy": "ETH", "profit": "0", "px": "2057.54", "ratio": "0.8", "totalAmt": "0" }], "recurringTime": "12", "state": "running", "stgyName": "stg1", "tag": "", "timeZone": "8", "totalAnnRate": "0", "totalPnl": "0", "uTime": "1699932136249" }] }`, "Liquidation Orders": `{"arg": {"channel": "liquidation-orders", "instType": "SWAP" }, "data": [ { "details": [ { "bkLoss": "0", "bkPx": "0.007831", "ccy": "", "posSide": "short", "side": "buy", "sz": "13", "ts": "1692266434010" } ], "instFamily": "IOST-USDT", "instId": "IOST-USDT-SWAP", "instType": "SWAP", "uly": "IOST-USDT"}]}`, "Economic Calendar": `{"arg": {"channel": "economic-calendar" }, "data": [ { "calendarId": "319275", "date": "1597026383085", "region": "United States", "category": "Manufacturing PMI", "event": "S&P Global Manufacturing PMI Final", "refDate": "1597026383085", "actual": "49.2", "previous": "47.3", "forecast": "49.3", "importance": "2", "prevInitial": "", "ccy": "", "unit": "", "ts": "1698648096590" } ] }`, "Failure": `{ "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"args\":[{ \"channel\" : \"block-tickers\", \"instId\" : \"LTC-USD-200327\"}]}", "connId": "a4d3ae55" }`, "Balance Save Error": `{"arg": {"channel": "balance_and_position","uid": "77982378738415880"},"data": [{"pTime": "1597026383085","eventType": "snapshot","balData": [{"ccy": "BTC","cashBal": "1","uTime": "1597026383085"}],"posData": [{"posId": "1111111111","tradeId": "2","instId": "BTC-USD-191018","instType": "FUTURES","mgnMode": "cross","posSide": "long","pos": "10","ccy": "BTC","posCcy": "","avgPx": "3320","uTIme": "1597026383085"}]}]}`, } func TestWsHandleData(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") for name, msg := range pushDataMap { switch name { case "Balance And Position": e.API.AuthenticatedSupport = true e.API.AuthenticatedWebsocketSupport = true e.SetCredentials("test", "test", "test", "", "", "") default: e.API.AuthenticatedSupport = false e.API.AuthenticatedWebsocketSupport = false } err := e.WsHandleData(t.Context(), []byte(msg)) if name == "Balance Save Error" { assert.ErrorIs(t, err, exchange.ErrAuthenticationSupportNotEnabled, "wsProcessBalanceAndPosition Accounts.Save should error without credentials") } else { require.NoErrorf(t, err, "%s must not error", name) } } } func TestPushDataDynamic(t *testing.T) { t.Parallel() dataMap := map[string]string{ "Ticker": `{"arg": {"channel": "tickers","instId": "BTC-USD-SWAP"},"data": [{"instType": "SWAP","instId": "BTC-USD-SWAP","last": "9999.99","lastSz": "0.1","askPx": "9999.99","askSz": "11","bidPx": "8888.88","bidSz": "5","open24h": "9000","high24h": "10000","low24h": "8888.88","volCcy24h": "2222","vol24h": "2222","sodUtc0": "2222","sodUtc8": "2222","ts": "1597026383085"}]}`, "Candlesticks": `{"arg": {"channel": "candle1D","instId": "BTC-USD-SWAP"},"data": [["1597026383085","8533.02","8553.74","8527.17","8548.26","45247","529.5858061"]]}`, "Snapshot OrderBook": `{"arg":{"channel":"books","instId":"BTC-USD-SWAP"},"action":"snapshot","data":[{"asks":[["0.07026","5","0","1"],["0.07027","765","0","3"],["0.07028","110","0","1"],["0.0703","1264","0","1"],["0.07034","280","0","1"],["0.07035","2255","0","1"],["0.07036","28","0","1"],["0.07037","63","0","1"],["0.07039","137","0","2"],["0.0704","48","0","1"],["0.07041","32","0","1"],["0.07043","3985","0","1"],["0.07057","257","0","1"],["0.07058","7870","0","1"],["0.07059","161","0","1"],["0.07061","4539","0","1"],["0.07068","1438","0","3"],["0.07088","3162","0","1"],["0.07104","99","0","1"],["0.07108","5018","0","1"],["0.07115","1540","0","1"],["0.07129","5080","0","1"],["0.07145","1512","0","1"],["0.0715","5016","0","1"],["0.07171","5026","0","1"],["0.07192","5062","0","1"],["0.07197","1517","0","1"],["0.0726","1511","0","1"],["0.07314","10376","0","1"],["0.07354","1","0","1"],["0.07466","10277","0","1"],["0.07626","269","0","1"],["0.07636","269","0","1"],["0.0809","1","0","1"],["0.08899","1","0","1"],["0.09789","1","0","1"],["0.10768","1","0","1"]],"bids":[["0.07014","56","0","2"],["0.07011","608","0","1"],["0.07009","110","0","1"],["0.07006","1264","0","1"],["0.07004","2347","0","3"],["0.07003","279","0","1"],["0.07001","52","0","1"],["0.06997","91","0","1"],["0.06996","4242","0","2"],["0.06995","486","0","1"],["0.06992","161","0","1"],["0.06991","63","0","1"],["0.06988","7518","0","1"],["0.06976","186","0","1"],["0.06975","71","0","1"],["0.06973","1086","0","1"],["0.06961","513","0","2"],["0.06959","4603","0","1"],["0.0695","186","0","1"],["0.06946","3043","0","1"],["0.06939","103","0","1"],["0.0693","5053","0","1"],["0.06909","5039","0","1"],["0.06888","5037","0","1"],["0.06886","1526","0","1"],["0.06867","5008","0","1"],["0.06846","5065","0","1"],["0.06826","1572","0","1"],["0.06801","1565","0","1"],["0.06748","67","0","1"],["0.0674","111","0","1"],["0.0672","10038","0","1"],["0.06652","1","0","1"],["0.06625","1526","0","1"],["0.06619","10924","0","1"],["0.05986","1","0","1"],["0.05387","1","0","1"],["0.04848","1","0","1"],["0.04363","1","0","1"]],"ts":"1659792392540","checksum":-1462286744}]}`, } var err error for x := range dataMap { err = e.WsHandleData(t.Context(), []byte(dataMap[x])) require.NoError(t, err) } } func TestGetHistoricTrades(t *testing.T) { t.Parallel() _, err := e.GetHistoricTrades(contextGenerate(), mainPair, asset.Spread, time.Now(), time.Now()) require.ErrorIs(t, err, asset.ErrNotSupported) result, err := e.GetHistoricTrades(contextGenerate(), mainPair, asset.Spot, time.Now().Add(-time.Minute*4), time.Now().Add(-time.Minute*2)) require.NoError(t, err) assert.NotNil(t, result) } func TestWSProcessTrades(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Test instance Setup must not error") assets, err := e.getAssetsFromInstrumentID(mainPair.String()) require.NoError(t, err, "getAssetsFromInstrumentID must not error") p := currency.NewPairWithDelimiter("BTC", "USDT", currency.DashDelimiter) for _, a := range assets { err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{ Asset: a, Pairs: currency.Pairs{p}, Channel: subscription.AllTradesChannel, Key: fmt.Sprintf("%s-%s", p, a), }) require.NoError(t, err, "AddSubscriptions must not error") } testexch.FixtureToDataHandler(t, "testdata/wsAllTrades.json", e.WsHandleData) exp := []trade.Data{ { Timestamp: time.UnixMilli(1740394561685).UTC(), Price: 95634.9, Amount: 0.00011186, Side: order.Buy, TID: "674510826", }, { Timestamp: time.UnixMilli(1740394561686).UTC(), Price: 95635.3, Amount: 0.00011194, Side: order.Sell, TID: "674510827", }, } total := len(assets) * len(exp) require.Len(t, e.Websocket.DataHandler, total, "Must see correct number of trades") trades := make(map[asset.Item][]trade.Data) for len(e.Websocket.DataHandler) > 0 { resp := <-e.Websocket.DataHandler switch v := resp.(type) { case trade.Data: trades[v.AssetType] = append(trades[v.AssetType], v) case error: t.Error(v) default: t.Errorf("Unexpected type in DataHandler: %T (%s)", v, v) } } for _, assetType := range assets { require.Lenf(t, trades[assetType], len(exp), "Must have received %d trades for asset %v", len(exp), assetType) slices.SortFunc(trades[assetType], func(a, b trade.Data) int { return strings.Compare(a.TID, b.TID) }) for i, tradeData := range trades[assetType] { expected := exp[i] expected.AssetType = assetType expected.Exchange = e.Name expected.CurrencyPair = p require.Equalf(t, expected, tradeData, "Trade %d (TID: %s) for asset %v must match expected data", i, tradeData.TID, assetType) } } } func TestGetServerTime(t *testing.T) { t.Parallel() result, err := e.GetServerTime(contextGenerate(), asset.Empty) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAvailableTransferChains(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAvailableTransferChains(contextGenerate(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestGetIntervalEnum(t *testing.T) { t.Parallel() tests := []struct { Description string Interval kline.Interval Expected string AppendUTC bool }{ {Expected: "", AppendUTC: true}, {Description: "kline.OneMin ", Interval: kline.OneMin, Expected: "1m"}, {Description: "kline.ThreeMin ", Interval: kline.ThreeMin, Expected: "3m"}, {Description: "kline.FiveMin ", Interval: kline.FiveMin, Expected: "5m"}, {Description: "kline.FifteenMin ", Interval: kline.FifteenMin, Expected: "15m"}, {Description: "kline.ThirtyMin ", Interval: kline.ThirtyMin, Expected: "30m"}, {Description: "kline.OneHour ", Interval: kline.OneHour, Expected: "1H"}, {Description: "kline.TwoHour ", Interval: kline.TwoHour, Expected: "2H"}, {Description: "kline.FourHour ", Interval: kline.FourHour, Expected: "4H"}, {Description: "kline.SixHour ", Interval: kline.SixHour, Expected: "6H"}, {Description: "kline.TwelveHour ", Interval: kline.TwelveHour, Expected: "12H"}, {Description: "kline.OneDay ", Interval: kline.OneDay, Expected: "1D"}, {Description: "kline.TwoDay ", Interval: kline.TwoDay, Expected: "2D"}, {Description: "kline.ThreeDay ", Interval: kline.ThreeDay, Expected: "3D"}, {Description: "kline.OneWeek ", Interval: kline.OneWeek, Expected: "1W"}, {Description: "kline.FiveDay ", Interval: kline.FiveDay, Expected: "5D"}, {Description: "kline.OneMonth ", Interval: kline.OneMonth, Expected: "1M"}, {Description: "kline.ThreeMonth ", Interval: kline.ThreeMonth, Expected: "3M"}, {Description: "kline.SixMonth ", Interval: kline.SixMonth, Expected: "6M"}, {Description: "kline.OneYear ", Interval: kline.OneYear, Expected: "1Y"}, {Description: "kline.SixHour + UTC", Interval: kline.SixHour, Expected: "6Hutc", AppendUTC: true}, {Description: "kline.TwelveHour + UTC ", Interval: kline.TwelveHour, Expected: "12Hutc", AppendUTC: true}, {Description: "kline.OneDay + UTC ", Interval: kline.OneDay, Expected: "1Dutc", AppendUTC: true}, {Description: "kline.TwoDay + UTC ", Interval: kline.TwoDay, Expected: "2Dutc", AppendUTC: true}, {Description: "kline.ThreeDay + UTC ", Interval: kline.ThreeDay, Expected: "3Dutc", AppendUTC: true}, {Description: "kline.FiveDay + UTC ", Interval: kline.FiveDay, Expected: "5Dutc", AppendUTC: true}, {Description: "kline.OneWeek + UTC ", Interval: kline.OneWeek, Expected: "1Wutc", AppendUTC: true}, {Description: "kline.OneMonth + UTC ", Interval: kline.OneMonth, Expected: "1Mutc", AppendUTC: true}, {Description: "kline.ThreeMonth + UTC ", Interval: kline.ThreeMonth, Expected: "3Mutc", AppendUTC: true}, {Description: "kline.SixMonth + UTC ", Interval: kline.SixMonth, Expected: "6Mutc", AppendUTC: true}, {Description: "kline.OneYear + UTC ", Interval: kline.OneYear, Expected: "1Yutc", AppendUTC: true}, } for _, tt := range tests { t.Run(tt.Description, func(t *testing.T) { t.Parallel() r := IntervalFromString(tt.Interval, tt.AppendUTC) require.Equalf(t, tt.Expected, r, "%s: received: %s but expected: %s", tt.Description, r, tt.Expected) }) } } func TestInstrument(t *testing.T) { t.Parallel() var i Instrument err := json.Unmarshal([]byte(instrumentJSON), &i) require.NoError(t, err) require.Empty(t, i.Alias, "expected empty alias") assert.Empty(t, i.BaseCurrency, "expected empty base currency") assert.Equal(t, "1", i.Category, "expected 1 category") assert.Equal(t, 1, int(i.ContractMultiplier.Int64()), "expected 1 contract multiplier") assert.Equal(t, "linear", i.ContractType, "expected linear contract type") assert.Equal(t, 0.0001, i.ContractValue.Float64(), "expected 0.0001 contract value") assert.Equal(t, currency.BTC.String(), i.ContractValueCurrency, "expected BTC contract value currency") assert.True(t, i.ExpTime.Time().IsZero(), "expected empty expiry time") assert.Equal(t, "BTC-USDC", i.InstrumentFamily, "expected BTC-USDC instrument family") assert.Equal(t, "BTC-USDC-SWAP", i.InstrumentID.String(), "expected BTC-USDC-SWAP instrument ID") swap := GetInstrumentTypeFromAssetItem(asset.PerpetualSwap) assert.Equal(t, swap, i.InstrumentType, "expected SWAP instrument type") assert.Equal(t, 125, int(i.MaxLeverage), "expected 125 leverage") assert.Equal(t, int64(1666076190000), i.ListTime.Time().UnixMilli(), "expected 1666076190000 listing time") assert.Equal(t, 1, int(i.LotSize)) assert.Equal(t, 100000000.0000000000000000, i.MaxSpotIcebergSize.Float64()) assert.Equal(t, 100000000, int(i.MaxQuantityOfSpotLimitOrder)) assert.Equal(t, 85000, int(i.MaxQuantityOfMarketLimitOrder)) assert.Equal(t, 85000, int(i.MaxStopSize)) assert.Equal(t, 100000000.0000000000000000, i.MaxTriggerSize.Float64()) assert.Equal(t, 0, int(i.MaxQuantityOfSpotTwapLimitOrder), "expected empty max TWAP size") assert.Equal(t, 1, int(i.MinimumOrderSize)) assert.Empty(t, i.OptionType, "expected empty option type") assert.Empty(t, i.QuoteCurrency, "expected empty quote currency") assert.Equal(t, currency.USDC.String(), i.SettlementCurrency, "expected USDC settlement currency") assert.Equal(t, "live", i.State) assert.Empty(t, i.StrikePrice, "expected empty strike price") assert.Equal(t, 0.1, i.TickSize.Float64()) assert.Equal(t, "BTC-USDC", i.Underlying, "expected BTC-USDC underlying") } func TestGetLatestFundingRate(t *testing.T) { t.Parallel() result, err := e.GetLatestFundingRates(contextGenerate(), &fundingrate.LatestRateRequest{ Asset: asset.PerpetualSwap, Pair: perpetualSwapPair, IncludePredictedRate: true, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetHistoricalFundingRates(t *testing.T) { t.Parallel() r := &fundingrate.HistoricalRatesRequest{ Asset: asset.PerpetualSwap, Pair: perpetualSwapPair, PaymentCurrency: currency.USDT, StartDate: time.Now().Add(-time.Hour * 24 * 2), EndDate: time.Now(), IncludePredictedRate: true, } r.StartDate = time.Now().Add(-time.Hour * 24 * 120) _, err := e.GetHistoricalFundingRates(contextGenerate(), r) require.ErrorIs(t, err, fundingrate.ErrFundingRateOutsideLimits) if sharedtestvalues.AreAPICredentialsSet(e) { r.IncludePayments = true } r.StartDate = time.Now().Add(-time.Hour * 24 * 12) result, err := e.GetHistoricalFundingRates(contextGenerate(), r) require.NoError(t, err) require.NotNil(t, result) r.RespectHistoryLimits = true result, err = e.GetHistoricalFundingRates(contextGenerate(), r) require.NoError(t, err) assert.NotNil(t, result) } func TestIsPerpetualFutureCurrency(t *testing.T) { t.Parallel() is, err := e.IsPerpetualFutureCurrency(asset.Binary, mainPair) require.NoError(t, err) require.False(t, is) is, err = e.IsPerpetualFutureCurrency(asset.PerpetualSwap, perpetualSwapPair) require.NoError(t, err) assert.True(t, is, "expected true") } func TestGetAssetsFromInstrumentTypeOrID(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") _, err := e.getAssetsFromInstrumentID("") assert.ErrorIs(t, err, errMissingInstrumentID) for _, a := range []asset.Item{asset.Spot, asset.Futures, asset.PerpetualSwap, asset.Options} { assets, err2 := e.getAssetsFromInstrumentID(e.CurrencyPairs.Pairs[a].Enabled[0].String()) require.NoErrorf(t, err2, "GetAssetsFromInstrumentTypeOrID must not error for asset: %s", a) switch a { case asset.Spot, asset.Margin: // spot and margin instruments are similar require.Len(t, assets, 2) default: require.Len(t, assets, 1) } assert.Containsf(t, assets, a, "Should contain asset: %s", a) } _, err = e.getAssetsFromInstrumentID("test") assert.ErrorIs(t, err, currency.ErrCurrencyNotSupported) _, err = e.getAssetsFromInstrumentID("test-test") assert.ErrorIs(t, err, asset.ErrNotEnabled) for _, a := range []asset.Item{asset.Margin, asset.Spot} { assets, err2 := e.getAssetsFromInstrumentID(e.CurrencyPairs.Pairs[a].Enabled[0].String()) require.NoErrorf(t, err2, "GetAssetsFromInstrumentTypeOrID must not error for asset: %s", a) assert.Contains(t, assets, a) } } func TestSetMarginType(t *testing.T) { t.Parallel() err := e.SetMarginType(contextGenerate(), asset.Spot, mainPair, margin.Isolated) assert.ErrorIs(t, err, common.ErrFunctionNotSupported) } func TestChangePositionMargin(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.ChangePositionMargin(contextGenerate(), &margin.PositionChangeRequest{ Pair: mainPair, Asset: asset.Margin, MarginType: margin.Isolated, OriginalAllocatedMargin: 4.0695, NewAllocatedMargin: 5, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCollateralMode(t *testing.T) { t.Parallel() _, err := e.GetCollateralMode(contextGenerate(), asset.USDTMarginedFutures) require.ErrorIs(t, err, asset.ErrNotSupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCollateralMode(contextGenerate(), asset.Spot) assert.NoError(t, err) assert.NotNil(t, result) } func TestSetCollateralMode(t *testing.T) { t.Parallel() err := e.SetCollateralMode(contextGenerate(), asset.Spot, collateral.SingleMode) assert.ErrorIs(t, err, common.ErrFunctionNotSupported) } func TestGetPositionSummary(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) pp, err := e.CurrencyPairs.GetPairs(asset.PerpetualSwap, true) require.NoError(t, err) result, err := e.GetFuturesPositionSummary(contextGenerate(), &futures.PositionSummaryRequest{ Asset: asset.PerpetualSwap, Pair: pp[0], UnderlyingPair: currency.EMPTYPAIR, }) require.NoError(t, err) require.NotNil(t, result) pp, err = e.CurrencyPairs.GetPairs(asset.Futures, true) require.NoError(t, err) _, err = e.GetFuturesPositionSummary(contextGenerate(), &futures.PositionSummaryRequest{ Asset: asset.Spot, Pair: pp[0], UnderlyingPair: mainPair, }) require.ErrorIsf(t, err, futures.ErrNotFuturesAsset, "received '%v', expected '%v'", err, futures.ErrNotFuturesAsset) result, err = e.GetFuturesPositionSummary(contextGenerate(), &futures.PositionSummaryRequest{ Asset: asset.Futures, Pair: pp[0], UnderlyingPair: currency.EMPTYPAIR, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFuturesPositions(t *testing.T) { t.Parallel() pp, err := e.CurrencyPairs.GetPairs(asset.Futures, true) require.NoError(t, err) _, err = e.GetFuturesPositionOrders(contextGenerate(), &futures.PositionsRequest{ Asset: asset.Spot, Pairs: []currency.Pair{pp[0]}, StartDate: time.Now().Add(time.Hour * 24 * -7), }) require.ErrorIs(t, err, asset.ErrNotSupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFuturesPositionOrders(contextGenerate(), &futures.PositionsRequest{ Asset: asset.Futures, Pairs: []currency.Pair{pp[0]}, StartDate: time.Now().Add(time.Hour * 24 * -7), EndDate: time.Now(), }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeverage(t *testing.T) { t.Parallel() pp, err := e.CurrencyPairs.GetPairs(asset.Futures, true) require.NoError(t, err) _, err = e.GetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, order.UnknownSide) require.ErrorIs(t, err, order.ErrSideIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Multi, order.UnknownSide) require.NoError(t, err) require.NotNil(t, result) result, err = e.GetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, order.Long) require.NoError(t, err) require.NotNil(t, result) result, err = e.GetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, order.Short) require.NoError(t, err) assert.NotNil(t, result) } func TestSetLeverage(t *testing.T) { t.Parallel() pp, err := e.CurrencyPairs.GetPairs(asset.Futures, true) require.NoError(t, err) err = e.SetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, 5, order.UnknownSide) require.ErrorIs(t, err, order.ErrSideIsInvalid) err = e.SetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, 5, order.CouldNotBuy) require.ErrorIs(t, err, order.ErrSideIsInvalid) err = e.SetLeverage(contextGenerate(), asset.Spot, pp[0], margin.Multi, 5, order.UnknownSide) require.ErrorIs(t, err, asset.ErrNotSupported) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) err = e.SetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Multi, 5, order.UnknownSide) require.NoError(t, err) err = e.SetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, 5, order.Long) require.NoError(t, err) err = e.SetLeverage(contextGenerate(), asset.Futures, pp[0], margin.Isolated, 5, order.Short) assert.NoError(t, err) } func TestGetFuturesContractDetails(t *testing.T) { t.Parallel() _, err := e.GetFuturesContractDetails(contextGenerate(), asset.Spot) require.ErrorIs(t, err, futures.ErrNotFuturesAsset) _, err = e.GetFuturesContractDetails(contextGenerate(), asset.USDTMarginedFutures) require.ErrorIs(t, err, asset.ErrNotSupported) for _, a := range []asset.Item{asset.Futures, asset.PerpetualSwap, asset.Spread} { result, err := e.GetFuturesContractDetails(contextGenerate(), a) require.NoError(t, err) require.NotNil(t, result) } } func TestWsProcessOrderbook5(t *testing.T) { t.Parallel() ob5payload := []byte(`{"arg":{"channel":"books5","instId":"OKB-USDT"},"data":[{"asks":[["0.0000007465","2290075956","0","4"],["0.0000007466","1747284705","0","4"],["0.0000007467","1338861655","0","3"],["0.0000007468","1661668387","0","6"],["0.0000007469","2715477116","0","5"]],"bids":[["0.0000007464","15693119","0","1"],["0.0000007463","2330835024","0","4"],["0.0000007462","1182926517","0","2"],["0.0000007461","3818684357","0","4"],["0.000000746","6021641435","0","7"]],"instId":"OKB-USDT","ts":"1695864901807","seqId":4826378794}]}`) err := e.wsProcessOrderbook5(ob5payload) require.NoError(t, err) required := currency.NewPairWithDelimiter("OKB", "USDT", "-") got, err := orderbook.Get(e.Name, required, asset.Spot) require.NoError(t, err) require.Len(t, got.Asks, 5) require.Len(t, got.Bids, 5) // Book replicated to margin got, err = orderbook.Get(e.Name, required, asset.Margin) require.NoError(t, err) require.Len(t, got.Asks, 5) assert.Len(t, got.Bids, 5) } func TestGetLeverateEstimatedInfo(t *testing.T) { t.Parallel() _, err := e.GetLeverageEstimatedInfo(contextGenerate(), "", "cross", "1", "", mainPair.String(), currency.BTC) require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetLeverageEstimatedInfo(contextGenerate(), "MARGIN", "", "1", "", mainPair.String(), currency.BTC) require.ErrorIs(t, err, margin.ErrMarginTypeUnsupported) _, err = e.GetLeverageEstimatedInfo(contextGenerate(), "MARGIN", "cross", "", "", mainPair.String(), currency.BTC) require.ErrorIs(t, err, errInvalidLeverage) _, err = e.GetLeverageEstimatedInfo(contextGenerate(), "MARGIN", "cross", "1", "", mainPair.String(), currency.EMPTYCODE) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLeverageEstimatedInfo(contextGenerate(), "MARGIN", "cross", "1", "", mainPair.String(), currency.BTC) require.NoError(t, err) assert.NotNil(t, result) } func TestManualBorrowAndRepayInQuickMarginMode(t *testing.T) { t.Parallel() _, err := e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{ InstrumentID: mainPair.String(), LoanCcy: currency.USDT, Side: "borrow", }) require.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{ Amount: 1, InstrumentID: mainPair.String(), Side: "borrow", }) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{ Amount: 1, InstrumentID: mainPair.String(), LoanCcy: currency.USDT, }) require.ErrorIs(t, err, order.ErrSideIsInvalid) _, err = e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{ Amount: 1, LoanCcy: currency.USDT, Side: "borrow", }) require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ManualBorrowAndRepayInQuickMarginMode(contextGenerate(), &BorrowAndRepay{ Amount: 1, InstrumentID: mainPair.String(), LoanCcy: currency.USDT, Side: "borrow", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetBorrowAndRepayHistoryInQuickMarginMode(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetBorrowAndRepayHistoryInQuickMarginMode(contextGenerate(), currency.EMPTYPAIR, currency.BTC, "borrow", "", "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetVIPInterestAccruedData(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetVIPInterestAccruedData(contextGenerate(), currency.ETH, "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetVIPInterestDeductedData(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetVIPInterestDeductedData(contextGenerate(), currency.ETH, "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetVIPLoanOrderList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetVIPLoanOrderList(contextGenerate(), "", "1", currency.BTC, time.Time{}, time.Now(), 20) require.NoError(t, err) assert.NotNil(t, result) } func TestGetVIPLoanOrderDetail(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetVIPLoanOrderDetail(contextGenerate(), "123456", currency.BTC, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestSetRiskOffsetType(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetRiskOffsetType(contextGenerate(), "3") require.NoError(t, err) assert.NotNil(t, result) } func TestActivateOption(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.ActivateOption(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestSetAutoLoan(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.SetAutoLoan(contextGenerate(), true) require.NoError(t, err) assert.NotNil(t, result) } func TestSetAccountMode(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetAccountMode(contextGenerate(), "1") require.NoError(t, err) assert.NotNil(t, result) } func TestResetMMPStatus(t *testing.T) { t.Parallel() _, err := e.ResetMMPStatus(contextGenerate(), instTypeOption, "") require.ErrorIs(t, err, errInstrumentFamilyRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ResetMMPStatus(contextGenerate(), instTypeOption, "BTC-USD") require.NoError(t, err) assert.NotNil(t, result) } func TestSetMMP(t *testing.T) { t.Parallel() _, err := e.SetMMP(contextGenerate(), &MMPConfig{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetMMP(contextGenerate(), &MMPConfig{ TimeInterval: 5000, }) require.ErrorIs(t, err, errInstrumentFamilyRequired) _, err = e.SetMMP(contextGenerate(), &MMPConfig{ InstrumentFamily: "BTC-USD", }) require.ErrorIs(t, err, errInvalidQuantityLimit) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetMMP(contextGenerate(), &MMPConfig{ InstrumentFamily: "BTC-USD", TimeInterval: 5000, FrozenInterval: 2000, QuantityLimit: 100, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMMPConfig(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMMPConfig(contextGenerate(), "BTC-USD") require.NoError(t, err) assert.NotNil(t, result) } func TestMassCancelOrder(t *testing.T) { t.Parallel() _, err := e.CancelAllMMPOrders(contextGenerate(), "", "BTC-USD", 2000) require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.CancelAllMMPOrders(contextGenerate(), "OPTION", "", 2000) require.ErrorIs(t, err, errInstrumentFamilyRequired) _, err = e.CancelAllMMPOrders(contextGenerate(), "OPTION", "BTC-USD", -1) require.ErrorIs(t, err, errMissingIntervalValue) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllMMPOrders(contextGenerate(), "OPTION", "BTC-USD", 2000) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllDelayed(t *testing.T) { t.Parallel() _, err := e.CancelAllDelayed(contextGenerate(), 2, "") require.ErrorIs(t, err, errCountdownTimeoutRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllDelayed(contextGenerate(), 60, "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetTradeAccountRateLimit(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetTradeAccountRateLimit(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestPreCheckOrder(t *testing.T) { t.Parallel() _, err := e.PreCheckOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) arg := &OrderPreCheckParams{ ClientOrderID: "b15", } _, err = e.PreCheckOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.PreCheckOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) arg.TradeMode = "cash" _, err = e.PreCheckOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) arg.Side = "buy" _, err = e.PreCheckOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = "limit" _, err = e.PreCheckOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PreCheckOrder(contextGenerate(), &OrderPreCheckParams{ InstrumentID: mainPair.String(), TradeMode: "cash", ClientOrderID: "b15", Side: order.Buy.Lower(), OrderType: "limit", Price: 2.15, Size: 2, }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendAlgoOrder(t *testing.T) { t.Parallel() _, err := e.AmendAlgoOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.AmendAlgoOrder(contextGenerate(), &AmendAlgoOrderParam{NewSize: 2}) require.ErrorIs(t, err, errMissingInstrumentID) _, err = e.AmendAlgoOrder(contextGenerate(), &AmendAlgoOrderParam{ InstrumentID: perpetualSwapPair.String(), NewSize: 2, }) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendAlgoOrder(contextGenerate(), &AmendAlgoOrderParam{ AlgoID: "2510789768709120", InstrumentID: perpetualSwapPair.String(), NewSize: 2, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAlgoOrderDetail(t *testing.T) { t.Parallel() _, err := e.GetAlgoOrderDetail(contextGenerate(), "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAlgoOrderDetail(contextGenerate(), "1234231231423", "") require.NoError(t, err) assert.NotNil(t, result) } func TestClosePositionForContractID(t *testing.T) { t.Parallel() _, err := e.ClosePositionForContractID(contextGenerate(), &ClosePositionParams{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.ClosePositionForContractID(contextGenerate(), &ClosePositionParams{AlgoID: "", MarketCloseAllPositions: true}) require.ErrorIs(t, err, errAlgoIDRequired) _, err = e.ClosePositionForContractID(contextGenerate(), &ClosePositionParams{AlgoID: "448965992920907776", MarketCloseAllPositions: false}) require.ErrorIs(t, err, order.ErrAmountMustBeSet) _, err = e.ClosePositionForContractID(contextGenerate(), &ClosePositionParams{AlgoID: "448965992920907776", MarketCloseAllPositions: false, Size: 123}) require.ErrorIs(t, err, limits.ErrPriceBelowMin) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.ClosePositionForContractID(contextGenerate(), &ClosePositionParams{ AlgoID: "448965992920907776", MarketCloseAllPositions: true, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelClosePositionOrderForContractGrid(t *testing.T) { t.Parallel() _, err := e.CancelClosePositionOrderForContractGrid(contextGenerate(), &CancelClosePositionOrder{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CancelClosePositionOrderForContractGrid(contextGenerate(), &CancelClosePositionOrder{OrderID: "570627699870375936"}) require.ErrorIs(t, err, errAlgoIDRequired) _, err = e.CancelClosePositionOrderForContractGrid(contextGenerate(), &CancelClosePositionOrder{AlgoID: "448965992920907776"}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelClosePositionOrderForContractGrid(contextGenerate(), &CancelClosePositionOrder{ AlgoID: "448965992920907776", OrderID: "570627699870375936", }) require.NoError(t, err) assert.NotNil(t, result) } func TestInstantTriggerGridAlgoOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.InstantTriggerGridAlgoOrder(contextGenerate(), "123456789") require.NoError(t, err) assert.NotNil(t, result) } func TestComputeMinInvestment(t *testing.T) { t.Parallel() arg := &ComputeInvestmentDataParam{ RunType: "1", } _, err := e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.InstrumentID = mainPair.String() _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidAlgoOrderType) arg.AlgoOrderType = "grid" _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.MaxPrice = 5000 _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.MinPrice = 5000 _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidGridQuantity) arg.GridNumber = 1234 arg.RunType = "" _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errRunTypeRequired) arg.RunType = "1" arg.AlgoOrderType = "contract_grid" _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errMissingRequiredArgumentDirection) arg.Direction = positionSideLong _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidLeverage) arg.Leverage = 5 arg.InvestmentData = []InvestmentData{{Currency: currency.ETH}} _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.InvestmentData = []InvestmentData{{Amount: 0.01}} _, err = e.ComputeMinInvestment(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) result, err := e.ComputeMinInvestment(contextGenerate(), &ComputeInvestmentDataParam{ InstrumentID: mainPair.String(), AlgoOrderType: "grid", GridNumber: 50, MaxPrice: 5000, MinPrice: 3000, RunType: "1", InvestmentData: []InvestmentData{ { Amount: 0.01, Currency: currency.BTC, }, { Amount: 100, Currency: currency.USDT, }, }, }) require.NoError(t, err) assert.NotNil(t, result) } func TestRSIBackTesting(t *testing.T) { t.Parallel() _, err := e.RSIBackTesting(contextGenerate(), "", "", "", 50, 14, kline.FiveMin) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.RSIBackTesting(contextGenerate(), mainPair.String(), "", "", 50, 14, kline.FiveMin) require.NoError(t, err) assert.NotNil(t, result) } func TestSignalBotTrading(t *testing.T) { t.Parallel() _, err := e.GetSignalBotOrderDetail(contextGenerate(), "", "623833708424069120") require.ErrorIs(t, err, errInvalidAlgoOrderType) _, err = e.GetSignalBotOrderDetail(contextGenerate(), "contract", "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.GetSignalBotOrderDetail(contextGenerate(), "contract", "623833708424069120") require.NoError(t, err) assert.NotNil(t, result) } func TestGetSignalOrderPositions(t *testing.T) { t.Parallel() _, err := e.GetSignalOrderPositions(contextGenerate(), "", "623833708424069120") require.ErrorIs(t, err, errInvalidAlgoOrderType) _, err = e.GetSignalOrderPositions(contextGenerate(), "contract", "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSignalOrderPositions(contextGenerate(), "contract", "623833708424069120") require.NoError(t, err) assert.NotNil(t, result) } func TestGetSignalBotSubOrders(t *testing.T) { t.Parallel() _, err := e.GetSignalBotSubOrders(contextGenerate(), "", "contract", "filled", "", "", "", time.Time{}, time.Time{}, 0) require.ErrorIs(t, err, errAlgoIDRequired) _, err = e.GetSignalBotSubOrders(contextGenerate(), "623833708424069120", "", "filled", "", "", "", time.Time{}, time.Time{}, 0) require.ErrorIs(t, err, errInvalidAlgoOrderType) _, err = e.GetSignalBotSubOrders(contextGenerate(), "623833708424069120", "contract", "", "", "", "", time.Time{}, time.Time{}, 0) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSignalBotSubOrders(contextGenerate(), "623833708424069120", "contract", "filled", "", "", "", time.Time{}, time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSignalBotEventHistory(t *testing.T) { t.Parallel() _, err := e.GetSignalBotEventHistory(contextGenerate(), "", time.Time{}, time.Now(), 50) require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSignalBotEventHistory(contextGenerate(), "12345", time.Time{}, time.Now(), 50) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceRecurringBuyOrder(t *testing.T) { t.Parallel() _, err := e.PlaceRecurringBuyOrder(contextGenerate(), nil) require.ErrorIs(t, err, common.ErrNilPointer) arg := &PlaceRecurringBuyOrderParam{ TimeZone: "3", } _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, errStrategyNameRequired) arg.StrategyName = "BTC|ETH recurring buy monthly" _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, common.ErrEmptyParams) arg.RecurringList = []RecurringListItem{{}} _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.RecurringList = []RecurringListItem{{Currency: currency.BTC}} _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, errRecurringDayRequired) arg.RecurringDay = "1" arg.RecurringTime = -10 _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, errRecurringBuyTimeRequired) arg.RecurringTime = 2 _, err = e.PlaceRecurringBuyOrder(contextGenerate(), arg) require.ErrorIs(t, err, errInvalidTradeModeValue) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceRecurringBuyOrder(contextGenerate(), &PlaceRecurringBuyOrderParam{ StrategyName: "BTC|ETH recurring buy monthly", Amount: 100, RecurringList: []RecurringListItem{ { Currency: currency.BTC, Ratio: 0.2, }, { Currency: currency.ETH, Ratio: 0.8, }, }, Period: "monthly", RecurringDay: "1", RecurringTime: 0, TimeZone: "8", // UTC +8 TradeMode: "cross", InvestmentCurrency: "USDT", }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendRecurringBuyOrder(t *testing.T) { t.Parallel() _, err := e.AmendRecurringBuyOrder(contextGenerate(), &AmendRecurringOrderParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.AmendRecurringBuyOrder(contextGenerate(), &AmendRecurringOrderParam{StrategyName: "stg1"}) require.ErrorIs(t, err, errAlgoIDRequired) _, err = e.AmendRecurringBuyOrder(contextGenerate(), &AmendRecurringOrderParam{AlgoID: "448965992920907776"}) require.ErrorIs(t, err, errStrategyNameRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendRecurringBuyOrder(contextGenerate(), &AmendRecurringOrderParam{ AlgoID: "448965992920907776", StrategyName: "stg1", }) require.NoError(t, err) assert.NotNil(t, result) } func TestStopRecurringBuyOrder(t *testing.T) { t.Parallel() _, err := e.StopRecurringBuyOrder(contextGenerate(), []StopRecurringBuyOrder{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.StopRecurringBuyOrder(contextGenerate(), []StopRecurringBuyOrder{{}}) require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.StopRecurringBuyOrder(contextGenerate(), []StopRecurringBuyOrder{{AlgoID: "1232323434234"}}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetRecurringBuyOrderList(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRecurringBuyOrderList(contextGenerate(), "", "paused", time.Time{}, time.Time{}, 30) require.NoError(t, err) assert.NotNil(t, result) } func TestGetRecurringBuyOrderHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRecurringBuyOrderHistory(contextGenerate(), "", time.Time{}, time.Time{}, 30) require.NoError(t, err) assert.NotNil(t, result) } func TestGetRecurringOrderDetails(t *testing.T) { t.Parallel() _, err := e.GetRecurringOrderDetails(contextGenerate(), "", "") require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRecurringOrderDetails(contextGenerate(), "560473220642766848", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetRecurringSubOrders(t *testing.T) { t.Parallel() _, err := e.GetRecurringSubOrders(contextGenerate(), "", "123422", time.Time{}, time.Now(), 0) require.ErrorIs(t, err, errAlgoIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetRecurringSubOrders(contextGenerate(), "560473220642766848", "123422", time.Time{}, time.Now(), 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetExistingLeadingPositions(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetExistingLeadingPositions(contextGenerate(), instTypeSpot, mainPair.String(), time.Now(), time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeadingPositionsHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLeadingPositionsHistory(contextGenerate(), "OPTION", "", time.Time{}, time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceLeadingStopOrder(t *testing.T) { t.Parallel() arg := &TPSLOrderParam{} _, err := e.PlaceLeadingStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, common.ErrEmptyParams) arg.Tag = "1235454" _, err = e.PlaceLeadingStopOrder(contextGenerate(), arg) require.ErrorIs(t, err, errSubPositionIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceLeadingStopOrder(contextGenerate(), &TPSLOrderParam{ SubPositionID: "1235454", TakeProfitTriggerPrice: 123455, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCloseLeadingPosition(t *testing.T) { t.Parallel() _, err := e.CloseLeadingPosition(contextGenerate(), &CloseLeadingPositionParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.CloseLeadingPosition(contextGenerate(), &CloseLeadingPositionParam{Tag: "tag-here"}) require.ErrorIs(t, err, errSubPositionIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CloseLeadingPosition(contextGenerate(), &CloseLeadingPositionParam{ SubPositionID: "518541406042591232", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeadingInstrument(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLeadingInstrument(contextGenerate(), "SWAP") require.NoError(t, err) assert.NotNil(t, result) } func TestAmendLeadingInstruments(t *testing.T) { t.Parallel() _, err := e.AmendLeadingInstruments(contextGenerate(), "", "") require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendLeadingInstruments(contextGenerate(), perpetualSwapPair.String(), "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetProfitSharingDetails(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetProfitSharingDetails(contextGenerate(), "", time.Now(), time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTotalProfitSharing(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetTotalProfitSharing(contextGenerate(), "SWAP") require.NoError(t, err) assert.NotNil(t, result) } func TestGetUnrealizedProfitSharingDetails(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetUnrealizedProfitSharingDetails(contextGenerate(), "SWAP") require.NoError(t, err) assert.NotNil(t, result) } func TestSetFirstCopySettings(t *testing.T) { t.Parallel() _, err := e.AmendCopySettings(contextGenerate(), &FirstCopySettings{}) require.ErrorIs(t, err, common.ErrEmptyParams) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendCopySettings(contextGenerate(), &FirstCopySettings{ InstrumentType: "SWAP", UniqueCode: "25CD5A80241D6FE6", CopyMarginMode: "cross", CopyInstrumentIDType: "copy", CopyMode: "ratio_copy", CopyRatio: 1, CopyTotalAmount: 500, SubPosCloseType: "copy_close", }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendCopySettings(t *testing.T) { t.Parallel() _, err := e.SetFirstCopySettings(contextGenerate(), &FirstCopySettings{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &FirstCopySettings{ CopyMode: "ratio_copy", } _, err = e.SetFirstCopySettings(contextGenerate(), arg) require.ErrorIs(t, err, errUniqueCodeRequired) arg.UniqueCode = "25CD5A80241D6FE6" _, err = e.SetFirstCopySettings(contextGenerate(), arg) require.ErrorIs(t, err, errCopyInstrumentIDTypeRequired) arg.CopyInstrumentIDType = "copy" _, err = e.SetFirstCopySettings(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.CopyTotalAmount = 500 _, err = e.SetFirstCopySettings(contextGenerate(), arg) require.ErrorIs(t, err, errSubPositionCloseTypeRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.SetFirstCopySettings(contextGenerate(), &FirstCopySettings{ InstrumentType: "SWAP", UniqueCode: "25CD5A80241D6FE6", CopyMarginMode: "cross", CopyInstrumentIDType: "copy", CopyMode: "ratio_copy", CopyRatio: 1, CopyTotalAmount: 500, SubPosCloseType: "copy_close", }) require.NoError(t, err) assert.NotNil(t, result) } func TestStopCopying(t *testing.T) { t.Parallel() _, err := e.StopCopying(contextGenerate(), &StopCopyingParameter{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.StopCopying(contextGenerate(), &StopCopyingParameter{ InstrumentType: "SWAP", SubPositionCloseType: "manual_close", }) require.ErrorIs(t, err, errUniqueCodeRequired) _, err = e.StopCopying(contextGenerate(), &StopCopyingParameter{ InstrumentType: "SWAP", UniqueCode: "25CD5A80241D6FE6", }) require.ErrorIs(t, err, errSubPositionCloseTypeRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.StopCopying(contextGenerate(), &StopCopyingParameter{ InstrumentType: "SWAP", UniqueCode: "25CD5A80241D6FE6", SubPositionCloseType: "manual_close", }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCopySettings(t *testing.T) { t.Parallel() _, err := e.GetCopySettings(contextGenerate(), "SWAP", "") require.ErrorIs(t, err, errUniqueCodeRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCopySettings(contextGenerate(), "SWAP", "213E8C92DC61EFAC") require.NoError(t, err) assert.NotNil(t, result) } func TestGetMultipleLeverages(t *testing.T) { t.Parallel() _, err := e.GetMultipleLeverages(contextGenerate(), "", "213E8C92DC61EFAC", "") require.ErrorIs(t, err, margin.ErrInvalidMarginType) _, err = e.GetMultipleLeverages(contextGenerate(), "isolated", "", "") require.ErrorIs(t, err, errUniqueCodeRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMultipleLeverages(contextGenerate(), "isolated", "213E8C92DC61EFAC", "") require.NoError(t, err) assert.NotNil(t, result) } func TestSetMultipleLeverages(t *testing.T) { t.Parallel() _, err := e.SetMultipleLeverages(contextGenerate(), &SetLeveragesParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.SetMultipleLeverages(contextGenerate(), &SetLeveragesParam{Leverage: 5}) require.ErrorIs(t, err, margin.ErrInvalidMarginType) _, err = e.SetMultipleLeverages(contextGenerate(), &SetLeveragesParam{MarginMode: "cross"}) require.ErrorIs(t, err, errInvalidLeverage) _, err = e.SetMultipleLeverages(contextGenerate(), &SetLeveragesParam{ MarginMode: "cross", Leverage: 5, }) require.ErrorIs(t, err, errMissingInstrumentID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.SetMultipleLeverages(contextGenerate(), &SetLeveragesParam{ MarginMode: "cross", Leverage: 5, InstrumentID: mainPair.String(), }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetMyLeadTraders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetMyLeadTraders(contextGenerate(), "SWAP") require.NoError(t, err) assert.NotNil(t, result) } func TestGetHistoryLeadTraders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetHistoryLeadTraders(contextGenerate(), "", "", "", 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetWeeklyTraderProfitAndLoss(t *testing.T) { t.Parallel() _, err := e.GetWeeklyTraderProfitAndLoss(contextGenerate(), "", "") require.ErrorIs(t, err, errUniqueCodeRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") mainResult, err := e.GetWeeklyTraderProfitAndLoss(contextGenerate(), "", leadTraderUniqueID) require.NoError(t, err) assert.NotNil(t, mainResult) } func TestGetDailyLeadTraderPNL(t *testing.T) { t.Parallel() _, err := e.GetDailyLeadTraderPNL(contextGenerate(), "SWAP", "", "2") require.ErrorIs(t, err, errUniqueCodeRequired) _, err = e.GetDailyLeadTraderPNL(contextGenerate(), "SWAP", "WOOF", "") require.ErrorIs(t, err, errLastDaysRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") mainResult, err := e.GetDailyLeadTraderPNL(contextGenerate(), "SWAP", leadTraderUniqueID, "2") require.NoError(t, err) assert.NotNil(t, mainResult) } func TestGetLeadTraderStats(t *testing.T) { t.Parallel() _, err := e.GetLeadTraderStats(contextGenerate(), "SWAP", "", "2") require.ErrorIs(t, err, errUniqueCodeRequired) _, err = e.GetLeadTraderStats(contextGenerate(), "SWAP", "RAWR", "") require.ErrorIs(t, err, errLastDaysRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") result, err := e.GetLeadTraderStats(contextGenerate(), "SWAP", leadTraderUniqueID, "2") require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeadTraderCurrencyPreferences(t *testing.T) { t.Parallel() _, err := e.GetLeadTraderCurrencyPreferences(contextGenerate(), "SWAP", "", "2") require.ErrorIs(t, err, errUniqueCodeRequired) _, err = e.GetLeadTraderCurrencyPreferences(contextGenerate(), "SWAP", "MEOW", "") require.ErrorIs(t, err, errLastDaysRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") result, err := e.GetLeadTraderCurrencyPreferences(contextGenerate(), "SWAP", leadTraderUniqueID, "2") require.NoError(t, err) assert.NotNil(t, result) } func TestGetLeadTraderCurrentLeadPositions(t *testing.T) { t.Parallel() _, err := e.GetLeadTraderCurrentLeadPositions(contextGenerate(), instTypeSwap, "", "", "", 10) require.ErrorIs(t, err, errUniqueCodeRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") _, err = e.GetLeadTraderCurrentLeadPositions(contextGenerate(), "SWAP", leadTraderUniqueID, "", "", 10) require.NoError(t, err) // No test validation of positions performed as the lead trader may not have any positions open } func TestGetLeadTraderLeadPositionHistory(t *testing.T) { t.Parallel() _, err := e.GetLeadTraderLeadPositionHistory(contextGenerate(), "SWAP", "", "", "", 10) require.ErrorIs(t, err, errUniqueCodeRequired) require.NoError(t, syncLeadTraderUniqueID(t), "syncLeadTraderUniqueID must not error") result, err := e.GetLeadTraderLeadPositionHistory(contextGenerate(), "SWAP", leadTraderUniqueID, "", "", 10) require.NoError(t, err) assert.NotNil(t, result) } func TestPlaceSpreadOrder(t *testing.T) { t.Parallel() _, err := e.PlaceSpreadOrder(contextGenerate(), &SpreadOrderParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &SpreadOrderParam{Tag: "tag-here"} _, err = e.PlaceSpreadOrder(contextGenerate(), arg) require.ErrorIs(t, err, errMissingInstrumentID) arg.SpreadID = spreadPair.String() _, err = e.PlaceSpreadOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrTypeIsInvalid) arg.OrderType = "limit" _, err = e.PlaceSpreadOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Size = 1 _, err = e.PlaceSpreadOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrPriceBelowMin) arg.Price = 12345 _, err = e.PlaceSpreadOrder(contextGenerate(), arg) require.ErrorIs(t, err, order.ErrSideIsInvalid) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceSpreadOrder(contextGenerate(), &SpreadOrderParam{ InstrumentID: spreadPair.String(), SpreadID: "1234", ClientOrderID: "12354123523", Side: order.Buy.Lower(), OrderType: "limit", Size: 1, Price: 12345, }) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelSpreadOrder(t *testing.T) { t.Parallel() _, err := e.CancelSpreadOrder(contextGenerate(), "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelSpreadOrder(request.WithVerbose(contextGenerate()), "12345", "") require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllSpreadOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllSpreadOrders(contextGenerate(), "123456") require.NoError(t, err) assert.NotNil(t, result) } func TestAmendSpreadOrder(t *testing.T) { t.Parallel() _, err := e.AmendSpreadOrder(contextGenerate(), &AmendSpreadOrderParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) _, err = e.AmendSpreadOrder(contextGenerate(), &AmendSpreadOrderParam{NewSize: 2}) require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.AmendSpreadOrder(contextGenerate(), &AmendSpreadOrderParam{OrderID: "2510789768709120"}) require.ErrorIs(t, err, errSizeOrPriceIsRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendSpreadOrder(contextGenerate(), &AmendSpreadOrderParam{ OrderID: "2510789768709120", NewSize: 2, }) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreadOrderDetails(t *testing.T) { t.Parallel() _, err := e.GetSpreadOrderDetails(contextGenerate(), "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSpreadOrderDetails(contextGenerate(), "1234567", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetActiveSpreadOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetActiveSpreadOrders(contextGenerate(), "", "post_only", "partially_filled", "", "", 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetCompletedSpreadOrdersLast7Days(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetCompletedSpreadOrdersLast7Days(contextGenerate(), "", "limit", "canceled", "", "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreadTradesOfLast7Days(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetSpreadTradesOfLast7Days(contextGenerate(), "", "", "", "", "", time.Time{}, time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreads(t *testing.T) { t.Parallel() result, err := e.GetPublicSpreads(contextGenerate(), "", "", "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreadOrderBooks(t *testing.T) { t.Parallel() _, err := e.GetPublicSpreadOrderBooks(contextGenerate(), "", 0) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetPublicSpreadOrderBooks(contextGenerate(), "BTC-USDT_BTC-USDT-SWAP", 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreadTickers(t *testing.T) { t.Parallel() _, err := e.GetPublicSpreadTickers(contextGenerate(), "") require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetPublicSpreadTickers(contextGenerate(), "BTC-USDT_BTC-USDT-SWAP") require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicSpreadTrades(t *testing.T) { t.Parallel() result, err := e.GetPublicSpreadTrades(contextGenerate(), "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetSpreadCandlesticks(t *testing.T) { t.Parallel() _, err := e.GetSpreadCandlesticks(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetSpreadCandlesticks(contextGenerate(), spreadPair.String(), kline.FiveMin, time.Now().AddDate(0, 0, -1), time.Now(), 10) require.NoError(t, err, "GetSpreadCandlesticks must not error") assert.NotEmpty(t, result, "GetSpreadCandlesticks should not return an empty result") } func TestGetSpreadCandlesticksHistory(t *testing.T) { t.Parallel() _, err := e.GetSpreadCandlesticksHistory(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetSpreadCandlesticksHistory(contextGenerate(), spreadPair.String(), kline.FiveMin, time.Now().AddDate(0, 0, -1), time.Now(), 10) require.NoError(t, err, "GetSpreadCandlesticksHistory must not error") assert.NotEmpty(t, result, "GetSpreadCandlesticksHistory should not return an empty result") } func TestGetOptionsTickBands(t *testing.T) { t.Parallel() _, err := e.GetOptionsTickBands(contextGenerate(), "", "") require.ErrorIs(t, err, errInvalidInstrumentType) result, err := e.GetOptionsTickBands(contextGenerate(), "OPTION", "") require.NoError(t, err) assert.NotNil(t, result) } func TestExtractIndexCandlestick(t *testing.T) { t.Parallel() data := []byte(`[ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "1" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "1" ]]`) var resp []CandlestickHistoryItem err := json.Unmarshal(data, &resp) require.NoError(t, err) require.Len(t, resp, 2) require.Equal(t, 3.743, resp[0].HighestPrice.Float64()) require.Equal(t, StateCompleted, resp[0].Confirm) } func TestGetHistoricIndexAndMarkPriceCandlesticks(t *testing.T) { t.Parallel() _, err := e.GetHistoricIndexCandlesticksHistory(contextGenerate(), "", time.Time{}, time.Time{}, kline.FiveMin, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetHistoricIndexCandlesticksHistory(contextGenerate(), "BTC-USD", time.Time{}, time.Time{}, kline.FiveMin, 10) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.GetMarkPriceCandlestickHistory(contextGenerate(), perpetualSwapPair.String(), time.Time{}, time.Time{}, kline.FiveMin, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetEconomicCanendarData(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetEconomicCalendarData(contextGenerate(), "", "", time.Now(), time.Time{}, 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetDepositWithdrawalStatus(t *testing.T) { t.Parallel() _, err := e.GetDepositWithdrawalStatus(contextGenerate(), currency.EMPTYCODE, "", "", "", "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) _, err = e.GetDepositWithdrawalStatus(contextGenerate(), currency.EMPTYCODE, "", "1244", "", "") require.ErrorIs(t, err, errMissingValidWithdrawalID) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetDepositWithdrawalStatus(contextGenerate(), currency.EMPTYCODE, "1244", "", "", "") require.NoError(t, err) assert.NotNil(t, result) } func TestGetPublicExchangeList(t *testing.T) { t.Parallel() result, err := e.GetPublicExchangeList(contextGenerate()) require.NoError(t, err) assert.NotNil(t, result) } func TestGetInviteesDetail(t *testing.T) { t.Parallel() _, err := e.GetInviteesDetail(contextGenerate(), "") require.ErrorIs(t, err, errUserIDRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetInviteesDetail(contextGenerate(), "1234") require.NoError(t, err) assert.NotNil(t, result) } func TestGetUserAffilateRebateInformation(t *testing.T) { t.Parallel() _, err := e.GetUserAffiliateRebateInformation(contextGenerate(), "") require.ErrorIs(t, err, errInvalidAPIKey) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetUserAffiliateRebateInformation(contextGenerate(), "1234") require.NoError(t, err) assert.NotNil(t, result) } func TestGetOpenInterest(t *testing.T) { t.Parallel() _, err := e.GetOpenInterest(contextGenerate(), key.PairAsset{ Base: currency.ETH.Item, Quote: currency.USDT.Item, Asset: asset.USDTMarginedFutures, }) require.ErrorIs(t, err, asset.ErrNotSupported) usdSwapCode := currency.NewCode("USD-SWAP") resp, err := e.GetOpenInterest(contextGenerate(), key.PairAsset{ Base: perpetualSwapPair.Base.Item, Quote: perpetualSwapPair.Quote.Item, Asset: asset.PerpetualSwap, }) assert.NoError(t, err) assert.NotEmpty(t, resp) cp1 := currency.NewPair(currency.DOGE, usdSwapCode) sharedtestvalues.SetupCurrencyPairsForExchangeAsset(t, e, asset.PerpetualSwap, cp1) resp, err = e.GetOpenInterest(contextGenerate(), key.PairAsset{ Base: currency.BTC.Item, Quote: usdSwapCode.Item, Asset: asset.PerpetualSwap, }, key.PairAsset{ Base: cp1.Base.Item, Quote: cp1.Quote.Item, Asset: asset.PerpetualSwap, }, ) assert.NoError(t, err) assert.NotEmpty(t, resp) resp, err = e.GetOpenInterest(contextGenerate()) assert.NoError(t, err) assert.NotEmpty(t, resp) } func TestGetCurrencyTradeURL(t *testing.T) { t.Parallel() testexch.UpdatePairsOnce(t, e) for _, a := range e.GetAssetTypes(false) { pairs, err := e.CurrencyPairs.GetPairs(a, false) assert.NoError(t, err) assert.NotEmpty(t, pairs) resp, err := e.GetCurrencyTradeURL(contextGenerate(), a, pairs[0]) assert.NoError(t, err) assert.NotEmpty(t, resp) } } func TestPlaceLendingOrder(t *testing.T) { t.Parallel() _, err := e.PlaceLendingOrder(contextGenerate(), &LendingOrderParam{}) require.ErrorIs(t, err, common.ErrEmptyParams) arg := &LendingOrderParam{AutoRenewal: true} _, err = e.PlaceLendingOrder(contextGenerate(), arg) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) arg.Currency = currency.USDT _, err = e.PlaceLendingOrder(contextGenerate(), arg) require.ErrorIs(t, err, limits.ErrAmountBelowMin) arg.Amount = 1 _, err = e.PlaceLendingOrder(contextGenerate(), arg) require.ErrorIs(t, err, errRateRequired) arg.Rate = 0.01 _, err = e.PlaceLendingOrder(contextGenerate(), arg) require.ErrorIs(t, err, errLendingTermIsRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.PlaceLendingOrder(contextGenerate(), &LendingOrderParam{ Currency: currency.USDT, Amount: 1, Rate: 0.01, Term: "30D", AutoRenewal: true, }) require.NoError(t, err) assert.NotNil(t, result) } func TestAmendLendingOrder(t *testing.T) { t.Parallel() _, err := e.AmendLendingOrder(contextGenerate(), "", 0, 0, false) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.AmendLendingOrder(contextGenerate(), "12312312", 1., 2., true) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLendingOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLendingOrders(contextGenerate(), "", "pending", currency.ETH, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetLendingSubOrderList(t *testing.T) { t.Parallel() _, err := e.GetLendingSubOrderList(contextGenerate(), "", "pending", time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetLendingSubOrderList(contextGenerate(), "12345", "", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelAllSpreadOrdersAfterCountdown(t *testing.T) { t.Parallel() _, err := e.CancelAllSpreadOrdersAfterCountdown(contextGenerate(), 2) require.ErrorIs(t, err, errCountdownTimeoutRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CancelAllSpreadOrdersAfterCountdown(contextGenerate(), 12) require.NoError(t, err) assert.NotNil(t, result) } func TestGetContractsOpenInterestHistory(t *testing.T) { t.Parallel() _, err := e.GetFuturesContractsOpenInterestHistory(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetFuturesContractsOpenInterestHistory(contextGenerate(), perpetualSwapPair.String(), kline.FiveMin, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFuturesContractTakerVolume(t *testing.T) { t.Parallel() _, err := e.GetFuturesContractTakerVolume(contextGenerate(), "", kline.FiveMin, 1, 10, time.Time{}, time.Time{}) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetFuturesContractTakerVolume(contextGenerate(), perpetualSwapPair.String(), kline.FiveMin, 1, 10, time.Time{}, time.Time{}) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFuturesContractLongShortAccountRatio(t *testing.T) { t.Parallel() _, err := e.GetFuturesContractLongShortAccountRatio(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetFuturesContractLongShortAccountRatio(contextGenerate(), perpetualSwapPair.String(), kline.FiveMin, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTopTradersFuturesContractLongShortRatio(t *testing.T) { t.Parallel() _, err := e.GetTopTradersFuturesContractLongShortAccountRatio(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetTopTradersFuturesContractLongShortAccountRatio(contextGenerate(), perpetualSwapPair.String(), kline.FiveMin, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetTopTradersFuturesContractLongShortPositionRatio(t *testing.T) { t.Parallel() _, err := e.GetTopTradersFuturesContractLongShortPositionRatio(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetTopTradersFuturesContractLongShortPositionRatio(contextGenerate(), perpetualSwapPair.String(), kline.FiveMin, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAccountInstruments(t *testing.T) { t.Parallel() _, err := e.GetAccountInstruments(contextGenerate(), asset.Empty, "", "", mainPair.String()) require.ErrorIs(t, err, errInvalidInstrumentType) _, err = e.GetAccountInstruments(contextGenerate(), asset.Futures, "", "", mainPair.String()) require.ErrorIs(t, err, errInvalidUnderlying) _, err = e.GetAccountInstruments(contextGenerate(), asset.Options, "", "", mainPair.String()) require.ErrorIs(t, err, errInstrumentFamilyOrUnderlyingRequired) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetAccountInstruments(contextGenerate(), asset.Spot, "", "", mainPair.String()) assert.NoError(t, err) assert.NotNil(t, result) result, err = e.GetAccountInstruments(contextGenerate(), asset.PerpetualSwap, "", mainPair.String(), perpetualSwapPair.String()) assert.NoError(t, err) assert.NotNil(t, result) testexch.UpdatePairsOnce(t, e) p, err := e.GetEnabledPairs(asset.Options) require.NoError(t, err, "GetEnabledPairs must not error") require.NotEmpty(t, p, "GetEnabledPairs must not return empty pairs") uly := p[0].Base.String() idx := strings.Index(p[0].Quote.String(), "-") require.NotEqual(t, -1, idx, "strings.Index must find a hyphen") uly += "-" + p[0].Quote.String()[:idx] result, err = e.GetAccountInstruments(contextGenerate(), asset.Options, uly, "", p[0].String()) require.NoError(t, err) assert.NotNil(t, result) } func TestOrderTypeString(t *testing.T) { t.Parallel() type OrderTypeWithTIF struct { OrderType order.Type TIF order.TimeInForce } orderTypesToStringMap := map[OrderTypeWithTIF]struct { Expected string Error error }{ {OrderType: order.Market, TIF: order.UnknownTIF}: {Expected: orderMarket}, {OrderType: order.Limit, TIF: order.UnknownTIF}: {Expected: orderLimit}, {OrderType: order.Limit, TIF: order.PostOnly}: {Expected: orderPostOnly}, {OrderType: order.Market, TIF: order.FillOrKill}: {Expected: orderFOK}, {OrderType: order.Market, TIF: order.ImmediateOrCancel}: {Expected: orderIOC}, {OrderType: order.OptimalLimit, TIF: order.ImmediateOrCancel}: {Expected: orderOptimalLimitIOC}, {OrderType: order.MarketMakerProtection, TIF: order.UnknownTIF}: {Expected: orderMarketMakerProtection}, {OrderType: order.MarketMakerProtection, TIF: order.PostOnly}: {Expected: orderMarketMakerProtectionAndPostOnly}, {OrderType: order.Liquidation, TIF: order.UnknownTIF}: {Error: order.ErrUnsupportedOrderType}, {OrderType: order.OCO, TIF: order.UnknownTIF}: {Expected: orderOCO}, {OrderType: order.TrailingStop, TIF: order.UnknownTIF}: {Expected: orderMoveOrderStop}, {OrderType: order.Chase, TIF: order.UnknownTIF}: {Expected: orderChase}, {OrderType: order.TWAP, TIF: order.UnknownTIF}: {Expected: orderTWAP}, {OrderType: order.ConditionalStop, TIF: order.UnknownTIF}: {Expected: orderConditional}, {OrderType: order.Chase, TIF: order.GoodTillCancel}: {Expected: orderChase}, {OrderType: order.TWAP, TIF: order.ImmediateOrCancel}: {Expected: orderTWAP}, {OrderType: order.ConditionalStop, TIF: order.GoodTillDay}: {Expected: orderConditional}, {OrderType: order.Trigger, TIF: order.UnknownTIF}: {Expected: orderTrigger}, {OrderType: order.UnknownType, TIF: order.PostOnly}: {Expected: orderPostOnly}, {OrderType: order.UnknownType, TIF: order.FillOrKill}: {Expected: orderFOK}, {OrderType: order.UnknownType, TIF: order.ImmediateOrCancel}: {Expected: orderIOC}, } for tc, val := range orderTypesToStringMap { t.Run(tc.OrderType.String()+"/"+tc.TIF.String(), func(t *testing.T) { t.Parallel() orderTypeString, err := orderTypeString(tc.OrderType, tc.TIF) require.ErrorIs(t, err, val.Error) assert.Equal(t, val.Expected, orderTypeString) }) } } func TestGetMarkPriceCandlesticks(t *testing.T) { t.Parallel() _, err := e.GetMarkPriceCandlesticks(contextGenerate(), "", kline.FiveMin, time.Time{}, time.Time{}, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetMarkPriceCandlesticks(contextGenerate(), mainPair.String(), kline.FiveMin, time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetHistoricIndexCandlesticksHistory(t *testing.T) { t.Parallel() _, err := e.GetHistoricIndexCandlesticksHistory(contextGenerate(), "", time.Time{}, time.Time{}, kline.TenMin, 10) require.ErrorIs(t, err, errMissingInstrumentID) result, err := e.GetHistoricIndexCandlesticksHistory(contextGenerate(), mainPair.String(), time.Time{}, time.Time{}, kline.FiveMin, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestAssetTypeString(t *testing.T) { t.Parallel() _, err := assetTypeString(asset.LinearContract) require.ErrorIs(t, err, asset.ErrNotSupported) assetTypes := e.GetAssetTypes(false) for a := range assetTypes { if assetTypes[a] == asset.Spread { continue } _, err := assetTypeString(assetTypes[a]) assert.NoError(t, err) } } func TestGetAnnouncements(t *testing.T) { t.Parallel() result, err := e.GetAnnouncements(contextGenerate(), "", 0) require.NoError(t, err) assert.NotNil(t, result) } func TestGetAnnouncementTypes(t *testing.T) { t.Parallel() _, err := e.GetAnnouncementTypes(contextGenerate()) assert.NoError(t, err) // No tests of contents of resp because currently in US based github actions announcement-types returns empty } func TestGetDepositOrderDetail(t *testing.T) { t.Parallel() _, err := e.GetDepositOrderDetail(contextGenerate(), "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetDepositOrderDetail(contextGenerate(), "12312312") require.NoError(t, err) assert.NotNil(t, result) } func TestGetFiatDepositOrderHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFiatDepositOrderHistory(contextGenerate(), currency.USDT, "TR_BANKS", "failed", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestGetWithdrawalOrderDetail(t *testing.T) { t.Parallel() _, err := e.GetWithdrawalOrderDetail(contextGenerate(), "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetWithdrawalOrderDetail(contextGenerate(), "024041201450544699") require.NoError(t, err) assert.NotNil(t, result) } func TestGetFiatWithdrawalOrderHistory(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFiatWithdrawalOrderHistory(contextGenerate(), currency.USDT, "SEPA", "failed", time.Time{}, time.Time{}, 10) require.NoError(t, err) assert.NotNil(t, result) } func TestCancelWithdrawalOrder(t *testing.T) { t.Parallel() _, err := e.CancelWithdrawalOrder(contextGenerate(), "") require.ErrorIs(t, err, order.ErrOrderIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.CancelWithdrawalOrder(contextGenerate(), "124041201450544699") require.NoError(t, err) assert.NotNil(t, result) } func TestCreateWithdrawalOrder(t *testing.T) { t.Parallel() _, err := e.CreateWithdrawalOrder(contextGenerate(), currency.BTC, "", "SEPA", "194a6975e98246538faeb0fab0d502df", 1000) require.ErrorIs(t, err, errIDNotSet) _, err = e.CreateWithdrawalOrder(contextGenerate(), currency.EMPTYCODE, "1231312312", "SEPA", "194a6975e98246538faeb0fab0d502df", 1000) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) _, err = e.CreateWithdrawalOrder(contextGenerate(), currency.BTC, "1231312312", "SEPA", "194a6975e98246538faeb0fab0d502df", 0) require.ErrorIs(t, err, limits.ErrAmountBelowMin) _, err = e.CreateWithdrawalOrder(contextGenerate(), currency.BTC, "1231312312", "", "194a6975e98246538faeb0fab0d502df", 1000) require.ErrorIs(t, err, errPaymentMethodRequired) _, err = e.CreateWithdrawalOrder(contextGenerate(), currency.BTC, "1231312312", "SEPA", "", 1000) require.ErrorIs(t, err, errIDNotSet) sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders) result, err := e.CreateWithdrawalOrder(contextGenerate(), currency.BTC, "1231312312", "SEPA", "194a6975e98246538faeb0fab0d502df", 1000) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFiatWithdrawalPaymentMethods(t *testing.T) { t.Parallel() _, err := e.GetFiatWithdrawalPaymentMethods(contextGenerate(), currency.EMPTYCODE) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFiatWithdrawalPaymentMethods(contextGenerate(), currency.TRY) require.NoError(t, err) assert.NotNil(t, result) } func TestGetFiatDepositPaymentMethods(t *testing.T) { t.Parallel() _, err := e.GetFiatDepositPaymentMethods(contextGenerate(), currency.EMPTYCODE) require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) result, err := e.GetFiatDepositPaymentMethods(contextGenerate(), currency.TRY) require.NoError(t, err) assert.NotNil(t, result) } func (e *Exchange) instrumentFamilyFromInstID(instrumentType, instID string) (string, error) { e.instrumentsInfoMapLock.Lock() defer e.instrumentsInfoMapLock.Unlock() if instrumentType != "" { insts, okay := e.instrumentsInfoMap[instrumentType] if !okay { return "", errInvalidInstrumentType } for a := range insts { if insts[a].InstrumentID.String() == instID { return insts[a].InstrumentFamily, nil } } } else { for _, insts := range e.instrumentsInfoMap { for a := range insts { if insts[a].InstrumentID.String() == instID { return insts[a].InstrumentFamily, nil } } } } return "", fmt.Errorf("instrument family not found for instrument %s", instID) } func TestGenerateSubscriptions(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") e.Websocket.SetCanUseAuthenticatedEndpoints(true) subs, err := e.generateSubscriptions() require.NoError(t, err, "generateSubscriptions must not error") exp := subscription.List{ {Channel: subscription.MyAccountChannel, QualifiedChannel: `{"channel":"account"}`, Authenticated: true}, } var pairs currency.Pairs for _, s := range e.Features.Subscriptions { for _, a := range e.GetAssetTypes(true) { if a == asset.Spread || (s.Asset != asset.All && s.Asset != a) { continue } pairs, err = e.GetEnabledPairs(a) require.NoErrorf(t, err, "GetEnabledPairs %s must not error", a) pairs = common.SortStrings(pairs).Format(currency.PairFormat{Uppercase: true, Delimiter: "-"}) s := s.Clone() //nolint:govet // Intentional lexical scope shadow s.Asset = a name := channelName(s) if isSymbolChannel(s) { for i, p := range pairs { s := s.Clone() //nolint:govet // Intentional lexical scope shadow s.QualifiedChannel = fmt.Sprintf(`{"channel":%q,"instID":%q}`, name, p) s.Pairs = pairs[i : i+1] exp = append(exp, s) } } else { s := s.Clone() //nolint:govet // Intentional lexical scope shadow if isAssetChannel(s) { s.QualifiedChannel = fmt.Sprintf(`{"channel":%q,"instType":%q}`, name, GetInstrumentTypeFromAssetItem(s.Asset)) } else { s.QualifiedChannel = `{"channel":"` + name + `"}` } s.Pairs = pairs exp = append(exp, s) } } } testsubs.EqualLists(t, exp, subs) e.Features.Subscriptions = subscription.List{{Channel: channelGridPositions, Params: map[string]any{"algoId": "42"}}} subs, err = e.generateSubscriptions() require.NoError(t, err, "generateSubscriptions must not error") exp = subscription.List{{Channel: channelGridPositions, Params: map[string]any{"algoId": "42"}, QualifiedChannel: `{"channel":"grid-positions","algoId":"42"}`}} testsubs.EqualLists(t, exp, subs) e.Features.Subscriptions = subscription.List{{Channel: channelGridPositions}} subs, err = e.generateSubscriptions() require.NoError(t, err, "generateSubscriptions must not error") exp = subscription.List{{Channel: channelGridPositions, QualifiedChannel: `{"channel":"grid-positions"}`}} testsubs.EqualLists(t, exp, subs) } func TestBusinessWSCandleSubscriptions(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") err := e.WsConnectBusiness(t.Context()) require.NoError(t, err, "WsConnectBusiness must not error") err = e.BusinessSubscribe(t.Context(), subscription.List{{Channel: channelCandle1D}}) require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) p := currency.Pairs{ mainPair, currency.NewPairWithDelimiter("ETH", "USDT", "-"), currency.NewPairWithDelimiter("OKB", "USDT", "-"), } for i, ch := range []string{channelCandle1D, channelMarkPriceCandle1M, channelIndexCandle1H} { err := e.BusinessSubscribe(t.Context(), subscription.List{{Channel: ch, Pairs: p[i : i+1]}}) require.NoErrorf(t, err, "BusinessSubscribe %s-%s must not error", ch, p[i]) } var got currency.Pairs assert.Eventually(t, func() bool { select { case a := <-e.Websocket.DataHandler: switch v := a.(type) { case websocket.KlineData: got = got.Add(v.Pair) case []CandlestickMarkPrice: if len(v) > 0 { got = got.Add(v[0].Pair) } } default: } return len(got) == 3 }, 4*time.Second, 100*time.Millisecond, "Should eventually get candles from the datahandler") } const ( processSpreadOrderbookJSON = `{"arg":{"channel":"sprd-books5", "sprdId": "BTC-USDT_BTC-USDT-SWAP" }, "data": [ { "asks": [ ["111.06","55154","2"], ["111.07","53276","2"], ["111.08","72435","2"], ["111.09","70312","2"], ["111.1","67272","2"]], "bids": [ ["111.05","57745","2"], ["111.04","57109","2"], ["111.03","69563","2"], ["111.02","71248","2"], ["111.01","65090","2"]], "ts": "1670324386802"}]}` wsProcessPublicSpreadTradesJSON = `{"arg":{"channel":"sprd-public-trades", "sprdId": "BTC-USDT_BTC-USDT-SWAP" }, "data": [ { "sprdId": "BTC-USDT_BTC-USDT-SWAP", "tradeId": "2499206329160695808", "px": "-10", "sz": "0.001", "side": "sell", "ts": "1726801105519"}]}` okxSpreadPublicTickerJSON = `{"arg":{"channel":"sprd-tickers", "sprdId": "BTC-USDT_BTC-USDT-SWAP" }, "data": [ { "sprdId": "BTC-USDT_BTC-USDT-SWAP", "last": "4", "lastSz": "0.01", "askPx": "19.7", "askSz": "5.79", "bidPx": "5.9", "bidSz": "5.79", "open24h": "-7", "high24h": "19.6", "low24h": "-7", "vol24h": "9.87", "ts": "1715247061026"}]}` wsProcessSpreadOrdersJSON = `{"arg":{"channel":"sprd-orders","sprdId": "BTC-USDT_BTC-USDT-SWAP", "uid": "614488474791936"}, "data": [{"sprdId": "BTC-USDT_BTC-UST-SWAP", "ordId": "312269865356374016", "clOrdId": "b1", "tag": "", "px": "999", "sz": "3", "ordType": "limit", "side": "buy", "fillSz": "0", "fillPx": "", "tradeId": "", "accFillSz": "0", "pendingFillSz": "2", "pendingSettleSz": "1", "canceledSz": "1", "state": "live", "avgPx": "0", "cancelSource": "", "uTime": "1597026383085", "cTime": "1597026383085", "code": "0", "msg": "", "reqId": "", "amendResult": ""}]}` wsProcessSpreadTradesJSON = `{"arg":{"channel":"sprd-trades", "sprdId": "BTC-USDT_BTC-USDT-SWAP", "uid": "614488474791936" }, "data":[ { "sprdId":"BTC-USDT-SWAP_BTC-USDT-200329", "tradeId":"123", "ordId":"123445", "clOrdId": "b16", "tag":"", "fillPx":"999", "fillSz":"3", "state": "filled", "side":"buy", "execType":"M", "ts":"1597026383085", "legs": [ { "instId": "BTC-USDT-SWAP", "px": "20000", "sz": "3", "szCont": "0.03", "side": "buy", "fee": "", "feeCcy": "", "tradeId": "1232342342" }, { "instId": "BTC-USDT-200329", "px": "21000", "sz": "3", "szCont": "0.03", "side": "sell", "fee": "", "feeCcy": "", "tradeId": "5345646634" } ], "code": "", "msg":""}]}` ) func TestWsProcessSpreadOrderbook(t *testing.T) { t.Parallel() err := e.wsProcessSpreadOrderbook([]byte(processSpreadOrderbookJSON)) assert.NoError(t, err) } func TestWsProcessPublicSpreadTrades(t *testing.T) { t.Parallel() err := e.wsProcessPublicSpreadTrades([]byte(wsProcessPublicSpreadTradesJSON)) assert.NoError(t, err) } func TestWsProcessPublicSpreadTicker(t *testing.T) { t.Parallel() err := e.wsProcessPublicSpreadTicker([]byte(okxSpreadPublicTickerJSON)) assert.NoError(t, err) } func TestWsProcessSpreadOrders(t *testing.T) { t.Parallel() err := e.wsProcessSpreadOrders([]byte(wsProcessSpreadOrdersJSON)) assert.NoError(t, err) } func TestWsProcessSpreadTradesJSON(t *testing.T) { t.Parallel() err := e.wsProcessSpreadTrades([]byte(wsProcessSpreadTradesJSON)) assert.NoError(t, err) } func TestOrderTypeFromString(t *testing.T) { t.Parallel() orderTypeStrings := map[string]struct { OType order.Type TIF order.TimeInForce Error error }{ "market": {OType: order.Market}, "LIMIT": {OType: order.Limit}, "limit": {OType: order.Limit}, "post_only": {OType: order.Limit, TIF: order.PostOnly}, "fok": {OType: order.Limit, TIF: order.FillOrKill}, "ioc": {OType: order.Limit, TIF: order.ImmediateOrCancel}, "optimal_limit_ioc": {OType: order.OptimalLimit, TIF: order.ImmediateOrCancel}, "mmp": {OType: order.MarketMakerProtection}, "mmp_and_post_only": {OType: order.MarketMakerProtection, TIF: order.PostOnly}, "trigger": {OType: order.UnknownType, Error: order.ErrTypeIsInvalid}, "chase": {OType: order.Chase}, "move_order_stop": {OType: order.TrailingStop}, "twap": {OType: order.TWAP}, "abcd": {OType: order.UnknownType, Error: order.ErrTypeIsInvalid}, } for s, exp := range orderTypeStrings { t.Run(s, func(t *testing.T) { t.Parallel() oType, tif, err := orderTypeFromString(s) require.ErrorIs(t, err, exp.Error) assert.Equal(t, exp.OType, oType) assert.Equal(t, exp.TIF.String(), tif.String()) }) } } func TestGetFee(t *testing.T) { t.Parallel() // CryptocurrencyWithdrawalFee Basic feeBuilder := &exchange.FeeBuilder{ Amount: 1, FeeType: exchange.CryptocurrencyWithdrawalFee, Pair: mainPair, PurchasePrice: 1, } _, err := e.GetFee(contextGenerate(), feeBuilder) require.ErrorIs(t, err, errFeeTypeUnsupported) feeBuilder.FeeType = exchange.OfflineTradeFee _, err = e.GetFee(contextGenerate(), feeBuilder) assert.NoError(t, err) sharedtestvalues.SkipTestIfCredentialsUnset(t, e) feeBuilder.FeeType = exchange.CryptocurrencyTradeFee _, err = e.GetFee(contextGenerate(), feeBuilder) require.NoError(t, err) } func TestPriceTypeString(t *testing.T) { t.Parallel() priceTypeToStringMap := map[order.PriceType]string{ order.LastPrice: "last", order.IndexPrice: "index", order.MarkPrice: "mark", order.UnknownPriceType: "", } var priceTString string for x := range priceTypeToStringMap { priceTString = priceTypeString(x) assert.Equal(t, priceTString, priceTypeToStringMap[x]) } } func TestMarginTypeToString(t *testing.T) { t.Parallel() marginTypeToStringMap := map[margin.Type]string{ margin.Isolated: "isolated", margin.Multi: "cross", margin.NoMargin: "cash", margin.SpotIsolated: "spot_isolated", margin.Unset: "", } var marginTypeString string for m := range marginTypeToStringMap { marginTypeString = e.marginTypeToString(m) assert.Equal(t, marginTypeString, marginTypeToStringMap[m]) } } func TestValidatePlaceOrderRequestParam(t *testing.T) { t.Parallel() var p *PlaceOrderRequestParam require.ErrorIs(t, p.Validate(), common.ErrNilPointer) p = &PlaceOrderRequestParam{} require.ErrorIs(t, p.Validate(), errMissingInstrumentID) p.InstrumentID = mainPair.String() require.ErrorIs(t, p.Validate(), order.ErrSideIsInvalid) p.Side = order.Buy.String() p.TradeMode = "abc" require.ErrorIs(t, p.Validate(), errInvalidTradeModeValue) p.TradeMode = TradeModeIsolated p.AssetType = asset.Futures require.ErrorIs(t, p.Validate(), order.ErrSideIsInvalid) p.PositionSide = "long" require.ErrorIs(t, p.Validate(), order.ErrTypeIsInvalid) p.OrderType = order.Market.String() require.ErrorIs(t, p.Validate(), limits.ErrAmountBelowMin) p.Amount = 1 p.TargetCurrency = "moo cows" require.ErrorIs(t, p.Validate(), errCurrencyQuantityTypeRequired) p.TargetCurrency = "base_ccy" require.NoError(t, p.Validate()) } func TestValidateSpreadOrderParam(t *testing.T) { t.Parallel() var p *SpreadOrderParam require.ErrorIs(t, p.Validate(), common.ErrNilPointer) p = &SpreadOrderParam{} require.ErrorIs(t, p.Validate(), errMissingInstrumentID) p.SpreadID = spreadPair.String() require.ErrorIs(t, p.Validate(), order.ErrTypeIsInvalid) p.OrderType = order.Market.String() require.ErrorIs(t, p.Validate(), limits.ErrAmountBelowMin) p.Size = 1 require.ErrorIs(t, p.Validate(), limits.ErrPriceBelowMin) p.Price = 1 require.ErrorIs(t, p.Validate(), order.ErrSideIsInvalid) p.Side = order.Buy.String() require.NoError(t, p.Validate()) }