mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 07:26:50 +00:00
* Exchanges: Remove example BespokeGenerateMessageID * Okx: Replace conn.RequestIDGenerator with MesssageID Continued overall direction to remove the closed-loop of e => conn => e roundtrip for message ids * Exchanges: Add MessageSequence This method removes the either/or nature of message id generation. We don't tie the message ids to connections, or to anything. Consumers just call whichever they want, or even combine them as they want. Anything more complicated will need a separate installation anyway * GateIO: Split usage of MessageID and MessageSequence * Binance: Switch to UUID message IDs * Kraken: Switch to e.MessageSequence * Kucoin: Switch to MessageID * HitBTC: Switch to UUIDv7 for ws message ID * Bybit: Switch to UUIDv7 for ws message ID * Bitfinex: Switch to UUIDv7 and MessageSequence Tested CID - It accepts 53 bits only for an int, so MessageSequence makes sense. Can't use MessageID * Websocket: Remove now unused MessageID function Moved all MessageID usage into funcs and onto base methods, to remove the closed loop of message IDs * Docs: Update guidance for message signatures
3353 lines
101 KiB
Go
3353 lines
101 KiB
Go
package binance
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
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/encoding/json"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/collateral"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/futures"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/margin"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
|
|
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 your own keys here for due diligence testing
|
|
const (
|
|
apiKey = ""
|
|
apiSecret = ""
|
|
canManipulateRealOrders = false
|
|
useTestNet = false
|
|
)
|
|
|
|
var (
|
|
e *Exchange
|
|
// this pair is used to ensure that endpoints match it correctly
|
|
testPairMapping = currency.NewPair(currency.DOGE, currency.USDT)
|
|
)
|
|
|
|
func setFeeBuilder() *exchange.FeeBuilder {
|
|
return &exchange.FeeBuilder{
|
|
Amount: 1,
|
|
FeeType: exchange.CryptocurrencyTradeFee,
|
|
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
|
PurchasePrice: 1,
|
|
}
|
|
}
|
|
|
|
// getTime returns a static time for mocking endpoints, if mock is not enabled
|
|
// this will default to time now with a window size of 30 days.
|
|
// Mock details are unix seconds; start = 1577836800 and end = 1580515200
|
|
func getTime() (start, end time.Time) {
|
|
if mockTests {
|
|
return time.Unix(1577836800, 0), time.Unix(1580515200, 0)
|
|
}
|
|
|
|
tn := time.Now()
|
|
offset := time.Hour * 24 * 6
|
|
return tn.Add(-offset), tn
|
|
}
|
|
|
|
func TestUServerTime(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UServerTime(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWrapperGetServerTime(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetServerTime(t.Context(), asset.Empty)
|
|
require.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
st, err := e.GetServerTime(t.Context(), asset.Spot)
|
|
require.NoError(t, err)
|
|
|
|
if st.IsZero() {
|
|
t.Fatal("expected a time")
|
|
}
|
|
|
|
st, err = e.GetServerTime(t.Context(), asset.USDTMarginedFutures)
|
|
require.NoError(t, err)
|
|
|
|
if st.IsZero() {
|
|
t.Fatal("expected a time")
|
|
}
|
|
|
|
st, err = e.GetServerTime(t.Context(), asset.CoinMarginedFutures)
|
|
require.NoError(t, err)
|
|
|
|
if st.IsZero() {
|
|
t.Fatal("expected a time")
|
|
}
|
|
}
|
|
|
|
func TestUpdateTicker(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := e.UpdateTicker(t.Context(), testPairMapping, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if r.Pair.Base != currency.DOGE && r.Pair.Quote != currency.USDT {
|
|
t.Error("invalid pair values")
|
|
}
|
|
tradablePairs, err := e.FetchTradablePairs(t.Context(), asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(tradablePairs) == 0 {
|
|
t.Fatal("no tradable pairs")
|
|
}
|
|
_, err = e.UpdateTicker(t.Context(), tradablePairs[0], asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
usdtMarginedPairs, err := e.FetchTradablePairs(t.Context(), asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(usdtMarginedPairs) == 0 {
|
|
t.Errorf("no pairs are enabled")
|
|
}
|
|
_, err = e.UpdateTicker(t.Context(), usdtMarginedPairs[0], asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateTickers(t *testing.T) {
|
|
err := e.UpdateTickers(t.Context(), asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = e.UpdateTickers(t.Context(), asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = e.UpdateTickers(t.Context(), asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
cp, err := currency.NewPairFromString("BTCUSDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UpdateOrderbook(t.Context(), cp, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UpdateOrderbook(t.Context(), cp, asset.Margin)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UpdateOrderbook(t.Context(), cp, asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
cp2, err := currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UpdateOrderbook(t.Context(), cp2, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// USDT Margined Futures
|
|
|
|
func TestUExchangeInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UExchangeInfo(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUFuturesOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UFuturesOrderbook(t.Context(), currency.NewBTCUSDT(), 1000)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestURecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.URecentTrades(t.Context(), currency.NewBTCUSDT(), "", 1000)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUCompressedTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UCompressedTrades(t.Context(), currency.NewBTCUSDT(), "", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UCompressedTrades(t.Context(), currency.NewPair(currency.LTC, currency.USDT), "", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UKlineData(t.Context(), currency.NewBTCUSDT(), "1d", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UKlineData(t.Context(), currency.NewPair(currency.LTC, currency.USDT), "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGetMarkPrice(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UGetMarkPrice(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UGetMarkPrice(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGetFundingHistory(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UGetFundingHistory(t.Context(), currency.NewBTCUSDT(), 1, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UGetFundingHistory(t.Context(), currency.NewPair(currency.LTC, currency.USDT), 1, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestU24HTickerPriceChangeStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.U24HTickerPriceChangeStats(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.U24HTickerPriceChangeStats(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUSymbolPriceTicker(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.USymbolPriceTicker(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.USymbolPriceTicker(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUSymbolOrderbookTicker(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.USymbolOrderbookTicker(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.USymbolOrderbookTicker(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UOpenInterest(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUOpenInterestStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UOpenInterestStats(t.Context(), currency.NewBTCUSDT(), "5m", 1, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UOpenInterestStats(t.Context(), currency.NewPair(currency.LTC, currency.USDT), "1d", 10, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUTopAcccountsLongShortRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UTopAcccountsLongShortRatio(t.Context(), currency.NewBTCUSDT(), "5m", 2, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UTopAcccountsLongShortRatio(t.Context(), currency.NewBTCUSDT(), "5m", 2, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUTopPostionsLongShortRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UTopPostionsLongShortRatio(t.Context(), currency.NewBTCUSDT(), "5m", 3, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UTopPostionsLongShortRatio(t.Context(), currency.NewBTCUSDT(), "1d", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGlobalLongShortRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UGlobalLongShortRatio(t.Context(), currency.NewBTCUSDT(), "5m", 3, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.UGlobalLongShortRatio(t.Context(), currency.NewBTCUSDT(), "4h", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUTakerBuySellVol(t *testing.T) {
|
|
t.Parallel()
|
|
start, end := getTime()
|
|
_, err := e.UTakerBuySellVol(t.Context(), currency.NewBTCUSDT(), "5m", 10, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUCompositeIndexInfo(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := e.UCompositeIndexInfo(t.Context(), currency.EMPTYPAIR)
|
|
require.NoError(t, err, "UCompositeIndexInfo with no pair must not error")
|
|
require.NotEmpty(t, r, "UCompositeIndexInfo must return composite index info")
|
|
cp, err := currency.NewPairFromString(r[0].Symbol)
|
|
require.NoErrorf(t, err, "NewPairFromString must not error for symbol %s", r[0].Symbol)
|
|
r, err = e.UCompositeIndexInfo(t.Context(), cp)
|
|
require.NoErrorf(t, err, "UCompositeIndexInfo for pair %s must not error", cp)
|
|
require.NotEmptyf(t, r, "UCompositeIndexInfo for pair %s must return composite index info", cp)
|
|
require.NotEmptyf(t, r[0].BaseAssetList, "UCompositeIndexInfo for pair %s must return a non empty base asset list", cp)
|
|
b := r[0].BaseAssetList[0]
|
|
assert.NotEmpty(t, b.BaseAsset, "BaseAsset should be set")
|
|
assert.NotEmpty(t, b.QuoteAsset, "QuoteAsset asset should be set")
|
|
assert.NotZero(t, b.WeightInQuantity, "WeightInQuantity should be set")
|
|
assert.NotZero(t, b.WeightInPercentage, "WeightInPercentage should be set")
|
|
}
|
|
|
|
func TestUFuturesNewOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UFuturesNewOrder(t.Context(),
|
|
&UFuturesNewOrderRequest{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Side: "BUY",
|
|
OrderType: "LIMIT",
|
|
TimeInForce: "GTC",
|
|
Quantity: 1,
|
|
Price: 1,
|
|
},
|
|
)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUPlaceBatchOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
var data []PlaceBatchOrderData
|
|
var tempData PlaceBatchOrderData
|
|
tempData.Symbol = "BTCUSDT"
|
|
tempData.Side = "BUY"
|
|
tempData.OrderType = "LIMIT"
|
|
tempData.Quantity = 4
|
|
tempData.Price = 1
|
|
tempData.TimeInForce = "GTC"
|
|
data = append(data, tempData)
|
|
_, err := e.UPlaceBatchOrders(t.Context(), data)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGetOrderData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UGetOrderData(t.Context(), currency.NewBTCUSDT(), "123", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUCancelOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UCancelOrder(t.Context(), currency.NewBTCUSDT(), "123", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUCancelAllOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UCancelAllOpenOrders(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUCancelBatchOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UCancelBatchOrders(t.Context(), currency.NewBTCUSDT(), []string{"123"}, []string{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAutoCancelAllOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UAutoCancelAllOpenOrders(t.Context(), currency.NewBTCUSDT(), 30)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUFetchOpenOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UFetchOpenOrder(t.Context(), currency.NewBTCUSDT(), "123", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAllAccountOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAllAccountOpenOrders(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAllAccountOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAllAccountOrders(t.Context(), currency.EMPTYPAIR, 0, 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UAllAccountOrders(t.Context(), currency.NewBTCUSDT(), 0, 5, time.Now().Add(-time.Hour*4), time.Now())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAccountBalanceV2(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAccountBalanceV2(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAccountInformationV2(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAccountInformationV2(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUChangeInitialLeverageRequest(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UChangeInitialLeverageRequest(t.Context(), currency.NewBTCUSDT(), 2)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUChangeInitialMarginType(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
err := e.UChangeInitialMarginType(t.Context(), currency.NewBTCUSDT(), "ISOLATED")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUModifyIsolatedPositionMarginReq(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UModifyIsolatedPositionMarginReq(t.Context(), currency.NewBTCUSDT(), "LONG", "add", 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUPositionMarginChangeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.UPositionMarginChangeHistory(t.Context(), currency.NewBTCUSDT(), "add", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUPositionsInfoV2(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UPositionsInfoV2(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAccountTradesHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAccountTradesHistory(t.Context(), currency.NewBTCUSDT(), "", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAccountIncomeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAccountIncomeHistory(t.Context(), currency.EMPTYPAIR, "", 5, time.Now().Add(-time.Hour*48), time.Now())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGetNotionalAndLeverageBrackets(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UGetNotionalAndLeverageBrackets(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUPositionsADLEstimate(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UPositionsADLEstimate(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUAccountForcedOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.UAccountForcedOrders(t.Context(), currency.NewBTCUSDT(), "ADL", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// Coin Margined Futures
|
|
|
|
func TestGetFuturesExchangeInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FuturesExchangeInfo(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesOrderbook(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 1000)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesPublicTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesPublicTrades(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPastPublicTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetPastPublicTrades(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 5, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAggregatedTradesList(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesAggregatedTradesList(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 0, 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPerpsExchangeInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetPerpMarkets(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetIndexAndMarkPrice(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetIndexAndMarkPrice(t.Context(), "", "BTCUSD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := e.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "1M", 5, time.Time{}, time.Time{})
|
|
require.NoError(t, err, "GetFuturesKlineData must not error")
|
|
if mockTests {
|
|
require.Equal(t, 5, len(r), "GetFuturesKlineData must return 5 items in mock test")
|
|
exp := FuturesCandleStick{
|
|
OpenTime: types.Time(time.UnixMilli(1596240000000)),
|
|
Open: 11785,
|
|
High: 12513.6,
|
|
Low: 11114.1,
|
|
Close: 11663.5,
|
|
Volume: 12155433,
|
|
CloseTime: types.Time(time.UnixMilli(1598918399999)),
|
|
BaseAssetVolume: 104142.54608485,
|
|
NumberOfTrades: 359100,
|
|
TakerBuyVolume: 6013546,
|
|
TakerBuyBaseAssetVolume: 51511.95826419,
|
|
}
|
|
assert.Equal(t, exp, r[0])
|
|
} else {
|
|
assert.NotEmpty(t, r, "GetFuturesKlineData should return data")
|
|
}
|
|
|
|
start, end := getTime()
|
|
r, err = e.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("LTCUSD", "PERP", "_"), "5m", 5, start, end)
|
|
require.NoError(t, err, "GetFuturesKlineData must not error")
|
|
assert.NotEmpty(t, r, "GetFuturesKlineData should return data")
|
|
}
|
|
|
|
func TestGetContinuousKlineData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetContinuousKlineData(t.Context(), "BTCUSD", "CURRENT_QUARTER", "1M", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetContinuousKlineData(t.Context(), "BTCUSD", "CURRENT_QUARTER", "1M", 5, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetIndexPriceKlines(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetIndexPriceKlines(t.Context(), "BTCUSD", "1M", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetIndexPriceKlines(t.Context(), "BTCUSD", "1M", 5, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesSwapTickerChangeStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesSwapTickerChangeStats(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetFuturesSwapTickerChangeStats(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetFuturesSwapTickerChangeStats(t.Context(), currency.EMPTYPAIR, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesGetFundingHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesGetFundingHistory(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.FuturesGetFundingHistory(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 50, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesHistoricalTrades(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetFuturesHistoricalTrades(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "", 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetFuturesHistoricalTrades(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "", 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesSymbolPriceTicker(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesSymbolPriceTicker(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesOrderbookTicker(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesOrderbookTicker(t.Context(), currency.EMPTYPAIR, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetFuturesOrderbookTicker(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.OpenInterest(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOpenInterestStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetOpenInterestStats(t.Context(), "BTCUSD", "CURRENT_QUARTER", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetOpenInterestStats(t.Context(), "BTCUSD", "CURRENT_QUARTER", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTraderFuturesAccountRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTraderFuturesAccountRatio(t.Context(), "BTCUSD", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetTraderFuturesAccountRatio(t.Context(), "BTCUSD", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTraderFuturesPositionsRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTraderFuturesPositionsRatio(t.Context(), "BTCUSD", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetTraderFuturesPositionsRatio(t.Context(), "BTCUSD", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarketRatio(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetMarketRatio(t.Context(), "BTCUSD", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetMarketRatio(t.Context(), "BTCUSD", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesTakerVolume(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesTakerVolume(t.Context(), "BTCUSD", "ALL", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetFuturesTakerVolume(t.Context(), "BTCUSD", "ALL", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesBasisData(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesBasisData(t.Context(), "BTCUSD", "CURRENT_QUARTER", "5m", 0, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
start, end := getTime()
|
|
_, err = e.GetFuturesBasisData(t.Context(), "BTCUSD", "CURRENT_QUARTER", "5m", 0, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesNewOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FuturesNewOrder(
|
|
t.Context(),
|
|
&FuturesNewOrderRequest{
|
|
Symbol: currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"),
|
|
Side: "BUY",
|
|
OrderType: "LIMIT",
|
|
TimeInForce: order.GoodTillCancel.String(),
|
|
Quantity: 1,
|
|
Price: 1,
|
|
},
|
|
)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesBatchOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
var data []PlaceBatchOrderData
|
|
var tempData PlaceBatchOrderData
|
|
tempData.Symbol = "BTCUSD_PERP"
|
|
tempData.Side = "BUY"
|
|
tempData.OrderType = "LIMIT"
|
|
tempData.Quantity = 1
|
|
tempData.Price = 1
|
|
tempData.TimeInForce = "GTC"
|
|
|
|
data = append(data, tempData)
|
|
_, err := e.FuturesBatchOrder(t.Context(), data)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesBatchCancelOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FuturesBatchCancelOrders(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), []string{"123"}, []string{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesGetOrderData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesGetOrderData(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "123", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelAllOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FuturesCancelAllOpenOrders(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAutoCancelAllOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.AutoCancelAllOpenOrders(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 30000)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesOpenOrderData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesOpenOrderData(t.Context(), currency.NewBTCUSDT(), "", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesAllOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetFuturesAllOpenOrders(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAllFuturesOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetAllFuturesOrders(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), currency.EMPTYPAIR, time.Time{}, time.Time{}, 0, 2)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesChangeMarginType(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FuturesChangeMarginType(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "ISOLATED")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesAccountBalance(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetFuturesAccountBalance(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetFuturesAccountInfo(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesChangeInitialLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.FuturesChangeInitialLeverage(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestModifyIsolatedPositionMargin(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.ModifyIsolatedPositionMargin(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "BOTH", "add", 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesMarginChangeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesMarginChangeHistory(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "add", time.Time{}, time.Time{}, 10)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesPositionsInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesPositionsInfo(t.Context(), "BTCUSD", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesTradeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesTradeHistory(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "", time.Time{}, time.Time{}, 5, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesIncomeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesIncomeHistory(t.Context(), currency.EMPTYPAIR, "TRANSFER", time.Time{}, time.Time{}, 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesForceOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesForceOrders(t.Context(), currency.EMPTYPAIR, "ADL", time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUGetNotionalLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesNotionalBracket(t.Context(), "BTCUSD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.FuturesNotionalBracket(t.Context(), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFuturesPositionsADLEstimate(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.FuturesPositionsADLEstimate(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarkPriceKline(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetMarkPriceKline(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "1M", 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetExchangeInfo(t *testing.T) {
|
|
t.Parallel()
|
|
info, err := e.GetExchangeInfo(t.Context())
|
|
require.NoError(t, err, "GetExchangeInfo must not error")
|
|
if mockTests {
|
|
exp := time.Date(2025, 8, 7, 21, 55, 41, int(167*time.Millisecond), time.UTC)
|
|
assert.Truef(t, info.ServerTime.Time().Equal(exp), "expected %v received %v", exp.UTC(), info.ServerTime.Time().UTC())
|
|
} else {
|
|
assert.WithinRange(t, info.ServerTime.Time(), time.Now().Add(-24*time.Hour), time.Now().Add(24*time.Hour), "ServerTime should be within a day of now")
|
|
}
|
|
}
|
|
|
|
func TestFetchTradablePairs(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FetchTradablePairs(t.Context(), asset.Spot)
|
|
if err != nil {
|
|
t.Error("Binance FetchTradablePairs(asset asets.AssetType) error", err)
|
|
}
|
|
|
|
_, err = e.FetchTradablePairs(t.Context(), asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = e.FetchTradablePairs(t.Context(), asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderBook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetOrderBook(t.Context(), currency.NewBTCUSDT(), 1000)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestGetMostRecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetMostRecentTrades(t.Context(),
|
|
RecentTradeRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Limit: 15,
|
|
})
|
|
if err != nil {
|
|
t.Error("Binance GetMostRecentTrades() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricalTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetHistoricalTrades(t.Context(), "BTCUSDT", 5, -1)
|
|
if !mockTests && err == nil {
|
|
t.Errorf("Binance GetHistoricalTrades() error: %v", "expected error")
|
|
} else if mockTests && err != nil {
|
|
t.Errorf("Binance GetHistoricalTrades() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetAggregatedTrades(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetAggregatedTrades(t.Context(),
|
|
&AggregatedTradeRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Limit: 5,
|
|
})
|
|
if err != nil {
|
|
t.Error("Binance GetAggregatedTrades() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetSpotKline(t *testing.T) {
|
|
t.Parallel()
|
|
start, end := getTime()
|
|
r, err := e.GetSpotKline(t.Context(), &KlinesRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Interval: kline.FiveMin.Short(),
|
|
Limit: 24,
|
|
StartTime: start,
|
|
EndTime: end,
|
|
})
|
|
require.NoError(t, err, "GetSpotKline must not error")
|
|
if mockTests {
|
|
require.Equal(t, 24, len(r), "GetSpotKline must return 24 items in mock test")
|
|
exp := CandleStick{
|
|
OpenTime: types.Time(time.UnixMilli(1577836800000)),
|
|
Open: 7195.24,
|
|
High: 7196.25,
|
|
Low: 7178.64,
|
|
Close: 7179.78,
|
|
Volume: 95.509133,
|
|
CloseTime: types.Time(time.UnixMilli(1577837099999)),
|
|
QuoteAssetVolume: 686317.13625177,
|
|
TradeCount: 1127,
|
|
TakerBuyAssetVolume: 32.773245,
|
|
TakerBuyQuoteAssetVolume: 235537.29504531,
|
|
}
|
|
assert.Equal(t, exp, r[0])
|
|
} else {
|
|
assert.NotEmpty(t, r, "GetSpotKline should return data")
|
|
}
|
|
}
|
|
|
|
func TestGetAveragePrice(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.GetAveragePrice(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error("Binance GetAveragePrice() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetPriceChangeStats(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.GetPriceChangeStats(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error("Binance GetPriceChangeStats() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetTickers(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetTickers(t.Context())
|
|
require.NoError(t, err)
|
|
|
|
resp, err := e.GetTickers(t.Context(),
|
|
currency.NewBTCUSDT(),
|
|
currency.NewPair(currency.ETH, currency.USDT))
|
|
require.NoError(t, err)
|
|
require.Len(t, resp, 2)
|
|
}
|
|
|
|
func TestGetLatestSpotPrice(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.GetLatestSpotPrice(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error("Binance GetLatestSpotPrice() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetBestPrice(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.GetBestPrice(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error("Binance GetBestPrice() error", err)
|
|
}
|
|
}
|
|
|
|
func TestQueryOrder(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.QueryOrder(t.Context(), currency.NewBTCUSDT(), "", 1337)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("QueryOrder() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("QueryOrder() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock QueryOrder() error", err)
|
|
}
|
|
}
|
|
|
|
func TestOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.OpenOrders(t.Context(), currency.EMPTYPAIR)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p := currency.NewBTCUSDT()
|
|
_, err = e.OpenOrders(t.Context(), p)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAllOrders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := e.AllOrders(t.Context(), currency.NewBTCUSDT(), "", "")
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("AllOrders() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("AllOrders() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock AllOrders() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
feeBuilder := setFeeBuilder()
|
|
_, err := e.GetFeeByType(t.Context(), feeBuilder)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !sharedtestvalues.AreAPICredentialsSet(e) || mockTests {
|
|
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()
|
|
|
|
feeBuilder := setFeeBuilder()
|
|
|
|
if sharedtestvalues.AreAPICredentialsSet(e) && mockTests {
|
|
// CryptocurrencyTradeFee Basic
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee High quantity
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.Amount = 1000
|
|
feeBuilder.PurchasePrice = 1000
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee IsMaker
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.IsMaker = true
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee Negative purchase price
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.PurchasePrice = -1000
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// CryptocurrencyWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyDepositFee
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// InternationalBankDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
|
feeBuilder.FiatCurrency = currency.HKD
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// InternationalBankWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
|
feeBuilder.FiatCurrency = currency.HKD
|
|
if _, err := e.GetFee(t.Context(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFormatWithdrawPermissions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.NoFiatWithdrawalsText
|
|
withdrawPermissions := e.FormatWithdrawPermissions()
|
|
if withdrawPermissions != expectedResult {
|
|
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
pair, err := currency.NewPairFromString("BTC_USDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
getOrdersRequest := order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Pairs: currency.Pairs{pair},
|
|
AssetType: asset.Spot,
|
|
Side: order.AnySide,
|
|
}
|
|
|
|
_, err = e.GetActiveOrders(t.Context(), &getOrdersRequest)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("GetActiveOrders() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("GetActiveOrders() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock GetActiveOrders() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
getOrdersRequest := order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
AssetType: asset.Spot,
|
|
Side: order.AnySide,
|
|
}
|
|
|
|
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
|
if err == nil {
|
|
t.Error("Expected: 'At least one currency is required to fetch order history'. received nil")
|
|
}
|
|
|
|
getOrdersRequest.Pairs = []currency.Pair{
|
|
currency.NewPair(currency.LTC,
|
|
currency.BTC),
|
|
}
|
|
|
|
_, err = e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("GetOrderHistory() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("GetOrderHistory() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock GetOrderHistory() error", err)
|
|
}
|
|
}
|
|
|
|
func TestNewOrderTest(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
req := &NewOrderRequest{
|
|
Symbol: currency.NewPair(currency.LTC, currency.BTC),
|
|
Side: order.Buy.String(),
|
|
TradeType: BinanceRequestParamsOrderLimit,
|
|
Price: 0.0025,
|
|
Quantity: 100000,
|
|
TimeInForce: order.GoodTillCancel.String(),
|
|
}
|
|
|
|
err := e.NewOrderTest(t.Context(), req)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("NewOrderTest() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("NewOrderTest() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock NewOrderTest() error", err)
|
|
}
|
|
|
|
req = &NewOrderRequest{
|
|
Symbol: currency.NewPair(currency.LTC, currency.BTC),
|
|
Side: order.Sell.String(),
|
|
TradeType: BinanceRequestParamsOrderMarket,
|
|
Price: 0.0045,
|
|
QuoteOrderQty: 10,
|
|
}
|
|
|
|
err = e.NewOrderTest(t.Context(), req)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("NewOrderTest() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("NewOrderTest() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock NewOrderTest() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricTrades(t *testing.T) {
|
|
t.Parallel()
|
|
p := currency.NewBTCUSDT()
|
|
start := time.Now().Add(-time.Hour * 24 * 90).Truncate(time.Minute) // 3 months ago
|
|
if mockTests {
|
|
start = time.Unix(1577977445, 0) // 2020-01-02 15:04:05
|
|
}
|
|
end := start.Add(15 * time.Minute)
|
|
result, err := e.GetHistoricTrades(t.Context(), p, asset.Spot, start, end)
|
|
require.NoError(t, err, "GetHistoricTrades must not error")
|
|
assert.Greater(t, len(result), 1001, "GetHistoricTrades should have enough trades")
|
|
for _, r := range result {
|
|
require.WithinRange(t, r.Timestamp, start, end, "All trades must be within time range")
|
|
}
|
|
}
|
|
|
|
// TestGetAggregatedTradesBatched exercises TestGetAggregatedTradesBatched to ensure our date and limit scanning works correctly
|
|
// This test is susceptible to failure if volumes change a lot, during wash trading or zero-fee periods
|
|
// In live tests, 45 minutes is expected to return more than 1000 records
|
|
func TestGetAggregatedTradesBatched(t *testing.T) {
|
|
t.Parallel()
|
|
type testCase struct {
|
|
name string
|
|
args *AggregatedTradeRequestParams
|
|
expFunc func(*testing.T, []AggregatedTrade)
|
|
}
|
|
|
|
var tests []testCase
|
|
if mockTests {
|
|
start := time.Date(2020, 1, 2, 15, 4, 5, 0, time.UTC)
|
|
tests = []testCase{
|
|
{
|
|
name: "mock batch with timerange",
|
|
args: &AggregatedTradeRequestParams{StartTime: start, EndTime: start.Add(75 * time.Minute)},
|
|
expFunc: func(t *testing.T, results []AggregatedTrade) {
|
|
t.Helper()
|
|
require.Equal(t, 1012, len(results), "must return correct number of records")
|
|
assert.Equal(t,
|
|
time.Date(2020, 1, 2, 16, 18, 31, int(919*time.Millisecond), time.UTC),
|
|
results[len(results)-1].TimeStamp.Time().UTC(),
|
|
"should return the correct time for the last record",
|
|
)
|
|
},
|
|
},
|
|
{
|
|
name: "mock custom limit with start time set, no end time",
|
|
args: &AggregatedTradeRequestParams{StartTime: start, Limit: 1001},
|
|
expFunc: func(t *testing.T, results []AggregatedTrade) {
|
|
t.Helper()
|
|
require.Equal(t, 1001, len(results), "must return correct number of records")
|
|
assert.Equal(t,
|
|
time.Date(2020, 1, 2, 15, 18, 39, int(226*time.Millisecond), time.UTC),
|
|
results[len(results)-1].TimeStamp.Time().UTC(),
|
|
"should return the correct time for the last record",
|
|
)
|
|
},
|
|
},
|
|
{
|
|
name: "mock limit less than returned",
|
|
args: &AggregatedTradeRequestParams{Limit: 3},
|
|
expFunc: func(t *testing.T, results []AggregatedTrade) {
|
|
t.Helper()
|
|
require.Equal(t, 3, len(results), "must return correct number of records")
|
|
assert.Equal(t,
|
|
time.Date(2020, 1, 2, 16, 19, 5, int(200*time.Millisecond), time.UTC),
|
|
results[len(results)-1].TimeStamp.Time().UTC(),
|
|
"should return the correct time for the last record",
|
|
)
|
|
},
|
|
},
|
|
}
|
|
} else {
|
|
start := time.Now().Add(-time.Hour * 24 * 90).Truncate(time.Minute) // 3 months ago
|
|
tests = []testCase{
|
|
{
|
|
name: "batch with timerange",
|
|
args: &AggregatedTradeRequestParams{StartTime: start, EndTime: start.Add(20 * time.Minute)},
|
|
expFunc: func(t *testing.T, results []AggregatedTrade) {
|
|
t.Helper()
|
|
// 2000-50000 records range was valid in 2025; Adjust if Binance enters a phase of zero-fees or low-volume
|
|
require.Greater(t, len(results), 2000, "must return a quantity above a sane threshold of records")
|
|
assert.Less(t, len(results), 50000, "should return a quantity below a sane threshold of records")
|
|
assert.WithinDuration(t, results[len(results)-1].TimeStamp.Time(), start, 20*time.Minute, "last record should be within range of start time")
|
|
},
|
|
},
|
|
{
|
|
name: "custom limit with start time set, no end time",
|
|
args: &AggregatedTradeRequestParams{StartTime: start, Limit: 2042},
|
|
expFunc: func(t *testing.T, results []AggregatedTrade) {
|
|
t.Helper()
|
|
// 2000 records in was about 6 minutes in 2025; Adjust if Binance enters a phase of zero-fees or low-volume
|
|
require.Equal(t, 2042, len(results), "must return exactly the limit number of records")
|
|
assert.WithinDuration(t, results[len(results)-1].TimeStamp.Time(), start, 20*time.Minute, "last record should be within 20 minutes of start time")
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
tt.args.Symbol = currency.NewBTCUSDT()
|
|
results, err := e.GetAggregatedTrades(t.Context(), tt.args)
|
|
require.NoError(t, err)
|
|
tt.expFunc(t, results)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetAggregatedTradesErrors(t *testing.T) {
|
|
t.Parallel()
|
|
start := time.Date(2020, 1, 2, 15, 4, 5, 0, time.UTC)
|
|
tests := []struct {
|
|
name string
|
|
args *AggregatedTradeRequestParams
|
|
}{
|
|
{
|
|
name: "get recent trades does not support custom limit",
|
|
args: &AggregatedTradeRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Limit: 1001,
|
|
},
|
|
},
|
|
{
|
|
name: "start time and fromId cannot be both set",
|
|
args: &AggregatedTradeRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
StartTime: start,
|
|
EndTime: start.Add(75 * time.Minute),
|
|
FromID: 2,
|
|
},
|
|
},
|
|
{
|
|
name: "can't get most recent 5000 (more than 1000 not allowed)",
|
|
args: &AggregatedTradeRequestParams{
|
|
Symbol: currency.NewBTCUSDT(),
|
|
Limit: 5000,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetAggregatedTrades(t.Context(), tt.args)
|
|
if err == nil {
|
|
t.Errorf("Binance.GetAggregatedTrades() error = %v, wantErr true", err)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
}
|
|
|
|
orderSubmission := &order.Submit{
|
|
Exchange: e.Name,
|
|
Pair: currency.Pair{
|
|
Delimiter: "_",
|
|
Base: currency.LTC,
|
|
Quote: currency.BTC,
|
|
},
|
|
Side: order.Buy,
|
|
Type: order.Limit,
|
|
Price: 1,
|
|
Amount: 1000000000,
|
|
ClientID: "meowOrder",
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
_, err := e.SubmitOrder(t.Context(), orderSubmission)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("SubmitOrder() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("SubmitOrder() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock SubmitOrder() error", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelExchangeOrder(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
}
|
|
orderCancellation := &order.Cancel{
|
|
OrderID: "1",
|
|
AccountID: "1",
|
|
Pair: currency.NewPair(currency.LTC, currency.BTC),
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
err := e.CancelOrder(t.Context(), orderCancellation)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("CancelExchangeOrder() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("CancelExchangeOrder() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock CancelExchangeOrder() error", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelAllExchangeOrders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
}
|
|
orderCancellation := &order.Cancel{
|
|
OrderID: "1",
|
|
AccountID: "1",
|
|
Pair: currency.NewPair(currency.LTC, currency.BTC),
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
_, err := e.CancelAllOrders(t.Context(), orderCancellation)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("CancelAllExchangeOrders() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("CancelAllExchangeOrders() expecting an error when no keys are set")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock CancelAllExchangeOrders() error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
items := asset.Items{
|
|
asset.CoinMarginedFutures,
|
|
asset.USDTMarginedFutures,
|
|
asset.Spot,
|
|
asset.Margin,
|
|
}
|
|
for i := range items {
|
|
assetType := items[i]
|
|
t.Run(fmt.Sprintf("Update info of account [%s]", assetType.String()), func(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UpdateAccountInfo(t.Context(), assetType)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWrapperGetActiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
p, err := currency.NewPairFromString("EOS-USDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetActiveOrders(t.Context(), &order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Side: order.AnySide,
|
|
Pairs: currency.Pairs{p},
|
|
AssetType: asset.CoinMarginedFutures,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p2, err := currency.NewPairFromString("BTCUSDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetActiveOrders(t.Context(), &order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Side: order.AnySide,
|
|
Pairs: currency.Pairs{p2},
|
|
AssetType: asset.USDTMarginedFutures,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWrapperGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
p, err := currency.NewPairFromString("EOSUSD_PERP")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetOrderHistory(t.Context(), &order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Side: order.AnySide,
|
|
FromOrderID: "123",
|
|
Pairs: currency.Pairs{p},
|
|
AssetType: asset.CoinMarginedFutures,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p2, err := currency.NewPairFromString("BTCUSDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetOrderHistory(t.Context(), &order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
Side: order.AnySide,
|
|
FromOrderID: "123",
|
|
Pairs: currency.Pairs{p2},
|
|
AssetType: asset.USDTMarginedFutures,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = e.GetOrderHistory(t.Context(), &order.MultiOrderRequest{
|
|
AssetType: asset.USDTMarginedFutures,
|
|
})
|
|
if err == nil {
|
|
t.Errorf("expecting an error since invalid param combination is given. Got err: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
p, err := currency.NewPairFromString("EOS-USDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
fPair, err := e.FormatExchangeCurrency(p, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = e.CancelOrder(t.Context(), &order.Cancel{
|
|
AssetType: asset.CoinMarginedFutures,
|
|
Pair: fPair,
|
|
OrderID: "1234",
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p2, err := currency.NewPairFromString("BTC-USDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
fpair2, err := e.FormatExchangeCurrency(p2, asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = e.CancelOrder(t.Context(), &order.Cancel{
|
|
AssetType: asset.USDTMarginedFutures,
|
|
Pair: fpair2,
|
|
OrderID: "1234",
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
tradablePairs, err := e.FetchTradablePairs(t.Context(),
|
|
asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(tradablePairs) == 0 {
|
|
t.Fatal("no tradable pairs")
|
|
}
|
|
_, err = e.GetOrderInfo(t.Context(),
|
|
"123", tradablePairs[0], asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestModifyOrder(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.ModifyOrder(t.Context(),
|
|
&order.Modify{AssetType: asset.Spot})
|
|
if err == nil {
|
|
t.Error("ModifyOrder() error cannot be nil")
|
|
}
|
|
}
|
|
|
|
func TestGetAllCoinsInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
}
|
|
_, err := e.GetAllCoinsInfo(t.Context())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWithdraw(t *testing.T) {
|
|
t.Parallel()
|
|
if !mockTests {
|
|
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)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("Withdraw() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("Withdraw() expecting an error when no keys are set")
|
|
}
|
|
}
|
|
|
|
func TestDepositHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
}
|
|
_, err := e.DepositHistory(t.Context(), currency.ETH, "", time.Time{}, time.Time{}, 0, 10000)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error(err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("expecting an error when no keys are set")
|
|
}
|
|
}
|
|
|
|
func TestWithdrawHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !mockTests {
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
|
}
|
|
_, err := e.GetWithdrawalsHistory(t.Context(), currency.ETH, asset.Spot)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("GetWithdrawalsHistory() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("GetWithdrawalsHistory() expecting an error when no keys are set")
|
|
}
|
|
}
|
|
|
|
func TestWithdrawFiat(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.WithdrawFiatFunds(t.Context(),
|
|
&withdraw.Request{})
|
|
if err != common.ErrFunctionNotSupported {
|
|
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
|
}
|
|
}
|
|
|
|
func TestWithdrawInternationalBank(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(),
|
|
&withdraw.Request{})
|
|
if err != common.ErrFunctionNotSupported {
|
|
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
|
}
|
|
}
|
|
|
|
func TestGetDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetDepositAddress(t.Context(), currency.USDT, "", currency.BNB.String())
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error("GetDepositAddress() error", err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("GetDepositAddress() error cannot be nil")
|
|
case mockTests && err != nil:
|
|
t.Error("Mock GetDepositAddress() error", err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkWsHandleData(bb *testing.B) {
|
|
bb.ReportAllocs()
|
|
ap, err := e.CurrencyPairs.GetPairs(asset.Spot, false)
|
|
require.NoError(bb, err)
|
|
err = e.CurrencyPairs.StorePairs(asset.Spot, ap, true)
|
|
require.NoError(bb, err)
|
|
|
|
data, err := os.ReadFile("testdata/wsHandleData.json")
|
|
require.NoError(bb, err)
|
|
lines := bytes.Split(data, []byte("\n"))
|
|
require.Len(bb, lines, 8)
|
|
go func() {
|
|
for {
|
|
<-e.Websocket.DataHandler
|
|
}
|
|
}()
|
|
for bb.Loop() {
|
|
for x := range lines {
|
|
assert.NoError(bb, e.wsHandleData(lines[x]))
|
|
}
|
|
}
|
|
}
|
|
|
|
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")
|
|
channels, err := e.generateSubscriptions() // Note: We grab this before it's overwritten by MockWsInstance below
|
|
require.NoError(t, err, "generateSubscriptions must not error")
|
|
if mockTests {
|
|
exp := []string{"btcusdt@depth@100ms", "btcusdt@kline_1m", "btcusdt@ticker", "btcusdt@trade", "dogeusdt@depth@100ms", "dogeusdt@kline_1m", "dogeusdt@ticker", "dogeusdt@trade"}
|
|
mock := func(tb testing.TB, msg []byte, w *gws.Conn) error {
|
|
tb.Helper()
|
|
var req WsPayload
|
|
require.NoError(tb, json.Unmarshal(msg, &req), "Unmarshal must not error")
|
|
require.ElementsMatch(tb, req.Params, exp, "Params must have correct channels")
|
|
return w.WriteMessage(gws.TextMessage, fmt.Appendf(nil, `{"result":null,"id":"%s"}`, req.ID))
|
|
}
|
|
e = testexch.MockWsInstance[Exchange](t, mockws.CurryWsMockUpgrader(t, mock))
|
|
} else {
|
|
testexch.SetupWs(t, e)
|
|
}
|
|
err = e.Subscribe(channels)
|
|
require.NoError(t, err, "Subscribe must not error")
|
|
err = e.Unsubscribe(channels)
|
|
require.NoError(t, err, "Unsubscribe must not error")
|
|
}
|
|
|
|
func TestSubscribeBadResp(t *testing.T) {
|
|
t.Parallel()
|
|
channels := subscription.List{
|
|
{Channel: "moons@ticker"},
|
|
}
|
|
mock := func(tb testing.TB, msg []byte, w *gws.Conn) error {
|
|
tb.Helper()
|
|
var req WsPayload
|
|
err := json.Unmarshal(msg, &req)
|
|
require.NoError(tb, err, "Unmarshal must not error")
|
|
return w.WriteMessage(gws.TextMessage, fmt.Appendf(nil, `{"result":{"error":"carrots"},"id":"%s"}`, req.ID))
|
|
}
|
|
b := testexch.MockWsInstance[Exchange](t, mockws.CurryWsMockUpgrader(t, mock))
|
|
err := b.Subscribe(channels)
|
|
assert.ErrorIs(t, err, common.ErrUnknownError, "Subscribe should error correctly")
|
|
assert.ErrorContains(t, err, "carrots", "Subscribe should error containing the carrots")
|
|
}
|
|
|
|
func TestWsTickerUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
pressXToJSON := []byte(`{"stream":"btcusdt@ticker","data":{"e":"24hrTicker","E":1580254809477,"s":"ETHBTC","p":"420.97000000","P":"4.720","w":"9058.27981278","x":"8917.98000000","c":"9338.96000000","Q":"0.17246300","b":"9338.03000000","B":"0.18234600","a":"9339.70000000","A":"0.14097600","o":"8917.99000000","h":"9373.19000000","l":"8862.40000000","v":"72229.53692000","q":"654275356.16896672","O":1580168409456,"C":1580254809456,"F":235294268,"L":235894703,"n":600436}}`)
|
|
err := e.wsHandleData(pressXToJSON)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsKlineUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
pressXToJSON := []byte(`{"stream":"btcusdt@kline_1m","data":{
|
|
"e": "kline",
|
|
"E": 1234567891,
|
|
"s": "ETHBTC",
|
|
"k": {
|
|
"t": 1234000001,
|
|
"T": 1234600001,
|
|
"s": "BTCUSDT",
|
|
"i": "1m",
|
|
"f": 100,
|
|
"L": 200,
|
|
"o": "0.0010",
|
|
"c": "0.0020",
|
|
"h": "0.0025",
|
|
"l": "0.0015",
|
|
"v": "1000",
|
|
"n": 100,
|
|
"x": false,
|
|
"q": "1.0000",
|
|
"V": "500",
|
|
"Q": "0.500",
|
|
"B": "123456"
|
|
}
|
|
}}`)
|
|
err := e.wsHandleData(pressXToJSON)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsTradeUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
e.SetSaveTradeDataStatus(true)
|
|
pressXToJSON := []byte(`{"stream":"btcusdt@trade","data":{
|
|
"e": "trade",
|
|
"E": 1234567891,
|
|
"s": "ETHBTC",
|
|
"t": 12345,
|
|
"p": "0.001",
|
|
"q": "100",
|
|
"b": 88,
|
|
"a": 50,
|
|
"T": 1234567851,
|
|
"m": true,
|
|
"M": true
|
|
}}`)
|
|
err := e.wsHandleData(pressXToJSON)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsDepthUpdate(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.setupOrderbookManager(t.Context())
|
|
seedLastUpdateID := int64(161)
|
|
book := OrderBookResponse{
|
|
Asks: []orderbook.Level{
|
|
{Price: 6621.80000000, Amount: 0.00198100},
|
|
{Price: 6622.14000000, Amount: 4.00000000},
|
|
{Price: 6622.46000000, Amount: 2.30000000},
|
|
{Price: 6622.47000000, Amount: 1.18633300},
|
|
{Price: 6622.64000000, Amount: 4.00000000},
|
|
{Price: 6622.73000000, Amount: 0.02900000},
|
|
{Price: 6622.76000000, Amount: 0.12557700},
|
|
{Price: 6622.81000000, Amount: 2.08994200},
|
|
{Price: 6622.82000000, Amount: 0.01500000},
|
|
{Price: 6623.17000000, Amount: 0.16831300},
|
|
},
|
|
Bids: []orderbook.Level{
|
|
{Price: 6621.55000000, Amount: 0.16356700},
|
|
{Price: 6621.45000000, Amount: 0.16352600},
|
|
{Price: 6621.41000000, Amount: 0.86091200},
|
|
{Price: 6621.25000000, Amount: 0.16914100},
|
|
{Price: 6621.23000000, Amount: 0.09193600},
|
|
{Price: 6621.22000000, Amount: 0.00755100},
|
|
{Price: 6621.13000000, Amount: 0.08432000},
|
|
{Price: 6621.03000000, Amount: 0.00172000},
|
|
{Price: 6620.94000000, Amount: 0.30506700},
|
|
{Price: 6620.93000000, Amount: 0.00200000},
|
|
},
|
|
LastUpdateID: seedLastUpdateID,
|
|
}
|
|
|
|
update1 := []byte(`{"stream":"btcusdt@depth","data":{
|
|
"e": "depthUpdate",
|
|
"E": 1234567881,
|
|
"s": "BTCUSDT",
|
|
"U": 157,
|
|
"u": 160,
|
|
"b": [
|
|
["6621.45", "0.3"]
|
|
],
|
|
"a": [
|
|
["6622.46", "1.5"]
|
|
]
|
|
}}`)
|
|
|
|
p := currency.NewPairWithDelimiter("BTC", "USDT", "-")
|
|
if err := e.SeedLocalCacheWithBook(p, &book); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := e.wsHandleData(update1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
e.obm.state[currency.BTC][currency.USDT][asset.Spot].fetchingBook = false
|
|
|
|
ob, err := e.Websocket.Orderbook.GetOrderbook(p, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if exp, got := seedLastUpdateID, ob.LastUpdateID; got != exp {
|
|
t.Fatalf("Unexpected Last update id of orderbook for old update. Exp: %d, got: %d", exp, got)
|
|
}
|
|
if exp, got := 2.3, ob.Asks[2].Amount; got != exp {
|
|
t.Fatalf("Ask altered by outdated update. Exp: %f, got %f", exp, got)
|
|
}
|
|
if exp, got := 0.163526, ob.Bids[1].Amount; got != exp {
|
|
t.Fatalf("Bid altered by outdated update. Exp: %f, got %f", exp, got)
|
|
}
|
|
|
|
update2 := []byte(`{"stream":"btcusdt@depth","data":{
|
|
"e": "depthUpdate",
|
|
"E": 1234567892,
|
|
"s": "BTCUSDT",
|
|
"U": 161,
|
|
"u": 165,
|
|
"b": [
|
|
["6621.45", "0.163526"]
|
|
],
|
|
"a": [
|
|
["6622.46", "2.3"],
|
|
["6622.47", "1.9"]
|
|
]
|
|
}}`)
|
|
|
|
if err = e.wsHandleData(update2); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ob, err = e.Websocket.Orderbook.GetOrderbook(p, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if exp, got := int64(165), ob.LastUpdateID; got != exp {
|
|
t.Fatalf("Unexpected Last update id of orderbook for new update. Exp: %d, got: %d", exp, got)
|
|
}
|
|
if exp, got := 2.3, ob.Asks[2].Amount; got != exp {
|
|
t.Fatalf("Unexpected Ask amount. Exp: %f, got %f", exp, got)
|
|
}
|
|
if exp, got := 1.9, ob.Asks[3].Amount; got != exp {
|
|
t.Fatalf("Unexpected Ask amount. Exp: %f, got %f", exp, got)
|
|
}
|
|
if exp, got := 0.163526, ob.Bids[1].Amount; got != exp {
|
|
t.Fatalf("Unexpected Bid amount. Exp: %f, got %f", exp, got)
|
|
}
|
|
|
|
// reset order book sync status
|
|
e.obm.state[currency.BTC][currency.USDT][asset.Spot].lastUpdateID = 0
|
|
}
|
|
|
|
func TestWsBalanceUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
pressXToJSON := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{
|
|
"e": "balanceUpdate",
|
|
"E": 1573200697110,
|
|
"a": "BTC",
|
|
"d": "100.00000000",
|
|
"T": 1573200697068}}`)
|
|
err := e.wsHandleData(pressXToJSON)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsOCO(t *testing.T) {
|
|
t.Parallel()
|
|
pressXToJSON := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{
|
|
"e": "listStatus",
|
|
"E": 1564035303637,
|
|
"s": "ETHBTC",
|
|
"g": 2,
|
|
"c": "OCO",
|
|
"l": "EXEC_STARTED",
|
|
"L": "EXECUTING",
|
|
"r": "NONE",
|
|
"C": "F4QN4G8DlFATFlIUQ0cjdD",
|
|
"T": 1564035303625,
|
|
"O": [
|
|
{
|
|
"s": "ETHBTC",
|
|
"i": 17,
|
|
"c": "AJYsMjErWJesZvqlJCTUgL"
|
|
},
|
|
{
|
|
"s": "ETHBTC",
|
|
"i": 18,
|
|
"c": "bfYPSQdLoqAJeNrOr9adzq"
|
|
}
|
|
]
|
|
}}`)
|
|
err := e.wsHandleData(pressXToJSON)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetWsAuthStreamKey(t *testing.T) {
|
|
authKey, err := e.GetWsAuthStreamKey(t.Context())
|
|
switch {
|
|
case mockTests && err != nil,
|
|
!mockTests && sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Fatal(err)
|
|
case !mockTests && !sharedtestvalues.AreAPICredentialsSet(e) && err == nil:
|
|
t.Fatal("Expected error")
|
|
}
|
|
|
|
if authKey == "" && (sharedtestvalues.AreAPICredentialsSet(e) || mockTests) {
|
|
t.Error("Expected key")
|
|
}
|
|
}
|
|
|
|
func TestMaintainWsAuthStreamKey(t *testing.T) {
|
|
err := e.MaintainWsAuthStreamKey(t.Context())
|
|
switch {
|
|
case mockTests && err != nil,
|
|
!mockTests && sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Fatal(err)
|
|
case !mockTests && !sharedtestvalues.AreAPICredentialsSet(e) && err == nil:
|
|
t.Fatal("Expected error")
|
|
}
|
|
}
|
|
|
|
func TestExecutionTypeToOrderStatus(t *testing.T) {
|
|
type TestCases struct {
|
|
Case string
|
|
Result order.Status
|
|
}
|
|
testCases := []TestCases{
|
|
{Case: "NEW", Result: order.New},
|
|
{Case: "PARTIALLY_FILLED", Result: order.PartiallyFilled},
|
|
{Case: "FILLED", Result: order.Filled},
|
|
{Case: "CANCELED", Result: order.Cancelled},
|
|
{Case: "PENDING_CANCEL", Result: order.PendingCancel},
|
|
{Case: "REJECTED", Result: order.Rejected},
|
|
{Case: "EXPIRED", Result: order.Expired},
|
|
{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 TestGetHistoricCandles(t *testing.T) {
|
|
t.Parallel()
|
|
startTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
end := startTime.Add(time.Hour * 24 * 7)
|
|
bAssets := e.GetAssetTypes(false)
|
|
for i := range bAssets {
|
|
cps, err := e.GetAvailablePairs(bAssets[i])
|
|
require.NoErrorf(t, err, "GetAvailablePairs for asset %s must not error", bAssets[i])
|
|
require.NotEmptyf(t, cps, "GetAvailablePairs for asset %s must return at least one pair", bAssets[i])
|
|
err = e.CurrencyPairs.EnablePair(bAssets[i], cps[0])
|
|
require.Truef(t, err == nil || errors.Is(err, currency.ErrPairAlreadyEnabled),
|
|
"EnablePair for asset %s and pair %s must not error: %s", bAssets[i], cps[0], err)
|
|
_, err = e.GetHistoricCandles(t.Context(), cps[0], bAssets[i], kline.OneDay, startTime, end)
|
|
assert.NoErrorf(t, err, "GetHistoricCandles should not error for asset %s and pair %s", bAssets[i], cps[0])
|
|
}
|
|
|
|
startTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
enabledPairs, err := e.GetEnabledPairs(asset.Spot)
|
|
require.NoError(t, err, "GetEnabledPairs must not error")
|
|
|
|
_, err = e.GetHistoricCandles(t.Context(), enabledPairs[0], asset.Spot, kline.Interval(time.Hour*7), startTime, end)
|
|
require.ErrorIs(t, err, kline.ErrRequestExceedsExchangeLimits)
|
|
}
|
|
|
|
func TestGetHistoricCandlesExtended(t *testing.T) {
|
|
t.Parallel()
|
|
startTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
end := startTime.Add(time.Hour * 24 * 7)
|
|
bAssets := e.GetAssetTypes(false)
|
|
for i := range bAssets {
|
|
cps, err := e.GetAvailablePairs(bAssets[i])
|
|
require.NoErrorf(t, err, "GetAvailablePairs for asset %s must not error", bAssets[i])
|
|
require.NotEmptyf(t, cps, "GetAvailablePairs for asset %s must return at least one pair", bAssets[i])
|
|
err = e.CurrencyPairs.EnablePair(bAssets[i], cps[0])
|
|
require.Truef(t, err == nil || errors.Is(err, currency.ErrPairAlreadyEnabled),
|
|
"EnablePair for asset %s and pair %s must not error: %s", bAssets[i], cps[0], err)
|
|
_, err = e.GetHistoricCandlesExtended(t.Context(), cps[0], bAssets[i], kline.OneDay, startTime, end)
|
|
assert.NoErrorf(t, err, "GetHistoricCandlesExtended should not error for asset %s and pair %s", bAssets[i], cps[0])
|
|
}
|
|
}
|
|
|
|
func TestFormatExchangeKlineInterval(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tc := range []struct {
|
|
interval kline.Interval
|
|
output string
|
|
}{
|
|
{
|
|
kline.OneMin,
|
|
"1m",
|
|
},
|
|
{
|
|
kline.OneDay,
|
|
"1d",
|
|
},
|
|
{
|
|
kline.OneWeek,
|
|
"1w",
|
|
},
|
|
{
|
|
kline.OneMonth,
|
|
"1M",
|
|
},
|
|
} {
|
|
t.Run(tc.interval.String(), func(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Equal(t, tc.output, e.FormatExchangeKlineInterval(tc.interval))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetRecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
pair := currency.NewBTCUSDT()
|
|
_, err := e.GetRecentTrades(t.Context(),
|
|
pair, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetRecentTrades(t.Context(),
|
|
pair, asset.USDTMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pair.Base = currency.NewCode("BTCUSD")
|
|
pair.Quote = currency.PERP
|
|
_, err = e.GetRecentTrades(t.Context(),
|
|
pair, asset.CoinMarginedFutures)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAvailableTransferChains(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetAvailableTransferChains(t.Context(), currency.BTC)
|
|
switch {
|
|
case sharedtestvalues.AreAPICredentialsSet(e) && err != nil:
|
|
t.Error(err)
|
|
case !sharedtestvalues.AreAPICredentialsSet(e) && err == nil && !mockTests:
|
|
t.Error("error cannot be nil")
|
|
case mockTests && err != nil:
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSeedLocalCache(t *testing.T) {
|
|
t.Parallel()
|
|
err := e.SeedLocalCache(t.Context(), currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGenerateSubscriptions(t *testing.T) {
|
|
t.Parallel()
|
|
exp := subscription.List{}
|
|
pairs, err := e.GetEnabledPairs(asset.Spot)
|
|
assert.NoError(t, err, "GetEnabledPairs should not error")
|
|
wsFmt := currency.PairFormat{Uppercase: false, Delimiter: ""}
|
|
baseExp := subscription.List{
|
|
{Channel: subscription.CandlesChannel, QualifiedChannel: "kline_1m", Asset: asset.Spot, Interval: kline.OneMin},
|
|
{Channel: subscription.OrderbookChannel, QualifiedChannel: "depth@100ms", Asset: asset.Spot, Interval: kline.HundredMilliseconds},
|
|
{Channel: subscription.TickerChannel, QualifiedChannel: "ticker", Asset: asset.Spot},
|
|
{Channel: subscription.AllTradesChannel, QualifiedChannel: "trade", Asset: asset.Spot},
|
|
}
|
|
for _, p := range pairs {
|
|
for _, baseSub := range baseExp {
|
|
sub := baseSub.Clone()
|
|
sub.Pairs = currency.Pairs{p}
|
|
sub.QualifiedChannel = wsFmt.Format(p) + "@" + sub.QualifiedChannel
|
|
exp = append(exp, sub)
|
|
}
|
|
}
|
|
subs, err := e.generateSubscriptions()
|
|
require.NoError(t, err, "generateSubscriptions must not error")
|
|
testsubs.EqualLists(t, exp, subs)
|
|
}
|
|
|
|
// TestFormatChannelInterval exercises formatChannelInterval
|
|
func TestFormatChannelInterval(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Equal(t, "@1000ms", formatChannelInterval(&subscription.Subscription{Channel: subscription.OrderbookChannel, Interval: kline.ThousandMilliseconds}), "1s should format correctly for Orderbook")
|
|
assert.Equal(t, "@1m", formatChannelInterval(&subscription.Subscription{Channel: subscription.OrderbookChannel, Interval: kline.OneMin}), "Orderbook should format correctly")
|
|
assert.Equal(t, "_15m", formatChannelInterval(&subscription.Subscription{Channel: subscription.CandlesChannel, Interval: kline.FifteenMin}), "Candles should format correctly")
|
|
}
|
|
|
|
// TestFormatChannelLevels exercises formatChannelLevels
|
|
func TestFormatChannelLevels(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Equal(t, "10", formatChannelLevels(&subscription.Subscription{Channel: subscription.OrderbookChannel, Levels: 10}), "Levels should format correctly")
|
|
assert.Empty(t, formatChannelLevels(&subscription.Subscription{Channel: subscription.OrderbookChannel, Levels: 0}), "Levels should format correctly")
|
|
}
|
|
|
|
var websocketDepthUpdate = []byte(`{"E":1608001030784,"U":7145637266,"a":[["19455.19000000","0.59490200"],["19455.37000000","0.00000000"],["19456.11000000","0.00000000"],["19456.16000000","0.00000000"],["19458.67000000","0.06400000"],["19460.73000000","0.05139800"],["19461.43000000","0.00000000"],["19464.59000000","0.00000000"],["19466.03000000","0.45000000"],["19466.36000000","0.00000000"],["19508.67000000","0.00000000"],["19572.96000000","0.00217200"],["24386.00000000","0.00256600"]],"b":[["19455.18000000","2.94649200"],["19453.15000000","0.01233600"],["19451.18000000","0.00000000"],["19446.85000000","0.11427900"],["19446.74000000","0.00000000"],["19446.73000000","0.00000000"],["19444.45000000","0.14937800"],["19426.75000000","0.00000000"],["19416.36000000","0.36052100"]],"e":"depthUpdate","s":"BTCUSDT","u":7145637297}`)
|
|
|
|
func TestProcessOrderbookUpdate(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.setupOrderbookManager(t.Context())
|
|
p := currency.NewBTCUSDT()
|
|
var depth WebsocketDepthStream
|
|
err := json.Unmarshal(websocketDepthUpdate, &depth)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = e.obm.stageWsUpdate(&depth, p, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = e.obm.fetchBookViaREST(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = e.obm.cleanup(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// reset order book sync status
|
|
e.obm.state[currency.BTC][currency.USDT][asset.Spot].lastUpdateID = 0
|
|
}
|
|
|
|
func TestUFuturesHistoricalTrades(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
cp, err := currency.NewPairFromString("BTCUSDT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UFuturesHistoricalTrades(t.Context(), cp, "", 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.UFuturesHistoricalTrades(t.Context(), cp, "", 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsOrderExecutionReport(t *testing.T) {
|
|
t.Parallel()
|
|
e := new(Exchange) //nolint:govet // Intentional shadow
|
|
require.NoError(t, testexch.Setup(e), "Test instance Setup must not error")
|
|
payload := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"executionReport","E":1616627567900,"s":"BTCUSDT","c":"c4wyKsIhoAaittTYlIVLqk","S":"BUY","o":"LIMIT","f":"GTC","q":"0.00028400","p":"52789.10000000","P":"0.00000000","F":"0.00000000","g":-1,"C":"","x":"NEW","X":"NEW","r":"NONE","i":5340845958,"l":"0.00000000","z":"0.00000000","L":"0.00000000","n":"0","N":"BTC","T":1616627567900,"t":-1,"I":11388173160,"w":true,"m":false,"M":false,"O":1616627567900,"Z":"0.00000000","Y":"0.00000000","Q":"0.00000000","W":1616627567900}}`)
|
|
// this is a buy BTC order, normally commission is charged in BTC, vice versa.
|
|
expectedResult := order.Detail{
|
|
Price: 52789.1,
|
|
Amount: 0.00028400,
|
|
AverageExecutedPrice: 0,
|
|
QuoteAmount: 0,
|
|
ExecutedAmount: 0,
|
|
RemainingAmount: 0.00028400,
|
|
Cost: 0,
|
|
CostAsset: currency.USDT,
|
|
Fee: 0,
|
|
FeeAsset: currency.BTC,
|
|
Exchange: "Binance",
|
|
OrderID: "5340845958",
|
|
ClientOrderID: "c4wyKsIhoAaittTYlIVLqk",
|
|
Type: order.Limit,
|
|
Side: order.Buy,
|
|
Status: order.New,
|
|
AssetType: asset.Spot,
|
|
Date: time.UnixMilli(1616627567900),
|
|
LastUpdated: time.UnixMilli(1616627567900),
|
|
Pair: currency.NewBTCUSDT(),
|
|
}
|
|
// empty the channel. otherwise mock_test will fail
|
|
for len(e.Websocket.DataHandler) > 0 {
|
|
<-e.Websocket.DataHandler
|
|
}
|
|
|
|
err := e.wsHandleData(payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
res := <-e.Websocket.DataHandler
|
|
switch r := res.(type) {
|
|
case *order.Detail:
|
|
if !reflect.DeepEqual(expectedResult, *r) {
|
|
t.Errorf("Results do not match:\nexpected: %v\nreceived: %v", expectedResult, *r)
|
|
}
|
|
default:
|
|
t.Fatalf("expected type order.Detail, found %T", res)
|
|
}
|
|
|
|
payload = []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"executionReport","E":1616633041556,"s":"BTCUSDT","c":"YeULctvPAnHj5HXCQo9Mob","S":"BUY","o":"LIMIT","f":"GTC","q":"0.00028600","p":"52436.85000000","P":"0.00000000","F":"0.00000000","g":-1,"C":"","x":"TRADE","X":"FILLED","r":"NONE","i":5341783271,"l":"0.00028600","z":"0.00028600","L":"52436.85000000","n":"0.00000029","N":"BTC","T":1616633041555,"t":726946523,"I":11390206312,"w":false,"m":false,"M":true,"O":1616633041555,"Z":"14.99693910","Y":"14.99693910","Q":"0.00000000","W":1616633041555}}`)
|
|
err = e.wsHandleData(payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestWsOutboundAccountPosition(t *testing.T) {
|
|
t.Parallel()
|
|
payload := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"outboundAccountPosition","E":1616628815745,"u":1616628815745,"B":[{"a":"BTC","f":"0.00225109","l":"0.00123000"},{"a":"BNB","f":"0.00000000","l":"0.00000000"},{"a":"USDT","f":"54.43390661","l":"0.00000000"}]}}`)
|
|
if err := e.wsHandleData(payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestFormatExchangeCurrency(t *testing.T) {
|
|
t.Parallel()
|
|
type testos struct {
|
|
name string
|
|
pair currency.Pair
|
|
asset asset.Item
|
|
expectedDelimiter string
|
|
}
|
|
testerinos := []testos{
|
|
{
|
|
name: "spot-btcusdt",
|
|
pair: currency.NewPairWithDelimiter("BTC", "USDT", currency.UnderscoreDelimiter),
|
|
asset: asset.Spot,
|
|
expectedDelimiter: "",
|
|
},
|
|
{
|
|
name: "coinmarginedfutures-btcusd_perp",
|
|
pair: currency.NewPairWithDelimiter("BTCUSD", "PERP", currency.DashDelimiter),
|
|
asset: asset.CoinMarginedFutures,
|
|
expectedDelimiter: currency.UnderscoreDelimiter,
|
|
},
|
|
{
|
|
name: "coinmarginedfutures-btcusd_211231",
|
|
pair: currency.NewPairWithDelimiter("BTCUSD", "211231", currency.DashDelimiter),
|
|
asset: asset.CoinMarginedFutures,
|
|
expectedDelimiter: currency.UnderscoreDelimiter,
|
|
},
|
|
{
|
|
name: "margin-ltousdt",
|
|
pair: currency.NewPairWithDelimiter("LTO", "USDT", currency.UnderscoreDelimiter),
|
|
asset: asset.Margin,
|
|
expectedDelimiter: "",
|
|
},
|
|
{
|
|
name: "usdtmarginedfutures-btcusdt",
|
|
pair: currency.NewPairWithDelimiter("btc", "usdt", currency.DashDelimiter),
|
|
asset: asset.USDTMarginedFutures,
|
|
expectedDelimiter: "",
|
|
},
|
|
{
|
|
name: "usdtmarginedfutures-btcusdt_211231",
|
|
pair: currency.NewPairWithDelimiter("btcusdt", "211231", currency.UnderscoreDelimiter),
|
|
asset: asset.USDTMarginedFutures,
|
|
expectedDelimiter: currency.UnderscoreDelimiter,
|
|
},
|
|
}
|
|
for i := range testerinos {
|
|
tt := testerinos[i]
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
result, err := e.FormatExchangeCurrency(tt.pair, tt.asset)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if result.Delimiter != tt.expectedDelimiter {
|
|
t.Errorf("received '%v' expected '%v'", result.Delimiter, tt.expectedDelimiter)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFormatSymbol(t *testing.T) {
|
|
t.Parallel()
|
|
type testos struct {
|
|
name string
|
|
pair currency.Pair
|
|
asset asset.Item
|
|
expectedString string
|
|
}
|
|
testerinos := []testos{
|
|
{
|
|
name: "spot-BTCUSDT",
|
|
pair: currency.NewPairWithDelimiter("BTC", "USDT", currency.UnderscoreDelimiter),
|
|
asset: asset.Spot,
|
|
expectedString: "BTCUSDT",
|
|
},
|
|
{
|
|
name: "coinmarginedfutures-btcusdperp",
|
|
pair: currency.NewPairWithDelimiter("BTCUSD", "PERP", currency.DashDelimiter),
|
|
asset: asset.CoinMarginedFutures,
|
|
expectedString: "BTCUSD_PERP",
|
|
},
|
|
{
|
|
name: "coinmarginedfutures-BTCUSD_211231",
|
|
pair: currency.NewPairWithDelimiter("BTCUSD", "211231", currency.DashDelimiter),
|
|
asset: asset.CoinMarginedFutures,
|
|
expectedString: "BTCUSD_211231",
|
|
},
|
|
{
|
|
name: "margin-LTOUSDT",
|
|
pair: currency.NewPairWithDelimiter("LTO", "USDT", currency.UnderscoreDelimiter),
|
|
asset: asset.Margin,
|
|
expectedString: "LTOUSDT",
|
|
},
|
|
{
|
|
name: "usdtmarginedfutures-BTCUSDT",
|
|
pair: currency.NewPairWithDelimiter("btc", "usdt", currency.DashDelimiter),
|
|
asset: asset.USDTMarginedFutures,
|
|
expectedString: "BTCUSDT",
|
|
},
|
|
{
|
|
name: "usdtmarginedfutures-BTCUSDT_211231",
|
|
pair: currency.NewPairWithDelimiter("btcusdt", "211231", currency.UnderscoreDelimiter),
|
|
asset: asset.USDTMarginedFutures,
|
|
expectedString: "BTCUSDT_211231",
|
|
},
|
|
}
|
|
for _, tt := range testerinos {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
result, err := e.FormatSymbol(tt.pair, tt.asset)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if result != tt.expectedString {
|
|
t.Errorf("received '%v' expected '%v'", result, tt.expectedString)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFormatUSDTMarginedFuturesPair(t *testing.T) {
|
|
t.Parallel()
|
|
pairFormat := currency.PairFormat{Uppercase: true}
|
|
resp := e.formatUSDTMarginedFuturesPair(currency.NewPair(currency.DOGE, currency.USDT), pairFormat)
|
|
if resp.String() != "DOGEUSDT" {
|
|
t.Errorf("received '%v' expected '%v'", resp.String(), "DOGEUSDT")
|
|
}
|
|
|
|
resp = e.formatUSDTMarginedFuturesPair(currency.NewPair(currency.DOGE, currency.NewCode("1234567890")), pairFormat)
|
|
if resp.String() != "DOGE_1234567890" {
|
|
t.Errorf("received '%v' expected '%v'", resp.String(), "DOGE_1234567890")
|
|
}
|
|
}
|
|
|
|
func TestFetchExchangeLimits(t *testing.T) {
|
|
t.Parallel()
|
|
l, err := e.FetchExchangeLimits(t.Context(), asset.Spot)
|
|
assert.NoError(t, err, "FetchExchangeLimits should not error")
|
|
assert.NotEmpty(t, l, "Should get some limits back")
|
|
|
|
l, err = e.FetchExchangeLimits(t.Context(), asset.Margin)
|
|
assert.NoError(t, err, "FetchExchangeLimits should not error")
|
|
assert.NotEmpty(t, l, "Should get some limits back")
|
|
|
|
_, err = e.FetchExchangeLimits(t.Context(), asset.Futures)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported, "FetchExchangeLimits should error on other asset types")
|
|
}
|
|
|
|
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
|
t.Parallel()
|
|
testexch.UpdatePairsOnce(t, e)
|
|
for _, a := range e.GetAssetTypes(false) {
|
|
t.Run(a.String(), func(t *testing.T) {
|
|
t.Parallel()
|
|
require.NoError(t, e.UpdateOrderExecutionLimits(t.Context(), a), "UpdateOrderExecutionLimits must not error")
|
|
pairs, err := e.CurrencyPairs.GetPairs(a, false)
|
|
require.NoError(t, err, "GetPairs must not error")
|
|
l, err := e.GetOrderExecutionLimits(a, pairs[0])
|
|
require.NoError(t, err, "GetOrderExecutionLimits must not error")
|
|
assert.Positive(t, l.MinPrice, "MinPrice should be positive")
|
|
assert.Positive(t, l.MaxPrice, "MaxPrice should be positive")
|
|
assert.Positive(t, l.PriceStepIncrementSize, "PriceStepIncrementSize should be positive")
|
|
assert.Positive(t, l.MinimumBaseAmount, "MinimumBaseAmount should be positive")
|
|
assert.Positive(t, l.MaximumBaseAmount, "MaximumBaseAmount should be positive")
|
|
assert.Positive(t, l.AmountStepIncrementSize, "AmountStepIncrementSize should be positive")
|
|
assert.Positive(t, l.MarketMaxQty, "MarketMaxQty should be positive")
|
|
assert.Positive(t, l.MaxTotalOrders, "MaxTotalOrders should be positive")
|
|
switch a {
|
|
case asset.Spot, asset.Margin:
|
|
assert.Positive(t, l.MaxIcebergParts, "MaxIcebergParts should be positive")
|
|
case asset.USDTMarginedFutures:
|
|
assert.Positive(t, l.MinNotional, "MinNotional should be positive")
|
|
fallthrough
|
|
case asset.CoinMarginedFutures:
|
|
assert.Positive(t, l.MultiplierUp, "MultiplierUp should be positive")
|
|
assert.Positive(t, l.MultiplierDown, "MultiplierDown should be positive")
|
|
assert.Positive(t, l.MarketMinQty, "MarketMinQty should be positive")
|
|
assert.Positive(t, l.MarketStepIncrementSize, "MarketStepIncrementSize should be positive")
|
|
assert.Positive(t, l.MaxAlgoOrders, "MaxAlgoOrders should be positive")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricalFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
start, end := getTime()
|
|
_, err := e.GetHistoricalFundingRates(t.Context(), &fundingrate.HistoricalRatesRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: currency.NewBTCUSDT(),
|
|
StartDate: start,
|
|
EndDate: end,
|
|
IncludePayments: true,
|
|
IncludePredictedRate: true,
|
|
})
|
|
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
|
|
_, err = e.GetHistoricalFundingRates(t.Context(), &fundingrate.HistoricalRatesRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: currency.NewBTCUSDT(),
|
|
StartDate: start,
|
|
EndDate: end,
|
|
PaymentCurrency: currency.DOGE,
|
|
})
|
|
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
|
|
r := &fundingrate.HistoricalRatesRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: currency.NewBTCUSDT(),
|
|
StartDate: start,
|
|
EndDate: end,
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(e) {
|
|
r.IncludePayments = true
|
|
}
|
|
_, err = e.GetHistoricalFundingRates(t.Context(), r)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
r.Asset = asset.CoinMarginedFutures
|
|
r.Pair, err = currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = e.GetHistoricalFundingRates(t.Context(), r)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetLatestFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
cp := currency.NewBTCUSDT()
|
|
_, err := e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: cp,
|
|
IncludePredictedRate: true,
|
|
})
|
|
assert.ErrorIs(t, err, common.ErrFunctionNotSupported)
|
|
|
|
err = e.CurrencyPairs.EnablePair(asset.USDTMarginedFutures, cp)
|
|
require.Truef(t, err == nil || errors.Is(err, currency.ErrPairAlreadyEnabled),
|
|
"EnablePair for asset %s and pair %s must not error: %s", asset.USDTMarginedFutures, cp, err)
|
|
|
|
_, err = e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: cp,
|
|
})
|
|
assert.NoError(t, err, "GetLatestFundingRates should not error for USDTMarginedFutures")
|
|
_, err = e.GetLatestFundingRates(t.Context(), &fundingrate.LatestRateRequest{
|
|
Asset: asset.CoinMarginedFutures,
|
|
})
|
|
assert.NoError(t, err, "GetLatestFundingRates should not error for CoinMarginedFutures")
|
|
}
|
|
|
|
func TestIsPerpetualFutureCurrency(t *testing.T) {
|
|
t.Parallel()
|
|
is, err := e.IsPerpetualFutureCurrency(asset.Binary, currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if is {
|
|
t.Error("expected false")
|
|
}
|
|
|
|
is, err = e.IsPerpetualFutureCurrency(asset.CoinMarginedFutures, currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if is {
|
|
t.Error("expected false")
|
|
}
|
|
is, err = e.IsPerpetualFutureCurrency(asset.CoinMarginedFutures, currency.NewPair(currency.BTC, currency.PERP))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if !is {
|
|
t.Error("expected true")
|
|
}
|
|
|
|
is, err = e.IsPerpetualFutureCurrency(asset.USDTMarginedFutures, currency.NewBTCUSDT())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if !is {
|
|
t.Error("expected true")
|
|
}
|
|
is, err = e.IsPerpetualFutureCurrency(asset.USDTMarginedFutures, currency.NewPair(currency.BTC, currency.PERP))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if is {
|
|
t.Error("expected false")
|
|
}
|
|
}
|
|
|
|
func TestGetUserMarginInterestHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetUserMarginInterestHistory(t.Context(), currency.USDT, currency.NewBTCUSDT(), time.Now().Add(-time.Hour*24), time.Now(), 1, 10, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSetAssetsMode(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
is, err := e.GetAssetsMode(t.Context())
|
|
assert.NoError(t, err)
|
|
|
|
err = e.SetAssetsMode(t.Context(), !is)
|
|
assert.NoError(t, err)
|
|
|
|
err = e.SetAssetsMode(t.Context(), is)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestGetAssetsMode(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetAssetsMode(t.Context())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestGetCollateralMode(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.GetCollateralMode(t.Context(), asset.Spot)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
_, err = e.GetCollateralMode(t.Context(), asset.CoinMarginedFutures)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
_, err = e.GetCollateralMode(t.Context(), asset.USDTMarginedFutures)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestSetCollateralMode(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
err := e.SetCollateralMode(t.Context(), asset.Spot, collateral.SingleMode)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
err = e.SetCollateralMode(t.Context(), asset.CoinMarginedFutures, collateral.SingleMode)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
err = e.SetCollateralMode(t.Context(), asset.USDTMarginedFutures, collateral.MultiMode)
|
|
assert.NoError(t, err)
|
|
|
|
err = e.SetCollateralMode(t.Context(), asset.USDTMarginedFutures, collateral.PortfolioMode)
|
|
assert.ErrorIs(t, err, order.ErrCollateralInvalid)
|
|
}
|
|
|
|
func TestChangePositionMargin(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
_, err := e.ChangePositionMargin(t.Context(), &margin.PositionChangeRequest{
|
|
Pair: currency.NewBTCUSDT(),
|
|
Asset: asset.USDTMarginedFutures,
|
|
MarginType: margin.Isolated,
|
|
OriginalAllocatedMargin: 1337,
|
|
NewAllocatedMargin: 1333337,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPositionSummary(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
|
|
bb := currency.NewBTCUSDT()
|
|
_, err := e.GetFuturesPositionSummary(t.Context(), &futures.PositionSummaryRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: bb,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
bb.Quote = currency.BUSD
|
|
_, err = e.GetFuturesPositionSummary(t.Context(), &futures.PositionSummaryRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pair: bb,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err := currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bb.Quote = currency.USD
|
|
_, err = e.GetFuturesPositionSummary(t.Context(), &futures.PositionSummaryRequest{
|
|
Asset: asset.CoinMarginedFutures,
|
|
Pair: p,
|
|
UnderlyingPair: bb,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = e.GetFuturesPositionSummary(t.Context(), &futures.PositionSummaryRequest{
|
|
Asset: asset.Spot,
|
|
Pair: p,
|
|
UnderlyingPair: bb,
|
|
})
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
}
|
|
|
|
func TestGetFuturesPositionOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetFuturesPositionOrders(t.Context(), &futures.PositionsRequest{
|
|
Asset: asset.USDTMarginedFutures,
|
|
Pairs: []currency.Pair{currency.NewBTCUSDT()},
|
|
StartDate: time.Now().Add(-time.Hour * 24 * 70),
|
|
RespectOrderHistoryLimits: true,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err := currency.NewPairFromString("ADAUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = e.GetFuturesPositionOrders(t.Context(), &futures.PositionsRequest{
|
|
Asset: asset.CoinMarginedFutures,
|
|
Pairs: []currency.Pair{p},
|
|
StartDate: time.Now().Add(time.Hour * 24 * -70),
|
|
RespectOrderHistoryLimits: true,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSetMarginType(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
|
|
err := e.SetMarginType(t.Context(), asset.USDTMarginedFutures, currency.NewBTCUSDT(), margin.Isolated)
|
|
assert.NoError(t, err)
|
|
|
|
p, err := currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = e.SetMarginType(t.Context(), asset.CoinMarginedFutures, p, margin.Isolated)
|
|
assert.NoError(t, err)
|
|
|
|
err = e.SetMarginType(t.Context(), asset.Spot, currency.NewBTCUSDT(), margin.Isolated)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
}
|
|
|
|
func TestGetLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
_, err := e.GetLeverage(t.Context(), asset.USDTMarginedFutures, currency.NewBTCUSDT(), 0, order.UnknownSide)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err := currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = e.GetLeverage(t.Context(), asset.CoinMarginedFutures, p, 0, order.UnknownSide)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = e.GetLeverage(t.Context(), asset.Spot, currency.NewBTCUSDT(), 0, order.UnknownSide)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
}
|
|
|
|
func TestSetLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
err := e.SetLeverage(t.Context(), asset.USDTMarginedFutures, currency.NewBTCUSDT(), margin.Multi, 5, order.UnknownSide)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err := currency.NewPairFromString("BTCUSD_PERP")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = e.SetLeverage(t.Context(), asset.CoinMarginedFutures, p, margin.Multi, 5, order.UnknownSide)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = e.SetLeverage(t.Context(), asset.Spot, p, margin.Multi, 5, order.UnknownSide)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
}
|
|
|
|
func TestGetCryptoLoansIncomeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanIncomeHistory(t.Context(), currency.USDT, "", time.Time{}, time.Time{}, 100); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanBorrow(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.CryptoLoanBorrow(t.Context(), currency.EMPTYCODE, 1000, currency.BTC, 1, 7)
|
|
assert.ErrorIs(t, err, errLoanCoinMustBeSet)
|
|
_, err = e.CryptoLoanBorrow(t.Context(), currency.USDT, 1000, currency.EMPTYCODE, 1, 7)
|
|
assert.ErrorIs(t, err, errCollateralCoinMustBeSet)
|
|
_, err = e.CryptoLoanBorrow(t.Context(), currency.USDT, 0, currency.BTC, 1, 0)
|
|
assert.ErrorIs(t, err, errLoanTermMustBeSet)
|
|
_, err = e.CryptoLoanBorrow(t.Context(), currency.USDT, 0, currency.BTC, 0, 7)
|
|
assert.ErrorIs(t, err, errEitherLoanOrCollateralAmountsMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.CryptoLoanBorrow(t.Context(), currency.USDT, 1000, currency.BTC, 1, 7); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanBorrowHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanBorrowHistory(t.Context(), 0, currency.USDT, currency.BTC, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanOngoingOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanOngoingOrders(t.Context(), 0, currency.USDT, currency.BTC, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanRepay(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.CryptoLoanRepay(t.Context(), 0, 1000, 1, false)
|
|
assert.ErrorIs(t, err, errOrderIDMustBeSet)
|
|
_, err = e.CryptoLoanRepay(t.Context(), 42069, 0, 1, false)
|
|
assert.ErrorIs(t, err, errAmountMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.CryptoLoanRepay(t.Context(), 42069, 1000, 1, false); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanRepaymentHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanRepaymentHistory(t.Context(), 0, currency.USDT, currency.BTC, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanAdjustLTV(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.CryptoLoanAdjustLTV(t.Context(), 0, true, 1)
|
|
assert.ErrorIs(t, err, errOrderIDMustBeSet)
|
|
_, err = e.CryptoLoanAdjustLTV(t.Context(), 42069, true, 0)
|
|
assert.ErrorIs(t, err, errAmountMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.CryptoLoanAdjustLTV(t.Context(), 42069, true, 1); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanLTVAdjustmentHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanLTVAdjustmentHistory(t.Context(), 0, currency.USDT, currency.BTC, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanAssetsData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanAssetsData(t.Context(), currency.EMPTYCODE, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanCollateralAssetsData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanCollateralAssetsData(t.Context(), currency.EMPTYCODE, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanCheckCollateralRepayRate(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.CryptoLoanCheckCollateralRepayRate(t.Context(), currency.EMPTYCODE, currency.BNB, 69)
|
|
assert.ErrorIs(t, err, errLoanCoinMustBeSet)
|
|
_, err = e.CryptoLoanCheckCollateralRepayRate(t.Context(), currency.BUSD, currency.EMPTYCODE, 69)
|
|
assert.ErrorIs(t, err, errCollateralCoinMustBeSet)
|
|
_, err = e.CryptoLoanCheckCollateralRepayRate(t.Context(), currency.BUSD, currency.BNB, 0)
|
|
assert.ErrorIs(t, err, errAmountMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.CryptoLoanCheckCollateralRepayRate(t.Context(), currency.BUSD, currency.BNB, 69); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCryptoLoanCustomiseMarginCall(t *testing.T) {
|
|
t.Parallel()
|
|
if _, err := e.CryptoLoanCustomiseMarginCall(t.Context(), 0, currency.BTC, 0); err == nil {
|
|
t.Error("expected an error")
|
|
}
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.CryptoLoanCustomiseMarginCall(t.Context(), 1337, currency.BTC, .70); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanBorrow(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FlexibleLoanBorrow(t.Context(), currency.EMPTYCODE, currency.USDC, 1, 0)
|
|
assert.ErrorIs(t, err, errLoanCoinMustBeSet)
|
|
_, err = e.FlexibleLoanBorrow(t.Context(), currency.ATOM, currency.EMPTYCODE, 1, 0)
|
|
assert.ErrorIs(t, err, errCollateralCoinMustBeSet)
|
|
_, err = e.FlexibleLoanBorrow(t.Context(), currency.ATOM, currency.USDC, 0, 0)
|
|
assert.ErrorIs(t, err, errEitherLoanOrCollateralAmountsMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.FlexibleLoanBorrow(t.Context(), currency.ATOM, currency.USDC, 1, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanOngoingOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleLoanOngoingOrders(t.Context(), currency.EMPTYCODE, currency.EMPTYCODE, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanBorrowHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleLoanBorrowHistory(t.Context(), currency.EMPTYCODE, currency.EMPTYCODE, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanRepay(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FlexibleLoanRepay(t.Context(), currency.EMPTYCODE, currency.BTC, 1, false, false)
|
|
assert.ErrorIs(t, err, errLoanCoinMustBeSet)
|
|
_, err = e.FlexibleLoanRepay(t.Context(), currency.USDT, currency.EMPTYCODE, 1, false, false)
|
|
assert.ErrorIs(t, err, errCollateralCoinMustBeSet)
|
|
_, err = e.FlexibleLoanRepay(t.Context(), currency.USDT, currency.BTC, 0, false, false)
|
|
assert.ErrorIs(t, err, errAmountMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.FlexibleLoanRepay(t.Context(), currency.ATOM, currency.USDC, 1, false, false); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanRepayHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleLoanRepayHistory(t.Context(), currency.EMPTYCODE, currency.EMPTYCODE, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanAdjustLTV(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.FlexibleLoanAdjustLTV(t.Context(), currency.EMPTYCODE, currency.BTC, 1, true)
|
|
assert.ErrorIs(t, err, errLoanCoinMustBeSet)
|
|
_, err = e.FlexibleLoanAdjustLTV(t.Context(), currency.USDT, currency.EMPTYCODE, 1, true)
|
|
assert.ErrorIs(t, err, errCollateralCoinMustBeSet)
|
|
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
|
if _, err := e.FlexibleLoanAdjustLTV(t.Context(), currency.USDT, currency.BTC, 1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanLTVAdjustmentHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleLoanLTVAdjustmentHistory(t.Context(), currency.EMPTYCODE, currency.EMPTYCODE, time.Time{}, time.Time{}, 0, 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleLoanAssetsData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleLoanAssetsData(t.Context(), currency.EMPTYCODE); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFlexibleCollateralAssetsData(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
|
if _, err := e.FlexibleCollateralAssetsData(t.Context(), currency.EMPTYCODE); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesContractDetails(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFuturesContractDetails(t.Context(), asset.Spot)
|
|
assert.ErrorIs(t, err, futures.ErrNotFuturesAsset)
|
|
|
|
_, err = e.GetFuturesContractDetails(t.Context(), asset.Futures)
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
|
|
_, err = e.GetFuturesContractDetails(t.Context(), asset.USDTMarginedFutures)
|
|
assert.NoError(t, err)
|
|
|
|
_, err = e.GetFuturesContractDetails(t.Context(), asset.CoinMarginedFutures)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestGetFundingRateInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.GetFundingRateInfo(t.Context())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestUGetFundingRateInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := e.UGetFundingRateInfo(t.Context())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestGetOpenInterest(t *testing.T) {
|
|
t.Parallel()
|
|
resp, err := e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: currency.BTC.Item,
|
|
Quote: currency.USDT.Item,
|
|
Asset: asset.USDTMarginedFutures,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
resp, err = e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: currency.NewCode("BTCUSD").Item,
|
|
Quote: currency.PERP.Item,
|
|
Asset: asset.CoinMarginedFutures,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
|
|
_, err = e.GetOpenInterest(t.Context(), key.PairAsset{
|
|
Base: currency.BTC.Item,
|
|
Quote: currency.USDT.Item,
|
|
Asset: asset.Spot,
|
|
})
|
|
assert.ErrorIs(t, err, asset.ErrNotSupported)
|
|
}
|
|
|
|
func TestGetCurrencyTradeURL(t *testing.T) {
|
|
t.Parallel()
|
|
testexch.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])
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp)
|
|
}
|
|
}
|