Files
gocryptotrader/exchanges/kucoin/kucoin_test.go
Gareth Kirwan 73e200e4e7 accounts: Move to instance methods, fix races and isolate tests (#1923)
* Bybit: Fix race in TestUpdateAccountInfo and  TestWSHandleData

* DriveBy rename TestWSHandleData
* This doesn't address running with -race=2+ due to the singleton

* Accounts: Add account.GetService()

* exchange: Assertify TestSetupDefaults

* Exchanges: Add account.Service override for testing

* Exchanges: Remove duplicate IsWebsocketEnabled test from TestSetupDefaults

* Dispatch: Replace nil checks with NilGuard

* Engine: Remove deprecated printAccountHoldingsChangeSummary

* Dispatcher: Add EnsureRunning method

* Accounts: Move singleton accounts service to exchange Accounts

* Move singleton accounts service to exchange Accounts

This maintains the concept of a global store, whilst allowing exchanges
to override it when needed, particularly for testing.

APIServer:

* Remove getAllActiveAccounts from apiserver

Deprecated apiserver only thing using this, so remove it instead of
updating it

* Update comment for UpdateAccountBalances everywhere

* Docs: Add punctuation to function comments

* Bybit: Coverage for wsProcessWalletPushData Save
2025-10-28 13:52:45 +11:00

4513 lines
167 KiB
Go

package kucoin
import (
"bytes"
"context"
"errors"
"fmt"
"log"
"os"
"testing"
"time"
"github.com/gofrs/uuid"
"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/config"
"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"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"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/sharedtestvalues"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"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"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Please supply your own keys here to do authenticated endpoint testing
const (
apiKey = ""
apiSecret = ""
passPhrase = ""
canManipulateRealOrders = false
)
var (
e *Exchange
spotTradablePair, marginTradablePair, futuresTradablePair currency.Pair
assertToTradablePairMap map[asset.Item]currency.Pair
)
func TestMain(m *testing.M) {
e = new(Exchange)
if err := testexch.Setup(e); err != nil {
log.Fatalf("Kucoin Setup error: %s", err)
}
if apiKey != "" && apiSecret != "" && passPhrase != "" {
e.API.AuthenticatedSupport = true
e.API.AuthenticatedWebsocketSupport = true
e.API.CredentialsValidator.RequiresBase64DecodeSecret = false
e.SetCredentials(apiKey, apiSecret, passPhrase, "", "", "")
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
}
getFirstTradablePairOfAssets(context.Background())
assertToTradablePairMap = map[asset.Item]currency.Pair{
asset.Spot: spotTradablePair,
asset.Margin: marginTradablePair,
asset.Futures: futuresTradablePair,
}
fetchedFuturesOrderbook = map[string]bool{}
os.Exit(m.Run())
}
// Spot asset test cases starts from here
func TestGetSymbols(t *testing.T) {
t.Parallel()
symbols, err := e.GetSymbols(t.Context(), "")
assert.NoError(t, err)
assert.NotEmpty(t, symbols)
// Using market string reduces the scope of what is returned.
symbols, err = e.GetSymbols(t.Context(), "ETF")
assert.NoError(t, err)
assert.NotEmpty(t, symbols, "should return all available ETF symbols")
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := e.GetTicker(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetTicker(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllTickers(t *testing.T) {
t.Parallel()
result, err := e.GetTickers(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTickers(t *testing.T) {
t.Parallel()
tickers, err := e.GetFuturesTickers(t.Context())
assert.NoError(t, err)
for i := range tickers {
assert.Positive(t, tickers[i].Last, "Last should be positive")
assert.Positive(t, tickers[i].Bid, "Bid should be positive")
assert.Positive(t, tickers[i].Ask, "Ask should be positive")
assert.NotEmpty(t, tickers[i].Pair, "Pair should not be empty")
assert.NotEmpty(t, tickers[i].LastUpdated, "LastUpdated should not be empty")
assert.Equal(t, e.Name, tickers[i].ExchangeName)
assert.Equal(t, asset.Futures, tickers[i].AssetType)
}
}
func TestGet24hrStats(t *testing.T) {
t.Parallel()
_, err := e.Get24hrStats(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.Get24hrStats(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarketList(t *testing.T) {
t.Parallel()
_, err := e.GetMarketList(t.Context())
assert.NoError(t, err)
}
func TestGetPartOrderbook20(t *testing.T) {
t.Parallel()
_, err := e.GetPartOrderbook20(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetPartOrderbook20(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetPartOrderbook100(t *testing.T) {
t.Parallel()
_, err := e.GetPartOrderbook100(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetPartOrderbook100(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := e.GetOrderbook(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetOrderbook(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
}
func TestGetTradeHistory(t *testing.T) {
t.Parallel()
_, err := e.GetTradeHistory(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.GetTradeHistory(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
}
func TestKlineUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[["1746645900","96248.3","96060.4","96248.3","95991.1","7.30387554","701787.956631596"],["1746645600","96407.2","96243.5","96420.2","96213.1","6.72799595","648257.95148221"],["1746645300","96382.8","96407.2","96466.1","96227.8","7.31425727","704541.034713515"],["1746645000","96490.5","96382.8","96503","96376.7","5.06147446","488102.261377795"],["1746644700","96424","96490.5","96517.9","96323.4","12.04216802","1160916.511036681"],["1746644400","96593.4","96423.9","96608.6","96403","10.75654084","1037793.471887188"],["1746644100","96200.5","96588.1","96591.6","96200.5","10.12317892","976893.020212471"],["1746643800","96182.2","96191.8","96241.7","95998.6","8.00901063","769988.0586614"],["1746643500","96404.1","96160.1","96477.6","96102.8","10.86244787","1045287.271213675"],["1746643200","96680.1","96395.4","96734.7","96395.3","9.54921963","921978.587594588"],["1746642900","96790.7","96680.1","96851.6","96587.5","11.35501379","1098593.622144195"],["1746642600","96447.7","96760","96868.5","96291.1","16.35392542","1580649.199051741"]]`)
var target []Kline
err := json.Unmarshal(data, &target)
require.NoError(t, err)
require.Len(t, target, 12)
assert.Equal(t, Kline{
StartTime: types.Time(time.Unix(1746645900, 0)),
Open: 96248.3,
Close: 96060.4,
High: 96248.3,
Low: 95991.1,
Volume: 7.30387554,
Amount: 701787.956631596,
}, target[0])
}
func TestGetKlines(t *testing.T) {
t.Parallel()
_, err := e.GetKlines(t.Context(), "", "1week", time.Time{}, time.Time{})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.GetKlines(t.Context(), spotTradablePair.String(), "invalid-period", time.Time{}, time.Time{})
require.ErrorIs(t, err, errInvalidPeriod)
result, err := e.GetKlines(t.Context(), spotTradablePair.String(), "1week", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetKlines(t.Context(), spotTradablePair.String(), "5min", time.Now().Add(-time.Hour*1), time.Now())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetCurrenciesV3(t *testing.T) {
t.Parallel()
_, err := e.GetCurrenciesV3(t.Context())
assert.NoError(t, err)
}
func TestGetCurrencyV3(t *testing.T) {
t.Parallel()
_, err := e.GetCurrencyDetailV3(t.Context(), currency.EMPTYCODE, "")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
result, err := e.GetCurrencyDetailV3(t.Context(), currency.BTC, "")
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetCurrencyDetailV3(t.Context(), currency.BTC, "ETH")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFiatPrice(t *testing.T) {
t.Parallel()
result, err := e.GetFiatPrice(t.Context(), "", "")
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetFiatPrice(t.Context(), "EUR", "ETH,BTC")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetLeveragedTokenInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetLeveragedTokenInfo(t.Context(), currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarkPrice(t *testing.T) {
t.Parallel()
_, err := e.GetMarkPrice(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetMarkPrice(t.Context(), marginTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllMarginTradingPairsMarkPrices(t *testing.T) {
t.Parallel()
result, err := e.GetAllMarginTradingPairsMarkPrices(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarginConfiguration(t *testing.T) {
t.Parallel()
result, err := e.GetMarginConfiguration(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarginAccount(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetMarginAccount(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetCrossMarginRiskLimitCurrencyConfig(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetCrossMarginRiskLimitCurrencyConfig(t.Context(), "", currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetIsolatedMarginRiskLimitCurrencyConfig(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetIsolatedMarginRiskLimitCurrencyConfig(t.Context(), "", currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostBorrowOrder(t *testing.T) {
t.Parallel()
_, err := e.PostMarginBorrowOrder(t.Context(), &MarginBorrowParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.PostMarginBorrowOrder(t.Context(), &MarginBorrowParam{IsIsolated: true})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.PostMarginBorrowOrder(t.Context(), &MarginBorrowParam{IsIsolated: true, Currency: currency.BTC})
require.ErrorIs(t, err, errTimeInForceRequired)
_, err = e.PostMarginBorrowOrder(t.Context(),
&MarginBorrowParam{
Currency: currency.USDT,
TimeInForce: "FOK",
Size: 0,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PostMarginBorrowOrder(t.Context(),
&MarginBorrowParam{
Currency: currency.USDT,
TimeInForce: "IOC",
Size: 0.05,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarginBorrowingHistory(t *testing.T) {
t.Parallel()
_, err := e.GetMarginBorrowingHistory(t.Context(), currency.EMPTYCODE, true, marginTradablePair.String(), "", time.Time{}, time.Now().Add(-time.Hour*80), 0, 10)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.GetMarginBorrowingHistory(t.Context(), currency.BTC, true, "", "", time.Time{}, time.Now().Add(-time.Hour*80), 0, 10)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetMarginBorrowingHistory(t.Context(), currency.BTC, true, marginTradablePair.String(), "", time.Time{}, time.Now().Add(-time.Hour*80), 0, 10)
assert.NoError(t, err)
}
func TestPostRepayment(t *testing.T) {
t.Parallel()
_, err := e.PostRepayment(t.Context(), &RepayParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.PostRepayment(t.Context(), &RepayParam{Size: 0.05})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.PostRepayment(t.Context(), &RepayParam{Currency: currency.ETH})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PostRepayment(t.Context(), &RepayParam{
Currency: currency.USDT,
Size: 0.05,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetCrossIsolatedMarginInterestRecords(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetCrossIsolatedMarginInterestRecords(t.Context(), false, "", currency.BTC, time.Now().Add(-time.Hour*50), time.Now(), 0, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetRepaymentHistory(t *testing.T) {
t.Parallel()
_, err := e.GetRepaymentHistory(t.Context(), currency.EMPTYCODE, true, spotTradablePair.String(), "", time.Time{}, time.Now().Add(-time.Hour*80), 0, 10)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetRepaymentHistory(t.Context(), currency.BTC, true, spotTradablePair.String(), "", time.Time{}, time.Now().Add(-time.Hour*80), 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetIsolatedMarginPairConfig(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetIsolatedMarginPairConfig(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetIsolatedMarginAccountInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetIsolatedMarginAccountInfo(t.Context(), "")
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetIsolatedMarginAccountInfo(t.Context(), "USDT")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetSingleIsolatedMarginAccountInfo(t *testing.T) {
t.Parallel()
_, err := e.GetSingleIsolatedMarginAccountInfo(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetSingleIsolatedMarginAccountInfo(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetCurrentServerTime(t *testing.T) {
t.Parallel()
result, err := e.GetCurrentServerTime(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetServiceStatus(t *testing.T) {
t.Parallel()
result, err := e.GetServiceStatus(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostOrder(t *testing.T) {
t.Parallel()
// default order type is limit
_, err := e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: "",
})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
customID, err := uuid.NewV4()
assert.NoError(t, err)
_, err = e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair,
OrderType: "",
})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: currency.EMPTYPAIR,
Size: 0.1, Side: "buy", Price: 234565,
})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
_, err = e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit", Size: 0.1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair, Side: "buy",
OrderType: "limit", Price: 234565,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(),
Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit",
Size: 0.005,
Price: 1000,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostOrderTest(t *testing.T) {
t.Parallel()
// default order type is limit
_, err := e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: "",
})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
customID, err := uuid.NewV4()
assert.NoError(t, err)
_, err = e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair,
OrderType: "",
})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: currency.EMPTYPAIR,
Size: 0.1, Side: "buy", Price: 234565,
})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
_, err = e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit", Size: 0.1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair, Side: "buy",
OrderType: "limit", Price: 234565,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.PostOrderTest(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(),
Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit",
Size: 0.005,
Price: 1000,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestHandlePostOrder(t *testing.T) {
t.Parallel()
// default order type is limit
_, err := e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: "",
}, "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
customID, err := uuid.NewV4()
assert.NoError(t, err)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair,
OrderType: "",
}, "")
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: currency.EMPTYPAIR,
Size: 0.1, Side: "buy", Price: 234565,
}, "")
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "OCO", Size: 0.1,
}, "")
require.ErrorIs(t, err, order.ErrTypeIsInvalid)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit", Size: 0.1,
}, "")
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit", Size: 0, Price: 1000,
}, "")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Side: "buy",
Symbol: spotTradablePair,
OrderType: "limit", Size: .1, Price: 1000, VisibleSize: -1,
}, "")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.HandlePostOrder(t.Context(), &SpotOrderParam{
ClientOrderID: customID.String(), Symbol: spotTradablePair, Side: "buy",
OrderType: "market", Price: 234565,
}, "")
require.ErrorIs(t, err, errSizeOrFundIsRequired)
}
func TestPostMarginOrder(t *testing.T) {
t.Parallel()
// default order type is limit
_, err := e.PostMarginOrder(t.Context(), &MarginOrderParam{
ClientOrderID: "",
})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.PostMarginOrder(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: marginTradablePair,
OrderType: "",
})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostMarginOrder(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: currency.EMPTYPAIR,
Size: 0.1, Side: "buy", Price: 234565,
})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.PostMarginOrder(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy",
Symbol: marginTradablePair,
OrderType: "limit", Size: 0.1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.PostMarginOrder(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: marginTradablePair, Side: "buy",
OrderType: "limit", Price: 234565,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
// default order type is limit and margin mode is cross
result, err := e.PostMarginOrder(t.Context(),
&MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy", Symbol: marginTradablePair,
Price: 1000, Size: 0.1, PostOnly: true,
})
assert.NoError(t, err)
assert.NotNil(t, result)
// market isolated order
result, err = e.PostMarginOrder(t.Context(),
&MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy", Symbol: marginTradablePair,
OrderType: "market", Funds: 1234,
Remark: "remark", MarginModel: "cross", Price: 1000, PostOnly: true, AutoBorrow: true,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostMarginOrderTest(t *testing.T) {
t.Parallel()
// default order type is limit
_, err := e.PostMarginOrderTest(t.Context(), &MarginOrderParam{
ClientOrderID: "",
})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.PostMarginOrderTest(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: marginTradablePair,
OrderType: "",
})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostMarginOrderTest(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: currency.EMPTYPAIR,
Size: 0.1, Side: "buy", Price: 234565,
})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.PostMarginOrderTest(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy",
Symbol: marginTradablePair,
OrderType: "limit", Size: 0.1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.PostMarginOrderTest(t.Context(), &MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Symbol: marginTradablePair, Side: "buy",
OrderType: "limit", Price: 234565,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
// default order type is limit and margin mode is cross
result, err := e.PostMarginOrderTest(t.Context(),
&MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy", Symbol: marginTradablePair,
Price: 1000, Size: 0.1, PostOnly: true,
})
assert.NoError(t, err)
assert.NotNil(t, result)
// market isolated order
result, err = e.PostMarginOrderTest(t.Context(),
&MarginOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy", Symbol: marginTradablePair,
OrderType: "market", Funds: 1234,
Remark: "remark", MarginModel: "cross", Price: 1000, PostOnly: true, AutoBorrow: true,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostBulkOrder(t *testing.T) {
t.Parallel()
_, err := e.PostBulkOrder(t.Context(), "", []OrderRequest{})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{})
require.ErrorIs(t, err, common.ErrEmptyParams)
arg := OrderRequest{
Size: 0.01,
}
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{arg})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
arg.ClientOID = "3d07008668054da6b3cb12e432c2b13a"
arg.Size = 0
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{arg})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
arg.Side = "Sell"
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{arg})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.Price = 1000
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{arg})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
_, err = e.PostBulkOrder(t.Context(), spotTradablePair.String(), []OrderRequest{
{
ClientOID: "3d07008668054da6b3cb12e432c2b13a",
Side: "buy",
Type: "limit",
Price: 1000,
Size: 0.01,
},
{
ClientOID: "37245dbe6e134b5c97732bfb36cd4a9d",
Side: "buy",
Type: "limit",
Price: 1000,
Size: 0.01,
},
})
assert.NoError(t, err)
}
func TestCancelSingleOrder(t *testing.T) {
t.Parallel()
_, err := e.CancelSingleOrder(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelSingleOrder(t.Context(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelOrderByClientOID(t *testing.T) {
t.Parallel()
_, err := e.CancelOrderByClientOID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelOrderByClientOID(t.Context(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllOpenOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllOpenOrders(t.Context(), "", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
const ordersListResponseJSON = `{"currentPage": 1, "pageSize": 1, "totalNum": 153408, "totalPage": 153408, "items": [ { "id": "5c35c02703aa673ceec2a168", "symbol": "BTC-USDT", "opType": "DEAL", "type": "limit", "side": "buy", "price": "10", "size": "2", "funds": "0", "dealFunds": "0.166", "dealSize": "2", "fee": "0", "feeCurrency": "USDT", "stp": "", "stop": "", "stopTriggered": false, "stopPrice": "0", "timeInForce": "GTC", "postOnly": false, "hidden": false, "iceberg": false, "visibleSize": "0", "cancelAfter": 0, "channel": "IOS", "clientOid": "", "remark": "", "tags": "", "isActive": false, "cancelExist": false, "createdAt": 1547026471000, "tradeType": "TRADE" } ] }`
func TestGetOrders(t *testing.T) {
t.Parallel()
var resp *OrdersListResponse
err := json.Unmarshal([]byte(ordersListResponseJSON), &resp)
assert.NoError(t, err)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.ListOrders(t.Context(), "", "", "", "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetRecentOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetRecentOrders(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderByID(t *testing.T) {
t.Parallel()
_, err := e.GetOrderByID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetOrderByID(t.Context(), "5c35c02703aa673ceec2a168")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderByClientOID(t *testing.T) {
t.Parallel()
_, err := e.GetOrderByClientSuppliedOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetOrderByClientSuppliedOrderID(t.Context(), "6d539dc614db312")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFills(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFills(t.Context(), "", "", "", "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetFills(t.Context(), "5c35c02703aa673ceec2a168", spotTradablePair.String(), "buy", "limit", SpotTradeType, time.Now().Add(-time.Hour*12), time.Now())
assert.NoError(t, err)
assert.NotNil(t, result)
}
const limitFillsResponseJSON = `[{ "counterOrderId":"5db7ee769797cf0008e3beea", "createdAt":1572335233000, "fee":"0.946357371456", "feeCurrency":"USDT", "feeRate":"0.001", "forceTaker":true, "funds":"946.357371456", "liquidity":"taker", "orderId":"5db7ee805d53620008dce1ba", "price":"9466.8", "side":"buy", "size":"0.09996592", "stop":"", "symbol":"BTC-USDT", "tradeId":"5db7ee8054c05c0008069e21", "tradeType":"MARGIN_TRADE", "type":"market" }, { "counterOrderId":"5db7ee4b5d53620008dcde8e", "createdAt":1572335207000, "fee":"0.94625", "feeCurrency":"USDT", "feeRate":"0.001", "forceTaker":true, "funds":"946.25", "liquidity":"taker", "orderId":"5db7ee675d53620008dce01e", "price":"9462.5", "side":"sell", "size":"0.1", "stop":"", "symbol":"BTC-USDT", "tradeId":"5db7ee6754c05c0008069e03", "tradeType":"MARGIN_TRADE", "type":"market" }]`
func TestGetRecentFills(t *testing.T) {
t.Parallel()
var resp []Fill
err := json.Unmarshal([]byte(limitFillsResponseJSON), &resp)
assert.NoError(t, err)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetRecentFills(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostStopOrder(t *testing.T) {
t.Parallel()
_, err := e.PostStopOrder(t.Context(), "", "buy", spotTradablePair.String(), "", "", "entry", "CO", SpotTradeType, "", 0.1, 1, 10, 0, 0, 0, true, false, false)
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.PostStopOrder(t.Context(), "5bd6e9286d99522a52e458de", "", spotTradablePair.String(), "", "", "entry", "CO", SpotTradeType, "", 0.1, 1, 10, 0, 0, 0, true, false, false)
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostStopOrder(t.Context(), "5bd6e9286d99522a52e458de", "buy", "", "", "", "entry", "CO", SpotTradeType, "", 0.1, 1, 10, 0, 0, 0, true, false, false)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PostStopOrder(t.Context(), "5bd6e9286d99522a52e458de", "buy", spotTradablePair.String(), "", "", "entry", "CO", SpotTradeType, "", 0.1, 1, 10, 0, 0, 0, true, false, false)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelStopOrder(t *testing.T) {
t.Parallel()
_, err := e.CancelStopOrder(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelStopOrder(t.Context(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelStopOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelStopOrderByClientOrderID(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelStopOrderByClientOrderID(t.Context(), "5bd6e9286d99522a52e458de", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllStopOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelStopOrders(t.Context(), "", "", []string{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
const stopOrderResponseJSON = `{"id": "vs8hoo8q2ceshiue003b67c0", "symbol": "KCS-USDT", "userId": "60fe4956c43cbc0006562c2c", "status": "NEW", "type": "limit", "side": "buy", "price": "0.01000000000000000000", "size": "0.01000000000000000000", "funds": null, "stp": null, "timeInForce": "GTC", "cancelAfter": -1, "postOnly": false, "hidden": false, "iceberg": false, "visibleSize": null, "channel": "API", "clientOid": "40e0eb9efe6311eb8e58acde48001122", "remark": null, "tags": null, "orderTime": 1629098781127530345, "domainId": "kucoin", "tradeSource": "USER", "tradeType": "TRADE", "feeCurrency": "USDT", "takerFeeRate": "0.00200000000000000000", "makerFeeRate": "0.00200000000000000000", "createdAt": 1629098781128, "stop": "loss", "stopTriggerTime": null, "stopPrice": "10.00000000000000000000" }`
func TestGetStopOrder(t *testing.T) {
t.Parallel()
var resp *StopOrder
err := json.Unmarshal([]byte(stopOrderResponseJSON), &resp)
assert.NoError(t, err)
_, err = e.GetStopOrder(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetStopOrder(t.Context(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllStopOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.ListStopOrders(t.Context(), "", "", "", "", []string{}, time.Time{}, time.Time{}, 0, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetStopOrderByClientID(t *testing.T) {
t.Parallel()
_, err := e.GetStopOrderByClientID(t.Context(), "", "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetStopOrderByClientID(t.Context(), "", "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelStopOrderByClientID(t *testing.T) {
t.Parallel()
_, err := e.CancelStopOrderByClientID(t.Context(), "", "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelStopOrderByClientID(t.Context(), "", "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllAccounts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAllAccounts(t.Context(), currency.EMPTYCODE, "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAccount(t *testing.T) {
t.Parallel()
_, err := e.GetAccountDetail(t.Context(), "")
require.ErrorIs(t, err, errAccountIDMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAccountDetail(t.Context(), "62fcd1969474ea0001fd20e4")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetCrossMarginAccountsDetail(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetCrossMarginAccountsDetail(t.Context(), "KCS", "MARGIN_V2")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetIsolatedMarginAccountDetail(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetIsolatedMarginAccountDetail(t.Context(), marginTradablePair.String(), "BTC", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesAccountDetail(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesAccountDetail(t.Context(), currency.USDT)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetSubAccounts(t *testing.T) {
t.Parallel()
_, err := e.GetSubAccounts(t.Context(), "", false)
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetSubAccounts(t.Context(), "5caefba7d9575a0688f83c45", false)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllFuturesSubAccountBalances(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAllFuturesSubAccountBalances(t.Context(), currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
const accountLedgerResponseJSON = `{"currentPage": 1, "pageSize": 50, "totalNum": 2, "totalPage": 1, "items": [ { "id": "611a1e7c6a053300067a88d9", "currency": "USDT", "amount": "10.00059547", "fee": "0", "balance": "0", "accountType": "MAIN", "bizType": "Loans Repaid", "direction": "in", "createdAt": 1629101692950, "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}" }, { "id": "611a18bc6a0533000671e1bf", "currency": "USDT", "amount": "10.00059547", "fee": "0", "balance": "0", "accountType": "MAIN", "bizType": "Loans Repaid", "direction": "in", "createdAt": 1629100220843, "context": "{\"borrowerUserId\":\"5e3f4623dbf52d000800292f\",\"loanRepayDetailNo\":\"611a18bc7255c200063ea545\"}" } ] }`
func TestGetAccountLedgers(t *testing.T) {
t.Parallel()
var resp *AccountLedgerResponse
err := json.Unmarshal([]byte(accountLedgerResponseJSON), &resp)
assert.NoError(t, err)
_, err = e.GetAccountLedgers(t.Context(), currency.EMPTYCODE, "", "", time.Now(), time.Now().Add(-time.Hour*24*10))
require.ErrorIs(t, err, common.ErrStartAfterEnd)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAccountLedgers(t.Context(), currency.EMPTYCODE, "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAccountLedgersHFTrade(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := e.GetAccountLedgersHFTrade(t.Context(), currency.BTC, "", "", 0, 10, time.Time{}, time.Now())
assert.NoError(t, err)
}
func TestGetAccountLedgerHFMargin(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAccountLedgerHFMargin(t.Context(), currency.BTC, "", "", 0, 0, time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesAccountLedgers(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesAccountLedgers(t.Context(), currency.BTC, true, time.Time{}, time.Now(), 0, 100)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllSubAccountsInfoV1(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAllSubAccountsInfoV1(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllSubAccountsInfoV2(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAllSubAccountsInfoV2(t.Context(), 0, 30)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAccountSummaryInformation(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAccountSummaryInformation(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAggregatedSubAccountBalance(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAggregatedSubAccountBalance(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAllSubAccountsBalanceV2(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAllSubAccountsBalanceV2(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetPaginatedSubAccountInformation(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetPaginatedSubAccountInformation(t.Context(), 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetTransferableBalance(t *testing.T) {
t.Parallel()
_, err := e.GetTransferableBalance(t.Context(), currency.EMPTYCODE, "MAIN", "")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.GetTransferableBalance(t.Context(), currency.BTC, "", "")
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetTransferableBalance(t.Context(), currency.BTC, "MAIN", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetUniversalTransfer(t *testing.T) {
t.Parallel()
_, err := e.GetUniversalTransfer(t.Context(), &UniversalTransferParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
arg := &UniversalTransferParam{
ToAccountTag: "1234",
}
_, err = e.GetUniversalTransfer(t.Context(), arg)
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
arg.ClientSuppliedOrderID = "64ccc0f164781800010d8c09"
_, err = e.GetUniversalTransfer(t.Context(), arg)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
arg.Amount = 1
_, err = e.GetUniversalTransfer(t.Context(), arg)
require.ErrorIs(t, err, errAccountTypeMissing)
arg.FromAccountType = "MAIN"
_, err = e.GetUniversalTransfer(t.Context(), arg)
require.ErrorIs(t, err, errTransferTypeMissing)
arg.TransferType = "INTERNAL"
_, err = e.GetUniversalTransfer(t.Context(), arg)
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.GetUniversalTransfer(t.Context(), &UniversalTransferParam{
ClientSuppliedOrderID: "64ccc0f164781800010d8c09",
TransferType: "INTERNAL",
Currency: currency.BTC,
Amount: 1,
FromAccountType: SpotTradeType,
ToAccountType: "CONTRACT",
})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetUniversalTransfer(t.Context(), &UniversalTransferParam{
ClientSuppliedOrderID: "64ccc0f164781800010d8c09",
TransferType: "PARENT_TO_SUB",
Currency: currency.BTC,
Amount: 1,
FromAccountType: SpotTradeType,
ToUserID: "62f5f5d4d72aaf000122707e",
ToAccountType: "CONTRACT",
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestTransferMainToSubAccount(t *testing.T) {
t.Parallel()
_, err := e.TransferMainToSubAccount(t.Context(), currency.EMPTYCODE, 1, "62fcd1969474ea0001fd20e4", "OUT", "", "", "5caefba7d9575a0688f83c45")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.TransferMainToSubAccount(t.Context(), currency.BTC, 1, "", "OUT", "", "", "5caefba7d9575a0688f83c45")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.TransferMainToSubAccount(t.Context(), currency.BTC, 0, "62fcd1969474ea0001fd20e4", "OUT", "", "", "5caefba7d9575a0688f83c45")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.TransferMainToSubAccount(t.Context(), currency.BTC, 1, "62fcd1969474ea0001fd20e4", "", "", "", "5caefba7d9575a0688f83c45")
require.ErrorIs(t, err, errTransferDirectionRequired)
_, err = e.TransferMainToSubAccount(t.Context(), currency.BTC, 1, "62fcd1969474ea0001fd20e4", "OUT", "", "", "")
require.ErrorIs(t, err, errSubUserIDRequired)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.TransferMainToSubAccount(t.Context(), currency.BTC, 1, "62fcd1969474ea0001fd20e4", "OUT", "", "", "5caefba7d9575a0688f83c45")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestMakeInnerTransfer(t *testing.T) {
t.Parallel()
_, err := e.MakeInnerTransfer(t.Context(), 0, currency.EMPTYCODE, "62fcd1969474ea0001fd20e4", "trade", "main", "1", "")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.MakeInnerTransfer(t.Context(), 0, currency.USDT, "", "trade", "main", "1", "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.MakeInnerTransfer(t.Context(), 0, currency.USDT, "62fcd1969474ea0001fd20e4", "", "main", "", "")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.MakeInnerTransfer(t.Context(), 1, currency.USDT, "62fcd1969474ea0001fd20e4", "", "main", "", "")
require.ErrorIs(t, err, errAccountTypeMissing)
_, err = e.MakeInnerTransfer(t.Context(), 5, currency.USDT, "62fcd1969474ea0001fd20e4", "margin_hf", "", "", "")
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.MakeInnerTransfer(t.Context(), 10, currency.USDT, "62fcd1969474ea0001fd20e4", "main", "trade_hf", "", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestTransferToMainOrTradeAccount(t *testing.T) {
t.Parallel()
_, err := e.TransferToMainOrTradeAccount(t.Context(), &FundTransferFuturesParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.TransferToMainOrTradeAccount(t.Context(), &FundTransferFuturesParam{RecieveAccountType: "MAIN"})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.TransferToMainOrTradeAccount(t.Context(), &FundTransferFuturesParam{Amount: 1, RecieveAccountType: "MAIN"})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.TransferToMainOrTradeAccount(t.Context(), &FundTransferFuturesParam{
Amount: 1,
Currency: currency.USDT,
RecieveAccountType: SpotTradeType,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestTransferToFuturesAccount(t *testing.T) {
t.Parallel()
_, err := e.TransferToFuturesAccount(t.Context(), &FundTransferToFuturesParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.TransferToFuturesAccount(t.Context(), &FundTransferToFuturesParam{PaymentAccountType: "Main"})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.TransferToFuturesAccount(t.Context(), &FundTransferToFuturesParam{PaymentAccountType: "Main", Amount: 12})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.TransferToFuturesAccount(t.Context(), &FundTransferToFuturesParam{
Amount: 60,
Currency: currency.USDT,
PaymentAccountType: SpotTradeType,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTransferOutRequestRecords(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesTransferOutRequestRecords(t.Context(), time.Time{}, time.Now(), "", "", currency.BTC, 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCreateDepositAddress(t *testing.T) {
t.Parallel()
_, err := e.CreateDepositAddress(t.Context(), &DepositAddressParams{})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CreateDepositAddress(t.Context(), &DepositAddressParams{
Currency: currency.BTC,
})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.CreateDepositAddress(t.Context(),
&DepositAddressParams{
Currency: currency.USDT,
Chain: "TRC20",
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetDepositAddressV2(t *testing.T) {
t.Parallel()
_, err := e.GetDepositAddressesV2(t.Context(), currency.EMPTYCODE)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetDepositAddressesV2(t.Context(), currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetDepositAddressesV1(t *testing.T) {
t.Parallel()
_, err := e.GetDepositAddressV1(t.Context(), currency.EMPTYCODE, "")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetDepositAddressV1(t.Context(), currency.BTC, "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
const depositResponseJSON = `{"currentPage": 1, "pageSize": 50, "totalNum": 1, "totalPage": 1, "items": [ { "currency": "XRP", "chain": "xrp", "status": "SUCCESS", "address": "rNFugeoj3ZN8Wv6xhuLegUBBPXKCyWLRkB", "memo": "1919537769", "isInner": false, "amount": "20.50000000", "fee": "0.00000000", "walletTxId": "2C24A6D5B3E7D5B6AA6534025B9B107AC910309A98825BF5581E25BEC94AD83B@e8902757998fc352e6c9d8890d18a71c", "createdAt": 1666600519000, "updatedAt": 1666600549000, "remark": "Deposit" } ] }`
func TestGetDepositList(t *testing.T) {
t.Parallel()
var resp DepositResponse
err := json.Unmarshal([]byte(depositResponseJSON), &resp)
assert.NoError(t, err)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetDepositList(t.Context(), currency.EMPTYCODE, "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
const historicalDepositResponseJSON = `{"currentPage":1, "pageSize":1, "totalNum":9, "totalPage":9, "items":[ { "currency":"BTC", "createAt":1528536998, "amount":"0.03266638", "walletTxId":"55c643bc2c68d6f17266383ac1be9e454038864b929ae7cee0bc408cc5c869e8@12ffGWmMMD1zA1WbFm7Ho3JZ1w6NYXjpFk@234", "isInner":false, "status":"SUCCESS" } ] }`
func TestGetHistoricalDepositList(t *testing.T) {
t.Parallel()
var resp *HistoricalDepositWithdrawalResponse
err := json.Unmarshal([]byte(historicalDepositResponseJSON), &resp)
assert.NoError(t, err)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHistoricalDepositList(t.Context(), currency.EMPTYCODE, "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetWithdrawalList(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetWithdrawalList(t.Context(), currency.EMPTYCODE, "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetHistoricalWithdrawalList(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHistoricalWithdrawalList(t.Context(), currency.EMPTYCODE, "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetWithdrawalQuotas(t *testing.T) {
t.Parallel()
_, err := e.GetWithdrawalQuotas(t.Context(), currency.EMPTYCODE, "")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetWithdrawalQuotas(t.Context(), currency.BTC, "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestApplyWithdrawal(t *testing.T) {
t.Parallel()
_, err := e.ApplyWithdrawal(t.Context(), currency.EMPTYCODE, "0x597873884BC3a6C10cB6Eb7C69172028Fa85B25A", "", "", "", "", false, 1)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.ApplyWithdrawal(t.Context(), currency.ETH, "", "", "", "", "", false, 1)
require.ErrorIs(t, err, errAddressRequired)
_, err = e.ApplyWithdrawal(t.Context(), currency.ETH, "0x597873884BC3a6C10cB6Eb7C69172028Fa85B25A", "", "", "", "", false, 0)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.ApplyWithdrawal(t.Context(), currency.ETH, "0x597873884BC3a6C10cB6Eb7C69172028Fa85B25A", "", "", "", "", false, 1)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelWithdrawal(t *testing.T) {
t.Parallel()
err := e.CancelWithdrawal(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
err = e.CancelWithdrawal(t.Context(), "5bffb63303aa675e8bbe18f9")
assert.NoError(t, err)
}
func TestGetBasicFee(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetBasicFee(t.Context(), "1")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetTradingFee(t *testing.T) {
t.Parallel()
_, err := e.GetTradingFee(t.Context(), nil)
require.ErrorIs(t, err, currency.ErrCurrencyPairsEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
avail, err := e.GetAvailablePairs(asset.Spot)
assert.NoError(t, err)
assert.NotEmpty(t, avail)
pairs := currency.Pairs{avail[0]}
btcusdTradingFee, err := e.GetTradingFee(t.Context(), pairs)
assert.NoErrorf(t, err, "received %v, expected %v", err, nil)
assert.Len(t, btcusdTradingFee, 1)
// NOTE: Test below will error out from an external call as this will exceed
// the allowed pairs. If this does not error then this endpoint will allow
// more items to be requested.
pairs = append(pairs, avail[1:10]...)
result, err := e.GetTradingFee(t.Context(), pairs)
assert.NoError(t, err)
assert.NotNil(t, result)
got, err := e.GetTradingFee(t.Context(), pairs[:10])
assert.NoError(t, err)
assert.Len(t, got, 10)
}
// futures
func TestGetFuturesOpenContracts(t *testing.T) {
t.Parallel()
result, err := e.GetFuturesOpenContracts(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesContract(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesContract(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesContract(t.Context(), "XBTUSDTM")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTicker(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesTicker(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
tick, err := e.GetFuturesTicker(t.Context(), "XBTUSDTM")
if assert.NoError(t, err) {
assert.Positive(t, tick.Sequence, "Sequence should be positive")
assert.Equal(t, "XBTUSDTM", tick.Symbol)
assert.Contains(t, []order.Side{order.Buy, order.Sell}, tick.Side, "Side should be a side")
assert.Positive(t, tick.Size, "Size should be positive")
assert.Positive(t, tick.Price.Float64(), "Price should be positive")
assert.Positive(t, tick.BestBidPrice.Float64(), "BestBidPrice should be positive")
assert.Positive(t, tick.BestBidSize, "BestBidSize should be positive")
assert.Positive(t, tick.BestAskPrice.Float64(), "BestAskPrice should be positive")
assert.Positive(t, tick.BestAskSize, "BestAskSize should be positive")
assert.NotEmpty(t, tick.TradeID, "TradeID should not be empty")
assert.WithinRange(t, tick.FilledTime.Time(), time.Now().Add(time.Hour*-24), time.Now().Add(time.Hour))
}
}
func TestGetFuturesOrderbook(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesOrderbook(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesOrderbook(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPartOrderbook20(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPartOrderbook20(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesPartOrderbook20(t.Context(), "XBTUSDTM")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPartOrderbook100(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPartOrderbook100(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesPartOrderbook100(t.Context(), "XBTUSDTM")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTradeHistory(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesTradeHistory(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesTradeHistory(t.Context(), "XBTUSDTM")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesInterestRate(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesInterestRate(t.Context(), "", time.Time{}, time.Time{}, false, false, 0, 0)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesInterestRate(t.Context(), futuresTradablePair.String(), time.Time{}, time.Time{}, false, false, 0, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesIndexList(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesIndexList(t.Context(), "", time.Time{}, time.Time{}, false, false, 0, 10)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesIndexList(t.Context(), futuresTradablePair.String(), time.Time{}, time.Time{}, false, false, 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesCurrentMarkPrice(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesCurrentMarkPrice(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesCurrentMarkPrice(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPremiumIndex(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPremiumIndex(t.Context(), "", time.Time{}, time.Time{}, false, false, 0, 0)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesPremiumIndex(t.Context(), futuresTradablePair.String(), time.Time{}, time.Time{}, false, false, 0, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGet24HourFuturesTransactionVolume(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
resp, err := e.Get24HourFuturesTransactionVolume(t.Context())
assert.NoError(t, err)
assert.NotNil(t, resp)
}
func TestGetFuturesCurrentFundingRate(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesCurrentFundingRate(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesCurrentFundingRate(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetPublicFundingRate(t *testing.T) {
t.Parallel()
_, err := e.GetPublicFundingRate(t.Context(), "", time.Now().Add(-time.Hour*24*30), time.Now().Add(-time.Hour*5))
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetPublicFundingRate(t.Context(), futuresTradablePair.String(), time.Now().Add(-time.Hour*24*30), time.Now().Add(-time.Hour*5))
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesServerTime(t *testing.T) {
t.Parallel()
result, err := e.GetFuturesServerTime(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesServiceStatus(t *testing.T) {
t.Parallel()
result, err := e.GetFuturesServiceStatus(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestFuturesKlineUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[1746518400000,1806.48,1806.48,1794.41,1794.41,1560]`)
var target *FuturesKline
err := json.Unmarshal(data, &target)
require.NoError(t, err)
require.NotNil(t, target)
assert.Equal(t, FuturesKline{
StartTime: types.Time(time.UnixMilli(1746518400000)),
Open: 1806.48,
High: 1806.48,
Low: 1794.41,
Close: 1794.41,
Volume: 1560,
}, *target)
}
func TestGetFuturesKline(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesKline(t.Context(), 0, "XBTUSDTM", time.Time{}, time.Time{})
require.ErrorIs(t, err, kline.ErrInvalidInterval)
_, err = e.GetFuturesKline(t.Context(), int64(kline.ThirtyMin.Duration().Seconds()), futuresTradablePair.String(), time.Time{}, time.Time{})
require.ErrorIs(t, err, kline.ErrUnsupportedInterval)
_, err = e.GetFuturesKline(t.Context(), int64(kline.ThirtyMin.Duration().Minutes()), "", time.Time{}, time.Time{})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
result, err := e.GetFuturesKline(t.Context(), int64(kline.ThirtyMin.Duration().Minutes()), futuresTradablePair.String(), time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPostFuturesOrder(t *testing.T) {
t.Parallel()
_, err := e.PostFuturesOrder(t.Context(), &FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy"})
require.ErrorIs(t, err, errInvalidLeverage)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{Side: "buy", Leverage: 1})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Leverage: 1})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Leverage: 1})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
// With Stop order configuration
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "", TimeInForce: "", Size: 1, Price: 1000, StopPrice: 0, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, errInvalidStopPriceType)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "TP", TimeInForce: "", Size: 1, Price: 1000, StopPrice: 0, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "TP", StopPrice: 123456, TimeInForce: "", Size: 1, Price: 1000, Leverage: 1, VisibleSize: 0,
})
assert.NoError(t, err)
assert.NotNil(t, result)
// Limit Orders
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair,
OrderType: "limit", Remark: "10", Leverage: 1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10", Price: 1000, Leverage: 1, VisibleSize: 0})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
result, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Size: 1, Price: 1000, Leverage: 1, VisibleSize: 0,
})
assert.NoError(t, err)
assert.NotNil(t, result)
// Market Orders
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair,
OrderType: "market", Remark: "10", Leverage: 1,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "market", Remark: "10",
Size: 1, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
result, err = e.PostFuturesOrder(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy",
Symbol: futuresTradablePair,
OrderType: "limit",
Remark: "10",
Stop: "",
StopPriceType: "",
TimeInForce: "",
Size: 1,
Price: 1000,
StopPrice: 0,
Leverage: 1,
VisibleSize: 0,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestFillFuturesPostOrderArgumentFilter(t *testing.T) {
t.Parallel()
err := e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy"})
require.ErrorIs(t, err, errInvalidLeverage)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{Side: "buy", Leverage: 1})
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Leverage: 1})
require.ErrorIs(t, err, order.ErrSideIsInvalid)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Leverage: 1})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
// With Stop order configuration
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "", TimeInForce: "", Size: 1, Price: 1000, StopPrice: 0, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, errInvalidStopPriceType)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "TP", TimeInForce: "", Size: 1, Price: 1000, StopPrice: 0, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Stop: "up", StopPriceType: "TP", StopPrice: 123456, TimeInForce: "", Size: 1, Price: 1000, Leverage: 1, VisibleSize: 0,
})
assert.NoError(t, err)
// Limit Orders
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair,
OrderType: "limit", Remark: "10", Leverage: 1,
})
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10", Price: 1000, Leverage: 1, VisibleSize: 0})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "limit", Remark: "10",
Size: 1, Price: 1000, Leverage: 1, VisibleSize: 0,
})
assert.NoError(t, err)
// Market Orders
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair,
OrderType: "market", Remark: "10", Leverage: 1,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de", Side: "buy", Symbol: futuresTradablePair, OrderType: "market", Remark: "10",
Size: 0, Leverage: 1, VisibleSize: 0,
})
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
err = e.FillFuturesPostOrderArgumentFilter(&FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy",
Symbol: futuresTradablePair,
OrderType: "limit",
Remark: "10",
Stop: "",
StopPriceType: "",
TimeInForce: "",
Size: 1,
Price: 1000,
StopPrice: 0,
Leverage: 1,
VisibleSize: 0,
})
assert.NoError(t, err)
}
func TestPostFuturesOrderTest(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
response, err := e.PostFuturesOrderTest(t.Context(), &FuturesOrderParam{
ClientOrderID: "5bd6e9286d99522a52e458de",
Side: "buy",
Symbol: futuresTradablePair,
OrderType: "market",
Remark: "10",
Stop: "",
StopPriceType: "",
TimeInForce: "",
Size: 1,
StopPrice: 0,
Leverage: 1,
VisibleSize: 0,
})
assert.NoError(t, err)
assert.NotNil(t, response)
}
func TestPlaceMultipleFuturesOrders(t *testing.T) {
t.Parallel()
_, err := e.PlaceMultipleFuturesOrders(t.Context(), []FuturesOrderParam{})
require.ErrorIs(t, err, common.ErrEmptyParams)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PlaceMultipleFuturesOrders(t.Context(), []FuturesOrderParam{
{
ClientOrderID: "5c52e11203aa677f33e491",
Side: "buy",
Symbol: futuresTradablePair,
OrderType: "limit",
Price: 2150,
Size: 2,
Leverage: 1,
},
{
ClientOrderID: "5c52e11203aa677f33e492",
Side: "buy",
Symbol: futuresTradablePair,
OrderType: "limit",
Price: 32150,
Size: 2,
Leverage: 1,
},
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelFuturesOrder(t *testing.T) {
t.Parallel()
_, err := e.CancelFuturesOrderByOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelFuturesOrderByOrderID(t.Context(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelFuturesOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelFuturesOrderByClientOrderID(t.Context(), "", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.CancelFuturesOrderByClientOrderID(t.Context(), futuresTradablePair.String(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelFuturesOrderByClientOrderID(t.Context(), futuresTradablePair.String(), "5bd6e9286d99522a52e458de")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllFuturesOpenOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelMultipleFuturesLimitOrders(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllFuturesStopOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllFuturesStopOrders(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesOrders(t.Context(), "", "", "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetUntriggeredFuturesStopOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetUntriggeredFuturesStopOrders(t.Context(), "", "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesRecentCompletedOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesRecentCompletedOrders(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesOrderDetails(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesOrderDetails(t.Context(), "", "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesOrderDetails(t.Context(), "5cdfc138b21023a909e5ad55", "2212332")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesOrderDetailsByClientID(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesOrderDetailsByClientOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesOrderDetailsByClientOrderID(t.Context(), "eresc138b21023a909e5ad59")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesFills(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesFills(t.Context(), "", "", "", "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesRecentFills(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesRecentFills(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesOpenOrderStats(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesOpenOrderStats(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesOpenOrderStats(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPosition(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPosition(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesPosition(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPositionList(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesPositionList(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSetAutoDepositMargin(t *testing.T) {
t.Parallel()
_, err := e.SetAutoDepositMargin(t.Context(), "", true)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SetAutoDepositMargin(t.Context(), futuresTradablePair.String(), true)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMaxWithdrawMargin(t *testing.T) {
t.Parallel()
_, err := e.GetMaxWithdrawMargin(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetMaxWithdrawMargin(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestRemoveMarginManually(t *testing.T) {
t.Parallel()
_, err := e.RemoveMarginManually(t.Context(), &WithdrawMarginResponse{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.RemoveMarginManually(t.Context(), &WithdrawMarginResponse{
WithdrawAmount: 1,
})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.RemoveMarginManually(t.Context(), &WithdrawMarginResponse{
Symbol: "ADAUSDTM",
WithdrawAmount: 1,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestAddMargin(t *testing.T) {
t.Parallel()
_, err := e.AddMargin(t.Context(), "", "6200c9b83aecfb000152dasfdee", 1)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.AddMargin(t.Context(), futuresTradablePair.String(), "6200c9b83aecfb000152dasfdee", 1)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesRiskLimitLevel(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesRiskLimitLevel(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesRiskLimitLevel(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestUpdateRiskLmitLevel(t *testing.T) {
t.Parallel()
_, err := e.FuturesUpdateRiskLmitLevel(t.Context(), "", 2)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.FuturesUpdateRiskLmitLevel(t.Context(), futuresTradablePair.String(), 2)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesFundingHistory(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesFundingHistory(t.Context(), "", 0, 0, true, true, time.Time{}, time.Time{})
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesFundingHistory(t.Context(), futuresTradablePair.String(), 0, 0, true, true, time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesAccountOverview(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesAccountOverview(t.Context(), "BTC")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTransactionHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesTransactionHistory(t.Context(), currency.EMPTYCODE, "", 0, 0, true, time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCreateFuturesSubAccountAPIKey(t *testing.T) {
t.Parallel()
_, err := e.CreateFuturesSubAccountAPIKey(t.Context(), "", "passphrase", "", "", "subAccName")
require.ErrorIs(t, err, errRemarkIsRequired)
_, err = e.CreateFuturesSubAccountAPIKey(t.Context(), "", "passphrase", "", "remark", "")
require.ErrorIs(t, err, errInvalidSubAccountName)
_, err = e.CreateFuturesSubAccountAPIKey(t.Context(), "", "", "", "remark", "subAccName")
require.ErrorIs(t, err, errInvalidPassPhraseInstance)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CreateFuturesSubAccountAPIKey(t.Context(), "", "passphrase", "", "remark", "subAccName")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestTransferFuturesFundsToMainAccount(t *testing.T) {
t.Parallel()
var resp *TransferRes
err := json.Unmarshal([]byte(transferFuturesFundsResponseJSON), &resp)
assert.NoError(t, err)
_, err = e.TransferFuturesFundsToMainAccount(t.Context(), 0, currency.USDT, "MAIN")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.TransferFuturesFundsToMainAccount(t.Context(), 1, currency.EMPTYCODE, "MAIN")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.TransferFuturesFundsToMainAccount(t.Context(), 1, currency.ETH, "")
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.TransferFuturesFundsToMainAccount(t.Context(), 1, currency.USDT, "MAIN")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestTransferFundsToFuturesAccount(t *testing.T) {
t.Parallel()
err := e.TransferFundsToFuturesAccount(t.Context(), 0, currency.USDT, "MAIN")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
err = e.TransferFundsToFuturesAccount(t.Context(), 1, currency.EMPTYCODE, "MAIN")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
err = e.TransferFundsToFuturesAccount(t.Context(), 1, currency.USDT, "")
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
err = e.TransferFundsToFuturesAccount(t.Context(), 1, currency.USDT, "MAIN")
assert.NoError(t, err)
}
func TestGetFuturesTransferOutList(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesTransferOutList(t.Context(), currency.EMPTYCODE, "", time.Time{}, time.Time{})
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesTransferOutList(t.Context(), currency.USDT, "", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestFetchTradablePairs(t *testing.T) {
t.Parallel()
assetTypes := e.GetAssetTypes(true)
for _, assetType := range assetTypes {
result, err := e.FetchTradablePairs(t.Context(), assetType)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestUpdateOrderbook(t *testing.T) {
t.Parallel()
var result *orderbook.Book
var err error
for assetType, tp := range assertToTradablePairMap {
result, err = e.UpdateOrderbook(t.Context(), tp, assetType)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestUpdateTickers(t *testing.T) {
t.Parallel()
for _, a := range e.GetAssetTypes(true) {
err := e.UpdateTickers(t.Context(), a)
assert.NoError(t, err)
pairs, err := e.GetEnabledPairs(a)
assert.NoError(t, err)
assert.NotEmpty(t, pairs)
for _, p := range pairs {
tick, err := ticker.GetTicker(e.Name, p, a)
if assert.NoError(t, err) {
assert.Positivef(t, tick.Last, "%s %s Tick Last should be positive", a, p)
assert.NotEmptyf(t, tick.Pair, "%s %s Tick Pair should not be empty", a, p)
assert.Equalf(t, e.Name, tick.ExchangeName, "ExchangeName should be correct")
assert.Equalf(t, a, tick.AssetType, "AssetType should be correct")
assert.NotEmptyf(t, tick.LastUpdated, "%s %s Tick LastUpdated should not be empty", a, p)
}
}
}
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
var result *ticker.Price
var err error
for assetType, tp := range assertToTradablePairMap {
result, err = e.UpdateTicker(t.Context(), tp, assetType)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestGetHistoricCandles(t *testing.T) {
startTime := time.Now().Add(-time.Hour * 48)
endTime := time.Now().Add(-time.Hour * 3)
var result *kline.Item
var err error
for assetType, tp := range assertToTradablePairMap {
result, err = e.GetHistoricCandles(t.Context(), tp, assetType, kline.OneHour, startTime, endTime)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestGetHistoricCandlesExtended(t *testing.T) {
startTime := time.Now().Add(-time.Hour * 48 * 10)
endTime := time.Now().Add(-time.Hour * 1)
result, err := e.GetHistoricCandlesExtended(t.Context(), futuresTradablePair, asset.Futures, kline.FifteenMin, startTime, endTime)
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetHistoricCandlesExtended(t.Context(), spotTradablePair, asset.Spot, kline.FifteenMin, startTime, endTime)
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetHistoricCandlesExtended(t.Context(), marginTradablePair, asset.Margin, kline.FifteenMin, startTime, endTime)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetServerTime(t *testing.T) {
t.Parallel()
for _, a := range []asset.Item{asset.Spot, asset.Futures, asset.Margin} {
result, err := e.GetServerTime(t.Context(), a)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestGetRecentTrades(t *testing.T) {
t.Parallel()
var result []trade.Data
var err error
for assetType, tp := range assertToTradablePairMap {
result, err = e.GetRecentTrades(t.Context(), tp, assetType)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
func TestGetOrderHistory(t *testing.T) {
t.Parallel()
getOrdersRequest := order.MultiOrderRequest{
Type: order.Limit,
Pairs: []currency.Pair{futuresTradablePair},
AssetType: asset.Binary,
Side: order.AnySide,
}
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
require.ErrorIs(t, err, asset.ErrNotSupported)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
getOrdersRequest.AssetType = asset.Futures
result, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.AssetType = asset.Spot
getOrdersRequest.Pairs = []currency.Pair{}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.Pairs = []currency.Pair{spotTradablePair}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.Type = order.OCO
getOrdersRequest.Pairs = []currency.Pair{}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.Pairs = []currency.Pair{spotTradablePair}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.AssetType = asset.Margin
getOrdersRequest.Type = order.Stop
getOrdersRequest.Pairs = []currency.Pair{spotTradablePair}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.Pairs = []currency.Pair{}
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
getOrdersRequest.Type = order.StopLimit
getOrdersRequest.MarginType = margin.Multi
result, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetActiveOrders(t *testing.T) {
t.Parallel()
var getOrdersRequest order.MultiOrderRequest
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
assert.NoError(t, err)
getOrdersRequest = order.MultiOrderRequest{
Pairs: enabledPairs,
AssetType: asset.Spot,
Side: order.Buy,
}
getOrdersRequest.Type = order.OptimalLimit
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
require.ErrorIs(t, err, order.ErrUnsupportedOrderType)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
getOrdersRequest.Type = order.Limit
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Pairs = []currency.Pair{}
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.Market
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
enabledPairs, err = e.GetEnabledPairs(asset.Spot)
assert.NoError(t, err)
getOrdersRequest = order.MultiOrderRequest{
Type: order.Limit,
Pairs: enabledPairs,
AssetType: asset.Margin,
Side: order.Buy,
}
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Pairs = []currency.Pair{}
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.Market
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.OCO
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.StopMarket
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.Stop
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
enabledPairs, err = e.GetEnabledPairs(asset.Futures)
assert.NoError(t, err)
getOrdersRequest = order.MultiOrderRequest{
Type: order.Limit,
Pairs: enabledPairs,
AssetType: asset.Futures,
Side: order.Buy,
}
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Pairs = []currency.Pair{}
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
getOrdersRequest.Type = order.StopLimit
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
assert.NoError(t, err)
}
func TestGetFeeByType(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFeeByType(t.Context(), &exchange.FeeBuilder{
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), currency.DashDelimiter),
PurchasePrice: 1,
FiatCurrency: currency.USD,
BankTransactionType: exchange.WireTransfer,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestValidateCredentials(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
assetTypes := e.CurrencyPairs.GetAssetTypes(true)
for _, at := range assetTypes {
err := e.ValidateCredentials(t.Context(), at)
assert.NoError(t, err)
}
}
func TestGetInstanceServers(t *testing.T) {
t.Parallel()
result, err := e.GetInstanceServers(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAuthenticatedServersInstances(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAuthenticatedInstanceServers(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPushData(t *testing.T) {
t.Parallel()
e := testInstance(t) //nolint:govet // Intentional shadow
e.SetCredentials("mock", "test", "test", "", "", "")
e.API.AuthenticatedSupport = true
e.API.AuthenticatedWebsocketSupport = true
fErrs := testexch.FixtureToDataHandlerWithErrors(t, "testdata/wsHandleData.json", func(ctx context.Context, r []byte) error {
if bytes.Contains(r, []byte("FANGLE-ACCOUNTS")) {
hold := e.Accounts
e.Accounts = nil
defer func() { e.Accounts = hold }()
}
return e.wsHandleData(ctx, r)
})
close(e.Websocket.DataHandler)
assert.Len(t, e.Websocket.DataHandler, 29, "Should see correct number of messages")
require.Len(t, fErrs, 1, "Must get exactly one error message")
assert.ErrorContains(t, fErrs[0].Err, "cannot save holdings: nil pointer: *accounts.Accounts")
}
func TestGenerateSubscriptions(t *testing.T) {
t.Parallel()
ku := testInstance(t)
// Pairs overlap for spot/margin tests:
// Only in Spot: BTC-USDT, ETH-USDT
// In Both: ETH-BTC, LTC-USDT
// Only in Margin: TRX-BTC, SOL-USDC
pairs := map[string]currency.Pairs{}
for a, ss := range map[string][]string{
"spot": {"BTC-USDT", "ETH-BTC", "ETH-USDT", "LTC-USDT"},
"margin": {"ETH-BTC", "LTC-USDT", "SOL-USDC", "TRX-BTC"},
"futures": {"ETHUSDCM", "SOLUSDTM", "XBTUSDCM"},
} {
for _, s := range ss {
p, err := currency.NewPairFromString(s)
require.NoError(t, err, "NewPairFromString must not error")
pairs[a] = pairs[a].Add(p)
}
}
pairs["both"] = common.SortStrings(pairs["spot"].Add(pairs["margin"]...))
exp := subscription.List{
{Channel: subscription.TickerChannel, Asset: asset.Spot, Pairs: pairs["both"], QualifiedChannel: "/market/ticker:" + pairs["both"].Join()},
{Channel: subscription.TickerChannel, Asset: asset.Futures, Pairs: pairs["futures"], QualifiedChannel: "/contractMarket/tickerV2:" + pairs["futures"].Join()},
{
Channel: subscription.OrderbookChannel, Asset: asset.Spot, Pairs: pairs["both"], QualifiedChannel: "/spotMarket/level2Depth5:" + pairs["both"].Join(),
Interval: kline.HundredMilliseconds,
},
{
Channel: subscription.OrderbookChannel, Asset: asset.Futures, Pairs: pairs["futures"], QualifiedChannel: "/contractMarket/level2Depth5:" + pairs["futures"].Join(),
Interval: kline.HundredMilliseconds,
},
{Channel: subscription.AllTradesChannel, Asset: asset.Spot, Pairs: pairs["both"], QualifiedChannel: "/market/match:" + pairs["both"].Join()},
}
subs, err := ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions must not error")
testsubs.EqualLists(t, exp, subs)
ku.Websocket.SetCanUseAuthenticatedEndpoints(true)
var loanPairs currency.Pairs
loanCurrs := common.SortStrings(pairs["both"].GetCurrencies())
for _, c := range loanCurrs {
loanPairs = append(loanPairs, currency.Pair{Base: c})
}
exp = append(exp, subscription.List{
{Asset: asset.Futures, Channel: futuresTradeOrderChannel, QualifiedChannel: "/contractMarket/tradeOrders", Pairs: pairs["futures"]},
{Asset: asset.Futures, Channel: futuresStopOrdersLifecycleEventChannel, QualifiedChannel: "/contractMarket/advancedOrders", Pairs: pairs["futures"]},
{Asset: asset.Futures, Channel: futuresAccountBalanceEventChannel, QualifiedChannel: "/contractAccount/wallet", Pairs: pairs["futures"]},
{Asset: asset.Margin, Channel: marginPositionChannel, QualifiedChannel: "/margin/position", Pairs: pairs["margin"]},
{Asset: asset.Margin, Channel: marginLoanChannel, QualifiedChannel: "/margin/loan:" + loanCurrs.Join(), Pairs: loanPairs},
{Channel: accountBalanceChannel, QualifiedChannel: "/account/balance"},
}...)
subs, err = ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions with Auth must not error")
testsubs.EqualLists(t, exp, subs)
}
func TestGenerateTickerAllSub(t *testing.T) {
t.Parallel()
ku := testInstance(t)
avail, err := ku.GetAvailablePairs(asset.Spot)
require.NoError(t, err, "GetAvailablePairs must not error")
err = ku.CurrencyPairs.StorePairs(asset.Spot, avail[:11], true)
require.NoError(t, err, "StorePairs must not error")
ku.Features.Subscriptions = subscription.List{{Channel: subscription.TickerChannel, Asset: asset.Spot}}
exp := subscription.List{
{Channel: subscription.TickerChannel, Asset: asset.Spot, QualifiedChannel: "/market/ticker:all", Pairs: avail[:11]},
}
subs, err := ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions with Auth must not error")
testsubs.EqualLists(t, exp, subs)
}
// TestGenerateOtherSubscriptions exercises non-default subscriptions
func TestGenerateOtherSubscriptions(t *testing.T) {
t.Parallel()
ku := testInstance(t)
subs := subscription.List{
{Channel: subscription.CandlesChannel, Asset: asset.Spot, Interval: kline.FourHour},
{Channel: marketSnapshotChannel, Asset: asset.Spot},
}
for _, s := range subs {
ku.Features.Subscriptions = subscription.List{s}
got, err := ku.generateSubscriptions()
assert.NoError(t, err, "generateSubscriptions should not error")
require.Len(t, got, 1, "Must generate just one sub")
assert.NotEmpty(t, got[0].QualifiedChannel, "Qualified Channel should not be empty")
if got[0].Channel == subscription.CandlesChannel {
assert.Equal(t, "/market/candles:BTC-USDT_4hour,ETH-BTC_4hour,ETH-USDT_4hour,LTC-USDT_4hour", got[0].QualifiedChannel, "QualifiedChannel should be correct")
}
}
}
// TestGenerateMarginSubscriptions is a regression test for #1755 and ensures margin subscriptions work without spot subs
func TestGenerateMarginSubscriptions(t *testing.T) {
t.Parallel()
ku := testInstance(t)
avail, err := ku.GetAvailablePairs(asset.Spot)
require.NoError(t, err, "GetAvailablePairs must not error storing spot pairs")
avail = common.SortStrings(avail)
err = ku.CurrencyPairs.StorePairs(asset.Margin, avail[:6], true)
require.NoError(t, err, "StorePairs must not error storing margin pairs")
err = ku.CurrencyPairs.StorePairs(asset.Spot, avail[:3], true)
require.NoError(t, err, "StorePairs must not error storing spot pairs")
ku.Features.Subscriptions = subscription.List{{Channel: subscription.TickerChannel, Asset: asset.Margin}}
subs, err := ku.Features.Subscriptions.ExpandTemplates(ku)
require.NoError(t, err, "ExpandTemplates must not error")
require.Len(t, subs, 1, "Must generate just one sub")
assert.Equal(t, asset.Margin, subs[0].Asset, "Asset should be correct")
assert.Equal(t, "/market/ticker:"+avail[:6].Join(), subs[0].QualifiedChannel, "QualifiedChannel should be correct")
require.NoError(t, ku.CurrencyPairs.SetAssetEnabled(asset.Margin, false), "SetAssetEnabled Spot must not error")
require.NoError(t, err, "SetAssetEnabled must not error")
ku.Features.Subscriptions = subscription.List{{Channel: subscription.TickerChannel, Asset: asset.All}}
subs, err = ku.Features.Subscriptions.ExpandTemplates(ku)
require.NoError(t, err, "mergeMarginPairs must not cause errAssetRecords by adding an empty asset when Margin is disabled")
require.NotEmpty(t, subs, "ExpandTemplates must return some subs")
require.NoError(t, ku.CurrencyPairs.SetAssetEnabled(asset.Margin, true), "SetAssetEnabled Margin must not error")
require.NoError(t, ku.CurrencyPairs.SetAssetEnabled(asset.Spot, false), "SetAssetEnabled Spot must not error")
require.NoError(t, ku.CurrencyPairs.SetAssetEnabled(asset.Futures, false), "SetAssetEnabled Futures must not error")
ku.Features.Subscriptions = subscription.List{{Channel: subscription.TickerChannel, Asset: asset.All}}
subs, err = ku.Features.Subscriptions.ExpandTemplates(ku)
require.NoError(t, err, "mergeMarginPairs must not cause errAssetRecords by adding an empty asset when Spot is disabled")
require.NotEmpty(t, subs, "ExpandTemplates must return some subs")
}
// TestCheckSubscriptions ensures checkSubscriptions upgrades user config correctly
func TestCheckSubscriptions(t *testing.T) {
t.Parallel()
ku := &Exchange{
Base: exchange.Base{
Config: &config.Exchange{
Features: &config.FeaturesConfig{
Subscriptions: subscription.List{
{Enabled: true, Channel: "ticker"},
{Enabled: true, Channel: "allTrades"},
{Enabled: true, Channel: "orderbook", Interval: kline.HundredMilliseconds},
{Enabled: true, Channel: "/contractMarket/tickerV2:%s"},
{Enabled: true, Channel: "/contractMarket/level2Depth50:%s"},
{Enabled: true, Channel: "/margin/fundingBook:%s", Authenticated: true},
{Enabled: true, Channel: "/account/balance", Authenticated: true},
{Enabled: true, Channel: "/margin/position", Authenticated: true},
{Enabled: true, Channel: "/margin/loan:%s", Authenticated: true},
{Enabled: true, Channel: "/contractMarket/tradeOrders", Authenticated: true},
{Enabled: true, Channel: "/contractMarket/advancedOrders", Authenticated: true},
{Enabled: true, Channel: "/contractAccount/wallet", Authenticated: true},
},
},
},
Features: exchange.Features{},
},
}
ku.checkSubscriptions()
testsubs.EqualLists(t, defaultSubscriptions, ku.Features.Subscriptions)
testsubs.EqualLists(t, defaultSubscriptions, ku.Config.Features.Subscriptions)
}
func TestGetAvailableTransferChains(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAvailableTransferChains(t.Context(), currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetWithdrawalsHistory(t *testing.T) {
t.Parallel()
_, err := e.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Options)
require.ErrorIs(t, err, asset.ErrNotSupported)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Futures)
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Spot)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
var result *order.Detail
var err error
result, err = e.GetOrderInfo(t.Context(), "54541241349183409134134133", futuresTradablePair, asset.Futures)
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetOrderInfo(t.Context(), "54541241349183409134134133", spotTradablePair, asset.Spot)
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.GetOrderInfo(t.Context(), "54541241349183409134134133", marginTradablePair, asset.Margin)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetDepositAddress(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := e.GetDepositAddress(t.Context(), currency.BTC, "", "")
assert.Truef(t, err == nil || errors.Is(err, errNoDepositAddress), "GetDepositAddress should not error: %s", err)
}
func TestWithdrawCryptocurrencyFunds(t *testing.T) {
t.Parallel()
_, err := e.WithdrawCryptocurrencyFunds(t.Context(), &withdraw.Request{
Exchange: e.Name,
Amount: 0.00000000001,
Crypto: withdraw.CryptoRequest{
Address: core.BitcoinDonationAddress,
},
})
assert.ErrorContains(t, err, withdraw.ErrStrNoCurrencySet)
_, err = e.WithdrawCryptocurrencyFunds(t.Context(), &withdraw.Request{
Exchange: e.Name,
Amount: 0.00000000001,
Currency: currency.BTC,
Crypto: withdraw.CryptoRequest{},
})
assert.ErrorContains(t, err, "address cannot be empty")
_, err = e.WithdrawCryptocurrencyFunds(t.Context(), &withdraw.Request{
Exchange: e.Name,
Currency: currency.BTC,
Crypto: withdraw.CryptoRequest{
Address: core.BitcoinDonationAddress,
},
})
assert.ErrorContains(t, err, withdraw.ErrStrAmountMustBeGreaterThanZero)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.WithdrawCryptocurrencyFunds(t.Context(), &withdraw.Request{
Exchange: e.Name,
Amount: 0.00000000001,
Currency: currency.BTC,
Crypto: withdraw.CryptoRequest{
Address: core.BitcoinDonationAddress,
},
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSubmitOrder(t *testing.T) {
t.Parallel()
orderSubmission := &order.Submit{
Pair: futuresTradablePair,
Exchange: e.Name,
Side: order.Bid,
Type: order.Limit,
Price: 1,
Amount: 100000,
ClientOrderID: "myOrder",
AssetType: asset.Options,
}
_, err := e.SubmitOrder(t.Context(), orderSubmission)
require.ErrorIs(t, err, asset.ErrNotSupported)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
orderSubmission.AssetType = asset.Futures
orderSubmission.Pair = futuresTradablePair
result, err := e.SubmitOrder(t.Context(), orderSubmission)
assert.NoError(t, err)
assert.NotNil(t, result)
orderSubmission.Type = order.OCO
orderSubmission.TriggerPrice = 50000
orderSubmission.TriggerPriceType = order.LastPrice
_, err = e.SubmitOrder(t.Context(), orderSubmission)
require.ErrorIs(t, err, order.ErrUnsupportedOrderType)
// Spot order creation tests
spotOrderSubmission := &order.Submit{
Side: order.Buy,
AssetType: asset.Spot,
Pair: spotTradablePair,
Type: order.Limit,
Price: 1,
Amount: 100000,
ClientOrderID: "myOrder",
}
result, err = e.SubmitOrder(t.Context(), spotOrderSubmission)
assert.NoError(t, err)
assert.NotNil(t, result)
spotOrderSubmission.Type = order.StopLimit
spotOrderSubmission.RiskManagementModes = order.RiskManagementModes{
StopEntry: order.RiskManagement{
Enabled: true,
Price: 1234,
TriggerPriceType: order.LastPrice,
},
}
result, err = e.SubmitOrder(t.Context(), spotOrderSubmission)
assert.NoError(t, err)
assert.NotNil(t, result)
spotOrderSubmission.Type = order.OCO
spotOrderSubmission.Side = order.Sell
spotOrderSubmission.RiskManagementModes.TakeProfit = order.RiskManagement{
Enabled: true,
Price: 1334,
TriggerPriceType: order.LastPrice,
}
spotOrderSubmission.RiskManagementModes.StopLoss = order.RiskManagement{
Enabled: true,
Price: 1234,
TriggerPriceType: order.LastPrice,
}
result, err = e.SubmitOrder(t.Context(), spotOrderSubmission)
assert.NoError(t, err)
assert.NotNil(t, result)
spotOrderSubmission.Type = order.ConditionalStop
_, err = e.SubmitOrder(t.Context(), spotOrderSubmission)
require.ErrorIs(t, err, order.ErrUnsupportedOrderType)
// Margin order creation tests
marginOrderSubmission := &order.Submit{
Side: order.Buy,
AssetType: asset.Margin,
Pair: marginTradablePair,
Type: order.Limit,
Price: 1,
Amount: 100000,
ClientOrderID: "myOrder",
}
result, err = e.SubmitOrder(t.Context(), marginOrderSubmission)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
orderCancellation := &order.Cancel{
OrderID: "1",
AccountID: "1",
Pair: futuresTradablePair,
AssetType: asset.Options,
}
err := e.CancelOrder(t.Context(), orderCancellation)
require.ErrorIs(t, err, asset.ErrNotSupported)
orderCancellation.AssetType = asset.Futures
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.OrderID = ""
orderCancellation.ClientOrderID = "12345"
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.Pair = currency.EMPTYPAIR
err = e.CancelOrder(t.Context(), orderCancellation)
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
orderCancellation.AssetType = asset.Spot
orderCancellation.Pair = spotTradablePair
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.Type = order.OCO
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.OrderID = "12345"
orderCancellation.ClientOrderID = ""
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.Type = order.Stop
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.OrderID = ""
orderCancellation.ClientOrderID = "12345"
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.Type = order.Limit
orderCancellation.AssetType = asset.Margin
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.ClientOrderID = ""
orderCancellation.OrderID = "12345"
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.AssetType = asset.Margin
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
orderCancellation.ClientOrderID = ""
orderCancellation.OrderID = "12345"
orderCancellation.AssetType = asset.Margin
err = e.CancelOrder(t.Context(), orderCancellation)
assert.NoError(t, err)
}
func TestCancelAllOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllOrders(t.Context(), &order.Cancel{
AssetType: asset.Futures,
MarginType: margin.Isolated,
})
assert.NoError(t, err)
assert.NotNil(t, result)
_, err = e.CancelAllOrders(t.Context(), &order.Cancel{
AssetType: asset.Margin,
MarginType: margin.Isolated,
})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
result, err = e.CancelAllOrders(t.Context(), &order.Cancel{
AssetType: asset.Spot,
Type: order.OCO,
})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.CancelAllOrders(t.Context(), &order.Cancel{
AssetType: asset.Spot,
Type: order.Stop,
})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.CancelAllOrders(t.Context(), &order.Cancel{
AssetType: asset.Spot,
Type: order.StopLimit,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
const (
subUserResponseJSON = `{"userId":"635002438793b80001dcc8b3", "uid":62356, "subName":"margin01", "status":2, "type":4, "access":"Margin", "createdAt":1666187844000, "remarks":null }`
transferFuturesFundsResponseJSON = `{"applyId": "620a0bbefeaa6a000110e833", "bizNo": "620a0bbefeaa6a000110e832", "payAccountType": "CONTRACT", "payTag": "DEFAULT", "remark": "", "recAccountType": "MAIN", "recTag": "DEFAULT", "recRemark": "", "recSystem": "KUCOIN", "status": "PROCESSING", "currency": "USDT", "amount": "0.001", "fee": "0", "sn": 889048787670001, "reason": "", "createdAt": 1644825534000, "updatedAt": 1644825534000}`
modifySubAccountSpotAPIs = `{"subName": "AAAAAAAAAA0007", "remark": "remark", "apiKey": "630325e0e750870001829864", "apiSecret": "110f31fc-61c5-4baf-a29f-3f19a62bbf5d", "passphrase": "passphrase", "permission": "General", "ipWhitelist": "", "createdAt": 1661150688000}`
)
func TestCreateSubUser(t *testing.T) {
t.Parallel()
var resp *SubAccount
err := json.Unmarshal([]byte(subUserResponseJSON), &resp)
assert.NoError(t, err)
_, err = e.CreateSubUser(t.Context(), "", "Subaccount-1", "", "")
require.ErrorIs(t, err, errInvalidSubAccountName)
_, err = e.CreateSubUser(t.Context(), "Subaccount-2", "", "", "")
require.ErrorIs(t, err, errInvalidPassPhraseInstance)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CreateSubUser(t.Context(), "Subaccount-2", "Subaccount-1", "", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetSubAccountSpotAPIList(t *testing.T) {
t.Parallel()
_, err := e.GetSubAccountSpotAPIList(t.Context(), "", "")
require.ErrorIs(t, err, errInvalidSubAccountName)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetSubAccountSpotAPIList(t.Context(), "Sam", "")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCreateSpotAPIsForSubAccount(t *testing.T) {
t.Parallel()
_, err := e.CreateSpotAPIsForSubAccount(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "",
Passphrase: "mysecretPassphrase123",
Remark: "the-remark",
})
require.ErrorIs(t, err, errInvalidSubAccountName)
_, err = e.CreateSpotAPIsForSubAccount(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "gocryptoTrader1",
Passphrase: "",
Remark: "the-remark",
})
require.ErrorIs(t, err, errInvalidPassPhraseInstance)
_, err = e.CreateSpotAPIsForSubAccount(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "gocryptoTrader1",
Passphrase: "mysecretPassphrase123",
Remark: "",
})
require.ErrorIs(t, err, errRemarkIsRequired)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CreateSpotAPIsForSubAccount(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "gocryptoTrader1",
Passphrase: "mysecretPassphrase123",
Remark: "the-remark",
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestModifySubAccountSpotAPIs(t *testing.T) {
t.Parallel()
var resp SpotAPISubAccount
err := json.Unmarshal([]byte(modifySubAccountSpotAPIs), &resp)
assert.NoError(t, err)
_, err = e.ModifySubAccountSpotAPIs(t.Context(), &SpotAPISubAccountParams{
APIKey: "65e7f22077172b0001f9ee41", SubAccountName: "", Passphrase: "mysecretPassphrase123",
})
require.ErrorIs(t, err, errInvalidSubAccountName)
_, err = e.ModifySubAccountSpotAPIs(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "gocryptoTrader1", Passphrase: "mysecretPassphrase123",
})
require.ErrorIs(t, err, errAPIKeyRequired)
_, err = e.ModifySubAccountSpotAPIs(t.Context(), &SpotAPISubAccountParams{
APIKey: "65e7f22077172b0001f9ee41", SubAccountName: "gocryptoTrader1", Passphrase: "",
})
require.ErrorIs(t, err, errInvalidPassPhraseInstance)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.ModifySubAccountSpotAPIs(t.Context(), &SpotAPISubAccountParams{
SubAccountName: "gocryptoTrader1",
Passphrase: "mysecretPassphrase123",
APIKey: apiKey,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestDeleteSubAccountSpotAPI(t *testing.T) {
t.Parallel()
_, err := e.DeleteSubAccountSpotAPI(t.Context(), "65e7f22077172b0001f9ee41", "", "the-passphrase")
require.ErrorIs(t, err, errInvalidSubAccountName)
_, err = e.DeleteSubAccountSpotAPI(t.Context(), "", "gocryptoTrader1", "the-passphrase")
require.ErrorIs(t, err, errAPIKeyRequired)
_, err = e.DeleteSubAccountSpotAPI(t.Context(), "65e7f22077172b0001f9ee41", "gocryptoTrader1", "")
require.ErrorIs(t, err, errInvalidPassPhraseInstance)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.DeleteSubAccountSpotAPI(t.Context(), apiKey, "gocryptoTrader1", "the-passphrase")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetUserInfoOfAllSubAccounts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetUserInfoOfAllSubAccounts(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetPaginatedListOfSubAccounts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetPaginatedListOfSubAccounts(t.Context(), 1, 100)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFundingHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAccountFundingHistory(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func getFirstTradablePairOfAssets(ctx context.Context) {
if err := e.UpdateTradablePairs(ctx); err != nil {
log.Fatalf("Kucoin error while updating tradable pairs. %v", err)
}
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
if err != nil {
log.Fatalf("Kucoin %v, trying to get %v enabled pairs error", err, asset.Spot)
}
spotTradablePair = enabledPairs[0]
enabledPairs, err = e.GetEnabledPairs(asset.Margin)
if err != nil {
log.Fatalf("Kucoin %v, trying to get %v enabled pairs error", err, asset.Margin)
}
marginTradablePair = enabledPairs[0]
enabledPairs, err = e.GetEnabledPairs(asset.Futures)
if err != nil {
log.Fatalf("Kucoin %v, trying to get %v enabled pairs error", err, asset.Futures)
}
futuresTradablePair = enabledPairs[0]
futuresTradablePair.Delimiter = ""
}
func TestUpdateAccountBalances(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
assetTypes := e.GetAssetTypes(true)
for _, assetType := range assetTypes {
result, err := e.UpdateAccountBalances(t.Context(), assetType)
assert.NoError(t, err)
assert.NotNil(t, result)
}
}
const (
orderbookLevel5PushData = `{"type": "message","topic": "/spotMarket/level2Depth50:BTC-USDT","subject": "level2","data": {"asks": [["21621.7","3.03206193"],["21621.8","1.00048239"],["21621.9","0.29558803"],["21622","0.0049653"],["21622.4","0.06177582"],["21622.9","0.39664116"],["21623.7","0.00803466"],["21624.2","0.65405"],["21624.3","0.34661426"],["21624.6","0.00035589"],["21624.9","0.61282048"],["21625.2","0.16421424"],["21625.4","0.90107014"],["21625.5","0.73484442"],["21625.9","0.04"],["21626.2","0.28569324"],["21626.4","0.18403701"],["21627.1","0.06503999"],["21627.2","0.56105832"],["21627.7","0.10649999"],["21628.1","2.66459953"],["21628.2","0.32"],["21628.5","0.27605551"],["21628.6","1.59482596"],["21628.9","0.16"],["21629.8","0.08"],["21630","0.04"],["21631.6","0.1"],["21631.8","0.0920185"],["21633.6","0.00447983"],["21633.7","0.00015044"],["21634.3","0.32193346"],["21634.4","0.00004"],["21634.5","0.1"],["21634.6","0.0002865"],["21635.6","0.12069941"],["21635.8","0.00117158"],["21636","0.00072816"],["21636.5","0.98611492"],["21636.6","0.00007521"],["21637.2","0.00699999"],["21637.6","0.00017129"],["21638","0.00013035"],["21638.1","0.05"],["21638.5","0.92427"],["21639.2","1.84998696"],["21639.3","0.04827233"],["21640","0.56255996"],["21640.9","0.8"],["21641","0.12"]],"bids": [["21621.6","0.40949924"],["21621.5","0.27703279"],["21621.3","0.04"],["21621.1","0.0086"],["21621","0.6653104"],["21620.9","0.35435999"],["21620.8","0.37224309"],["21620.5","0.416184"],["21620.3","0.24"],["21619.6","0.13883999"],["21619.5","0.21053355"],["21618.7","0.2"],["21618.6","0.001"],["21618.5","0.2258151"],["21618.4","0.06503999"],["21618.3","0.00370056"],["21618","0.12067842"],["21617.7","0.34844131"],["21617.6","0.92845495"],["21617.5","0.66460535"],["21617","0.01"],["21616.7","0.0004624"],["21616.4","0.02"],["21615.6","0.04828251"],["21615","0.59065665"],["21614.4","0.00227"],["21614.3","0.1"],["21613","0.32193346"],["21612.9","0.0028638"],["21612.6","0.1"],["21612.5","0.92539"],["21610.7","0.08208616"],["21610.6","0.00967666"],["21610.3","0.12"],["21610.2","0.00611126"],["21609.9","0.00226344"],["21609.8","0.00315812"],["21609.1","0.00547218"],["21608.6","0.09793157"],["21608.5","0.00437793"],["21608.4","1.85013454"],["21608.1","0.00366647"],["21607.9","0.00611595"],["21607.7","0.83263561"],["21607.6","0.00368919"],["21607.5","0.00280702"],["21607.1","0.66610849"],["21606.8","0.00364164"],["21606.2","0.80351642"],["21605.7","0.075"]],"timestamp": 1676319280783}}`
wsOrderbookData = `{"changes":{"asks":[["21621.7","3.03206193",""],["21621.8","1.00048239",""],["21621.9","0.29558803",""],["21622","0.0049653",""],["21622.4","0.06177582",""],["21622.9","0.39664116",""],["21623.7","0.00803466",""],["21624.2","0.65405",""],["21624.3","0.34661426",""],["21624.6","0.00035589",""],["21624.9","0.61282048",""],["21625.2","0.16421424",""],["21625.4","0.90107014",""],["21625.5","0.73484442",""],["21625.9","0.04",""],["21626.2","0.28569324",""],["21626.4","0.18403701",""],["21627.1","0.06503999",""],["21627.2","0.56105832",""],["21627.7","0.10649999",""],["21628.1","2.66459953",""],["21628.2","0.32",""],["21628.5","0.27605551",""],["21628.6","1.59482596",""],["21628.9","0.16",""],["21629.8","0.08",""],["21630","0.04",""],["21631.6","0.1",""],["21631.8","0.0920185",""],["21633.6","0.00447983",""],["21633.7","0.00015044",""],["21634.3","0.32193346",""],["21634.4","0.00004",""],["21634.5","0.1",""],["21634.6","0.0002865",""],["21635.6","0.12069941",""],["21635.8","0.00117158",""],["21636","0.00072816",""],["21636.5","0.98611492",""],["21636.6","0.00007521",""],["21637.2","0.00699999",""],["21637.6","0.00017129",""],["21638","0.00013035",""],["21638.1","0.05",""],["21638.5","0.92427",""],["21639.2","1.84998696",""],["21639.3","0.04827233",""],["21640","0.56255996",""],["21640.9","0.8",""],["21641","0.12",""]],"bids":[["21621.6","0.40949924",""],["21621.5","0.27703279",""],["21621.3","0.04",""],["21621.1","0.0086",""],["21621","0.6653104",""],["21620.9","0.35435999",""],["21620.8","0.37224309",""],["21620.5","0.416184",""],["21620.3","0.24",""],["21619.6","0.13883999",""],["21619.5","0.21053355",""],["21618.7","0.2",""],["21618.6","0.001",""],["21618.5","0.2258151",""],["21618.4","0.06503999",""],["21618.3","0.00370056",""],["21618","0.12067842",""],["21617.7","0.34844131",""],["21617.6","0.92845495",""],["21617.5","0.66460535",""],["21617","0.01",""],["21616.7","0.0004624",""],["21616.4","0.02",""],["21615.6","0.04828251",""],["21615","0.59065665",""],["21614.4","0.00227",""],["21614.3","0.1",""],["21613","0.32193346",""],["21612.9","0.0028638",""],["21612.6","0.1",""],["21612.5","0.92539",""],["21610.7","0.08208616",""],["21610.6","0.00967666",""],["21610.3","0.12",""],["21610.2","0.00611126",""],["21609.9","0.00226344",""],["21609.8","0.00315812",""],["21609.1","0.00547218",""],["21608.6","0.09793157",""],["21608.5","0.00437793",""],["21608.4","1.85013454",""],["21608.1","0.00366647",""],["21607.9","0.00611595",""],["21607.7","0.83263561",""],["21607.6","0.00368919",""],["21607.5","0.00280702",""],["21607.1","0.66610849",""],["21606.8","0.00364164",""],["21606.2","0.80351642",""],["21605.7","0.075",""]]},"sequenceEnd":1676319280783,"sequenceStart":0,"symbol":"BTC-USDT","time":1676319280783}`
)
func TestProcessOrderbook(t *testing.T) {
t.Parallel()
response := &WsOrderbook{}
err := json.Unmarshal([]byte(wsOrderbookData), &response)
assert.NoError(t, err)
e.setupOrderbookManager(t.Context())
result, err := e.updateLocalBuffer(response, asset.Spot)
assert.NoError(t, err)
assert.NotNil(t, result)
err = e.processOrderbook([]byte(orderbookLevel5PushData), "BTC-USDT", "")
assert.NoError(t, err)
assert.NotNil(t, result)
err = e.wsHandleData(t.Context(), []byte(orderbookLevel5PushData))
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestProcessMarketSnapshot(t *testing.T) {
t.Parallel()
ku := testInstance(t)
testexch.FixtureToDataHandler(t, "testdata/wsMarketSnapshot.json", ku.wsHandleData)
close(ku.Websocket.DataHandler)
assert.Len(t, ku.Websocket.DataHandler, 4, "Should see 4 tickers")
seenAssetTypes := map[asset.Item]int{}
for resp := range ku.Websocket.DataHandler {
switch v := resp.(type) {
case *ticker.Price:
switch len(ku.Websocket.DataHandler) {
case 3:
assert.Equal(t, asset.Margin, v.AssetType, "AssetType")
assert.Equal(t, time.UnixMilli(1700555342007), v.LastUpdated, "datetime")
assert.Equal(t, 0.004445, v.High, "high")
assert.Equal(t, 0.004415, v.Last, "lastTradedPrice")
assert.Equal(t, 0.004191, v.Low, "low")
assert.Equal(t, currency.NewPairWithDelimiter("TRX", "BTC", "-"), v.Pair, "symbol")
assert.Equal(t, 13097.3357, v.Volume, "volume")
assert.Equal(t, 57.44552981, v.QuoteVolume, "volValue")
case 2, 1:
assert.Equal(t, time.UnixMilli(1700555340197), v.LastUpdated, "datetime")
assert.Contains(t, []asset.Item{asset.Spot, asset.Margin}, v.AssetType, "AssetType is Spot or Margin")
seenAssetTypes[v.AssetType]++
assert.Equal(t, 1, seenAssetTypes[v.AssetType], "Each Asset Type is sent only once per unique snapshot")
assert.Equal(t, 0.054846, v.High, "high")
assert.Equal(t, 0.053778, v.Last, "lastTradedPrice")
assert.Equal(t, 0.05364, v.Low, "low")
assert.Equal(t, currency.NewPairWithDelimiter("ETH", "BTC", "-"), v.Pair, "symbol")
assert.Equal(t, 2958.3139116, v.Volume, "volume")
assert.Equal(t, 160.7847672784213, v.QuoteVolume, "volValue")
case 0:
assert.Equal(t, asset.Spot, v.AssetType, "AssetType")
assert.Equal(t, time.UnixMilli(1700555342151), v.LastUpdated, "datetime")
assert.Equal(t, 37750.0, v.High, "high")
assert.Equal(t, 37366.8, v.Last, "lastTradedPrice")
assert.Equal(t, 36700.0, v.Low, "low")
assert.Equal(t, currency.NewPairWithDelimiter("BTC", "USDT", "-"), v.Pair, "symbol")
assert.Equal(t, 2900.37846402, v.Volume, "volume")
assert.Equal(t, 108210331.34015164, v.QuoteVolume, "volValue")
}
case error:
t.Error(v)
default:
t.Errorf("Got unexpected data: %T %v", v, v)
}
}
}
// TestSubscribeBatches ensures that endpoints support batching, contrary to kucoin api docs
func TestSubscribeBatches(t *testing.T) {
t.Parallel()
ku := testInstance(t)
ku.Features.Subscriptions = subscription.List{}
testexch.SetupWs(t, ku)
ku.Features.Subscriptions = subscription.List{
{Asset: asset.Spot, Channel: subscription.CandlesChannel, Interval: kline.OneMin},
{Asset: asset.Futures, Channel: subscription.TickerChannel},
{Asset: asset.Spot, Channel: marketSnapshotChannel},
}
subs, err := ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions must not error")
require.Len(t, subs, len(ku.Features.Subscriptions), "Must generate batched subscriptions")
err = ku.Subscribe(subs)
assert.NoError(t, err, "Subscribe to small batches should not error")
}
// TestSubscribeTickerAll ensures that ticker subscriptions switch to using all and it works
// TestSubscribeBatchLimit exercises the kucoin batch limits of 400 per connection
// Ensures batching of 100 pairs and the connection symbol limit is still 400 at Kucoin's end
func TestSubscribeBatchLimit(t *testing.T) {
t.Parallel()
const expectedLimit = 400
ku := testInstance(t)
ku.Features.Subscriptions = subscription.List{}
testexch.SetupWs(t, ku)
avail, err := ku.GetAvailablePairs(asset.Spot)
require.NoError(t, err, "GetAvailablePairs must not error")
err = ku.CurrencyPairs.StorePairs(asset.Spot, avail[:expectedLimit], true)
require.NoError(t, err, "StorePairs must not error")
ku.Features.Subscriptions = subscription.List{{Asset: asset.Spot, Channel: subscription.AllTradesChannel}}
subs, err := ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions must not error")
require.Len(t, subs, 4, "Must get 4 subs")
err = ku.Subscribe(subs)
require.NoError(t, err, "Subscribe must not error")
err = ku.Unsubscribe(subs)
require.NoError(t, err, "Unsubscribe must not error")
err = ku.CurrencyPairs.StorePairs(asset.Spot, avail[:expectedLimit+20], true)
require.NoError(t, err, "StorePairs must not error")
ku.Features.Subscriptions = subscription.List{{Asset: asset.Spot, Channel: subscription.AllTradesChannel}}
subs, err = ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions must not error")
require.Len(t, subs, 5, "Must get 5 subs")
err = ku.Subscribe(subs)
require.Error(t, err, "Subscribe must error")
assert.ErrorContains(t, err, "exceed max subscription count limitation of 400 per session", "Subscribe to MarketSnapshot should error above connection symbol limit")
}
func TestSubscribeTickerAll(t *testing.T) {
t.Parallel()
ku := testInstance(t)
ku.Features.Subscriptions = subscription.List{}
testexch.SetupWs(t, ku)
avail, err := ku.GetAvailablePairs(asset.Spot)
require.NoError(t, err, "GetAvailablePairs must not error")
err = ku.CurrencyPairs.StorePairs(asset.Spot, avail[:500], true)
require.NoError(t, err, "StorePairs must not error")
ku.Features.Subscriptions = subscription.List{{Asset: asset.Spot, Channel: subscription.TickerChannel}}
subs, err := ku.generateSubscriptions()
require.NoError(t, err, "generateSubscriptions must not error")
require.Len(t, subs, 1, "Must generate one subscription")
assert.Equal(t, "/market/ticker:all", subs[0].QualifiedChannel, "QualifiedChannel should be correct")
err = ku.Subscribe(subs)
assert.NoError(t, err, "Subscribe to should not error")
}
func TestSeedLocalCache(t *testing.T) {
t.Parallel()
err := e.SeedLocalCache(t.Context(), marginTradablePair, asset.Margin)
assert.NoError(t, err)
}
func TestGetFuturesContractDetails(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesContractDetails(t.Context(), asset.Spot)
require.ErrorIs(t, err, futures.ErrNotFuturesAsset)
_, err = e.GetFuturesContractDetails(t.Context(), asset.USDTMarginedFutures)
require.ErrorIs(t, err, asset.ErrNotSupported)
result, err := e.GetFuturesContractDetails(t.Context(), asset.Futures)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetLatestFundingRates(t *testing.T) {
t.Parallel()
_, err := e.GetLatestFundingRates(t.Context(), nil)
require.ErrorIs(t, err, common.ErrNilPointer)
req := &fundingrate.LatestRateRequest{
Asset: asset.Futures,
Pair: currency.NewBTCUSD(),
}
_, err = e.GetLatestFundingRates(t.Context(), req)
require.ErrorIs(t, err, futures.ErrNotPerpetualFuture)
req = &fundingrate.LatestRateRequest{
Asset: asset.Futures,
Pair: currency.NewPair(currency.XBT, currency.USDTM),
}
resp, err := e.GetLatestFundingRates(t.Context(), req)
assert.NoError(t, err)
assert.Len(t, resp, 1)
req = &fundingrate.LatestRateRequest{
Asset: asset.Futures,
Pair: currency.EMPTYPAIR,
}
resp, err = e.GetLatestFundingRates(t.Context(), req)
assert.NoError(t, err)
assert.NotEmpty(t, resp)
}
func TestIsPerpetualFutureCurrency(t *testing.T) {
t.Parallel()
is, err := e.IsPerpetualFutureCurrency(asset.Spot, currency.EMPTYPAIR)
assert.NoError(t, err)
assert.False(t, is)
is, err = e.IsPerpetualFutureCurrency(asset.Futures, currency.EMPTYPAIR)
assert.NoError(t, err)
assert.False(t, is)
is, err = e.IsPerpetualFutureCurrency(asset.Futures, currency.NewPair(currency.XBT, currency.EOS))
assert.NoError(t, err)
assert.False(t, is)
is, err = e.IsPerpetualFutureCurrency(asset.Futures, currency.NewPair(currency.XBT, currency.USDTM))
assert.NoError(t, err)
assert.True(t, is)
is, err = e.IsPerpetualFutureCurrency(asset.Futures, currency.NewPair(currency.XBT, currency.USDM))
assert.NoError(t, err)
assert.True(t, is)
}
func TestChangePositionMargin(t *testing.T) {
t.Parallel()
_, err := e.ChangePositionMargin(t.Context(), nil)
require.ErrorIs(t, err, common.ErrNilPointer)
req := &margin.PositionChangeRequest{}
_, err = e.ChangePositionMargin(t.Context(), req)
require.ErrorIs(t, err, futures.ErrNotFuturesAsset)
req.Asset = asset.Futures
_, err = e.ChangePositionMargin(t.Context(), req)
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
req.Pair = currency.NewPair(currency.XBT, currency.USDTM)
_, err = e.ChangePositionMargin(t.Context(), req)
require.ErrorIs(t, err, margin.ErrMarginTypeUnsupported)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
req.MarginType = margin.Isolated
result, err := e.ChangePositionMargin(t.Context(), req)
assert.NoError(t, err)
assert.NotNil(t, result)
req.NewAllocatedMargin = 1337
result, err = e.ChangePositionMargin(t.Context(), req)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPositionSummary(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPositionSummary(t.Context(), nil)
require.ErrorIs(t, err, common.ErrNilPointer)
req := &futures.PositionSummaryRequest{}
_, err = e.GetFuturesPositionSummary(t.Context(), req)
require.ErrorIs(t, err, futures.ErrNotPerpetualFuture)
req.Asset = asset.Futures
_, err = e.GetFuturesPositionSummary(t.Context(), req)
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
req.Pair = currency.NewPair(currency.XBT, currency.USDTM)
result, err := e.GetFuturesPositionSummary(t.Context(), req)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesPositionOrders(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesPositionOrders(t.Context(), nil)
require.ErrorIs(t, err, common.ErrNilPointer)
req := &futures.PositionsRequest{}
_, err = e.GetFuturesPositionOrders(t.Context(), req)
require.ErrorIs(t, err, futures.ErrNotPerpetualFuture)
req.Asset = asset.Futures
_, err = e.GetFuturesPositionOrders(t.Context(), req)
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
req.Pairs = currency.Pairs{
currency.NewPair(currency.XBT, currency.USDTM),
}
_, err = e.GetFuturesPositionOrders(t.Context(), req)
require.ErrorIs(t, err, common.ErrDateUnset)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
req.EndDate = time.Now()
req.StartDate = req.EndDate.Add(-time.Hour * 24 * 7)
_, err = e.GetFuturesPositionOrders(t.Context(), req)
assert.NoError(t, err)
req.StartDate = req.EndDate.Add(-time.Hour * 24 * 30)
_, err = e.GetFuturesPositionOrders(t.Context(), req)
require.ErrorIs(t, err, futures.ErrOrderHistoryTooLarge)
req.RespectOrderHistoryLimits = true
result, err := e.GetFuturesPositionOrders(t.Context(), req)
assert.NoError(t, err)
assert.NotNil(t, result)
}
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.AmountStepIncrementSize, "AmountStepIncrementSize should not be zero")
})
}
}
func BenchmarkIntervalToString(b *testing.B) {
for b.Loop() {
result, err := IntervalToString(kline.OneWeek)
assert.NoError(b, err)
assert.NotNil(b, result)
}
}
func TestGetOpenInterest(t *testing.T) {
t.Parallel()
ku := testInstance(t)
_, err := ku.GetOpenInterest(t.Context(), key.PairAsset{
Base: currency.ETH.Item,
Quote: currency.USDT.Item,
Asset: asset.USDTMarginedFutures,
})
require.ErrorIs(t, err, asset.ErrNotSupported)
resp, err := ku.GetOpenInterest(t.Context(), key.PairAsset{
Base: futuresTradablePair.Base.Item,
Quote: futuresTradablePair.Quote.Item,
Asset: asset.Futures,
})
assert.NoError(t, err)
assert.NotEmpty(t, resp)
cp1 := currency.NewPair(currency.ETH, currency.USDTM)
sharedtestvalues.SetupCurrencyPairsForExchangeAsset(t, ku, asset.Futures, cp1)
resp, err = ku.GetOpenInterest(t.Context(),
key.PairAsset{
Base: futuresTradablePair.Base.Item,
Quote: futuresTradablePair.Quote.Item,
Asset: asset.Futures,
},
key.PairAsset{
Base: cp1.Base.Item,
Quote: cp1.Quote.Item,
Asset: asset.Futures,
},
)
assert.NoError(t, err)
assert.NotEmpty(t, resp)
resp, err = ku.GetOpenInterest(t.Context())
assert.NoError(t, err)
assert.NotEmpty(t, resp)
}
func TestValidatePlaceOrderParams(t *testing.T) {
t.Parallel()
arg := &PlaceHFParam{}
err := arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, common.ErrNilPointer)
arg.Size = 1
err = arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
arg.Symbol = spotTradablePair
err = arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, order.ErrTypeIsInvalid)
arg.OrderType = "limit"
err = arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, order.ErrSideIsInvalid)
arg.Side = "Sell"
err = arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.Price = 323423423
arg.Size = 0
err = arg.ValidatePlaceOrderParams()
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
arg.Size = 1
err = arg.ValidatePlaceOrderParams()
assert.NoError(t, err)
}
func TestSpotHFPlaceOrder(t *testing.T) {
t.Parallel()
_, err := e.HFSpotPlaceOrder(t.Context(), &PlaceHFParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.HFSpotPlaceOrder(t.Context(), &PlaceHFParam{
TimeInForce: "GTT",
Symbol: spotTradablePair,
OrderType: "limit",
Side: order.Sell.String(),
Price: 1234,
Size: 1,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSpotPlaceHFOrderTest(t *testing.T) {
t.Parallel()
_, err := e.SpotPlaceHFOrderTest(t.Context(), &PlaceHFParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SpotPlaceHFOrderTest(t.Context(), &PlaceHFParam{
TimeInForce: "GTT",
Symbol: spotTradablePair,
OrderType: "limit",
Side: order.Sell.String(),
Price: 1234,
Size: 1,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSyncPlaceHFOrder(t *testing.T) {
t.Parallel()
_, err := e.SyncPlaceHFOrder(t.Context(), &PlaceHFParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SyncPlaceHFOrder(t.Context(), &PlaceHFParam{
TimeInForce: "GTT",
Symbol: currency.Pair{Base: currency.ETH, Delimiter: "-", Quote: currency.BTC},
OrderType: "limit",
Side: order.Sell.String(),
Price: 1234,
Size: 1,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPlaceMultipleOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PlaceMultipleOrders(t.Context(), []PlaceHFParam{
{
TimeInForce: "GTT",
Symbol: spotTradablePair,
OrderType: "limit",
Side: order.Sell.String(),
Price: 1234,
Size: 1,
},
{
ClientOrderID: "3d07008668054da6b3cb12e432c2b13a",
Side: "buy",
OrderType: "limit",
Price: 0.01,
Size: 1,
Symbol: currency.Pair{Base: currency.ETH, Delimiter: "-", Quote: currency.USDT},
},
{
ClientOrderID: "37245dbe6e134b5c97732bfb36cd4a9d",
Side: "buy",
OrderType: "limit",
Price: 0.01,
Size: 1,
Symbol: currency.Pair{Base: currency.ETH, Delimiter: "-", Quote: currency.USDT},
},
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSyncPlaceMultipleHFOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SyncPlaceMultipleHFOrders(t.Context(), []PlaceHFParam{
{
TimeInForce: "GTT",
Symbol: spotTradablePair,
OrderType: "limit",
Side: order.Sell.String(),
Price: 1234,
Size: 1,
},
{
ClientOrderID: "3d07008668054da6b3cb12e432c2b13a",
Side: "buy",
OrderType: "limit",
Price: 0.01,
Size: 1,
Symbol: spotTradablePair,
},
{
ClientOrderID: "37245dbe6e134b5c97732bfb36cd4a9d",
Side: "buy",
OrderType: "limit",
Price: 0.01,
Size: 1,
Symbol: spotTradablePair,
},
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestModifyHFOrder(t *testing.T) {
t.Parallel()
_, err := e.ModifyHFOrder(t.Context(), &ModifyHFOrderParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
_, err = e.ModifyHFOrder(t.Context(), &ModifyHFOrderParam{OrderID: "1234"})
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.ModifyHFOrder(t.Context(), &ModifyHFOrderParam{
Symbol: spotTradablePair,
ClientOrderID: "4314oiu5345u2y554x",
OrderID: "4314oiu5345u2y554x",
NewPrice: 1234,
NewSize: 2,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelHFOrder(t *testing.T) {
t.Parallel()
_, err := e.CancelHFOrder(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.CancelHFOrder(t.Context(), "630625dbd9180300014c8d52", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelHFOrder(t.Context(), "630625dbd9180300014c8d52", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSyncCancelHFOrder(t *testing.T) {
t.Parallel()
_, err := e.SyncCancelHFOrder(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.SyncCancelHFOrder(t.Context(), "12312312", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SyncCancelHFOrder(t.Context(), "641d67ea162d47000160bfb8", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSyncCancelHFOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.SyncCancelHFOrderByClientOrderID(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.SyncCancelHFOrderByClientOrderID(t.Context(), "cliend-order-id", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SyncCancelHFOrderByClientOrderID(t.Context(), "client-order-id", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelHFOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelHFOrderByClientOrderID(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
_, err = e.CancelHFOrderByClientOrderID(t.Context(), "cliend-order-id", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelHFOrderByClientOrderID(t.Context(), "client-order-id", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelSpecifiedNumberHFOrdersByOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelSpecifiedNumberHFOrdersByOrderID(t.Context(), "", spotTradablePair.String(), 10.0)
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.CancelSpecifiedNumberHFOrdersByOrderID(t.Context(), "1", "", 10.0)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.CancelSpecifiedNumberHFOrdersByOrderID(t.Context(), "1", spotTradablePair.String(), 0)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelSpecifiedNumberHFOrdersByOrderID(t.Context(), "1", spotTradablePair.String(), 10.0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllHFOrdersBySymbol(t *testing.T) {
t.Parallel()
_, err := e.CancelAllHFOrdersBySymbol(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllHFOrdersBySymbol(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllHFOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllHFOrders(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetActiveHFOrders(t *testing.T) {
t.Parallel()
_, err := e.GetActiveHFOrders(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.GetActiveHFOrders(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetActiveHFOrders(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
}
func TestGetSymbolsWithActiveHFOrderList(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err := e.GetSymbolsWithActiveHFOrderList(t.Context())
assert.NoError(t, err)
}
func TestGetHFCompletedOrderList(t *testing.T) {
t.Parallel()
_, err := e.GetHFCompletedOrderList(t.Context(), "", "sell", "limit", "", time.Time{}, time.Now(), 0)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHFCompletedOrderList(t.Context(), spotTradablePair.String(), "sell", "limit", "", time.Time{}, time.Now(), 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetHFOrderDetailsByOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetHFOrderDetailsByOrderID(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.GetHFOrderDetailsByOrderID(t.Context(), "1234567", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHFOrderDetailsByOrderID(t.Context(), "1234567", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetHFOrderDetailsByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetHFOrderDetailsByClientOrderID(t.Context(), "", spotTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.GetHFOrderDetailsByClientOrderID(t.Context(), "1234567", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHFOrderDetailsByClientOrderID(t.Context(), "6d539dc614db312", spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestAutoCancelHFOrderSetting(t *testing.T) {
t.Parallel()
_, err := e.AutoCancelHFOrderSetting(t.Context(), 0, []string{})
require.ErrorIs(t, err, errTimeoutRequired)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.AutoCancelHFOrderSetting(t.Context(), 450, []string{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestAutoCancelHFOrderSettingQuery(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.AutoCancelHFOrderSettingQuery(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetHFFilledList(t *testing.T) {
t.Parallel()
_, err := e.GetHFFilledList(t.Context(), "", "", "sell", "market", "", time.Time{}, time.Now(), 0)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetHFFilledList(t.Context(), "", spotTradablePair.String(), "sell", "market", "", time.Time{}, time.Now(), 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPlaceOCOOrder(t *testing.T) {
t.Parallel()
_, err := e.PlaceOCOOrder(t.Context(), &OCOOrderParams{})
require.ErrorIs(t, err, common.ErrNilPointer)
arg := &OCOOrderParams{Remark: "oco-new-order"}
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
arg.Symbol = spotTradablePair
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, order.ErrSideIsInvalid)
arg.Side = "Sell"
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.Price = 1000
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
arg.Size = .1
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.StopPrice = .1
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.LimitPrice = .1
_, err = e.PlaceOCOOrder(t.Context(), arg)
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
cpDetail, err := e.GetTicker(t.Context(), spotTradablePair.String())
assert.NoError(t, err)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.PlaceOCOOrder(t.Context(), &OCOOrderParams{
Symbol: spotTradablePair,
Side: order.Buy.String(),
Price: cpDetail.Price - 3,
Size: 1,
StopPrice: cpDetail.Price - 2,
LimitPrice: cpDetail.Price - 1,
TradeType: SpotTradeType,
ClientOrderID: "6572fdd65723280007deb5e0",
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelOrderByOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelOCOOrderByOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelOCOOrderByOrderID(t.Context(), "6572fdd65723280007deb5e0")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelOCOOrderByClientOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrClientOrderIDMustBeSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelOCOOrderByClientOrderID(t.Context(), "6572fdd65723280007deb5e0")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelMultipleOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelOCOMultipleOrders(t.Context(), []string{}, spotTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderInfoByOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetOCOOrderInfoByOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetOCOOrderInfoByOrderID(t.Context(), "order-id-here")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOrderInfoByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetOCOOrderInfoByClientOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetOCOOrderInfoByClientOrderID(t.Context(), "client-order-id-here")
assert.NoError(t, err)
}
func TestGetOrderDetailsByOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetOCOOrderDetailsByOrderID(t.Context(), "")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetOCOOrderDetailsByOrderID(t.Context(), "order-id-here")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetOCOOrderList(t *testing.T) {
t.Parallel()
_, err := e.GetOCOOrderList(t.Context(), 9, 0, spotTradablePair.String(), time.Time{}, time.Now(), []string{})
require.ErrorIs(t, err, errPageSizeRequired)
_, err = e.GetOCOOrderList(t.Context(), 10, 0, spotTradablePair.String(), time.Time{}, time.Now(), []string{})
require.ErrorIs(t, err, errCurrentPageRequired)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetOCOOrderList(t.Context(), 10, 2, spotTradablePair.String(), time.Time{}, time.Now(), []string{})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSendPlaceMarginHFOrder(t *testing.T) {
t.Parallel()
_, err := e.SendPlaceMarginHFOrder(t.Context(), &PlaceMarginHFOrderParam{}, "")
require.ErrorIs(t, err, common.ErrNilPointer)
arg := &PlaceMarginHFOrderParam{PostOnly: true}
_, err = e.SendPlaceMarginHFOrder(t.Context(), arg, "")
require.ErrorIs(t, err, order.ErrClientOrderIDNotSupported)
arg.ClientOrderID = "first-order"
_, err = e.SendPlaceMarginHFOrder(t.Context(), arg, "")
require.ErrorIs(t, err, order.ErrSideIsInvalid)
arg.Side = "Sell"
_, err = e.SendPlaceMarginHFOrder(t.Context(), arg, "")
require.ErrorIs(t, err, currency.ErrCurrencyPairEmpty)
arg.Symbol = marginTradablePair
_, err = e.SendPlaceMarginHFOrder(t.Context(), arg, "")
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
arg.Price = 1000
_, err = e.SendPlaceMarginHFOrder(t.Context(), arg, "")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
}
func TestPlaceMarginHFOrder(t *testing.T) {
t.Parallel()
_, err := e.PlaceMarginHFOrder(t.Context(), &PlaceMarginHFOrderParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.PlaceMarginHFOrder(t.Context(), &PlaceMarginHFOrderParam{
ClientOrderID: "first-order",
Side: "sell",
Symbol: marginTradablePair,
OrderType: "market",
SelfTradePrevention: "CB",
Price: 1234,
Size: 0.0000001,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestPlaceMarginHFOrderTest(t *testing.T) {
t.Parallel()
_, err := e.PlaceMarginHFOrderTest(t.Context(), &PlaceMarginHFOrderParam{})
require.ErrorIs(t, err, common.ErrNilPointer)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.PlaceMarginHFOrderTest(t.Context(), &PlaceMarginHFOrderParam{
ClientOrderID: "first-order",
Side: "sell",
Symbol: marginTradablePair,
OrderType: "market",
SelfTradePrevention: "CB",
Price: 1234,
Size: 0.0000001,
})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelMarginHFOrderByOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelMarginHFOrderByOrderID(t.Context(), "", marginTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.CancelMarginHFOrderByOrderID(t.Context(), "order-id-here", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelMarginHFOrderByOrderID(t.Context(), "order-id-here", marginTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelMarginHFOrderByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.CancelMarginHFOrderByClientOrderID(t.Context(), "", marginTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.CancelMarginHFOrderByClientOrderID(t.Context(), "order-id-here", "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelMarginHFOrderByClientOrderID(t.Context(), "order-id-here", marginTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestCancelAllMarginHFOrdersBySymbol(t *testing.T) {
t.Parallel()
_, err := e.CancelAllMarginHFOrdersBySymbol(t.Context(), "", "MARGIN_TRADE")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.CancelAllMarginHFOrdersBySymbol(t.Context(), marginTradablePair.String(), "")
require.ErrorIs(t, err, errTradeTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.CancelAllMarginHFOrdersBySymbol(t.Context(), marginTradablePair.String(), "MARGIN_TRADE")
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = e.CancelAllMarginHFOrdersBySymbol(t.Context(), marginTradablePair.String(), "MARGIN_ISOLATED_TRADE")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetActiveMarginHFOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetActiveMarginHFOrders(t.Context(), marginTradablePair.String(), "MARGIN_TRADE")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFilledHFMarginOrders(t *testing.T) {
t.Parallel()
_, err := e.GetFilledHFMarginOrders(t.Context(), spotTradablePair.String(), "", "sell", "limit", time.Time{}, time.Now(), 0, 20)
require.ErrorIs(t, err, errTradeTypeMissing)
_, err = e.GetFilledHFMarginOrders(t.Context(), "", "MARGIN_TRADE", "sell", "limit", time.Time{}, time.Now(), 0, 20)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetFilledHFMarginOrders(t.Context(), marginTradablePair.String(), "MARGIN_TRADE", "sell", "limit", time.Time{}, time.Now(), 0, 20)
assert.NoError(t, err)
}
func TestGetMarginHFOrderDetailByOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetMarginHFOrderDetailByOrderID(t.Context(), "", marginTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetMarginHFOrderDetailByOrderID(t.Context(), "243432432423the-order-id", marginTradablePair.String())
assert.Truef(t, errors.Is(err, order.ErrOrderNotFound) || err == nil, "GetMarginHFOrderDetailByOrderID should not error: %s", err)
}
func TestGetMarginHFOrderDetailByClientOrderID(t *testing.T) {
t.Parallel()
_, err := e.GetMarginHFOrderDetailByClientOrderID(t.Context(), "", marginTradablePair.String())
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetMarginHFOrderDetailByClientOrderID(t.Context(), "the-client-order-id", marginTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarginHFTradeFills(t *testing.T) {
t.Parallel()
_, err := e.GetMarginHFTradeFills(t.Context(), "", marginTradablePair.String(), "", "sell", "", time.Time{}, time.Now(), 0, 30)
require.ErrorIs(t, err, errTradeTypeMissing)
_, err = e.GetMarginHFTradeFills(t.Context(), "", "", "MARGIN_TRADE", "sell", "", time.Time{}, time.Now(), 0, 30)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetMarginHFTradeFills(t.Context(), "12312312", marginTradablePair.String(), "MARGIN_TRADE", "sell", "market", time.Time{}, time.Now(), 0, 30)
assert.NoError(t, err)
}
func TestGetLendingCurrencyInformation(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetLendingCurrencyInformation(t.Context(), currency.ETH)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetInterestRate(t *testing.T) {
t.Parallel()
_, err := e.GetInterestRate(t.Context(), currency.EMPTYCODE)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetInterestRate(t.Context(), currency.ETH)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestMarginLendingSubscription(t *testing.T) {
t.Parallel()
_, err := e.MarginLendingSubscription(t.Context(), currency.EMPTYCODE, 1, 0.22)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.MarginLendingSubscription(t.Context(), currency.ETH, 0, 0.22)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.MarginLendingSubscription(t.Context(), currency.ETH, 1, 0)
require.ErrorIs(t, err, errMissingInterestRate)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.MarginLendingSubscription(t.Context(), currency.ETH, 1, 0.22)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestRedemption(t *testing.T) {
t.Parallel()
_, err := e.Redemption(t.Context(), currency.EMPTYCODE, 1, "1245")
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.Redemption(t.Context(), currency.ETH, 0, "1245")
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.Redemption(t.Context(), currency.ETH, 1, "")
require.ErrorIs(t, err, errMissingPurchaseOrderNumber)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.Redemption(t.Context(), currency.ETH, 1, "1245")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestModifySubscriptionOrder(t *testing.T) {
t.Parallel()
_, err := e.ModifySubscriptionOrder(t.Context(), currency.EMPTYCODE, "12345", 1.23)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.ModifySubscriptionOrder(t.Context(), currency.ETH, "12345", 0)
require.ErrorIs(t, err, errMissingInterestRate)
_, err = e.ModifySubscriptionOrder(t.Context(), currency.ETH, "", 1.23)
require.ErrorIs(t, err, errMissingPurchaseOrderNumber)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.ModifySubscriptionOrder(t.Context(), currency.ETH, "12345", 1.23)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetRedemptionOrders(t *testing.T) {
t.Parallel()
_, err := e.GetRedemptionOrders(t.Context(), currency.EMPTYCODE, "DONE", "2234", 0, 20)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.GetRedemptionOrders(t.Context(), currency.ETH, "", "", 0, 20)
require.ErrorIs(t, err, errStatusMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetRedemptionOrders(t.Context(), currency.BTC, "2234", "PENDING", 0, 20)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetSubscriptionOrders(t *testing.T) {
t.Parallel()
_, err := e.GetSubscriptionOrders(t.Context(), currency.EMPTYCODE, "2234", "DONE", 0, 20)
require.ErrorIs(t, err, currency.ErrCurrencyCodeEmpty)
_, err = e.GetSubscriptionOrders(t.Context(), currency.ETH, "", "", 0, 20)
require.ErrorIs(t, err, errStatusMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetSubscriptionOrders(t.Context(), currency.BTC, "2234", "DONE", 0, 20)
assert.NoError(t, err)
assert.NotNil(t, result)
}
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.NoErrorf(t, err, "cannot get pairs for %s", a)
assert.NotEmptyf(t, pairs, "no pairs for %s", a)
resp, err := e.GetCurrencyTradeURL(t.Context(), a, pairs[0])
assert.NoError(t, err)
assert.NotEmpty(t, resp)
}
}
// testInstance returns a local Kucoin for isolated testing
func testInstance(tb testing.TB) *Exchange {
tb.Helper()
kucoin := new(Exchange)
require.NoError(tb, testexch.Setup(kucoin), "Test instance Setup must not error")
kucoin.obm = &orderbookManager{
state: make(map[currency.Code]map[currency.Code]map[asset.Item]*update),
jobs: make(chan job, maxWSOrderbookJobs),
}
return kucoin
}
func TestGetTradingPairActualFees(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetTradingPairActualFees(t.Context(), []string{spotTradablePair.String()})
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetFuturesTradingPairsActualFees(t *testing.T) {
t.Parallel()
_, err := e.GetFuturesTradingPairsActualFees(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetFuturesTradingPairsActualFees(t.Context(), futuresTradablePair.String())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetPositionHistory(t *testing.T) {
t.Parallel()
_, err := e.GetPositionHistory(t.Context(), futuresTradablePair.String(), time.Now(), time.Now().Add(-time.Hour*5), 0, 10)
require.ErrorIs(t, err, common.ErrStartAfterEnd)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetPositionHistory(t.Context(), futuresTradablePair.String(), time.Time{}, time.Time{}, 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMaximumOpenPositionSize(t *testing.T) {
t.Parallel()
_, err := e.GetMaximumOpenPositionSize(t.Context(), "", 1, 1)
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
_, err = e.GetMaximumOpenPositionSize(t.Context(), futuresTradablePair.String(), 0., 1)
require.ErrorIs(t, err, limits.ErrPriceBelowMin)
_, err = e.GetMaximumOpenPositionSize(t.Context(), futuresTradablePair.String(), 1, 0)
require.ErrorIs(t, err, errInvalidLeverage)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetMaximumOpenPositionSize(t.Context(), futuresTradablePair.String(), 1, 1)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetLatestTickersForAllContracts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetLatestTickersForAllContracts(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestSubscribeToEarnFixedIncomeProduct(t *testing.T) {
t.Parallel()
_, err := e.SubscribeToEarnFixedIncomeProduct(t.Context(), "", "MAIN", 12.2)
require.ErrorIs(t, err, errProductIDMissing)
_, err = e.SubscribeToEarnFixedIncomeProduct(t.Context(), "1232412", "MAIN", 0)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
_, err = e.SubscribeToEarnFixedIncomeProduct(t.Context(), "1232412", "", 12.2)
require.ErrorIs(t, err, errAccountTypeMissing)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.SubscribeToEarnFixedIncomeProduct(t.Context(), "1232412", "MAIN", 12.2)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestRedeemByEarnHoldingID(t *testing.T) {
t.Parallel()
_, err := e.RedeemByEarnHoldingID(t.Context(), "", SpotTradeType, "1", 1)
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
_, err = e.RedeemByEarnHoldingID(t.Context(), "123231", "Main", "1", 0)
require.ErrorIs(t, err, limits.ErrAmountBelowMin)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
result, err := e.RedeemByEarnHoldingID(t.Context(), "123231", SpotTradeType, "1", 1)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnRedeemPreviewByHoldingID(t *testing.T) {
t.Parallel()
_, err := e.GetEarnRedeemPreviewByHoldingID(t.Context(), "", "MAIN")
require.ErrorIs(t, err, order.ErrOrderIDNotSet)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnRedeemPreviewByHoldingID(t.Context(), "12345", "MAIN")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnSavingsProducts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnSavingsProducts(t.Context(), currency.EMPTYCODE)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnFixedIncomeCurrentHoldings(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnFixedIncomeCurrentHoldings(t.Context(), "12312", "", currency.EMPTYCODE, 0, 10)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetLimitedTimePromotionProducts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetLimitedTimePromotionProducts(t.Context(), currency.BTC)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnKCSStakingProducts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnKCSStakingProducts(t.Context(), currency.EMPTYCODE)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnStakingProducts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnStakingProducts(t.Context(), currency.EMPTYCODE)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetEarnETHStakingProducts(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetEarnETHStakingProducts(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetInformationOnOffExchangeFundingAndLoans(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetInformationOnOffExchangeFundingAndLoans(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetInformationOnAccountInvolvedInOffExchangeLoans(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetInformationOnAccountInvolvedInOffExchangeLoans(t.Context())
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetAffilateUserRebateInformation(t *testing.T) {
t.Parallel()
_, err := e.GetAffilateUserRebateInformation(t.Context(), time.Time{}, "1234", 0)
require.ErrorIs(t, err, errQueryDateIsRequired)
_, err = e.GetAffilateUserRebateInformation(t.Context(), time.Now(), "", 0)
require.ErrorIs(t, err, errOffsetIsRequired)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetAffilateUserRebateInformation(t.Context(), time.Now(), "1234", 0)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetMarginPairsConfigurations(t *testing.T) {
t.Parallel()
_, err := e.GetMarginPairsConfigurations(t.Context(), "")
require.ErrorIs(t, err, currency.ErrSymbolStringEmpty)
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
_, err = e.GetMarginPairsConfigurations(t.Context(), marginTradablePair.String())
assert.NoError(t, err)
}
func TestModifyLeverageMultiplier(t *testing.T) {
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
err := e.ModifyLeverageMultiplier(t.Context(), spotTradablePair.String(), 1, true)
assert.NoError(t, err)
}
func TestGetActiveHFOrderSymbols(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
result, err := e.GetActiveHFOrderSymbols(t.Context(), "MARGIN_TRADE")
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestOrderSideString(t *testing.T) {
t.Parallel()
sideErrInput := []struct {
Side order.Side
Result string
Err error
}{
{Side: order.Sell, Result: "sell"},
{Side: order.Buy, Result: "buy"},
{Side: order.AnySide, Result: ""},
{Side: order.Bid, Result: "buy"},
{Side: order.Ask, Result: "sell"},
{Side: order.CouldNotShort, Result: "", Err: order.ErrSideIsInvalid},
}
var err error
var sideString string
for a := range sideErrInput {
sideString, err = e.OrderSideString(sideErrInput[a].Side)
require.ErrorIs(t, err, sideErrInput[a].Err)
assert.Equal(t, sideString, sideErrInput[a].Result)
}
}
func TestOrderTypeToString(t *testing.T) {
t.Parallel()
oTypeErrInputs := []struct {
OrderType order.Type
Result string
Err error
}{
{OrderType: order.Limit, Result: "limit"},
{OrderType: order.Market, Result: "market"},
{OrderType: order.AnyType, Result: ""},
{OrderType: order.OCO, Result: "", Err: order.ErrUnsupportedOrderType},
}
var err error
var oTypeString string
for a := range oTypeErrInputs {
oTypeString, err = OrderTypeToString(oTypeErrInputs[a].OrderType)
require.ErrorIs(t, err, oTypeErrInputs[a].Err)
assert.Equal(t, oTypeString, oTypeErrInputs[a].Result)
}
}
func TestMarginModeToString(t *testing.T) {
t.Parallel()
marginModeResults := []struct {
MarginMode margin.Type
Result string
}{
{MarginMode: margin.Isolated, Result: "isolated"},
{MarginMode: margin.Multi, Result: "cross"},
{MarginMode: margin.Unknown, Result: ""},
}
for a := range marginModeResults {
result := MarginModeToString(marginModeResults[a].MarginMode)
assert.Equal(t, result, marginModeResults[a].Result)
}
}
func TestAccountToTradeTypeString(t *testing.T) {
t.Parallel()
accountToTradeTypeResults := []struct {
AccountType asset.Item
MarginMode string
Result string
}{
{AccountType: asset.Margin, MarginMode: "cross", Result: "MARGIN_TRADE"},
{AccountType: asset.Margin, MarginMode: "isolated", Result: "MARGIN_ISOLATED_TRADE"},
{AccountType: asset.Spot, MarginMode: "cross", Result: SpotTradeType},
{AccountType: asset.Spot, MarginMode: "isolated", Result: SpotTradeType},
{AccountType: asset.Futures, MarginMode: "isolated", Result: ""},
{AccountType: asset.Futures, MarginMode: "isolated", Result: ""},
}
for a := range accountToTradeTypeResults {
result := e.AccountToTradeTypeString(accountToTradeTypeResults[a].AccountType, accountToTradeTypeResults[a].MarginMode)
assert.Equal(t, result, accountToTradeTypeResults[a].Result)
}
}
func TestStringToOrderStatus(t *testing.T) {
t.Parallel()
orderStatusResults := []struct {
Input string
Result order.Status
HasErr bool
}{
{Input: "match", Result: order.Filled},
{Input: "open", Result: order.Open},
{Input: "done", Result: order.Closed},
{Input: "accepted", Result: order.New},
{Input: "PLaced", Result: order.New},
{Input: "something", Result: order.UnknownStatus, HasErr: true},
}
for a := range orderStatusResults {
result, err := e.StringToOrderStatus(orderStatusResults[a].Input)
if !orderStatusResults[a].HasErr {
assert.NoError(t, err)
}
assert.Equal(t, result, orderStatusResults[a].Result)
}
}
func TestIntervalToString(t *testing.T) {
t.Parallel()
intervalStringResults := []struct {
Interval kline.Interval
Result string
Err error
}{
{Interval: kline.OneMin, Result: "1min"},
{Interval: kline.ThreeMin, Result: "3min"},
{Interval: kline.FiveMin, Result: "5min"},
{Interval: kline.TenMin, Result: "", Err: kline.ErrUnsupportedInterval},
}
for a := range intervalStringResults {
intervalString, err := IntervalToString(intervalStringResults[a].Interval)
require.ErrorIs(t, err, intervalStringResults[a].Err)
assert.Equal(t, intervalString, intervalStringResults[a].Result)
}
}
func TestGetHistoricalFundingRates(t *testing.T) {
t.Parallel()
r := &fundingrate.HistoricalRatesRequest{
Asset: asset.Spot,
Pair: futuresTradablePair,
StartDate: time.Now().Add(-time.Hour * 24 * 2),
EndDate: time.Now(),
}
_, err := e.GetHistoricalFundingRates(t.Context(), r)
require.ErrorIs(t, err, asset.ErrNotSupported)
r.Pair = currency.EMPTYPAIR
_, err = e.GetHistoricalFundingRates(t.Context(), r)
require.ErrorIs(t, err, asset.ErrNotSupported)
r.Asset = asset.Futures
r.Pair = futuresTradablePair
result, err := e.GetHistoricalFundingRates(t.Context(), r)
assert.NoError(t, err)
assert.NotNil(t, result)
}
func TestProcessFuturesKline(t *testing.T) {
t.Parallel()
data := fmt.Sprintf(`{"symbol":%q,"candles":["1714964400","63815.1","63890.8","63928.5","63797.8","17553.0","17553"],"time":1714964823722}`, futuresTradablePair.String())
err := e.processFuturesKline([]byte(data), "1hour")
assert.NoError(t, err)
}
func TestWithdrawInternationalBank(t *testing.T) {
t.Parallel()
withdrawFiatRequest := withdraw.Request{}
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(),
&withdrawFiatRequest)
assert.ErrorIs(t, common.ErrFunctionNotSupported, err)
}
func TestWithdrawFiatFunds(t *testing.T) {
t.Parallel()
_, err := e.WithdrawFiatFunds(t.Context(), &withdraw.Request{})
assert.ErrorIs(t, common.ErrFunctionNotSupported, err)
}
func TestModifyOrder(t *testing.T) {
_, err := e.ModifyOrder(t.Context(), &order.Modify{})
assert.ErrorIs(t, common.ErrFunctionNotSupported, err)
}
func TestGetHistoricTrades(t *testing.T) {
_, err := e.GetHistoricTrades(t.Context(), currency.EMPTYPAIR, asset.Spot, time.Time{}, time.Time{})
assert.ErrorIs(t, common.ErrFunctionNotSupported, err)
}
func TestCancelBatchOrders(t *testing.T) {
_, err := e.CancelBatchOrders(t.Context(), nil)
assert.ErrorIs(t, common.ErrFunctionNotSupported, err)
}
func TestChannelName(t *testing.T) {
t.Parallel()
for _, tt := range []struct {
a asset.Item
ch string
exp string
}{
{asset.Futures, futuresOrderbookDepth50Channel, futuresOrderbookDepth50Channel},
{asset.Futures, subscription.OrderbookChannel, futuresOrderbookDepth5Channel},
{asset.Futures, subscription.CandlesChannel, marketCandlesChannel},
{asset.Futures, subscription.TickerChannel, futuresTickerChannel},
{asset.Spot, subscription.OrderbookChannel, marketOrderbookDepth5Channel},
{asset.Spot, subscription.AllTradesChannel, marketMatchChannel},
{asset.Spot, subscription.CandlesChannel, marketCandlesChannel},
{asset.Spot, subscription.TickerChannel, marketTickerChannel},
} {
assert.Equal(t, tt.exp, channelName(&subscription.Subscription{Channel: tt.ch}, tt.a))
}
}
func TestStringToTimeInForce(t *testing.T) {
t.Parallel()
tifMap := []struct {
String string
PostOnly bool
TimeInForce order.TimeInForce
}{
{"GTC", false, order.GoodTillCancel},
{"GTC", true, order.GoodTillCancel | order.PostOnly},
{"GTT", false, order.GoodTillTime},
{"GTT", true, order.GoodTillTime | order.PostOnly},
{"IOC", false, order.ImmediateOrCancel},
{"ioC", false, order.ImmediateOrCancel},
{"Fok", false, order.FillOrKill},
}
for a := range tifMap {
result := StringToTimeInForce(tifMap[a].String, tifMap[a].PostOnly)
assert.Equal(t, tifMap[a].TimeInForce, result)
}
}