package kraken import ( "context" "errors" "fmt" "log" "net/http" "os" "strings" "testing" "time" "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/convert" "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" 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/stream" "github.com/thrasher-corp/gocryptotrader/exchanges/subscription" "github.com/thrasher-corp/gocryptotrader/exchanges/ticker" "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" ) var k = &Kraken{} var wsSetupRan bool // Please add your own APIkeys to do correct due diligence testing. const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false ) // TestSetup setup func func TestMain(m *testing.M) { k.SetDefaults() cfg := config.GetConfig() err := cfg.LoadConfig("../../testdata/configtest.json", true) if err != nil { log.Fatal(err) } krakenConfig, err := cfg.GetExchangeConfig("Kraken") if err != nil { log.Fatal(err) } krakenConfig.API.AuthenticatedSupport = true krakenConfig.API.Credentials.Key = apiKey krakenConfig.API.Credentials.Secret = apiSecret k.Websocket = sharedtestvalues.NewTestWebsocket() err = k.Setup(krakenConfig) if err != nil { log.Fatal(err) } err = k.UpdateTradablePairs(context.Background(), true) if err != nil { log.Fatal(err) } os.Exit(m.Run()) } func TestGetCurrentServerTime(t *testing.T) { t.Parallel() _, err := k.GetCurrentServerTime(context.Background()) if err != nil { t.Error("GetCurrentServerTime() error", err) } } func TestWrapperGetServerTime(t *testing.T) { t.Parallel() st, err := k.GetServerTime(context.Background(), asset.Spot) if !errors.Is(err, nil) { t.Fatalf("received: '%v' but expected: '%v'", err, nil) } if st.IsZero() { t.Error("expected a time") } } // TestUpdateOrderExecutionLimits exercises UpdateOrderExecutionLimits and GetOrderExecutionLimits func TestUpdateOrderExecutionLimits(t *testing.T) { t.Parallel() err := k.UpdateOrderExecutionLimits(context.Background(), asset.Spot) require.NoError(t, err, "UpdateOrderExecutionLimits must not error") for _, p := range []currency.Pair{ currency.NewPair(currency.ETH, currency.USDT), currency.NewPair(currency.XBT, currency.USDT), } { limits, err := k.GetOrderExecutionLimits(asset.Spot, p) require.NoErrorf(t, err, "%s GetOrderExecutionLimits must not error", p) assert.Positivef(t, limits.PriceStepIncrementSize, "%s PriceStepIncrementSize should be positive", p) assert.Positivef(t, limits.MinimumBaseAmount, "%s MinimumBaseAmount should be positive", p) } } func TestFetchTradablePairs(t *testing.T) { t.Parallel() _, err := k.FetchTradablePairs(context.Background(), asset.Futures) if err != nil { t.Error(err) } } func TestUpdateTicker(t *testing.T) { t.Parallel() sp, err := currency.NewPairFromString("XBTUSD") if err != nil { t.Error(err) } _, err = k.UpdateTicker(context.Background(), sp, asset.Spot) if err != nil { t.Error(err) } fp, err := currency.NewPairFromString("pi_xbtusd") if err != nil { t.Error(err) } _, err = k.UpdateTicker(context.Background(), fp, asset.Futures) if err != nil { t.Error(err) } } func TestUpdateTickers(t *testing.T) { t.Parallel() ap, err := k.GetAvailablePairs(asset.Spot) require.NoError(t, err) err = k.CurrencyPairs.StorePairs(asset.Spot, ap, true) require.NoError(t, err) err = k.UpdateTickers(context.Background(), asset.Spot) assert.NoError(t, err) for i := range ap { _, err = ticker.GetTicker(k.Name, ap[i], asset.Spot) assert.NoError(t, err) } ap, err = k.GetAvailablePairs(asset.Futures) require.NoError(t, err) err = k.CurrencyPairs.StorePairs(asset.Futures, ap, true) require.NoError(t, err) err = k.UpdateTickers(context.Background(), asset.Futures) assert.NoError(t, err) for i := range ap { _, err = ticker.GetTicker(k.Name, ap[i], asset.Futures) assert.NoError(t, err) } err = k.UpdateTickers(context.Background(), asset.Index) assert.ErrorIs(t, err, asset.ErrNotSupported) } func TestUpdateOrderbook(t *testing.T) { t.Parallel() sp, err := currency.NewPairFromString("BTCEUR") if err != nil { t.Error(err) } _, err = k.UpdateOrderbook(context.Background(), sp, asset.Spot) if err != nil { t.Error(err) } fp, err := currency.NewPairFromString("pi_xbtusd") if err != nil { t.Error(err) } _, err = k.UpdateOrderbook(context.Background(), fp, asset.Futures) if err != nil { t.Error(err) } } func TestUpdateAccountInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.UpdateAccountInfo(context.Background(), asset.Spot) if err != nil { t.Error(err) } } func TestWrapperGetOrderInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.GetOrderInfo(context.Background(), "123", currency.EMPTYPAIR, asset.Futures) if err != nil { t.Error(err) } } func TestFuturesBatchOrder(t *testing.T) { t.Parallel() var data []PlaceBatchOrderData var tempData PlaceBatchOrderData tempData.PlaceOrderType = "meow" tempData.OrderID = "test123" tempData.Symbol = "pi_xbtusd" data = append(data, tempData) _, err := k.FuturesBatchOrder(context.Background(), data) if !errors.Is(err, errInvalidBatchOrderType) { t.Fatalf("received: '%v' but expected: '%v'", err, errInvalidBatchOrderType) } sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) data[0].PlaceOrderType = "cancel" _, err = k.FuturesBatchOrder(context.Background(), data) if err != nil { t.Error(err) } } func TestFuturesEditOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) _, err := k.FuturesEditOrder(context.Background(), "test123", "", 5.2, 1, 0) if err != nil { t.Error(err) } } func TestFuturesSendOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) cp, err := currency.NewPairFromString("PI_XBTUSD") if err != nil { t.Error(err) } _, err = k.FuturesSendOrder(context.Background(), order.Limit, cp, "buy", "", "", "", true, 1, 1, 0.9) if err != nil { t.Error(err) } } func TestFuturesCancelOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) _, err := k.FuturesCancelOrder(context.Background(), "test123", "") if err != nil { t.Error(err) } } func TestFuturesGetFills(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.FuturesGetFills(context.Background(), time.Now().Add(-time.Hour*24)) if err != nil { t.Error(err) } } func TestFuturesTransfer(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.FuturesTransfer(context.Background(), "cash", "futures", "btc", 2) if err != nil { t.Error(err) } } func TestFuturesGetOpenPositions(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.FuturesGetOpenPositions(context.Background()) if err != nil { t.Error(err) } } func TestFuturesNotifications(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.FuturesNotifications(context.Background()) if err != nil { t.Error(err) } } func TestFuturesCancelAllOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) cp, err := currency.NewPairFromString("PI_XBTUSD") if err != nil { t.Error(err) } _, err = k.FuturesCancelAllOrders(context.Background(), cp) if err != nil { t.Error(err) } } func TestGetFuturesAccountData(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.GetFuturesAccountData(context.Background()) if err != nil { t.Error(err) } } func TestFuturesCancelAllOrdersAfter(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) _, err := k.FuturesCancelAllOrdersAfter(context.Background(), 50) if err != nil { t.Error(err) } } func TestFuturesOpenOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.FuturesOpenOrders(context.Background()) if err != nil { t.Error(err) } } func TestFuturesRecentOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) cp, err := currency.NewPairFromString("PI_XBTUSD") if err != nil { t.Error(err) } _, err = k.FuturesRecentOrders(context.Background(), cp) if err != nil { t.Error(err) } } func TestFuturesWithdrawToSpotWallet(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) _, err := k.FuturesWithdrawToSpotWallet(context.Background(), "xbt", 5) if err != nil { t.Error(err) } } func TestFuturesGetTransfers(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k, canManipulateRealOrders) _, err := k.FuturesGetTransfers(context.Background(), time.Now().Add(-time.Hour*24)) if err != nil { t.Error(err) } } func TestGetFuturesOrderbook(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("FI_xbtusd_200925") if err != nil { t.Error(err) } _, err = k.GetFuturesOrderbook(context.Background(), cp) if err != nil { t.Error(err) } } func TestGetFuturesMarkets(t *testing.T) { t.Parallel() _, err := k.GetInstruments(context.Background()) if err != nil { t.Error(err) } } func TestGetFuturesTickers(t *testing.T) { t.Parallel() _, err := k.GetFuturesTickers(context.Background()) if err != nil { t.Error(err) } } func TestGetFuturesTradeHistory(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("pi_xbtusd") if err != nil { t.Error(err) } _, err = k.GetFuturesTradeHistory(context.Background(), cp, time.Now().Add(-time.Hour*24)) if err != nil { t.Error(err) } } // TestGetAssets API endpoint test func TestGetAssets(t *testing.T) { t.Parallel() _, err := k.GetAssets(context.Background()) if err != nil { t.Error("GetAssets() error", err) } } func TestSeedAssetTranslator(t *testing.T) { t.Parallel() // Test currency pair if r := assetTranslator.LookupAltName("XXBTZUSD"); r != "XBTUSD" { t.Error("unexpected result") } if r := assetTranslator.LookupCurrency("XBTUSD"); r != "XXBTZUSD" { t.Error("unexpected result") } // Test fiat currency if r := assetTranslator.LookupAltName("ZUSD"); r != "USD" { t.Error("unexpected result") } if r := assetTranslator.LookupCurrency("USD"); r != "ZUSD" { t.Error("unexpected result") } // Test cryptocurrency if r := assetTranslator.LookupAltName("XXBT"); r != "XBT" { t.Error("unexpected result") } if r := assetTranslator.LookupCurrency("XBT"); r != "XXBT" { t.Error("unexpected result") } } func TestSeedAssets(t *testing.T) { t.Parallel() var a assetTranslatorStore if r := a.LookupAltName("ZUSD"); r != "" { t.Error("unexpected result") } a.Seed("ZUSD", "USD") if r := a.LookupAltName("ZUSD"); r != "USD" { t.Error("unexpected result") } a.Seed("ZUSD", "BLA") if r := a.LookupAltName("ZUSD"); r != "USD" { t.Error("unexpected result") } } func TestLookupCurrency(t *testing.T) { t.Parallel() var a assetTranslatorStore if r := a.LookupCurrency("USD"); r != "" { t.Error("unexpected result") } a.Seed("ZUSD", "USD") if r := a.LookupCurrency("USD"); r != "ZUSD" { t.Error("unexpected result") } if r := a.LookupCurrency("EUR"); r != "" { t.Error("unexpected result") } } // TestGetAssetPairs API endpoint test func TestGetAssetPairs(t *testing.T) { t.Parallel() _, err := k.GetAssetPairs(context.Background(), []string{}, "fees") if err != nil { t.Error("GetAssetPairs() error", err) } _, err = k.GetAssetPairs(context.Background(), []string{}, "leverage") if err != nil { t.Error("GetAssetPairs() error", err) } _, err = k.GetAssetPairs(context.Background(), []string{}, "margin") if err != nil { t.Error("GetAssetPairs() error", err) } _, err = k.GetAssetPairs(context.Background(), []string{}, "") if err != nil { t.Error("GetAssetPairs() error", err) } } // TestGetTicker API endpoint test func TestGetTicker(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("BCHEUR") if err != nil { t.Error(err) } _, err = k.GetTicker(context.Background(), cp) if err != nil { t.Error("GetTicker() error", err) } } // TestGetTickers API endpoint test func TestGetTickers(t *testing.T) { t.Parallel() _, err := k.GetTickers(context.Background(), "LTCUSD,ETCUSD") if err != nil { t.Error("GetTickers() error", err) } } // TestGetOHLC API endpoint test func TestGetOHLC(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("XXBTZUSD") if err != nil { t.Error(err) } _, err = k.GetOHLC(context.Background(), cp, "1440") if err != nil { t.Error("GetOHLC() error", err) } } // TestGetDepth API endpoint test func TestGetDepth(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("BCHEUR") if err != nil { t.Error(err) } _, err = k.GetDepth(context.Background(), cp) if err != nil { t.Error("GetDepth() error", err) } } // TestGetTrades API endpoint test func TestGetTrades(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("BCHEUR") if err != nil { t.Error(err) } _, err = k.GetTrades(context.Background(), cp) if err != nil { t.Error("GetTrades() error", err) } cp, err = currency.NewPairFromString("XXXXX") if err != nil { t.Error(err) } _, err = k.GetTrades(context.Background(), cp) if err == nil { t.Error("GetTrades() error: expecting error") } } // TestGetSpread API endpoint test func TestGetSpread(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("BCHEUR") if err != nil { t.Error(err) } _, err = k.GetSpread(context.Background(), cp) if err != nil { t.Error("GetSpread() error", err) } } // TestGetBalance API endpoint test func TestGetBalance(t *testing.T) { t.Parallel() _, err := k.GetBalance(context.Background()) if err == nil { t.Error("GetBalance() Expected error") } } // TestGetTradeBalance API endpoint test func TestGetDepositMethods(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.GetDepositMethods(context.Background(), "USDT") if err != nil { t.Error(err) } } // TestGetTradeBalance API endpoint test func TestGetTradeBalance(t *testing.T) { t.Parallel() args := TradeBalanceOptions{Asset: "ZEUR"} _, err := k.GetTradeBalance(context.Background(), args) if err == nil { t.Error("GetTradeBalance() Expected error") } } // TestGetOpenOrders API endpoint test func TestGetOpenOrders(t *testing.T) { t.Parallel() args := OrderInfoOptions{Trades: true} _, err := k.GetOpenOrders(context.Background(), args) if err == nil { t.Error("GetOpenOrders() Expected error") } } // TestGetClosedOrders API endpoint test func TestGetClosedOrders(t *testing.T) { t.Parallel() args := GetClosedOrdersOptions{Trades: true, Start: "OE4KV4-4FVQ5-V7XGPU"} _, err := k.GetClosedOrders(context.Background(), args) if err == nil { t.Error("GetClosedOrders() Expected error") } } // TestQueryOrdersInfo API endpoint test func TestQueryOrdersInfo(t *testing.T) { t.Parallel() args := OrderInfoOptions{Trades: true} _, err := k.QueryOrdersInfo(context.Background(), args, "OR6ZFV-AA6TT-CKFFIW", "OAMUAJ-HLVKG-D3QJ5F") if err == nil { t.Error("QueryOrdersInfo() Expected error") } } // TestGetTradesHistory API endpoint test func TestGetTradesHistory(t *testing.T) { t.Parallel() args := GetTradesHistoryOptions{Trades: true, Start: "TMZEDR-VBJN2-NGY6DX", End: "TVRXG2-R62VE-RWP3UW"} _, err := k.GetTradesHistory(context.Background(), args) if err == nil { t.Error("GetTradesHistory() Expected error") } } // TestQueryTrades API endpoint test func TestQueryTrades(t *testing.T) { t.Parallel() _, err := k.QueryTrades(context.Background(), true, "TMZEDR-VBJN2-NGY6DX", "TFLWIB-KTT7L-4TWR3L", "TDVRAH-2H6OS-SLSXRX") if err == nil { t.Error("QueryTrades() Expected error") } } // TestOpenPositions API endpoint test func TestOpenPositions(t *testing.T) { t.Parallel() _, err := k.OpenPositions(context.Background(), false) if err == nil { t.Error("OpenPositions() Expected error") } } // TestGetLedgers API endpoint test func TestGetLedgers(t *testing.T) { t.Parallel() args := GetLedgersOptions{Start: "LRUHXI-IWECY-K4JYGO", End: "L5NIY7-JZQJD-3J4M2V", Ofs: 15} _, err := k.GetLedgers(context.Background(), args) if err == nil { t.Error("GetLedgers() Expected error") } } // TestQueryLedgers API endpoint test func TestQueryLedgers(t *testing.T) { t.Parallel() _, err := k.QueryLedgers(context.Background(), "LVTSFS-NHZVM-EXNZ5M") if err == nil { t.Error("QueryLedgers() Expected error") } } // TestGetTradeVolume API endpoint test func TestGetTradeVolume(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("OAVY7T-MV5VK-KHDF5X") if err != nil { t.Error(err) } _, err = k.GetTradeVolume(context.Background(), true, cp) if err == nil { t.Error("GetTradeVolume() Expected error") } } // TestAddOrder API endpoint test func TestAddOrder(t *testing.T) { t.Parallel() args := AddOrderOptions{OrderFlags: "fcib"} cp, err := currency.NewPairFromString("XXBTZUSD") if err != nil { t.Error(err) } _, err = k.AddOrder(context.Background(), cp, order.Sell.Lower(), order.Limit.Lower(), 0.00000001, 0, 0, 0, &args) if err == nil { t.Error("AddOrder() Expected error") } } // TestCancelExistingOrder API endpoint test func TestCancelExistingOrder(t *testing.T) { t.Parallel() _, err := k.CancelExistingOrder(context.Background(), "OAVY7T-MV5VK-KHDF5X") if err == nil { t.Error("CancelExistingOrder() Expected error") } } func setFeeBuilder() *exchange.FeeBuilder { return &exchange.FeeBuilder{ Amount: 1, FeeType: exchange.CryptocurrencyTradeFee, Pair: currency.NewPair(currency.XXBT, currency.ZUSD), PurchasePrice: 1, FiatCurrency: currency.USD, BankTransactionType: exchange.WireTransfer, } } // TestGetFee logic test // TestGetFeeByTypeOfflineTradeFee logic test func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() _, err := k.GetFeeByType(context.Background(), feeBuilder) if err != nil { t.Error(err) } if !sharedtestvalues.AreAPICredentialsSet(k) { if feeBuilder.FeeType != exchange.OfflineTradeFee { t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) } } else { if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) } } } func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() if sharedtestvalues.AreAPICredentialsSet(k) { // CryptocurrencyTradeFee Basic if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee High quantity feeBuilder = setFeeBuilder() feeBuilder.Amount = 1000 feeBuilder.PurchasePrice = 1000 if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee Negative purchase price feeBuilder = setFeeBuilder() feeBuilder.PurchasePrice = -1000 if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // InternationalBankDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankDepositFee if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } } // CryptocurrencyDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CryptocurrencyDepositFee feeBuilder.Pair.Base = currency.XXBT if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyWithdrawalFee Invalid currency feeBuilder = setFeeBuilder() feeBuilder.Pair.Base = currency.NewCode("hello") feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // InternationalBankWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee feeBuilder.FiatCurrency = currency.USD if _, err := k.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } } // TestFormatWithdrawPermissions logic test func TestFormatWithdrawPermissions(t *testing.T) { t.Parallel() expectedResult := exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawCryptoWith2FAText + " & " + exchange.AutoWithdrawFiatWithSetupText + " & " + exchange.WithdrawFiatWith2FAText withdrawPermissions := k.FormatWithdrawPermissions() if withdrawPermissions != expectedResult { t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions) } } // TestGetActiveOrders wrapper test func TestGetActiveOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) pair, err := currency.NewPairFromString("LTC_USDT") if err != nil { t.Error(err) } var getOrdersRequest = order.MultiOrderRequest{ Type: order.AnyType, AssetType: asset.Spot, Pairs: currency.Pairs{pair}, Side: order.AnySide, } _, err = k.GetActiveOrders(context.Background(), &getOrdersRequest) if err != nil { t.Error(err) } } // TestGetOrderHistory wrapper test func TestGetOrderHistory(t *testing.T) { t.Parallel() var getOrdersRequest = order.MultiOrderRequest{ Type: order.AnyType, AssetType: asset.Spot, Side: order.AnySide, } _, err := k.GetOrderHistory(context.Background(), &getOrdersRequest) if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Could not get order history: %s", err) } else if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } } // TestGetOrderHistory wrapper test func TestGetOrderInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) _, err := k.GetOrderInfo(context.Background(), "OZPTPJ-HVYHF-EDIGXS", currency.EMPTYPAIR, asset.Spot) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting error") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { if !strings.Contains(err.Error(), "- Order ID not found:") { t.Error("Expected Order ID not found error") } else { t.Error(err) } } } // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- // TestSubmitOrder wrapper test func TestSubmitOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) var orderSubmission = &order.Submit{ Exchange: k.Name, Pair: currency.Pair{ Base: currency.XBT, Quote: currency.USD, }, Side: order.Buy, Type: order.Limit, Price: 1, Amount: 1, ClientID: "meowOrder", AssetType: asset.Spot, } response, err := k.SubmitOrder(context.Background(), orderSubmission) if sharedtestvalues.AreAPICredentialsSet(k) && (err != nil || response.Status != order.New) { t.Errorf("Order failed to be placed: %v", err) } else if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } } // TestCancelExchangeOrder wrapper test func TestCancelExchangeOrder(t *testing.T) { t.Parallel() if err := k.CancelOrder(context.Background(), &order.Cancel{ AssetType: asset.Options, OrderID: "1337", }); !errors.Is(err, asset.ErrNotSupported) { t.Errorf("expected: %v, received: %v", asset.ErrNotSupported, err) } sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) var orderCancellation = &order.Cancel{ OrderID: "OGEX6P-B5Q74-IGZ72R", AssetType: asset.Spot, } err := k.CancelOrder(context.Background(), orderCancellation) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Could not cancel orders: %v", err) } } // TestCancelExchangeOrder wrapper test func TestCancelBatchExchangeOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) pair := currency.Pair{ Delimiter: "/", Base: currency.BTC, Quote: currency.USD, } var ordersCancellation []order.Cancel ordersCancellation = append(ordersCancellation, order.Cancel{ Pair: pair, OrderID: "OGEX6P-B5Q74-IGZ72R,OGEX6P-B5Q74-IGZ722", AssetType: asset.Spot, }) _, err := k.CancelBatchOrders(context.Background(), ordersCancellation) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Could not cancel orders: %v", err) } } // TestCancelAllExchangeOrders wrapper test func TestCancelAllExchangeOrders(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) resp, err := k.CancelAllOrders(context.Background(), &order.Cancel{AssetType: asset.Spot}) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Could not cancel orders: %v", err) } if len(resp.Status) > 0 { t.Errorf("%v orders failed to cancel", len(resp.Status)) } } // TestGetAccountInfo wrapper test func TestGetAccountInfo(t *testing.T) { t.Parallel() if sharedtestvalues.AreAPICredentialsSet(k) { _, err := k.UpdateAccountInfo(context.Background(), asset.Spot) if err != nil { // Spot and Futures have separate api keys. Please ensure that the correct one is provided t.Error("GetAccountInfo() error", err) } } else { _, err := k.UpdateAccountInfo(context.Background(), asset.Spot) if err == nil { t.Error("GetAccountInfo() Expected error") } } } func TestUpdateFuturesAccountInfo(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.UpdateAccountInfo(context.Background(), asset.Futures) if err != nil { // Spot and Futures have separate api keys. Please ensure that the correct one is provided t.Error(err) } } // TestModifyOrder wrapper test func TestModifyOrder(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) _, err := k.ModifyOrder(context.Background(), &order.Modify{AssetType: asset.Spot}) if err == nil { t.Error("ModifyOrder() Expected error") } } // TestWithdraw wrapper test func TestWithdraw(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) withdrawCryptoRequest := withdraw.Request{ Exchange: k.Name, Crypto: withdraw.CryptoRequest{ Address: core.BitcoinDonationAddress, }, Amount: -1, Currency: currency.XXBT, Description: "WITHDRAW IT ALL", TradePassword: "Key", } _, err := k.WithdrawCryptocurrencyFunds(context.Background(), &withdrawCryptoRequest) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Withdraw failed to be placed: %v", err) } } // TestWithdrawFiat wrapper test func TestWithdrawFiat(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) var withdrawFiatRequest = withdraw.Request{ Amount: -1, Currency: currency.EUR, Description: "WITHDRAW IT ALL", TradePassword: "someBank", } _, err := k.WithdrawFiatFunds(context.Background(), &withdrawFiatRequest) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Withdraw failed to be placed: %v", err) } } // TestWithdrawInternationalBank wrapper test func TestWithdrawInternationalBank(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCannotManipulateOrders(t, k, canManipulateRealOrders) var withdrawFiatRequest = withdraw.Request{ Amount: -1, Currency: currency.EUR, Description: "WITHDRAW IT ALL", TradePassword: "someBank", } _, err := k.WithdrawFiatFundsToInternationalBank(context.Background(), &withdrawFiatRequest) if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("Expecting an error when no keys are set") } if sharedtestvalues.AreAPICredentialsSet(k) && err != nil { t.Errorf("Withdraw failed to be placed: %v", err) } } func TestGetCryptoDepositAddress(t *testing.T) { t.Parallel() sharedtestvalues.SkipTestIfCredentialsUnset(t, k) _, err := k.GetCryptoDepositAddress(context.Background(), "Bitcoin", "XBT", false) if err != nil { t.Error(err) } if !canManipulateRealOrders { t.Skip("canManipulateRealOrders not set, skipping test") } _, err = k.GetCryptoDepositAddress(context.Background(), "Bitcoin", "XBT", true) if err != nil { t.Error(err) } } // TestGetDepositAddress wrapper test func TestGetDepositAddress(t *testing.T) { t.Parallel() if sharedtestvalues.AreAPICredentialsSet(k) { _, err := k.GetDepositAddress(context.Background(), currency.USDT, "", "") if err != nil { t.Error("GetDepositAddress() error", err) } } else { _, err := k.GetDepositAddress(context.Background(), currency.BTC, "", "") if err == nil { t.Error("GetDepositAddress() error can not be nil") } } } // TestWithdrawStatus wrapper test func TestWithdrawStatus(t *testing.T) { t.Parallel() if sharedtestvalues.AreAPICredentialsSet(k) { _, err := k.WithdrawStatus(context.Background(), currency.BTC, "") if err != nil { t.Error("WithdrawStatus() error", err) } } else { _, err := k.WithdrawStatus(context.Background(), currency.BTC, "") if err == nil { t.Error("GetDepositAddress() error can not be nil") } } } // TestWithdrawCancel wrapper test func TestWithdrawCancel(t *testing.T) { t.Parallel() _, err := k.WithdrawCancel(context.Background(), currency.BTC, "") if sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Error("WithdrawCancel() error cannot be nil") } else if !sharedtestvalues.AreAPICredentialsSet(k) && err == nil { t.Errorf("WithdrawCancel() error - expecting an error when no keys are set but received nil") } } // ---------------------------- Websocket tests ----------------------------------------- func setupWsTests(t *testing.T) { t.Helper() if wsSetupRan { return } if !k.Websocket.IsEnabled() && !k.API.AuthenticatedWebsocketSupport || !sharedtestvalues.AreAPICredentialsSet(k) { t.Skip(stream.ErrWebsocketNotEnabled.Error()) } var dialer websocket.Dialer err := k.Websocket.Conn.Dial(&dialer, http.Header{}) if err != nil { t.Fatal(err) } err = k.Websocket.AuthConn.Dial(&dialer, http.Header{}) if err != nil { t.Fatal(err) } token, err := k.GetWebsocketToken(context.Background()) if err != nil { t.Error(err) } authToken = token comms := make(chan stream.Response) go k.wsFunnelConnectionData(k.Websocket.Conn, comms) go k.wsFunnelConnectionData(k.Websocket.AuthConn, comms) go k.wsReadData(comms) go func() { err := k.wsPingHandler() if err != nil { fmt.Println("error:", err) } }() wsSetupRan = true } // TestWebsocketSubscribe tests returning a message with an id func TestWebsocketSubscribe(t *testing.T) { setupWsTests(t) err := k.Subscribe([]subscription.Subscription{ { Channel: defaultSubscribedChannels[0], Pair: currency.NewPairWithDelimiter("XBT", "USD", "/"), }, }) if err != nil { t.Error(err) } } func TestGetWSToken(t *testing.T) { t.Parallel() if !sharedtestvalues.AreAPICredentialsSet(k) { t.Skip("API keys required, skipping") } resp, err := k.GetWebsocketToken(context.Background()) if err != nil { t.Error(err) } if resp == "" { t.Error("Token not returned") } } func TestWsAddOrder(t *testing.T) { setupWsTests(t) _, err := k.wsAddOrder(&WsAddOrderRequest{ OrderType: order.Limit.Lower(), OrderSide: order.Buy.Lower(), Pair: "XBT/USD", Price: -100, }) if err != nil { t.Error(err) } } func TestWsCancelOrder(t *testing.T) { setupWsTests(t) if err := k.wsCancelOrders([]string{"1337"}); err != nil { t.Error(err) } } func TestWsCancelAllOrders(t *testing.T) { setupWsTests(t) if _, err := k.wsCancelAllOrders(); err != nil { t.Error(err) } } func TestWsPong(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "event": "pong", "reqid": 42 }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsSystemStatus(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "connectionID": 8628615390848610000, "event": "systemStatus", "status": "online", "version": "1.0.0" }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsSubscriptionStatus(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 10001, "channelName": "ticker", "event": "subscriptionStatus", "pair": "XBT/EUR", "status": "subscribed", "subscription": { "name": "ticker" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`{ "channelID": 10001, "channelName": "ohlc-5", "event": "subscriptionStatus", "pair": "XBT/EUR", "reqid": 42, "status": "unsubscribed", "subscription": { "interval": 5, "name": "ohlc" } }`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`{ "channelName": "ownTrades", "event": "subscriptionStatus", "status": "subscribed", "subscription": { "name": "ownTrades" } }`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`{ "errorMessage": "Subscription depth not supported", "event": "subscriptionStatus", "pair": "XBT/USD", "status": "error", "subscription": { "depth": 42, "name": "book" } }`) err = k.wsHandleData(pressXToJSON) if err == nil { t.Error("Expected error") } } func TestWsTicker(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 1337, "channelName": "ticker", "event": "subscriptionStatus", "pair": "XBT/EUR", "status": "subscribed", "subscription": { "name": "ticker" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 1337, { "a": [ "5525.40000", 1, "1.000" ], "b": [ "5525.10000", 1, "1.000" ], "c": [ "5525.10000", "0.00398963" ], "h": [ "5783.00000", "5783.00000" ], "l": [ "5505.00000", "5505.00000" ], "o": [ "5760.70000", "5763.40000" ], "p": [ "5631.44067", "5653.78939" ], "t": [ 11493, 16267 ], "v": [ "2634.11501494", "3591.17907851" ] }, "ticker", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsOHLC(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 13337, "channelName": "ohlc", "event": "subscriptionStatus", "pair": "XBT/EUR", "status": "subscribed", "subscription": { "name": "ohlc" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 13337, [ "1542057314.748456", "1542057360.435743", "3586.70000", "3586.70000", "3586.60000", "3586.60000", "3586.68894", "0.03373000", 2 ], "ohlc-5", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsTrade(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 133337, "channelName": "trade", "event": "subscriptionStatus", "pair": "XBT/EUR", "status": "subscribed", "subscription": { "name": "trade" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 133337, [ [ "5541.20000", "0.15850568", "1534614057.321597", "s", "l", "" ], [ "6060.00000", "0.02455000", "1534614057.324998", "b", "l", "" ] ], "trade", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsSpread(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 1333337, "channelName": "spread", "event": "subscriptionStatus", "pair": "XBT/EUR", "status": "subscribed", "subscription": { "name": "spread" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 1333337, [ "5698.40000", "5700.00000", "1542057299.545897", "1.01234567", "0.98765432" ], "spread", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsOrdrbook(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "channelID": 13333337, "channelName": "book", "event": "subscriptionStatus", "pair": "XBT/USD", "status": "subscribed", "subscription": { "name": "book" } }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 13333337, { "as": [ [ "5541.30000", "2.50700000", "1534614248.123678" ], [ "5541.80000", "0.33000000", "1534614098.345543" ], [ "5542.70000", "0.64700000", "1534614244.654432" ], [ "5544.30000", "2.50700000", "1534614248.123678" ], [ "5545.80000", "0.33000000", "1534614098.345543" ], [ "5546.70000", "0.64700000", "1534614244.654432" ], [ "5547.70000", "0.64700000", "1534614244.654432" ], [ "5548.30000", "2.50700000", "1534614248.123678" ], [ "5549.80000", "0.33000000", "1534614098.345543" ], [ "5550.70000", "0.64700000", "1534614244.654432" ] ], "bs": [ [ "5541.20000", "1.52900000", "1534614248.765567" ], [ "5539.90000", "0.30000000", "1534614241.769870" ], [ "5539.50000", "5.00000000", "1534613831.243486" ], [ "5538.20000", "1.52900000", "1534614248.765567" ], [ "5537.90000", "0.30000000", "1534614241.769870" ], [ "5536.50000", "5.00000000", "1534613831.243486" ], [ "5535.20000", "1.52900000", "1534614248.765567" ], [ "5534.90000", "0.30000000", "1534614241.769870" ], [ "5533.50000", "5.00000000", "1534613831.243486" ], [ "5532.50000", "5.00000000", "1534613831.243486" ] ] }, "book-100", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 13333337, { "a": [ [ "5541.30000", "2.50700000", "1534614248.456738" ], [ "5542.50000", "0.40100000", "1534614248.456738" ] ], "c": "4187525586" }, "book-10", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ 13333337, { "b": [ [ "5541.30000", "0.00000000", "1534614335.345903" ] ], "c": "4187525586" }, "book-10", "XBT/USD" ]`) err = k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsOwnTrades(t *testing.T) { t.Parallel() pressXToJSON := []byte(`[ [ { "TDLH43-DVQXD-2KHVYY": { "cost": "1000000.00000", "fee": "1600.00000", "margin": "0.00000", "ordertxid": "TDLH43-DVQXD-2KHVYY", "ordertype": "limit", "pair": "XBT/USD", "postxid": "OGTT3Y-C6I3P-XRI6HX", "price": "100000.00000", "time": "1560516023.070651", "type": "sell", "vol": "1000000000.00000000" } }, { "TDLH43-DVQXD-2KHVYY": { "cost": "1000000.00000", "fee": "600.00000", "margin": "0.00000", "ordertxid": "TDLH43-DVQXD-2KHVYY", "ordertype": "limit", "pair": "XBT/USD", "postxid": "OGTT3Y-C6I3P-XRI6HX", "price": "100000.00000", "time": "1560516023.070658", "type": "buy", "vol": "1000000000.00000000" } }, { "TDLH43-DVQXD-2KHVYY": { "cost": "1000000.00000", "fee": "1600.00000", "margin": "0.00000", "ordertxid": "TDLH43-DVQXD-2KHVYY", "ordertype": "limit", "pair": "XBT/USD", "postxid": "OGTT3Y-C6I3P-XRI6HX", "price": "100000.00000", "time": "1560520332.914657", "type": "sell", "vol": "1000000000.00000000" } }, { "TDLH43-DVQXD-2KHVYY": { "cost": "1000000.00000", "fee": "600.00000", "margin": "0.00000", "ordertxid": "TDLH43-DVQXD-2KHVYY", "ordertype": "limit", "pair": "XBT/USD", "postxid": "OGTT3Y-C6I3P-XRI6HX", "price": "100000.00000", "time": "1560520332.914664", "type": "buy", "vol": "1000000000.00000000" } } ], "ownTrades" ]`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsOpenOrders(t *testing.T) { t.Parallel() n := new(Kraken) sharedtestvalues.TestFixtureToDataHandler(t, k, n, "testdata/wsOpenTrades.json", n.wsHandleData) seen := 0 for reading := true; reading; { select { default: reading = false case resp := <-n.Websocket.DataHandler: seen++ switch v := resp.(type) { case *order.Detail: switch seen { case 1: assert.Equal(t, "OGTT3Y-C6I3P-XRI6HR", v.OrderID, "OrderID") assert.Equal(t, order.Limit, v.Type, "order type") assert.Equal(t, order.Sell, v.Side, "order side") assert.Equal(t, order.Open, v.Status, "order status") assert.Equal(t, 34.5, v.Price, "price") assert.Equal(t, 10.00345345, v.Amount, "amount") case 2: assert.Equal(t, "OKB55A-UEMMN-YUXM2A", v.OrderID, "OrderID") assert.Equal(t, order.Market, v.Type, "order type") assert.Equal(t, order.Buy, v.Side, "order side") assert.Equal(t, order.Pending, v.Status, "order status") assert.Equal(t, 0.0, v.Price, "price") assert.Equal(t, 0.0001, v.Amount, "amount") assert.Equal(t, time.UnixMicro(1692851641361371), v.Date, "Date") case 3: assert.Equal(t, "OKB55A-UEMMN-YUXM2A", v.OrderID, "OrderID") assert.Equal(t, order.Open, v.Status, "order status") case 4: assert.Equal(t, "OKB55A-UEMMN-YUXM2A", v.OrderID, "OrderID") assert.Equal(t, order.UnknownStatus, v.Status, "order status") assert.Equal(t, 26425.2, v.AverageExecutedPrice, "AverageExecutedPrice") assert.Equal(t, 0.0001, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount") // Not in the message; Testing regression to bad derivation assert.Equal(t, 0.00687, v.Fee, "Fee") case 5: assert.Equal(t, "OKB55A-UEMMN-YUXM2A", v.OrderID, "OrderID") assert.Equal(t, order.Closed, v.Status, "order status") assert.Equal(t, 0.0001, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 26425.2, v.AverageExecutedPrice, "AverageExecutedPrice") assert.Equal(t, 0.00687, v.Fee, "Fee") assert.Equal(t, time.UnixMicro(1692851641361447), v.LastUpdated, "LastUpdated") case 6: assert.Equal(t, "OGTT3Y-C6I3P-XRI6HR", v.OrderID, "OrderID") assert.Equal(t, order.UnknownStatus, v.Status, "order status") assert.Equal(t, 10.00345345, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 0.001, v.Fee, "Fee") assert.Equal(t, 34.5, v.AverageExecutedPrice, "AverageExecutedPrice") case 7: assert.Equal(t, "OGTT3Y-C6I3P-XRI6HR", v.OrderID, "OrderID") assert.Equal(t, order.Closed, v.Status, "order status") assert.Equal(t, time.UnixMicro(1692675961789052), v.LastUpdated, "LastUpdated") assert.Equal(t, 10.00345345, v.ExecutedAmount, "ExecutedAmount") assert.Equal(t, 0.001, v.Fee, "Fee") assert.Equal(t, 34.5, v.AverageExecutedPrice, "AverageExecutedPrice") reading = false } default: t.Errorf("Unexpected type in DataHandler: %T (%s)", v, v) } } } assert.Equal(t, 7, seen, "number of DataHandler emissions") } func TestWsAddOrderJSON(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "descr": "buy 0.01770000 XBTUSD @ limit 4000", "event": "addOrderStatus", "status": "ok", "txid": "ONPNXH-KMKMU-F4MR5V" }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsCancelOrderJSON(t *testing.T) { t.Parallel() pressXToJSON := []byte(`{ "event": "cancelOrderStatus", "status": "ok" }`) err := k.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestParseTime(t *testing.T) { t.Parallel() // Test REST example r := convert.TimeFromUnixTimestampDecimal(1373750306.9819).UTC() if r.Year() != 2013 || r.Month().String() != "July" || r.Day() != 13 { t.Error("unexpected result") } // Test Websocket time example r = convert.TimeFromUnixTimestampDecimal(1534614098.345543).UTC() if r.Year() != 2018 || r.Month().String() != "August" || r.Day() != 18 { t.Error("unexpected result") } } func TestGetHistoricCandles(t *testing.T) { t.Parallel() pair, err := currency.NewPairFromString("XBT-USD") if err != nil { t.Fatal(err) } _, err = k.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneHour, time.Now().Add(-time.Hour*12), time.Now()) if err != nil { t.Error(err) } pairs, err := k.CurrencyPairs.GetPairs(asset.Futures, false) if err != nil { t.Error(err) } err = k.CurrencyPairs.EnablePair(asset.Futures, pairs[0]) if err != nil && !errors.Is(err, currency.ErrPairAlreadyEnabled) { t.Error(err) } _, err = k.GetHistoricCandles(context.Background(), pairs[0], asset.Futures, kline.OneHour, time.Now().Add(-time.Hour*12), time.Now()) if !errors.Is(err, asset.ErrNotSupported) { t.Error(err) } } func TestGetHistoricCandlesExtended(t *testing.T) { t.Parallel() pair, err := currency.NewPairFromString("XBT-USD") if err != nil { t.Fatal(err) } _, err = k.GetHistoricCandlesExtended(context.Background(), pair, asset.Spot, kline.OneMin, time.Now().Add(-time.Minute*3), time.Now()) if !errors.Is(err, common.ErrFunctionNotSupported) { t.Error(err) } } func Test_FormatExchangeKlineInterval(t *testing.T) { t.Parallel() testCases := []struct { name string interval kline.Interval output string }{ { "OneMin", kline.OneMin, "1", }, { "OneDay", kline.OneDay, "1440", }, } for x := range testCases { test := testCases[x] t.Run(test.name, func(t *testing.T) { t.Parallel() ret := k.FormatExchangeKlineInterval(test.interval) if ret != test.output { t.Errorf("unexpected result return expected: %v received: %v", test.output, ret) } }) } } func TestGetRecentTrades(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromString("BCHEUR") if err != nil { t.Fatal(err) } _, err = k.GetRecentTrades(context.Background(), cp, asset.Spot) if err != nil { t.Error(err) } cp, err = currency.NewPairFromStrings("PI", "BCHUSD") if err != nil { t.Error(err) } cp.Delimiter = "_" _, err = k.GetRecentTrades(context.Background(), cp, asset.Futures) if err != nil { t.Error(err) } } func TestGetHistoricTrades(t *testing.T) { t.Parallel() currencyPair, err := currency.NewPairFromString("XBTUSD") if err != nil { t.Fatal(err) } _, err = k.GetHistoricTrades(context.Background(), currencyPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now()) if err != nil && err != common.ErrFunctionNotSupported { t.Error(err) } } var testOb = orderbook.Base{ Asks: []orderbook.Item{ // NOTE: 0.00000500 float64 == 0.000005 {Price: 0.05005, StrPrice: "0.05005", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05010, StrPrice: "0.05010", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05015, StrPrice: "0.05015", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05020, StrPrice: "0.05020", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05025, StrPrice: "0.05025", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05030, StrPrice: "0.05030", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05035, StrPrice: "0.05035", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05040, StrPrice: "0.05040", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05045, StrPrice: "0.05045", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05050, StrPrice: "0.05050", Amount: 0.00000500, StrAmount: "0.00000500"}, }, Bids: []orderbook.Item{ {Price: 0.05000, StrPrice: "0.05000", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04995, StrPrice: "0.04995", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04990, StrPrice: "0.04990", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04980, StrPrice: "0.04980", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04975, StrPrice: "0.04975", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04970, StrPrice: "0.04970", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04965, StrPrice: "0.04965", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04960, StrPrice: "0.04960", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04955, StrPrice: "0.04955", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04950, StrPrice: "0.04950", Amount: 0.00000500, StrAmount: "0.00000500"}, }, } const krakenAPIDocChecksum = 974947235 func TestChecksumCalculation(t *testing.T) { t.Parallel() expected := "5005" if v := trim("0.05005"); v != expected { t.Errorf("expected %s but received %s", expected, v) } expected = "500" if v := trim("0.00000500"); v != expected { t.Errorf("expected %s but received %s", expected, v) } err := validateCRC32(&testOb, krakenAPIDocChecksum) if err != nil { t.Error(err) } } func TestGetCharts(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromStrings("PI", "BCHUSD") if err != nil { t.Error(err) } cp.Delimiter = "_" resp, err := k.GetFuturesCharts(context.Background(), "1d", "spot", cp, time.Time{}, time.Time{}) if err != nil { t.Error(err) } end := time.UnixMilli(resp.Candles[0].Time) _, err = k.GetFuturesCharts(context.Background(), "1d", "spot", cp, end.Add(-time.Hour*24*7), end) if err != nil { t.Error(err) } } func TestGetFuturesTrades(t *testing.T) { t.Parallel() cp, err := currency.NewPairFromStrings("PI", "BCHUSD") if err != nil { t.Error(err) } cp.Delimiter = "_" _, err = k.GetFuturesTrades(context.Background(), cp, time.Time{}, time.Time{}) if err != nil { t.Error(err) } _, err = k.GetFuturesTrades(context.Background(), cp, time.Now().Add(-time.Hour), time.Now()) if err != nil { t.Error(err) } } var websocketXDGUSDOrderbookUpdates = []string{ `{"channelID":2304,"channelName":"book-10","event":"subscriptionStatus","pair":"XDG/USD","reqid":163845014,"status":"subscribed","subscription":{"depth":10,"name":"book"}}`, `[2304,{"as":[["0.074602700","278.39626342","1690246067.832139"],["0.074611000","555.65134028","1690246086.243668"],["0.074613300","524.87121572","1690245901.574881"],["0.074624600","77.57180740","1690246060.668500"],["0.074632500","620.64648404","1690246010.904883"],["0.074698400","409.57419037","1690246041.269821"],["0.074700000","61067.71115772","1690246089.485595"],["0.074723200","4394.01869240","1690246087.557913"],["0.074725200","4229.57885125","1690246082.911452"],["0.074738400","212.25501214","1690246089.421559"]],"bs":[["0.074597400","53591.43163675","1690246089.451762"],["0.074596700","33594.18269213","1690246089.514152"],["0.074596600","53598.60351469","1690246089.340781"],["0.074594800","5358.57247081","1690246089.347962"],["0.074594200","30168.21074680","1690246089.345112"],["0.074590900","7089.69894583","1690246088.212880"],["0.074586700","46925.20182082","1690246089.074618"],["0.074577200","5500.00000000","1690246087.568856"],["0.074569600","8132.49888631","1690246086.841219"],["0.074562900","8413.11098009","1690246087.024863"]]},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074700000","0.00000000","1690246089.516119"],["0.074738500","125000.00000000","1690246063.352141","r"]],"c":"2219685759"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074678800","33476.70673703","1690246089.570183"]],"c":"1897176819"},"book-10","XDG/USD"]`, `[2304,{"b":[["0.074562900","0.00000000","1690246089.570206"],["0.074559600","4000.00000000","1690246086.478591","r"]],"c":"2498018751"},"book-10","XDG/USD"]`, `[2304,{"b":[["0.074577300","125000.00000000","1690246089.577140"]],"c":"155006629"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074678800","0.00000000","1690246089.584498"],["0.074738500","125000.00000000","1690246063.352141","r"]],"c":"3703147735"},"book-10","XDG/USD"]`, `[2304,{"b":[["0.074597500","10000.00000000","1690246089.602477"]],"c":"2989534775"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074738500","0.00000000","1690246089.608769"],["0.074750800","51369.02100000","1690246089.495500","r"]],"c":"1842075082"},"book-10","XDG/USD"]`, `[2304,{"b":[["0.074583500","8413.11098009","1690246089.612144"]],"c":"710274752"},"book-10","XDG/USD"]`, `[2304,{"b":[["0.074578500","9966.55841398","1690246089.634739"]],"c":"1646135532"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074738400","0.00000000","1690246089.638648"],["0.074751500","80499.09450000","1690246086.679402","r"]],"c":"2509689626"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074750700","290.96851266","1690246089.638754"]],"c":"3981738175"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074720000","61067.71115772","1690246089.662102"]],"c":"1591820326"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074602700","0.00000000","1690246089.670911"],["0.074750800","51369.02100000","1690246089.495500","r"]],"c":"3838272404"},"book-10","XDG/USD"]`, `[2304,{"a":[["0.074611000","0.00000000","1690246089.680343"],["0.074758500","159144.39750000","1690246035.158327","r"]],"c":"4241552383"},"book-10","XDG/USD"] `, } var websocketLUNAEUROrderbookUpdates = []string{ `{"channelID":9536,"channelName":"book-10","event":"subscriptionStatus","pair":"LUNA/EUR","reqid":106845459,"status":"subscribed","subscription":{"depth":10,"name":"book"}}`, `[9536,{"as":[["0.000074650000","147354.32016076","1690249755.076929"],["0.000074710000","5084881.40000000","1690250711.359411"],["0.000074760000","9700502.70476704","1690250743.279490"],["0.000074990000","2933380.23886300","1690249596.627969"],["0.000075000000","433333.33333333","1690245575.626780"],["0.000075020000","152914.84493416","1690243661.232520"],["0.000075070000","146529.90542161","1690249048.358424"],["0.000075250000","737072.85720004","1690211553.549248"],["0.000075400000","670061.64567140","1690250769.261196"],["0.000075460000","980226.63603417","1690250769.627523"]],"bs":[["0.000074590000","71029.87806720","1690250763.012724"],["0.000074580000","15935576.86404000","1690250763.012710"],["0.000074520000","33758611.79634000","1690250718.290955"],["0.000074350000","3156650.58590277","1690250766.499648"],["0.000074340000","301727260.79999999","1690250766.490238"],["0.000074320000","64611496.53837000","1690250742.680258"],["0.000074310000","104228596.60000000","1690250744.679121"],["0.000074300000","40366046.10582000","1690250762.685914"],["0.000074200000","3690216.57320475","1690250645.311465"],["0.000074060000","1337170.52532521","1690250742.012527"]]},"book-10","LUNA/EUR"]`, `[9536,{"b":[["0.000074060000","0.00000000","1690250770.616604"],["0.000074050000","16742421.17790510","1690250710.867730","r"]],"c":"418307145"},"book-10","LUNA/EUR"]`, } var websocketGSTEUROrderbookUpdates = []string{ `{"channelID":8912,"channelName":"book-10","event":"subscriptionStatus","pair":"GST/EUR","reqid":157734759,"status":"subscribed","subscription":{"depth":10,"name":"book"}}`, `[8912,{"as":[["0.01300","850.00000000","1690230914.230506"],["0.01400","323483.99590510","1690256356.615823"],["0.01500","100287.34442717","1690219133.193345"],["0.01600","67995.78441017","1690118389.451216"],["0.01700","41776.38397740","1689676303.381189"],["0.01800","11785.76177777","1688631951.812452"],["0.01900","23700.00000000","1686935422.319042"],["0.02000","3941.17000000","1689415829.176481"],["0.02100","16598.69173066","1689420942.541943"],["0.02200","17572.51572836","1689851425.907427"]],"bs":[["0.01200","14220.66466572","1690256540.842831"],["0.01100","160223.61546438","1690256401.072463"],["0.01000","63083.48958963","1690256604.037673"],["0.00900","6750.00000000","1690252470.633938"],["0.00800","213059.49706376","1690256360.386301"],["0.00700","1000.00000000","1689869458.464975"],["0.00600","4000.00000000","1690221333.528698"],["0.00100","245000.00000000","1690051368.753455"]]},"book-10","GST/EUR"]`, `[8912,{"b":[["0.01000","60583.48958963","1690256620.206768"],["0.01000","63083.48958963","1690256620.206783"]],"c":"69619317"},"book-10","GST/EUR"]`, } func TestWsOrderbookMax10Depth(t *testing.T) { t.Parallel() for x := range websocketXDGUSDOrderbookUpdates { err := k.wsHandleData([]byte(websocketXDGUSDOrderbookUpdates[x])) if err != nil { t.Fatal(err) } } for x := range websocketLUNAEUROrderbookUpdates { err := k.wsHandleData([]byte(websocketLUNAEUROrderbookUpdates[x])) // TODO: Known issue with LUNA pairs and big number float precision // storage and checksum calc. Might need to store raw strings as fields // in the orderbook.Item struct. // Required checksum: 7465000014735432016076747100005084881400000007476000097005027047670474990000293338023886300750000004333333333333375020000152914844934167507000014652990542161752500007370728572000475400000670061645671407546000098022663603417745900007102987806720745800001593557686404000745200003375861179634000743500003156650585902777434000030172726079999999743200006461149653837000743100001042285966000000074300000403660461058200074200000369021657320475740500001674242117790510 if err != nil && x != len(websocketLUNAEUROrderbookUpdates)-1 { t.Fatal(err) } } // This has less than 10 bids and still needs a checksum calc. for x := range websocketGSTEUROrderbookUpdates { err := k.wsHandleData([]byte(websocketGSTEUROrderbookUpdates[x])) if err != nil { t.Fatal(err) } } } func TestGetFuturesContractDetails(t *testing.T) { t.Parallel() _, err := k.GetFuturesContractDetails(context.Background(), asset.Spot) if !errors.Is(err, futures.ErrNotFuturesAsset) { t.Error(err) } _, err = k.GetFuturesContractDetails(context.Background(), asset.USDTMarginedFutures) if !errors.Is(err, asset.ErrNotSupported) { t.Error(err) } _, err = k.GetFuturesContractDetails(context.Background(), asset.Futures) assert.NoError(t, err, "GetFuturesContractDetails should not error") } func TestGetLatestFundingRates(t *testing.T) { t.Parallel() _, err := k.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{ Asset: asset.USDTMarginedFutures, Pair: currency.NewPair(currency.BTC, currency.USD), IncludePredictedRate: true, }) if !errors.Is(err, asset.ErrNotSupported) { t.Error(err) } _, err = k.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{ Asset: asset.Futures, }) if !errors.Is(err, nil) { t.Error(err) } cp := currency.NewPair(currency.PF, currency.NewCode("XBTUSD")) cp.Delimiter = "_" err = k.CurrencyPairs.EnablePair(asset.Futures, cp) if err != nil && !errors.Is(err, currency.ErrPairAlreadyEnabled) { t.Fatal(err) } _, err = k.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{ Asset: asset.Futures, Pair: cp, IncludePredictedRate: true, }) if err != nil { t.Error(err) } } func TestIsPerpetualFutureCurrency(t *testing.T) { t.Parallel() is, err := k.IsPerpetualFutureCurrency(asset.Binary, currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error(err) } if is { t.Error("expected false") } is, err = k.IsPerpetualFutureCurrency(asset.Futures, currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error(err) } if is { t.Error("expected false") } is, err = k.IsPerpetualFutureCurrency(asset.Futures, currency.NewPair(currency.PF, currency.NewCode("XBTUSD"))) if err != nil { t.Error(err) } if !is { t.Error("expected true") } } func TestGetOpenInterest(t *testing.T) { t.Parallel() _, err := k.GetOpenInterest(context.Background(), key.PairAsset{ Base: currency.ETH.Item, Quote: currency.USDT.Item, Asset: asset.USDTMarginedFutures, }) assert.ErrorIs(t, err, asset.ErrNotSupported) cp1 := currency.NewPair(currency.PF, currency.NewCode("ETHUSD")) cp2 := currency.NewPair(currency.PF, currency.NewCode("XBTUSD")) sharedtestvalues.SetupCurrencyPairsForExchangeAsset(t, k, asset.Futures, cp1, cp2) resp, err := k.GetOpenInterest(context.Background(), key.PairAsset{ Base: cp1.Base.Item, Quote: cp1.Quote.Item, Asset: asset.Futures, }) assert.NoError(t, err) assert.NotEmpty(t, resp) resp, err = k.GetOpenInterest(context.Background(), key.PairAsset{ Base: cp1.Base.Item, Quote: cp1.Quote.Item, Asset: asset.Futures, }, key.PairAsset{ Base: cp2.Base.Item, Quote: cp2.Quote.Item, Asset: asset.Futures, }) assert.NoError(t, err) assert.NotEmpty(t, resp) resp, err = k.GetOpenInterest(context.Background()) assert.NoError(t, err) assert.NotEmpty(t, resp) }