mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 23:16:53 +00:00
Huobi decided to not even return CW at all in [this test](https://github.com/thrasher-corp/gocryptotrader/actions/runs/17637897980/job/50117883059?pr=1990#step:11:1280) Reverse the test expectation. Just get *something* back in contract codes. We have to accept that runtime won't work sometimes when we want to convert codes that they haven't told us about... and that's the way it is.
2102 lines
67 KiB
Go
2102 lines
67 KiB
Go
package huobi
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/buger/jsonparser"
|
|
gws "github.com/gorilla/websocket"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/common/key"
|
|
"github.com/thrasher-corp/gocryptotrader/core"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
|
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/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"
|
|
mockws "github.com/thrasher-corp/gocryptotrader/internal/testing/websocket"
|
|
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
|
"github.com/thrasher-corp/gocryptotrader/types"
|
|
)
|
|
|
|
// Please supply you own test keys here for due diligence testing.
|
|
const (
|
|
apiKey = ""
|
|
apiSecret = ""
|
|
canManipulateRealOrders = false
|
|
)
|
|
|
|
var (
|
|
e *Exchange
|
|
btcFutureDatedPair currency.Pair
|
|
btccwPair = currency.NewPair(currency.BTC, currency.NewCode("CW"))
|
|
btcusdPair = currency.NewPairWithDelimiter("BTC", "USD", "-")
|
|
btcusdtPair = currency.NewPairWithDelimiter("BTC", "USDT", "-")
|
|
ethusdPair = currency.NewPairWithDelimiter("ETH", "USD", "-")
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
e = new(Exchange)
|
|
if err := testexch.Setup(e); err != nil {
|
|
log.Fatalf("HUOBI Setup error: %s", err)
|
|
}
|
|
|
|
if apiKey != "" && apiSecret != "" {
|
|
e.API.AuthenticatedSupport = true
|
|
e.API.AuthenticatedWebsocketSupport = true
|
|
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
|
}
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestGetCurrenciesIncludingChains(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := e.GetCurrenciesIncludingChains(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
assert.Greater(t, len(r), 1, "should get more than one currency back")
|
|
r, err = e.GetCurrenciesIncludingChains(t.Context(), currency.USDT)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, len(r), "Should only get one currency back")
|
|
}
|
|
|
|
func TestFGetContractInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetContractInfo(t.Context(), "", "", currency.EMPTYPAIR)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFIndexPriceInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FIndexPriceInfo(t.Context(), currency.BTC)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFContractPriceLimitations(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FContractPriceLimitations(t.Context(),
|
|
"BTC", "this_week", currency.EMPTYPAIR)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFContractOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FContractOpenInterest(t.Context(), "BTC", "this_week", currency.EMPTYPAIR)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetEstimatedDeliveryPrice(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetEstimatedDeliveryPrice(t.Context(), currency.BTC)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetMarketDepth(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetMarketDepth(t.Context(), btccwPair, "step5")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetKlineData(t.Context(), btccwPair, "5min", 5, time.Now().Add(-time.Minute*5), time.Now())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetMarketOverviewData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetMarketOverviewData(t.Context(), btccwPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFLastTradeData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FLastTradeData(t.Context(), btccwPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFRequestPublicBatchTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FRequestPublicBatchTrades(t.Context(), btccwPair, 50)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryTieredAdjustmentFactor(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FQueryTieredAdjustmentFactor(t.Context(), currency.BTC)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryHisOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FQueryHisOpenInterest(t.Context(), "BTC", "this_week", "60min", "cont", 3)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQuerySystemStatus(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FQuerySystemStatus(t.Context(), currency.BTC)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryTopAccountsRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FQueryTopAccountsRatio(t.Context(), "BTC", "5min")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryTopPositionsRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FQueryTopPositionsRatio(t.Context(), "BTC", "5min")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFLiquidationOrders(t *testing.T) {
|
|
t.Parallel()
|
|
if _, err := e.FLiquidationOrders(t.Context(), currency.BTC, "filled", 0, 0, "", 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFIndexKline(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FIndexKline(t.Context(), btccwPair, "5min", 5)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetBasisData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FGetBasisData(t.Context(), btccwPair, "5min", "open", 3)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetAccountInfo(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetPositionsInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetPositionsInfo(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetAllSubAccountAssets(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetAllSubAccountAssets(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetSingleSubAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetSingleSubAccountInfo(t.Context(), "", "154263566")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetSingleSubPositions(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetSingleSubPositions(t.Context(), "", "154263566")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetFinancialRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetFinancialRecords(t.Context(),
|
|
"BTC", "closeLong", 2, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetSettlementRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetSettlementRecords(t.Context(),
|
|
currency.BTC, 0, 0, time.Now().Add(-48*time.Hour), time.Now())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFContractTradingFee(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FContractTradingFee(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetTransferLimits(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetTransferLimits(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetPositionLimits(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetPositionLimits(t.Context(), currency.EMPTYCODE)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetAssetsAndPositions(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetAssetsAndPositions(t.Context(), currency.HT)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFTransfer(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FTransfer(t.Context(), "154263566", "HT", "sub_to_master", 5)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetTransferRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetTransferRecords(t.Context(), "HT", "master_to_sub", 90, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetAvailableLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetAvailableLeverage(t.Context(), currency.BTC)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FOrder(t.Context(), currency.EMPTYPAIR, "BTC", "quarter", "123", "BUY", "open", "limit", 1, 1, 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFPlaceBatchOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
var req []fBatchOrderData
|
|
order1 := fBatchOrderData{
|
|
Symbol: "btc",
|
|
ContractType: "quarter",
|
|
ClientOrderID: "",
|
|
Price: 5,
|
|
Volume: 1,
|
|
Direction: "buy",
|
|
Offset: "open",
|
|
LeverageRate: 1,
|
|
OrderPriceType: "limit",
|
|
}
|
|
order2 := fBatchOrderData{
|
|
Symbol: "xrp",
|
|
ContractType: "this_week",
|
|
ClientOrderID: "",
|
|
Price: 10000,
|
|
Volume: 1,
|
|
Direction: "sell",
|
|
Offset: "open",
|
|
LeverageRate: 1,
|
|
OrderPriceType: "limit",
|
|
}
|
|
req = append(req, order1, order2)
|
|
_, err := e.FPlaceBatchOrder(t.Context(), req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFCancelOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FCancelOrder(t.Context(), currency.BTC, "123", "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFCancelAllOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
updatePairsOnce(t, e)
|
|
_, err := e.FCancelAllOrders(t.Context(), btcFutureDatedPair, "", "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFFlashCloseOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FFlashCloseOrder(t.Context(),
|
|
currency.EMPTYPAIR, "BTC", "quarter", "BUY", "lightning", "", 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetOrderInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetOrderInfo(t.Context(), "BTC", "", "123")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFOrderDetails(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FOrderDetails(t.Context(), "BTC", "123", "quotation", time.Now().Add(-1*time.Hour), 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetOpenOrders(t.Context(), currency.BTC, 1, 2)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FGetOrderHistory(t.Context(),
|
|
currency.EMPTYPAIR, "BTC",
|
|
"all", "all", "limit",
|
|
[]order.Status{},
|
|
5, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFTradeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FTradeHistory(t.Context(), currency.EMPTYPAIR, "BTC", "all", 10, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFPlaceTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FPlaceTriggerOrder(t.Context(), currency.EMPTYPAIR, "EOS", "quarter", "greaterOrEqual", "limit", "buy", "close", 1.1, 1.05, 5, 2)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFCancelTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FCancelTriggerOrder(t.Context(), "ETH", "123")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFCancelAllTriggerOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FCancelAllTriggerOrders(t.Context(), currency.EMPTYPAIR, "BTC", "this_week")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryTriggerOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FQueryTriggerOpenOrders(t.Context(), currency.EMPTYPAIR, "BTC", 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFQueryTriggerOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FQueryTriggerOrderHistory(t.Context(), currency.EMPTYPAIR, "EOS", "all", "all", 10, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFetchTradablePairs(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FetchTradablePairs(t.Context(), asset.Futures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateTickerSpot(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateTicker(t.Context(), currency.NewPairWithDelimiter("INV", "ALID", "-"), asset.Spot)
|
|
assert.ErrorContains(t, err, "invalid symbol")
|
|
_, err = e.UpdateTicker(t.Context(), currency.NewPairWithDelimiter("BTC", "USDT", "_"), asset.Spot)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateTickerCMF(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateTicker(t.Context(), currency.NewPairWithDelimiter("INV", "ALID", "_"), asset.CoinMarginedFutures)
|
|
assert.ErrorContains(t, err, "symbol data error")
|
|
_, err = e.UpdateTicker(t.Context(), currency.NewPairWithDelimiter("BTC", "USD", "_"), asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateTickerFutures(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateTicker(t.Context(), btccwPair, asset.Futures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateOrderbookSpot(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateOrderbook(t.Context(), btcusdtPair, asset.Spot)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateOrderbookCMF(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateOrderbook(t.Context(), btcusdPair, asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateOrderbookFuture(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateOrderbook(t.Context(), btccwPair, asset.Futures)
|
|
require.NoError(t, err)
|
|
_, err = e.UpdateOrderbook(t.Context(), btcusdPair, asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
updatePairsOnce(t, e)
|
|
getOrdersRequest := order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Pairs: []currency.Pair{currency.NewBTCUSDT()},
|
|
AssetType: asset.Spot,
|
|
Side: order.AnySide,
|
|
}
|
|
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
|
require.NoError(t, err)
|
|
|
|
getOrdersRequest.Pairs = []currency.Pair{btcusdPair}
|
|
getOrdersRequest.AssetType = asset.CoinMarginedFutures
|
|
_, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
|
require.NoError(t, err)
|
|
getOrdersRequest.Pairs = []currency.Pair{btcFutureDatedPair}
|
|
getOrdersRequest.AssetType = asset.Futures
|
|
_, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelAllOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelAllOrders(t.Context(), &order.Cancel{AssetType: asset.Futures})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestQuerySwapIndexPriceInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.QuerySwapIndexPriceInfo(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSwapOpenInterestInformation(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.SwapOpenInterestInformation(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapMarketDepth(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSwapMarketDepth(t.Context(), btcusdPair, "step0")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := e.GetSwapKlineData(t.Context(), btcusdPair, "5min", 5, time.Now().Add(-time.Hour), time.Now())
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, r.Data, "GetSwapKlineData should return some data")
|
|
}
|
|
|
|
func TestGetSwapMarketOverview(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSwapMarketOverview(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetLastTrade(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetLastTrade(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetBatchTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetBatchTrades(t.Context(), btcusdPair, 5)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTieredAjustmentFactorInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTieredAjustmentFactorInfo(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetOpenInterestInfo(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t, e)
|
|
_, err := e.GetOpenInterestInfo(t.Context(), btcusdPair, "5min", "cryptocurrency", 50)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTraderSentimentIndexAccount(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTraderSentimentIndexAccount(t.Context(), btcusdPair, "5min")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTraderSentimentIndexPosition(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTraderSentimentIndexPosition(t.Context(), btcusdPair, "5min")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetLiquidationOrders(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetLiquidationOrders(t.Context(), btcusdPair, "closed", time.Now().AddDate(0, 0, -2), time.Now(), "", 0)
|
|
assert.NoError(t, err, "GetLiquidationOrders should not error")
|
|
}
|
|
|
|
func TestGetHistoricalFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetHistoricalFundingRatesForPair(t.Context(), btcusdPair, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetPremiumIndexKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetPremiumIndexKlineData(t.Context(), btcusdPair, "5min", 15)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetEstimatedFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetPremiumIndexKlineData(t.Context(), btcusdPair, "5min", 15)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetBasisData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetBasisData(t.Context(), btcusdPair, "5min", "close", 5)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSystemStatusInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSystemStatusInfo(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapPriceLimits(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSwapPriceLimits(t.Context(), btcusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMarginRates(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetMarginRates(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapAccountInfo(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapPositionsInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapPositionsInfo(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapAssetsAndPositions(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapAssetsAndPositions(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapAllSubAccAssets(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapAllSubAccAssets(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSubAccPositionInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSubAccPositionInfo(t.Context(), ethusdPair, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetAccountFinancialRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetAccountFinancialRecords(t.Context(), ethusdPair, "3,4", 15, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapSettlementRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
r, err := e.GetSwapSettlementRecords(t.Context(), ethusdPair, time.Now().AddDate(0, -1, 0), time.Now(), 0, 0)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, r.Data, "GetSwapSettlementRecords should return some data")
|
|
}
|
|
|
|
func TestGetAvailableLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetAvailableLeverage(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapOrderLimitInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapOrderLimitInfo(t.Context(), ethusdPair, "limit")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapTradingFeeInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapTradingFeeInfo(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapTransferLimitInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapTransferLimitInfo(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapPositionLimitInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapPositionLimitInfo(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestAccountTransferData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.AccountTransferData(t.Context(), ethusdPair, "123", "master_to_sub", 15)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestAccountTransferRecords(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.AccountTransferRecords(t.Context(), ethusdPair, "master_to_sub", 12, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestPlaceSwapOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.PlaceSwapOrders(t.Context(), ethusdPair, "", "buy", "open", "limit", 0.01, 1, 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestPlaceSwapBatchOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
var req BatchOrderRequestType
|
|
order1 := batchOrderData{
|
|
ContractCode: "ETH-USD",
|
|
ClientOrderID: "",
|
|
Price: 5,
|
|
Volume: 1,
|
|
Direction: "buy",
|
|
Offset: "open",
|
|
LeverageRate: 1,
|
|
OrderPriceType: "limit",
|
|
}
|
|
order2 := batchOrderData{
|
|
ContractCode: "BTC-USD",
|
|
ClientOrderID: "",
|
|
Price: 2.5,
|
|
Volume: 1,
|
|
Direction: "buy",
|
|
Offset: "open",
|
|
LeverageRate: 1,
|
|
OrderPriceType: "limit",
|
|
}
|
|
req.Data = append(req.Data, order1, order2)
|
|
|
|
_, err := e.PlaceSwapBatchOrders(t.Context(), req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelSwapOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelSwapOrder(t.Context(), "test123", "", ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelAllSwapOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelAllSwapOrders(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestPlaceLightningCloseOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.PlaceLightningCloseOrder(t.Context(), ethusdPair, "buy", "lightning", 5, 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapOrderInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapOrderInfo(t.Context(), ethusdPair, "123", "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapOrderDetails(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapOrderDetails(t.Context(), ethusdPair, "123", "10", "cancelledOrder", 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapOpenOrders(t.Context(), ethusdPair, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapOrderHistory(t.Context(), ethusdPair, "all", "all", []order.Status{order.PartiallyCancelled, order.Active}, 25, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapTradeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapTradeHistory(t.Context(), ethusdPair, "liquidateShort", 10, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestPlaceSwapTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.PlaceSwapTriggerOrder(t.Context(), ethusdPair, "greaterOrEqual", "buy", "open", "optimal_5", 5, 3, 1, 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelSwapTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelSwapTriggerOrder(t.Context(), ethusdPair, "test123")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelAllSwapTriggerOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelAllSwapTriggerOrders(t.Context(), ethusdPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapTriggerOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetSwapTriggerOrderHistory(t.Context(), ethusdPair, "open", "all", 15, 0, 0)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSwapMarkets(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSwapMarkets(t.Context(), currency.EMPTYPAIR)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSpotKline(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSpotKline(t.Context(), KlinesRequestParams{Symbol: btcusdtPair, Period: "1min"})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetHistoricCandles(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
updatePairsOnce(t, e)
|
|
|
|
endTime := time.Now().Add(-time.Hour).Truncate(time.Hour)
|
|
_, err := e.GetHistoricCandles(t.Context(), btcusdtPair, asset.Spot, kline.OneMin, endTime.Add(-time.Hour), endTime)
|
|
require.NoError(t, err)
|
|
|
|
_, err = e.GetHistoricCandles(t.Context(), btcusdtPair, asset.Spot, kline.OneDay, endTime.AddDate(0, 0, -7), endTime)
|
|
require.NoError(t, err)
|
|
|
|
_, err = e.GetHistoricCandles(t.Context(), btcFutureDatedPair, asset.Futures, kline.OneDay, endTime.AddDate(0, 0, -7), endTime)
|
|
require.NoError(t, err)
|
|
|
|
_, err = e.GetHistoricCandles(t.Context(), btcusdPair, asset.CoinMarginedFutures, kline.OneDay, endTime.AddDate(0, 0, -7), endTime)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetHistoricCandlesExtended(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
updatePairsOnce(t, e)
|
|
|
|
endTime := time.Now().Add(-time.Hour).Truncate(time.Hour)
|
|
_, err := e.GetHistoricCandlesExtended(t.Context(), btcusdtPair, asset.Spot, kline.OneMin, endTime.Add(-time.Hour), endTime)
|
|
require.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
|
|
_, err = e.GetHistoricCandlesExtended(t.Context(), btcFutureDatedPair, asset.Futures, kline.OneDay, endTime.AddDate(0, 0, -7), endTime)
|
|
require.NoError(t, err)
|
|
|
|
// demonstrate that adjusting time doesn't wreck non-day intervals
|
|
_, err = e.GetHistoricCandlesExtended(t.Context(), btcFutureDatedPair, asset.Futures, kline.OneHour, endTime.AddDate(0, 0, -1), endTime)
|
|
require.NoError(t, err)
|
|
|
|
_, err = e.GetHistoricCandlesExtended(t.Context(), btcusdPair, asset.CoinMarginedFutures, kline.OneDay, endTime.AddDate(0, 0, -7), time.Now())
|
|
require.NoError(t, err)
|
|
|
|
_, err = e.GetHistoricCandlesExtended(t.Context(), btcusdPair, asset.CoinMarginedFutures, kline.OneHour, endTime.AddDate(0, 0, -1), time.Now())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMarketDetailMerged(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetMarketDetailMerged(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetDepth(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetDepth(t.Context(),
|
|
&OrderBookDataRequestParams{
|
|
Symbol: btcusdtPair,
|
|
Type: OrderBookDataRequestParamsTypeStep1,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTrades(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetLatestSpotPrice(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetLatestSpotPrice(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTradeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTradeHistory(t.Context(), btcusdtPair, 50)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMarketDetail(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetMarketDetail(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetSymbols(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSymbols(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetCurrencies(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetCurrencies(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGet24HrMarketSummary(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.Get24HrMarketSummary(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTicker(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTickers(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetTimestamp(t *testing.T) {
|
|
t.Parallel()
|
|
st, err := e.GetCurrentServerTime(t.Context())
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, st, "GetCurrentServerTime should return a time")
|
|
}
|
|
|
|
func TestWrapperGetServerTime(t *testing.T) {
|
|
t.Parallel()
|
|
st, err := e.GetServerTime(t.Context(), asset.Spot)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, st, "GetServerTime should return a time")
|
|
}
|
|
|
|
func TestGetAccounts(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.GetAccounts(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetAccountBalance(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
result, err := e.GetAccounts(t.Context())
|
|
require.NoError(t, err, "GetAccounts must not error")
|
|
|
|
userID := strconv.FormatInt(result[0].ID, 10)
|
|
_, err = e.GetAccountBalance(t.Context(), userID)
|
|
require.NoError(t, err, "GetAccountBalance must not error")
|
|
}
|
|
|
|
func TestGetAggregatedBalance(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetAggregatedBalance(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSpotNewOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
arg := SpotNewOrderRequestParams{
|
|
Symbol: btcusdtPair,
|
|
AccountID: 1997024,
|
|
Amount: 0.01,
|
|
Price: 10.1,
|
|
Type: SpotNewOrderRequestTypeBuyLimit,
|
|
}
|
|
|
|
_, err := e.SpotNewOrder(t.Context(), &arg)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelExistingOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelExistingOrder(t.Context(), 1337)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestGetOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.GetOrder(t.Context(), 1337)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMarginLoanOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetMarginLoanOrders(t.Context(), btcusdtPair, "", "", "", "", "", "", "")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMarginAccountBalance(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetMarginAccountBalance(t.Context(), btcusdtPair)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelWithdraw(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelWithdraw(t.Context(), 1337)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func setFeeBuilder() *exchange.FeeBuilder {
|
|
return &exchange.FeeBuilder{
|
|
Amount: 1,
|
|
FeeType: exchange.CryptocurrencyTradeFee,
|
|
Pair: currency.NewPairWithDelimiter(currency.BTC.String(),
|
|
currency.LTC.String(),
|
|
"_"),
|
|
PurchasePrice: 1,
|
|
FiatCurrency: currency.USD,
|
|
BankTransactionType: exchange.WireTransfer,
|
|
}
|
|
}
|
|
|
|
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
|
feeBuilder := setFeeBuilder()
|
|
_, err := e.GetFeeByType(t.Context(), feeBuilder)
|
|
require.NoError(t, err)
|
|
if !sharedtestvalues.AreAPICredentialsSet(e) {
|
|
assert.Equal(t, exchange.OfflineTradeFee, feeBuilder.FeeType)
|
|
} else {
|
|
assert.Equal(t, exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
|
}
|
|
}
|
|
|
|
func TestGetFee(t *testing.T) {
|
|
t.Parallel()
|
|
feeBuilder := setFeeBuilder()
|
|
// CryptocurrencyTradeFee Basic
|
|
_, err := e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyTradeFee High quantity
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.Amount = 1000
|
|
feeBuilder.PurchasePrice = 1000
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyTradeFee IsMaker
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.IsMaker = true
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyTradeFee Negative purchase price
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.PurchasePrice = -1000
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyWithdrawalFee Invalid currency
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.Pair.Base = currency.NewCode("hello")
|
|
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// CryptocurrencyDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyDepositFee
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// InternationalBankDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
|
|
// InternationalBankWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
|
feeBuilder.FiatCurrency = currency.USD
|
|
_, err = e.GetFee(feeBuilder)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFormatWithdrawPermissions(t *testing.T) {
|
|
t.Parallel()
|
|
expectedResult := exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.NoFiatWithdrawalsText
|
|
withdrawPermissions := e.FormatWithdrawPermissions()
|
|
assert.Equal(t, expectedResult, withdrawPermissions)
|
|
}
|
|
|
|
func TestGetActiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
getOrdersRequest := order.MultiOrderRequest{
|
|
AssetType: asset.Spot,
|
|
Type: order.AnyType,
|
|
Pairs: []currency.Pair{currency.NewBTCUSDT()},
|
|
Side: order.AnySide,
|
|
}
|
|
|
|
_, err := e.GetActiveOrders(t.Context(), &getOrdersRequest)
|
|
if sharedtestvalues.AreAPICredentialsSet(e) {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.ErrorIs(t, err, exchange.ErrAuthenticationSupportNotEnabled)
|
|
}
|
|
}
|
|
|
|
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
|
// ----------------------------------------------------------------------------------------------------------------------------
|
|
func TestSubmitOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
accounts, err := e.GetAccounts(t.Context())
|
|
require.NoError(t, err, "GetAccounts must not error")
|
|
|
|
orderSubmission := &order.Submit{
|
|
Exchange: e.Name,
|
|
Pair: currency.Pair{
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
},
|
|
Side: order.Buy,
|
|
Type: order.Limit,
|
|
Price: 5,
|
|
Amount: 1,
|
|
ClientID: strconv.FormatInt(accounts[0].ID, 10),
|
|
AssetType: asset.Spot,
|
|
}
|
|
response, err := e.SubmitOrder(t.Context(), orderSubmission)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, order.New, response.Status, "response status should be correct")
|
|
}
|
|
|
|
func TestCancelExchangeOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
orderCancellation := &order.Cancel{
|
|
OrderID: "1",
|
|
AccountID: "1",
|
|
Pair: btcusdtPair,
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
err := e.CancelOrder(t.Context(), orderCancellation)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelAllExchangeOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
|
orderCancellation := order.Cancel{
|
|
OrderID: "1",
|
|
AccountID: "1",
|
|
Pair: currencyPair,
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
_, err := e.CancelAllOrders(t.Context(), &orderCancellation)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
for _, a := range []asset.Item{asset.Spot, asset.CoinMarginedFutures, asset.Futures} {
|
|
_, err := e.UpdateAccountInfo(t.Context(), a)
|
|
assert.NoErrorf(t, err, "UpdateAccountInfo should not error for asset %s", a)
|
|
}
|
|
}
|
|
|
|
func TestModifyOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
_, err := e.ModifyOrder(t.Context(), &order.Modify{AssetType: asset.Spot})
|
|
require.Error(t, err, "ModifyOrder must error without any order details")
|
|
}
|
|
|
|
func TestWithdraw(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
|
|
withdrawCryptoRequest := withdraw.Request{
|
|
Exchange: e.Name,
|
|
Amount: -1,
|
|
Currency: currency.BTC,
|
|
Description: "WITHDRAW IT ALL",
|
|
Crypto: withdraw.CryptoRequest{
|
|
Address: core.BitcoinDonationAddress,
|
|
},
|
|
}
|
|
|
|
_, err := e.WithdrawCryptocurrencyFunds(t.Context(), &withdrawCryptoRequest)
|
|
require.ErrorContains(t, err, withdraw.ErrStrAmountMustBeGreaterThanZero)
|
|
}
|
|
|
|
func TestWithdrawFiat(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.WithdrawFiatFunds(t.Context(), &withdraw.Request{})
|
|
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
}
|
|
|
|
func TestWithdrawInternationalBank(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(), &withdraw.Request{})
|
|
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
}
|
|
|
|
func TestQueryDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.QueryDepositAddress(t.Context(), currency.USDT)
|
|
if sharedtestvalues.AreAPICredentialsSet(e) {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.ErrorIs(t, err, exchange.ErrAuthenticationSupportNotEnabled)
|
|
}
|
|
}
|
|
|
|
func TestGetDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetDepositAddress(t.Context(), currency.USDT, "", "uSdTeRc20")
|
|
if sharedtestvalues.AreAPICredentialsSet(e) {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.ErrorIs(t, err, exchange.ErrAuthenticationSupportNotEnabled)
|
|
}
|
|
}
|
|
|
|
func TestQueryWithdrawQuota(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.QueryWithdrawQuotas(t.Context(), currency.BTC.Lower().String())
|
|
if sharedtestvalues.AreAPICredentialsSet(e) {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.ErrorIs(t, err, exchange.ErrAuthenticationSupportNotEnabled)
|
|
}
|
|
}
|
|
|
|
func TestWSCandles(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "market.btcusdt.kline.1min", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.CandlesChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
testexch.FixtureToDataHandler(t, "testdata/wsCandles.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Len(t, e.Websocket.DataHandler, 1, "Must see correct number of records")
|
|
cAny := <-e.Websocket.DataHandler
|
|
c, ok := cAny.(websocket.KlineData)
|
|
require.True(t, ok, "Must get the correct type from DataHandler")
|
|
exp := websocket.KlineData{
|
|
Timestamp: time.UnixMilli(1489474082831),
|
|
Pair: btcusdtPair,
|
|
AssetType: asset.Spot,
|
|
Exchange: e.Name,
|
|
OpenPrice: 7962.62,
|
|
ClosePrice: 8014.56,
|
|
HighPrice: 14962.77,
|
|
LowPrice: 5110.14,
|
|
Volume: 4.4,
|
|
Interval: "0s",
|
|
}
|
|
assert.Equal(t, exp, c)
|
|
}
|
|
|
|
func TestWSOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "market.btcusdt.depth.step0", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.OrderbookChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
testexch.FixtureToDataHandler(t, "testdata/wsOrderbook.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Len(t, e.Websocket.DataHandler, 1, "Must see correct number of records")
|
|
dAny := <-e.Websocket.DataHandler
|
|
d, ok := dAny.(*orderbook.Depth)
|
|
require.True(t, ok, "Must get the correct type from DataHandler")
|
|
require.NotNil(t, d)
|
|
l, err := d.GetAskLength()
|
|
require.NoError(t, err, "GetAskLength must not error")
|
|
assert.Equal(t, 2, l, "Ask length should be correct")
|
|
liq, _, err := d.TotalAskAmounts()
|
|
require.NoError(t, err, "TotalAskAmount must not error")
|
|
assert.Equal(t, 0.502591, liq, "Ask Liquidity should be correct")
|
|
l, err = d.GetBidLength()
|
|
require.NoError(t, err, "GetBidLength must not error")
|
|
assert.Equal(t, 2, l, "Bid length should be correct")
|
|
liq, _, err = d.TotalBidAmounts()
|
|
require.NoError(t, err, "TotalBidAmount must not error")
|
|
assert.Equal(t, 0.56281, liq, "Bid Liquidity should be correct")
|
|
}
|
|
|
|
// TestWSHandleAllTradesMsg ensures wsHandleAllTrades sends trade.Data to the ws.DataHandler
|
|
func TestWSHandleAllTradesMsg(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "market.btcusdt.trade.detail", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.AllTradesChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
e.SetSaveTradeDataStatus(true)
|
|
testexch.FixtureToDataHandler(t, "testdata/wsAllTrades.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
exp := []trade.Data{
|
|
{
|
|
Exchange: e.Name,
|
|
CurrencyPair: btcusdtPair,
|
|
Timestamp: time.UnixMilli(1630994963173).UTC(),
|
|
Price: 52648.62,
|
|
Amount: 0.006754,
|
|
Side: order.Buy,
|
|
TID: "102523573486",
|
|
AssetType: asset.Spot,
|
|
},
|
|
{
|
|
Exchange: e.Name,
|
|
CurrencyPair: btcusdtPair,
|
|
Timestamp: time.UnixMilli(1630994963184).UTC(),
|
|
Price: 52648.73,
|
|
Amount: 0.006755,
|
|
Side: order.Sell,
|
|
TID: "102523573487",
|
|
AssetType: asset.Spot,
|
|
},
|
|
}
|
|
require.Len(t, e.Websocket.DataHandler, 2, "Must see correct number of trades")
|
|
for resp := range e.Websocket.DataHandler {
|
|
switch v := resp.(type) {
|
|
case trade.Data:
|
|
i := 1 - len(e.Websocket.DataHandler)
|
|
require.Equalf(t, exp[i], v, "Trade [%d] must be correct", i)
|
|
case error:
|
|
t.Error(v)
|
|
default:
|
|
t.Errorf("Unexpected type in DataHandler: %T(%s)", v, v)
|
|
}
|
|
}
|
|
require.Empty(t, e.Websocket.DataHandler, "Must not see any errors going to datahandler")
|
|
}
|
|
|
|
func TestWSTicker(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "market.btcusdt.detail", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.TickerChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
testexch.FixtureToDataHandler(t, "testdata/wsTicker.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Len(t, e.Websocket.DataHandler, 1, "Must see correct number of records")
|
|
tickAny := <-e.Websocket.DataHandler
|
|
tick, ok := tickAny.(*ticker.Price)
|
|
require.True(t, ok, "Must get the correct type from DataHandler")
|
|
require.NotNil(t, tick)
|
|
exp := &ticker.Price{
|
|
High: 52924.14,
|
|
Low: 51000,
|
|
Bid: 0,
|
|
Volume: 13991.028076056185,
|
|
QuoteVolume: 7.27676440200527e+08,
|
|
Open: 51823.62,
|
|
Close: 52379.99,
|
|
Pair: btcusdtPair,
|
|
ExchangeName: e.Name,
|
|
AssetType: asset.Spot,
|
|
LastUpdated: time.UnixMilli(1630998026649),
|
|
}
|
|
assert.Equal(t, exp, tick)
|
|
}
|
|
|
|
func TestWSAccountUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "accounts.update#2", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.MyAccountChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
e.SetSaveTradeDataStatus(true)
|
|
testexch.FixtureToDataHandler(t, "testdata/wsMyAccount.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Len(t, e.Websocket.DataHandler, 3, "Must see correct number of records")
|
|
exp := []WsAccountUpdate{
|
|
{Currency: "btc", AccountID: 123456, Balance: 23.111, ChangeType: "transfer", AccountType: "trade", ChangeTime: types.Time(time.UnixMilli(1568601800000)), SeqNum: 1},
|
|
{Currency: "btc", AccountID: 33385, Available: 2028.69, ChangeType: "order.match", AccountType: "trade", ChangeTime: types.Time(time.UnixMilli(1574393385167)), SeqNum: 2},
|
|
{Currency: "usdt", AccountID: 14884859, Available: 20.29388158, Balance: 20.29388158, AccountType: "trade", SeqNum: 3},
|
|
}
|
|
for _, ex := range exp {
|
|
uAny := <-e.Websocket.DataHandler
|
|
u, ok := uAny.(WsAccountUpdate)
|
|
require.True(t, ok, "Must get the correct type from DataHandler")
|
|
require.NotNil(t, u)
|
|
assert.Equal(t, ex, u)
|
|
}
|
|
}
|
|
|
|
func TestWSOrderUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "orders#*", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.MyOrdersChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
e.SetSaveTradeDataStatus(true)
|
|
errs := testexch.FixtureToDataHandlerWithErrors(t, "testdata/wsMyOrders.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Equal(t, 1, len(errs), "Must receive the correct number of errors back")
|
|
require.ErrorContains(t, errs[0].Err, "error with order \"test1\": invalid.client.order.id (NT) (2002)")
|
|
require.Len(t, e.Websocket.DataHandler, 4, "Must see correct number of records")
|
|
exp := []*order.Detail{
|
|
{
|
|
Exchange: e.Name,
|
|
Pair: btcusdtPair,
|
|
Side: order.Buy,
|
|
Status: order.Rejected,
|
|
ClientOrderID: "test1",
|
|
AssetType: asset.Spot,
|
|
LastUpdated: time.UnixMicro(1583853365586000),
|
|
},
|
|
{
|
|
Exchange: e.Name,
|
|
Pair: btcusdtPair,
|
|
Side: order.Buy,
|
|
Status: order.Cancelled,
|
|
ClientOrderID: "test2",
|
|
AssetType: asset.Spot,
|
|
LastUpdated: time.UnixMicro(1583853365586000),
|
|
},
|
|
{
|
|
Exchange: e.Name,
|
|
Pair: btcusdtPair,
|
|
Side: order.Sell,
|
|
Status: order.New,
|
|
ClientOrderID: "test3",
|
|
AssetType: asset.Spot,
|
|
Price: 77,
|
|
Amount: 2,
|
|
Type: order.Limit,
|
|
OrderID: "27163533",
|
|
LastUpdated: time.UnixMicro(1583853365586000),
|
|
},
|
|
{
|
|
Exchange: e.Name,
|
|
Pair: btcusdtPair,
|
|
Side: order.Buy,
|
|
Status: order.New,
|
|
AssetType: asset.Spot,
|
|
Price: 70000,
|
|
Amount: 0.000157,
|
|
Type: order.Limit,
|
|
OrderID: "1199329381585359",
|
|
LastUpdated: time.UnixMicro(1731039387696000),
|
|
},
|
|
}
|
|
for _, ex := range exp {
|
|
m := <-e.Websocket.DataHandler
|
|
require.IsType(t, &order.Detail{}, m, "Must get the correct type from DataHandler")
|
|
d, _ := m.(*order.Detail)
|
|
require.NotNil(t, d)
|
|
assert.Equal(t, ex, d, "Order Detail should match")
|
|
}
|
|
}
|
|
|
|
func TestWSMyTrades(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Setup Instance must not error")
|
|
err := e.Websocket.AddSubscriptions(e.Websocket.Conn, &subscription.Subscription{Key: "trade.clearing#btcusdt#1", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}, Channel: subscription.MyTradesChannel})
|
|
require.NoError(t, err, "AddSubscriptions must not error")
|
|
e.SetSaveTradeDataStatus(true)
|
|
testexch.FixtureToDataHandler(t, "testdata/wsMyTrades.json", e.wsHandleData)
|
|
close(e.Websocket.DataHandler)
|
|
require.Len(t, e.Websocket.DataHandler, 1, "Must see correct number of records")
|
|
m := <-e.Websocket.DataHandler
|
|
exp := &order.Detail{
|
|
Exchange: e.Name,
|
|
Pair: btcusdtPair,
|
|
Side: order.Buy,
|
|
Status: order.PartiallyFilled,
|
|
ClientOrderID: "a001",
|
|
OrderID: "99998888",
|
|
AssetType: asset.Spot,
|
|
Date: time.UnixMicro(1583853365586000),
|
|
LastUpdated: time.UnixMicro(1583853365996000),
|
|
Price: 10000,
|
|
Amount: 1,
|
|
Trades: []order.TradeHistory{
|
|
{
|
|
Price: 9999.99,
|
|
Amount: 0.96,
|
|
Fee: 19.88,
|
|
Exchange: e.Name,
|
|
TID: "919219323232",
|
|
Side: order.Buy,
|
|
IsMaker: false,
|
|
Timestamp: time.UnixMicro(1583853365996000),
|
|
},
|
|
},
|
|
}
|
|
require.IsType(t, &order.Detail{}, m, "Must get the correct type from DataHandler")
|
|
d, _ := m.(*order.Detail)
|
|
require.NotNil(t, d)
|
|
assert.Equal(t, exp, d, "Order Detail should match")
|
|
}
|
|
|
|
func TestStringToOrderStatus(t *testing.T) {
|
|
t.Parallel()
|
|
type TestCases struct {
|
|
Case string
|
|
Result order.Status
|
|
}
|
|
testCases := []TestCases{
|
|
{Case: "submitted", Result: order.New},
|
|
{Case: "canceled", Result: order.Cancelled},
|
|
{Case: "partial-filled", Result: order.PartiallyFilled},
|
|
{Case: "partial-canceled", Result: order.PartiallyCancelled},
|
|
{Case: "LOL", Result: order.UnknownStatus},
|
|
}
|
|
for i := range testCases {
|
|
result, _ := stringToOrderStatus(testCases[i].Case)
|
|
if result != testCases[i].Result {
|
|
t.Errorf("Expected: %v, received: %v", testCases[i].Result, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStringToOrderSide(t *testing.T) {
|
|
t.Parallel()
|
|
type TestCases struct {
|
|
Case string
|
|
Result order.Side
|
|
}
|
|
testCases := []TestCases{
|
|
{Case: "buy-limit", Result: order.Buy},
|
|
{Case: "sell-limit", Result: order.Sell},
|
|
{Case: "woah-nelly", Result: order.UnknownSide},
|
|
}
|
|
for i := range testCases {
|
|
result, _ := stringToOrderSide(testCases[i].Case)
|
|
if result != testCases[i].Result {
|
|
t.Errorf("Expected: %v, received: %v", testCases[i].Result, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStringToOrderType(t *testing.T) {
|
|
t.Parallel()
|
|
type TestCases struct {
|
|
Case string
|
|
Result order.Type
|
|
}
|
|
testCases := []TestCases{
|
|
{Case: "buy-limit", Result: order.Limit},
|
|
{Case: "sell-market", Result: order.Market},
|
|
{Case: "woah-nelly", Result: order.UnknownType},
|
|
}
|
|
for i := range testCases {
|
|
result, _ := stringToOrderType(testCases[i].Case)
|
|
if result != testCases[i].Result {
|
|
t.Errorf("Expected: %v, received: %v", testCases[i].Result, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFormatExchangeKlineInterval(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tt := range []struct {
|
|
interval kline.Interval
|
|
output string
|
|
}{
|
|
{kline.OneMin, "1min"},
|
|
{kline.FourHour, "4hour"},
|
|
{kline.OneDay, "1day"},
|
|
{kline.OneWeek, "1week"},
|
|
{kline.OneMonth, "1mon"},
|
|
{kline.OneYear, "1year"},
|
|
{kline.TwoWeek, ""},
|
|
} {
|
|
assert.Equalf(t, tt.output, e.FormatExchangeKlineInterval(tt.interval), "FormatExchangeKlineInterval should return correctly for %s", tt.output)
|
|
}
|
|
}
|
|
|
|
func TestGetRecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetRecentTrades(t.Context(), btcusdtPair, asset.Spot)
|
|
require.NoError(t, err)
|
|
_, err = e.GetRecentTrades(t.Context(), btccwPair, asset.Futures)
|
|
require.NoError(t, err)
|
|
_, err = e.GetRecentTrades(t.Context(), btcusdPair, asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetHistoricTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetHistoricTrades(t.Context(), btcusdtPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
|
require.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
}
|
|
|
|
func TestGetAvailableTransferChains(t *testing.T) {
|
|
t.Parallel()
|
|
c, err := e.GetAvailableTransferChains(t.Context(), currency.USDT)
|
|
require.NoError(t, err)
|
|
require.Greater(t, len(c), 2, "Must get more than 2 chains")
|
|
}
|
|
|
|
func TestFormatFuturesPair(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t, e)
|
|
|
|
r, err := e.formatFuturesPair(btccwPair, false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "BTC_CW", r)
|
|
|
|
// pair in the format of BTC210827 but make it lower case to test correct formatting
|
|
r, err = e.formatFuturesPair(btcFutureDatedPair.Lower(), false)
|
|
require.NoError(t, err)
|
|
assert.Len(t, r, 9, "Should be an 9 character string")
|
|
assert.Equal(t, "BTC2", r[0:4], "Should start with btc and a date this millennium")
|
|
|
|
r, err = e.formatFuturesPair(btccwPair, true)
|
|
require.NoError(t, err)
|
|
assert.Len(t, r, 9, "Should be an 9 character string")
|
|
assert.Equal(t, "BTC2", r[0:4], "Should start with btc and a date this millennium")
|
|
|
|
r, err = e.formatFuturesPair(currency.NewBTCUSDT(), false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "BTC-USDT", r)
|
|
}
|
|
|
|
func TestSearchForExistedWithdrawsAndDeposits(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.SearchForExistedWithdrawsAndDeposits(t.Context(), currency.BTC, "deposit", "", 0, 100)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelOrderBatch(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelOrderBatch(t.Context(), []string{"1234"}, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestCancelBatchOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.CancelBatchOrders(t.Context(), []order.Cancel{
|
|
{
|
|
OrderID: "1234",
|
|
AssetType: asset.Spot,
|
|
Pair: currency.NewBTCUSDT(),
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetWithdrawalsHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetWithdrawalsHistory(t.Context(), currency.BTC, asset.Spot)
|
|
require.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)
|
|
|
|
_, err = e.GetFuturesContractDetails(t.Context(), asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
_, err = e.GetFuturesContractDetails(t.Context(), asset.Futures)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetLatestFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Test Instance Setup must not fail")
|
|
updatePairsOnce(t, e)
|
|
|
|
_, err := e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: currency.NewBTCUSD(),
|
|
IncludePredictedRate: true,
|
|
})
|
|
require.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
_, err = e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.CoinMarginedFutures,
|
|
Pair: currency.NewBTCUSD(),
|
|
IncludePredictedRate: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = e.CurrencyPairs.EnablePair(asset.CoinMarginedFutures, currency.NewBTCUSD())
|
|
require.ErrorIs(t, err, currency.ErrPairAlreadyEnabled)
|
|
|
|
_, err = e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.CoinMarginedFutures,
|
|
IncludePredictedRate: true,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIsPerpetualFutureCurrency(t *testing.T) {
|
|
t.Parallel()
|
|
is, err := e.IsPerpetualFutureCurrency(asset.Binary, currency.NewBTCUSDT())
|
|
require.NoError(t, err)
|
|
assert.False(t, is)
|
|
|
|
is, err = e.IsPerpetualFutureCurrency(asset.CoinMarginedFutures, currency.NewBTCUSDT())
|
|
require.NoError(t, err)
|
|
assert.True(t, is)
|
|
}
|
|
|
|
func TestGetSwapFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetSwapFundingRates(t.Context())
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestGetBatchCoinMarginSwapContracts(t *testing.T) {
|
|
t.Parallel()
|
|
resp, err := e.GetBatchCoinMarginSwapContracts(t.Context())
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
|
|
func TestGetBatchLinearSwapContracts(t *testing.T) {
|
|
t.Parallel()
|
|
resp, err := e.GetBatchLinearSwapContracts(t.Context())
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
|
|
func TestGetBatchFuturesContracts(t *testing.T) {
|
|
t.Parallel()
|
|
resp, err := e.GetBatchFuturesContracts(t.Context())
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
|
|
func TestUpdateTickers(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t, e)
|
|
for _, a := range e.GetAssetTypes(false) {
|
|
err := e.UpdateTickers(t.Context(), a)
|
|
require.NoErrorf(t, err, "asset %s", a)
|
|
avail, err := e.GetAvailablePairs(a)
|
|
require.NoError(t, err)
|
|
for _, p := range avail {
|
|
_, err = ticker.GetTicker(e.Name, p, a)
|
|
assert.NoErrorf(t, err, "Could not get ticker for %s %s", a, p)
|
|
}
|
|
}
|
|
}
|
|
|
|
var expiryWindows = map[string]uint{
|
|
"CW": 14,
|
|
"NW": 21,
|
|
"CQ": 190,
|
|
"NQ": 282,
|
|
}
|
|
|
|
// TestPairFromContractExpiryCode ensures at least some contract codes are available and loaded with sane dates
|
|
// Expectations are relaxed because dates are unpredictable and codes disappear intermittently
|
|
func TestPairFromContractExpiryCode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Test Instance Setup must not fail")
|
|
|
|
_, err := e.FetchTradablePairs(t.Context(), asset.Futures)
|
|
require.NoError(t, err)
|
|
|
|
tz, err := time.LoadLocation("Asia/Singapore") // Huobi HQ and apparent local time for when codes become effective
|
|
require.NoError(t, err, "LoadLocation must not error")
|
|
|
|
today := time.Now()
|
|
today = time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, tz) // Do not use Truncate; https://github.com/golang/go/issues/55921
|
|
|
|
require.NotEmpty(t, e.futureContractCodes, "At least one contract code must be loaded")
|
|
|
|
for cType, cachedContract := range e.futureContractCodes {
|
|
t.Run(cType, func(t *testing.T) {
|
|
t.Parallel()
|
|
p, err := e.pairFromContractExpiryCode(currency.Pair{
|
|
Base: currency.BTC,
|
|
Quote: currency.NewCode(cType),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, currency.BTC, p.Base, "pair Base should be BTC")
|
|
assert.Equal(t, cachedContract, p.Quote, "pair Quote should match futureContractCodes value")
|
|
exp, err := time.ParseInLocation("060102", p.Quote.String(), tz)
|
|
require.NoError(t, err, "currency code must be a parsable date")
|
|
require.Falsef(t, exp.Before(today), "expiry must be today or after; Got: %q", exp)
|
|
diff := uint(exp.Sub(today).Hours() / 24)
|
|
require.LessOrEqualf(t, diff, expiryWindows[cType], "expiry must be within expected update window; Today: %q, Expiry: %q",
|
|
today.Format(time.DateOnly),
|
|
exp.Format(time.DateOnly),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t, e)
|
|
|
|
_, err := e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: currency.ETH.Item,
|
|
Quote: currency.USDT.Item,
|
|
Asset: asset.USDTMarginedFutures,
|
|
})
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
resp, err := e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: currency.BTC.Item,
|
|
Quote: currency.USD.Item,
|
|
Asset: asset.CoinMarginedFutures,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: btccwPair.Base.Item,
|
|
Quote: btccwPair.Quote.Item,
|
|
Asset: asset.Futures,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.GetOpenInterest(t.Context())
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
|
|
func TestContractOpenInterestUSDT(t *testing.T) {
|
|
t.Parallel()
|
|
resp, err := e.ContractOpenInterestUSDT(t.Context(), currency.EMPTYPAIR, currency.EMPTYPAIR, "", "")
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
cp := currency.NewBTCUSDT()
|
|
resp, err = e.ContractOpenInterestUSDT(t.Context(), cp, currency.EMPTYPAIR, "", "")
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.ContractOpenInterestUSDT(t.Context(), currency.EMPTYPAIR, cp, "", "")
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.ContractOpenInterestUSDT(t.Context(), cp, currency.EMPTYPAIR, "this_week", "")
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.ContractOpenInterestUSDT(t.Context(), currency.EMPTYPAIR, currency.EMPTYPAIR, "", "swap")
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
|
|
func TestGetCurrencyTradeURL(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t, e)
|
|
for _, a := range e.GetAssetTypes(false) {
|
|
pairs, err := e.CurrencyPairs.GetPairs(a, false)
|
|
require.NoErrorf(t, err, "cannot get pairs for %s", a)
|
|
require.NotEmptyf(t, pairs, "no pairs for %s", a)
|
|
resp, err := e.GetCurrencyTradeURL(t.Context(), a, pairs[0])
|
|
if (a == asset.Futures || a == asset.CoinMarginedFutures) && !pairs[0].Quote.Equal(currency.USD) && !pairs[0].Quote.Equal(currency.USDT) {
|
|
require.ErrorIs(t, err, common.ErrNotYetImplemented)
|
|
} else {
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateSubscriptions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
|
|
|
e.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
|
subs, err := e.generateSubscriptions()
|
|
require.NoError(t, err, "generateSubscriptions must not error")
|
|
exp := subscription.List{}
|
|
for _, s := range e.Features.Subscriptions {
|
|
if s.Asset == asset.Empty {
|
|
s := s.Clone() //nolint:govet // Intentional lexical scope shadow
|
|
s.QualifiedChannel = channelName(s)
|
|
exp = append(exp, s)
|
|
continue
|
|
}
|
|
for _, a := range e.GetAssetTypes(true) {
|
|
if s.Asset != asset.All && s.Asset != a {
|
|
continue
|
|
}
|
|
pairs, err := e.GetEnabledPairs(a)
|
|
require.NoErrorf(t, err, "GetEnabledPairs %s must not error", a)
|
|
pairs = common.SortStrings(pairs).Format(currency.PairFormat{Uppercase: false, Delimiter: ""})
|
|
s := s.Clone() //nolint:govet // Intentional lexical scope shadow
|
|
s.Asset = a
|
|
if isWildcardChannel(s) {
|
|
s.Pairs = pairs
|
|
s.QualifiedChannel = channelName(s)
|
|
exp = append(exp, s)
|
|
continue
|
|
}
|
|
for i, p := range pairs {
|
|
s := s.Clone() //nolint:govet // Intentional lexical scope shadow
|
|
s.QualifiedChannel = channelName(s, p)
|
|
switch s.Channel {
|
|
case subscription.OrderbookChannel:
|
|
s.QualifiedChannel += ".step0"
|
|
case subscription.CandlesChannel:
|
|
s.QualifiedChannel += ".1min"
|
|
}
|
|
s.Pairs = pairs[i : i+1]
|
|
exp = append(exp, s)
|
|
}
|
|
}
|
|
}
|
|
testsubs.EqualLists(t, exp, subs)
|
|
}
|
|
|
|
func wsFixture(tb testing.TB, msg []byte, w *gws.Conn) error {
|
|
tb.Helper()
|
|
action, _ := jsonparser.GetString(msg, "action")
|
|
ch, _ := jsonparser.GetString(msg, "ch")
|
|
if action == "req" && ch == "auth" {
|
|
return w.WriteMessage(gws.TextMessage, []byte(`{"action":"req","code":200,"ch":"auth","data":{}}`))
|
|
}
|
|
if action == "sub" {
|
|
return w.WriteMessage(gws.TextMessage, []byte(`{"action":"sub","code":200,"ch":"`+ch+`"}`))
|
|
}
|
|
id, _ := jsonparser.GetString(msg, "id")
|
|
sub, _ := jsonparser.GetString(msg, "sub")
|
|
if id != "" && sub != "" {
|
|
return w.WriteMessage(gws.TextMessage, []byte(`{"id":"`+id+`","status":"ok","subbed":"`+sub+`"}`))
|
|
}
|
|
return fmt.Errorf("%w: %s", errors.New("Unhandled mock websocket message"), msg)
|
|
}
|
|
|
|
// TestSubscribe exercises live public subscriptions
|
|
func TestSubscribe(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
|
subs, err := e.Features.Subscriptions.ExpandTemplates(e)
|
|
require.NoError(t, err, "ExpandTemplates must not error")
|
|
testexch.SetupWs(t, e)
|
|
err = e.Subscribe(subs)
|
|
require.NoError(t, err, "Subscribe must not error")
|
|
got := e.Websocket.GetSubscriptions()
|
|
require.Equal(t, 8, len(got), "Must get correct number of subscriptions")
|
|
for _, s := range got {
|
|
assert.Equal(t, subscription.SubscribedState, s.State())
|
|
}
|
|
}
|
|
|
|
// TestAuthSubscribe exercises mock subscriptions including private
|
|
func TestAuthSubscribe(t *testing.T) {
|
|
t.Parallel()
|
|
subCfg := e.Features.Subscriptions
|
|
h := testexch.MockWsInstance[Exchange](t, mockws.CurryWsMockUpgrader(t, wsFixture))
|
|
h.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
|
subs, err := subCfg.ExpandTemplates(h)
|
|
require.NoError(t, err, "ExpandTemplates must not error")
|
|
err = h.Subscribe(subs)
|
|
require.NoError(t, err, "Subscribe must not error")
|
|
got := h.Websocket.GetSubscriptions()
|
|
require.Equal(t, 11, len(got), "Must get correct number of subscriptions")
|
|
for _, s := range got {
|
|
assert.Equal(t, subscription.SubscribedState, s.State())
|
|
}
|
|
}
|
|
|
|
func TestChannelName(t *testing.T) {
|
|
assert.Equal(t, "market.BTC-USD.kline", channelName(&subscription.Subscription{Channel: subscription.CandlesChannel}, btcusdPair))
|
|
assert.Equal(t, "trade.clearing#*#1", channelName(&subscription.Subscription{Channel: subscription.MyTradesChannel}, btcusdPair))
|
|
assert.Panics(t, func() { channelName(&subscription.Subscription{Channel: wsOrderbookChannel}, btcusdPair) })
|
|
}
|
|
|
|
func TestIsWildcardChannel(t *testing.T) {
|
|
assert.False(t, isWildcardChannel(&subscription.Subscription{Channel: subscription.CandlesChannel}))
|
|
assert.True(t, isWildcardChannel(&subscription.Subscription{Channel: subscription.MyOrdersChannel}))
|
|
assert.Panics(t, func() { channelName(&subscription.Subscription{Channel: wsOrderbookChannel}) })
|
|
}
|
|
|
|
func TestGetErrResp(t *testing.T) {
|
|
err := getErrResp([]byte(`{"status":"error","err-code":"bad-request","err-msg":"invalid topic promiscuous.drop🐻s.nearby"}`))
|
|
assert.ErrorContains(t, err, "invalid topic promiscuous.drop🐻s.nearby (bad-request)", "V1 errors should return correctly")
|
|
err = getErrResp([]byte(`{"status":"ok","subbed":"market.btcusdt.trade.detail"}`))
|
|
assert.NoError(t, err, "V1 success should not error")
|
|
|
|
err = getErrResp([]byte(`{"action":"sub","code":2001,"ch":"naughty.drop🐻s.locally","message":"invalid.ch"}`))
|
|
assert.ErrorContains(t, err, "invalid.ch (2001)", "V2 errors should return correctly")
|
|
|
|
err = getErrResp([]byte(`{"action":"sub","code":200,"ch":"orders#btcusdt","data":{}}`))
|
|
assert.NoError(t, err, "V2 success should not error")
|
|
}
|
|
|
|
func TestBootstrap(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange)
|
|
require.NoError(t, testexch.Setup(e), "Test Instance Setup must not fail")
|
|
|
|
c, err := e.Bootstrap(t.Context())
|
|
require.NoError(t, err)
|
|
assert.True(t, c, "Bootstrap should return true to continue")
|
|
|
|
e.futureContractCodes = nil
|
|
e.Features.Enabled.AutoPairUpdates = false
|
|
_, err = e.Bootstrap(t.Context())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, e.futureContractCodes)
|
|
}
|
|
|
|
var (
|
|
updatePairsMutex sync.Mutex
|
|
futureContractCodesCache map[string]currency.Code
|
|
)
|
|
|
|
// updatePairsOnce updates the pairs once, and ensures a future dated contract is enabled
|
|
func updatePairsOnce(tb testing.TB, h *Exchange) {
|
|
tb.Helper()
|
|
|
|
updatePairsMutex.Lock()
|
|
defer updatePairsMutex.Unlock()
|
|
|
|
testexch.UpdatePairsOnce(tb, h)
|
|
|
|
h.futureContractCodesMutex.Lock()
|
|
if len(h.futureContractCodes) == 0 {
|
|
// Restored pairs from cache, so haven't populated futureContract Codes
|
|
require.NotEmpty(tb, futureContractCodesCache, "futureContractCodesCache must not be empty")
|
|
h.futureContractCodes = futureContractCodesCache
|
|
} else {
|
|
futureContractCodesCache = h.futureContractCodes
|
|
}
|
|
h.futureContractCodesMutex.Unlock()
|
|
|
|
if btcFutureDatedPair.Equal(currency.EMPTYPAIR) {
|
|
p, err := h.pairFromContractExpiryCode(btccwPair)
|
|
require.NoError(tb, err, "pairFromContractCode must not error")
|
|
btcFutureDatedPair = p
|
|
}
|
|
|
|
err := h.CurrencyPairs.EnablePair(asset.Futures, btcFutureDatedPair) // Must enable every time we refresh the CurrencyPairs from cache
|
|
require.NoError(tb, common.ExcludeError(err, currency.ErrPairAlreadyEnabled))
|
|
}
|