package binanceus

import (
	"context"
	"encoding/json"
	"errors"
	"log"
	"os"
	reflects "reflect"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/thrasher-corp/gocryptotrader/common"
	"github.com/thrasher-corp/gocryptotrader/config"
	"github.com/thrasher-corp/gocryptotrader/core"
	"github.com/thrasher-corp/gocryptotrader/currency"
	exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
	"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
	"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
	"github.com/thrasher-corp/gocryptotrader/exchanges/order"
	"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
	"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
)

// Please supply your own keys here to test authenticated endpoints
const (
	apiKey                  = ""
	apiSecret               = ""
	canManipulateRealOrders = false
)

var (
	bi              Binanceus
	testPairMapping = currency.NewPair(currency.BTC, currency.USDT)
	// this lock guards against orderbook tests race
	binanceusOrderBookLock = &sync.Mutex{}
)

func TestMain(m *testing.M) {
	cfg := config.GetConfig()
	err := cfg.LoadConfig("../../testdata/configtest.json", true)
	if err != nil {
		log.Fatal("Binanceus load config error", err)
	}

	exchCfg, err := cfg.GetExchangeConfig("Binanceus")
	if err != nil {
		log.Fatal(err)
	}
	exchCfg.API.AuthenticatedSupport = true
	exchCfg.API.AuthenticatedWebsocketSupport = true
	exchCfg.API.Credentials.Key = apiKey
	exchCfg.API.Credentials.Secret = apiSecret
	bi.SetDefaults()
	bi.Websocket = sharedtestvalues.NewTestWebsocket()
	bi.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
	err = bi.Setup(exchCfg)
	if err != nil {
		log.Fatal("Binanceus TestMain()", err)
	}
	bi.setupOrderbookManager()
	err = bi.Start(context.Background(), nil)
	if !errors.Is(err, common.ErrNilPointer) {
		log.Fatalf("%s received: '%v' but expected: '%v'", bi.Name, err, common.ErrNilPointer)
	}
	var testWg sync.WaitGroup
	err = bi.Start(context.Background(), &testWg)
	if err != nil {
		log.Fatal("Binanceus Starting error ", err)
	}
	os.Exit(m.Run())
}

func areTestAPIKeysSet() bool {
	return bi.ValidateAPICredentials(bi.GetDefaultCredentials()) == nil
}

func TestServerTime(t *testing.T) {
	t.Parallel()
	if _, er := bi.GetServerTime(context.Background(), asset.Spot); er != nil {
		t.Error("Binanceus SystemTime() error", er)
	}
}

func TestServerStatus(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetSystemStatus(context.Background()); er != nil {
		t.Error("Binanceus GetSystemStatus() error", er)
	}
}

func TestGetExchangeInfo(t *testing.T) {
	t.Parallel()
	_, err := bi.GetExchangeInfo(context.Background())
	if err != nil {
		t.Error("Binanceus GetExchangeInfo() error", err)
	}
}

func TestUpdateTicker(t *testing.T) {
	t.Parallel()
	r, err := bi.UpdateTicker(context.Background(), testPairMapping, asset.Spot)
	if err != nil {
		t.Error(err)
	}
	if r.Pair.Base != currency.BTC && r.Pair.Quote != currency.USDT {
		t.Error("Binanceus UpdateTicker() invalid pair values")
	}
}

func TestUpdateTickers(t *testing.T) {
	t.Parallel()
	err := bi.UpdateTickers(context.Background(), asset.Spot)
	if err != nil {
		t.Error(err)
	}
}

func TestUpdateOrderBook(t *testing.T) {
	t.Parallel()
	_, er := bi.UpdateOrderbook(context.Background(), testPairMapping, asset.Spot)
	if er != nil {
		t.Error("Binanceus UpdateOrderBook() error", er)
	}
}

func TestFetchTradablePairs(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, err := bi.FetchTradablePairs(context.Background(), asset.Spot)
	if err != nil {
		t.Error("Binanceus FetchTradablePairs() error", err)
	}
}

func TestUpdateTradablePairs(t *testing.T) {
	t.Parallel()
	err := bi.UpdateTradablePairs(context.Background(), false)
	if err != nil {
		t.Error("Binanceus UpdateTradablePairs() error", err)
	}
}

func TestFetchAccountInfo(t *testing.T) {
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	t.Parallel()
	if _, err := bi.FetchAccountInfo(context.Background(), asset.Spot); err != nil {
		t.Error("Binanceus FetchAccountInfo() error", err)
	}
}

func TestUpdateAccountInfo(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, err := bi.UpdateAccountInfo(context.Background(), asset.Spot)
	if err != nil {
		t.Error("Binanceus UpdateAccountInfo() error", err)
	}
}

func TestGetRecentTrades(t *testing.T) {
	t.Parallel()
	pair := currency.Pair{Base: currency.BTC, Quote: currency.USD}
	_, err := bi.GetRecentTrades(context.Background(), pair, asset.Spot)
	if err != nil {
		t.Error("Binanceus GetRecentTrades() error", err)
	}
}

func TestGetHistoricTrades(t *testing.T) {
	t.Parallel()
	pair := currency.Pair{Base: currency.BTC, Quote: currency.USD}
	_, err := bi.GetHistoricTrades(context.Background(), pair, asset.Spot, time.Time{}, time.Time{})
	if err != nil {
		t.Error("Binanceus GetHistoricTrades() error", err)
	}
}

func TestGetFeeByType(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetFeeByType(context.Background(), &exchange.FeeBuilder{
		IsMaker: true,
		Pair:    currency.NewPair(currency.USD, currency.BTC),
		FeeType: exchange.CryptocurrencyTradeFee,
	}); er != nil {
		t.Error("Binanceus GetFeeByType() error", er)
	}
	if _, er := bi.GetFeeByType(context.Background(), &exchange.FeeBuilder{
		IsMaker: true,
		Pair:    currency.NewPair(currency.USD, currency.BTC),
		FeeType: exchange.CryptocurrencyWithdrawalFee,
	}); er != nil {
		t.Error("Binanceus GetFeeByType() error", er)
	}
}

func TestSubmitOrder(t *testing.T) {
	t.Parallel()
	if areTestAPIKeysSet() && !canManipulateRealOrders {
		t.Skip(bi.Name, "API keys set, canManipulateRealOrders false, skipping test")
	}
	var orderSubmission = &order.Submit{
		Pair: currency.Pair{
			Base:  currency.XRP,
			Quote: currency.USD,
		},
		AssetType: asset.Spot,
		Side:      order.Sell,
		Type:      order.Limit,
		Price:     1000,
		Amount:    20,
		ClientID:  "binanceSamOrder",
		Exchange:  bi.Name,
	}
	response, err := bi.SubmitOrder(context.Background(), orderSubmission)
	switch {
	case areTestAPIKeysSet() && err != nil && strings.Contains(err.Error(), "{\"code\":-1013,\"msg\":\"Market is closed.\""):
		t.Skip("Binanceus SubmitOrder() Market is Closed")
	case areTestAPIKeysSet() && err != nil:
		t.Errorf("Binanceus SubmitOrder() Could not place order: %v", err)
	case areTestAPIKeysSet() && response.Status != order.Filled:
		t.Error("Binanceus SubmitOrder() Order not placed")
	case !areTestAPIKeysSet() && err == nil:
		t.Error("Binanceus SubmitOrder() Expecting an error when no keys are set")
	}
}

func TestCancelOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	pair := currency.NewPair(currency.BTC, currency.USD)
	err := bi.CancelOrder(context.Background(), &order.Cancel{
		AssetType: asset.Spot,
		OrderID:   "1337",
	})
	if err != nil && !errors.Is(err, errMissingCurrencySymbol) {
		t.Error("Binanceus CancelOrder() error", err)
	}
	err = bi.CancelOrder(context.Background(), &order.Cancel{
		AssetType: asset.Spot,
		Pair:      currency.NewPair(currency.BTC, currency.USDT),
	})
	if err != nil && !(errors.Is(err, errEitherOrderIDOrClientOrderIDIsRequired) || strings.Contains(err.Error(), "ID not set")) {
		t.Errorf("Binanceus CancelOrder() expecting %v, but found %v", errEitherOrderIDOrClientOrderIDIsRequired, err)
	}
	var cancellationOrder = &order.Cancel{
		OrderID:   "1",
		Pair:      pair,
		AssetType: asset.Spot,
	}
	err = bi.CancelOrder(context.Background(), cancellationOrder)
	if err != nil && !strings.Contains(err.Error(), "Unknown order sent.") {
		t.Error("Binanceus CancelOrder() error", err)
	}
}

func TestCancelAllOrders(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if areTestAPIKeysSet() && !canManipulateRealOrders {
		t.Skip("Binanceus API keys set, canManipulateRealOrders false, skipping test")
	}
	var orderCancellation = &order.Cancel{
		Pair:      currency.NewPair(currency.LTC, currency.BTC),
		AssetType: asset.Spot,
	}
	if _, err := bi.CancelAllOrders(context.Background(), orderCancellation); err != nil {
		t.Error("Binanceus CancelAllOrders() error", err)
	}
}

func TestGetOrderInfo(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.Skip("Binanceus GetOrderInfo() skipping test: api keys not set")
	}
	tradablePairs, err := bi.FetchTradablePairs(context.Background(),
		asset.Spot)
	if err != nil {
		t.Error(err)
	}
	if len(tradablePairs) == 0 {
		t.Fatal("Binanceus GetOrderInfo() no tradable pairs")
	}
	_, err = bi.GetOrderInfo(context.Background(),
		"123",
		tradablePairs[0],
		asset.Spot)
	if !strings.Contains(err.Error(), "Order does not exist.") {
		t.Error("Binanceus GetOrderInfo() error", err)
	}
}

func TestGetDepositAddress(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, err := bi.GetDepositAddress(context.Background(), currency.EMPTYCODE, "", currency.BNB.String())
	if err != nil && !errors.Is(err, errMissingRequiredArgumentCoin) {
		t.Errorf("Binanceus GetDepositAddress() expecting %v, but found %v", errMissingRequiredArgumentCoin, err)
	}
	if _, err := bi.GetDepositAddress(context.Background(), currency.USDT, "", currency.BNB.String()); err != nil {
		t.Error("Binanceus GetDepositAddress() error", err)
	}
}

func TestGetWithdrawalHistory(t *testing.T) {
	t.Parallel()
	if areTestAPIKeysSet() && !canManipulateRealOrders {
		t.Skip("Binanceus API keys set, canManipulateRealOrders false, skipping test")
	}
	_, err := bi.GetWithdrawalsHistory(context.Background(), currency.ETH, asset.Spot)
	switch {
	case areTestAPIKeysSet() && err != nil:
		t.Error("Binanceus GetWithdrawalsHistory() error", err)
	case !areTestAPIKeysSet() && err == nil:
		t.Error("Binanceus GetWithdrawalsHistory() expecting an error when no keys are set")
	}
}

func TestWithdrawFiat(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	if _, er := bi.WithdrawFiat(context.Background(), &WithdrawFiatRequestParams{
		PaymentChannel: "SILVERGATE",
		PaymentAccount: "myaccount",
		PaymentMethod:  "SEN",
		Amount:         1,
	}); er != nil && !strings.Contains(er.Error(), "You are not authorized to execute this request.") {
		t.Error("Binanceus WithdrawFiat() error", er)
	}
}

func TestGetActiveOrders(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	var getOrdersRequest = order.GetOrdersRequest{
		Type:      order.AnyType,
		AssetType: asset.Spot,
		Side:      order.AnySide,
	}
	_, err := bi.GetActiveOrders(context.Background(), &getOrdersRequest)
	if err != nil {
		t.Error("Binanceus GetActiveOrders() error", err)
	}
}

func TestWithdraw(t *testing.T) {
	t.Parallel()
	if !(areTestAPIKeysSet() && canManipulateRealOrders) {
		t.Skip("Binanceus API keys set, canManipulateRealOrders false, skipping test")
	}
	withdrawCryptoRequest := withdraw.Request{
		Exchange:    bi.Name,
		Amount:      -1,
		Currency:    currency.BTC,
		Description: "WITHDRAW IT ALL",
		Crypto: withdraw.CryptoRequest{
			Address: core.BitcoinDonationAddress,
			Chain:   "BSC",
		},
	}
	_, err := bi.WithdrawCryptocurrencyFunds(context.Background(), &withdrawCryptoRequest)
	if err != nil && !strings.EqualFold(errAmountValueMustBeGreaterThan0.Error(), err.Error()) {
		t.Errorf("Binanceus Withdraw() expecting %v, but found %v", errAmountValueMustBeGreaterThan0, err)
	} else if !areTestAPIKeysSet() && err == nil {
		t.Error("Binanceus Withdraw() expecting an error when no keys are set")
	}
	withdrawCryptoRequest.Amount = 1
	_, err = bi.WithdrawCryptocurrencyFunds(context.Background(), &withdrawCryptoRequest)
	if err != nil && !strings.Contains(err.Error(), "You are not authorized to execute this request.") {
		t.Error("Binanceus WithdrawCryptocurrencyFunds() error", err)
	}
}

func TestGetFee(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	var feeBuilder = &exchange.FeeBuilder{
		Amount:        1,
		FeeType:       exchange.CryptocurrencyTradeFee,
		Pair:          currency.NewPair(currency.BTC, currency.LTC),
		PurchasePrice: 1,
	}
	_, er := bi.GetFeeByType(context.Background(), feeBuilder)
	if er != nil {
		t.Fatal("Binanceus GetFeeByType() error", er)
	}
	var withdrawalFeeBuilder = &exchange.FeeBuilder{
		Amount:        1,
		FeeType:       exchange.CryptocurrencyWithdrawalFee,
		Pair:          currency.NewPair(currency.BTC, currency.LTC),
		PurchasePrice: 1,
	}
	_, er = bi.GetFeeByType(context.Background(), withdrawalFeeBuilder)
	if er != nil {
		t.Fatal("Binanceus GetFeeByType() error", er)
	}
	var offlineFeeTradeBuilder = &exchange.FeeBuilder{
		Amount:        1,
		FeeType:       exchange.OfflineTradeFee,
		Pair:          currency.NewPair(currency.BTC, currency.LTC),
		PurchasePrice: 1,
	}
	_, er = bi.GetFeeByType(context.Background(), offlineFeeTradeBuilder)
	if er != nil {
		t.Fatal("Binanceus GetFeeByType() error", er)
	}
}

func TestGetHistoricCandles(t *testing.T) {
	t.Parallel()
	pair := currency.NewPair(currency.BTC, currency.USDT)
	startTime := time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC)
	endTime := time.Date(2021, 2, 15, 0, 0, 0, 0, time.UTC)

	_, err := bi.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.Interval(time.Hour*5), startTime, endTime)
	if !errors.Is(err, kline.ErrRequestExceedsExchangeLimits) {
		t.Fatalf("received: '%v', but expected: '%v'", err, kline.ErrRequestExceedsExchangeLimits)
	}

	_, err = bi.GetHistoricCandles(context.Background(), pair, asset.Spot, kline.OneDay, startTime, endTime)
	if err != nil {
		t.Error("Binanceus GetHistoricCandles() error", err)
	}
}

func TestGetHistoricCandlesExtended(t *testing.T) {
	t.Parallel()
	pair := currency.NewPair(currency.BTC, currency.USDT)
	startTime := time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC)
	endTime := time.Date(2021, 2, 15, 0, 0, 0, 0, time.UTC)

	_, err := bi.GetHistoricCandlesExtended(context.Background(), pair, asset.Spot, kline.OneDay, startTime, endTime)
	if err != nil {
		t.Fatal(err)
	}

	startTime = time.Now().Add(-time.Hour * 30)
	endTime = time.Now()

	_, err = bi.GetHistoricCandlesExtended(context.Background(), pair, asset.Spot, kline.FourHour, startTime, endTime)
	if err != nil {
		t.Error("Binanceus GetHistoricCandlesExtended() error", err)
	}
}

/************************************************************************/

// TestGetMostRecentTrades -- test most recent trades end-point
func TestGetMostRecentTrades(t *testing.T) {
	t.Parallel()
	_, err := bi.GetMostRecentTrades(context.Background(), RecentTradeRequestParams{
		Symbol: currency.NewPair(currency.BTC, currency.USDT),
		Limit:  15,
	})
	if err != nil {
		t.Error("Binanceus GetMostRecentTrades() error", err)
	}
}

func TestGetHistoricalTrades(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, err := bi.GetHistoricalTrades(context.Background(), HistoricalTradeParams{
		Symbol: "BTCUSDT",
		Limit:  5,
		FromID: 0,
	})
	if err != nil {
		t.Errorf("Binanceus GetHistoricalTrades() error: %v", err)
	}
}

func TestGetAggregateTrades(t *testing.T) {
	t.Parallel()
	_, err := bi.GetAggregateTrades(context.Background(),
		&AggregatedTradeRequestParams{
			Symbol: currency.NewPair(currency.BTC, currency.USDT),
			Limit:  5,
		})
	if err != nil {
		t.Error("Binanceus GetAggregateTrades() error", err)
	}
}

func TestGetOrderBookDepth(t *testing.T) {
	t.Parallel()
	_, er := bi.GetOrderBookDepth(context.Background(), &OrderBookDataRequestParams{
		Symbol: currency.NewPair(currency.BTC, currency.USDT),
		Limit:  1000,
	})
	if er != nil {
		t.Error("Binanceus GetOrderBook() error", er)
	}
}

func TestGetCandlestickData(t *testing.T) {
	t.Parallel()
	_, er := bi.GetSpotKline(context.Background(), &KlinesRequestParams{
		Symbol:    currency.NewPair(currency.BTC, currency.USDT),
		Interval:  kline.FiveMin.Short(),
		Limit:     24,
		StartTime: time.Unix(1577836800, 0),
		EndTime:   time.Unix(1580515200, 0),
	})
	if er != nil {
		t.Error("Binanceus GetSpotKline() error", er)
	}
}

func TestGetPriceDatas(t *testing.T) {
	t.Parallel()
	_, er := bi.GetPriceDatas(context.Background())
	if er != nil {
		t.Error("Binanceus GetPriceDatas() error", er)
	}
}

func TestGetSinglePriceData(t *testing.T) {
	t.Parallel()
	_, er := bi.GetSinglePriceData(context.Background(), currency.Pair{
		Base:  currency.BTC,
		Quote: currency.USDT,
	})
	if er != nil {
		t.Error("Binanceus GetSinglePriceData() error", er)
	}
}

func TestGetAveragePrice(t *testing.T) {
	t.Parallel()
	_, err := bi.GetAveragePrice(context.Background(), currency.NewPair(currency.BTC, currency.USDT))
	if err != nil {
		t.Error("Binance GetAveragePrice() error", err)
	}
}

func TestGetBestPrice(t *testing.T) {
	t.Parallel()
	_, err := bi.GetBestPrice(context.Background(), currency.NewPair(currency.BTC, currency.USDT))
	if err != nil {
		t.Error("Binanceus GetBestPrice() error", err)
	}
}

func TestGetPriceChangeStats(t *testing.T) {
	t.Parallel()
	_, err := bi.GetPriceChangeStats(context.Background(), currency.NewPair(currency.BTC, currency.USDT))
	if err != nil {
		t.Error("Binance GetPriceChangeStats() error", err)
	}
}

func TestGetTickers(t *testing.T) {
	t.Parallel()
	_, err := bi.GetTickers(context.Background())
	if err != nil {
		t.Error("Binance TestGetTickers error", err)
	}
}

func TestGetAccount(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetAccount(context.Background())
	if er != nil {
		t.Error("Binanceus GetAccount() error", er)
	}
}

func TestGetUserAccountStatus(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetUserAccountStatus(context.Background(), 3000)
	if er != nil {
		t.Error("Binanceus GetUserAccountStatus() error", er)
	}
}

func TestGetUserAPITradingStatus(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetUserAPITradingStatus(context.Background(), 3000)
	if er != nil {
		t.Error("Binanceus GetUserAPITradingStatus() error", er)
	}
}
func TestGetTradeFee(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetTradeFee(context.Background(), 3000, "BTC-USDT")
	if er != nil {
		t.Error("Binanceus GetTradeFee() error", er)
	}
}

func TestGetAssetDistributionHistory(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetAssetDistributionHistory(context.Background(), "", 0, 0, 3000)
	if er != nil {
		t.Error("Binanceus GetAssetDistributionHistory() error", er)
	}
}

func TestGetMasterAccountTotalUSDValue(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetMasterAccountTotalUSDValue(context.Background(), "", 0, 0); er != nil && !strings.Contains(er.Error(), "Sub-account function is not enabled.") {
		t.Errorf("Binanceus GetMasterAccountTotalUSDValue() expecting %s, but found %v", "Sub-account function is not enabled.", er)
	}
}

func TestGetSubaccountStatusList(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetSubaccountStatusList(context.Background(), ""); er != nil && !errors.Is(er, errMissingSubAccountEmail) {
		t.Errorf("Binanceus GetSubaccountStatusList() expecting %v, but found %v", errMissingSubAccountEmail, er)
	}
	if _, er := bi.GetSubaccountStatusList(context.Background(), "someone@thrasher.corp"); er != nil && !strings.Contains(er.Error(), "Sub-account function is not enabled.") {
		t.Errorf("Binanceus GetSubaccountStatusList() expecting %s, but found %v", "Sub-account function is not enabled.", er)
	}
}

func TestGetSubAccountDepositAddress(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetSubAccountDepositAddress(context.Background(), SubAccountDepositAddressRequestParams{}); er != nil && !errors.Is(er, errMissingSubAccountEmail) {
		t.Errorf("Binanceus GetSubAccountDepositAddress() %v, but found %v", errMissingSubAccountEmail, er)
	}
	if _, er := bi.GetSubAccountDepositAddress(context.Background(), SubAccountDepositAddressRequestParams{
		Email: "someone@thrasher.io",
	}); er != nil && !errors.Is(er, errMissingCurrencyCoin) {
		t.Errorf("Binanceus GetSubAccountDepositAddress() %v, but found %v", errMissingCurrencyCoin, er)
	}
	if _, er := bi.GetSubAccountDepositAddress(context.Background(), SubAccountDepositAddressRequestParams{
		Email: "someone@thrasher.io",
		Coin:  currency.BTC,
	}); er != nil && !strings.Contains(er.Error(), "This parent sub have no relation") {
		t.Errorf("Binanceus GetSubAccountDepositAddress() %v, but found %v", errMissingCurrencyCoin, er)
	}
}

var subAccountDepositHistoryItemJSON = `{
	"amount": "9.9749",
	"coin": "BTC", 
	"network": "btc",
	"status": 4, 
	"address": "bc1qxurvdd7tzn09agdvg3j8xpm3f7e978y07wg83s",
	"addressTag": "",
	"txId": "0x1b4b8c8090d15e3c1b0476b1c19118b1f00066e01de567cd7bc5b6e9c100193f",
	"insertTime": 1652942429211,
	"transferType": 0,
	"confirmTimes": "0/0"
}`

func TestGetSubAccountDepositHistory(t *testing.T) {
	t.Parallel()
	var resp SubAccountDepositItem
	if er := json.Unmarshal([]byte(subAccountDepositHistoryItemJSON), &resp); er != nil {
		t.Error("Binanceus Decerializing to SubAccountDepositItem error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetSubAccountDepositHistory(context.Background(), "", currency.BTC, 1, time.Time{}, time.Time{}, 0, 0); er != nil && !errors.Is(er, errMissingSubAccountEmail) {
		t.Errorf("Binanceus GetSubAccountDepositHistory() expecting %v, but found %v", errMissingSubAccountEmail, er)
	}
	if _, er := bi.GetSubAccountDepositHistory(context.Background(), "someone@thrasher.io", currency.BTC, 1, time.Time{}, time.Time{}, 0, 0); er != nil && !strings.Contains(er.Error(), "This parent sub have no relation") {
		t.Errorf("Binanceus GetSubAccountDepositHistory() expecting %s, but found %v", "This parent sub have no relation", er)
	}
}

var subaccountItemJSON = `{
	"email": "123@test.com",
	"status": "enabled",
	"activated": true,
	"mobile": "91605290",
	"gAuth": true,
	"createTime": 1544433328000
}`

func TestGetSubaccountInformation(t *testing.T) {
	t.Parallel()
	var resp SubAccount
	if er := json.Unmarshal([]byte(subaccountItemJSON), &resp); er != nil {
		t.Error("Binanceus decerializing to SubAccount error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetSubaccountInformation(context.Background(), 1, 100, "", "")
	if er != nil && !strings.Contains(er.Error(), "Sub-account function is not enabled.") {
		t.Error("Binanceus GetSubaccountInformation() error", er)
	}
}

var referalRewardHistoryResponse = `{
    "total": 1,
    "rows": [
        {
            "userId": 350991652,
            "rewardAmount": "8",
            "receiveDateTime": 1651131084091,
            "rewardType": "USD"
        }
    ]
}`

func TestGetReferralRewardHistory(t *testing.T) {
	t.Parallel()
	var resp ReferralRewardHistoryResponse
	if er := json.Unmarshal([]byte(referalRewardHistoryResponse), &resp); er != nil {
		t.Error("Binanceus decerializing to ReferalRewardHistoryResponse error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetReferralRewardHistory(context.Background(), 9, 5, 50); !errors.Is(er, errInvalidUserBusinessType) {
		t.Errorf("Binanceus GetReferralRewardHistory() expecting %v, but found %v", errInvalidUserBusinessType, er)
	}
	if _, er := bi.GetReferralRewardHistory(context.Background(), 1, 0, 50); !errors.Is(er, errMissingPageNumber) {
		t.Errorf("Binanceus GetReferralRewardHistory() expecting %v, but found %v", errMissingPageNumber, er)
	}
	if _, er := bi.GetReferralRewardHistory(context.Background(), 1, 5, 0); !errors.Is(er, errInvalidRowNumber) {
		t.Errorf("Binanceus GetReferralRewardHistory() expecting %v, but found %v", errInvalidRowNumber, er)
	}
	if _, er := bi.GetReferralRewardHistory(context.Background(), 1, 5, 50); er != nil {
		t.Error("Binanceus GetReferralRewardHistory() error", er)
	}
}

func TestGetSubaccountTransferHistory(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetSubaccountTransferHistory(context.Background(), "", 0, 0, 0, 0)
	if !errors.Is(er, errNotValidEmailAddress) {
		t.Errorf("Binanceus GetSubaccountTransferHistory() expected %v, but received: %s", errNotValidEmailAddress, er)
	}
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.Skip("Binanceus GetSubaccountTransferHistory() skipping test, either api keys or canManipulateRealOrders isn't set")
	}
	_, er = bi.GetSubaccountTransferHistory(context.Background(), "example@golang.org", 0, 0, 0, 0)
	if er != nil && !(errors.Is(er, errNotValidEmailAddress) || strings.Contains(er.Error(), "Sub-account function is not enabled.")) {
		t.Fatalf("Binanceus GetSubaccountTransferHistory() error %v", er)
	}
}

func TestExecuteSubAccountTransfer(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	_, er := bi.ExecuteSubAccountTransfer(context.Background(), &SubAccountTransferRequestParams{})
	if !errors.Is(er, errUnacceptableSenderEmail) {
		t.Errorf("binanceus error: expected %v, but found %v", errUnacceptableSenderEmail, er)
	}
	_, er = bi.ExecuteSubAccountTransfer(context.Background(), &SubAccountTransferRequestParams{
		FromEmail: "fromemail@thrasher.io",
		ToEmail:   "toemail@threasher.io",
		Asset:     "BTC",
		Amount:    0.000005,
	})
	if er != nil && !strings.Contains(er.Error(), "You are not authorized to execute this request.") {
		t.Errorf("Binanceus GetSubaccountTransferHistory() error %v", er)
	}
}

func TestGetSubaccountAssets(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetSubaccountAssets(context.Background(), "")
	if !errors.Is(er, errNotValidEmailAddress) {
		t.Errorf("Binanceus GetSubaccountAssets() expected %v, but found %v", er, errNotValidEmailAddress)
	}
	_, er = bi.GetSubaccountAssets(context.Background(), "subaccount@thrasher.io")
	if er != nil && !strings.Contains(er.Error(), "This account does not exist.") {
		t.Fatal("Binanceus GetSubaccountAssets() error", er)
	}
}

func TestGetOrderRateLimits(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetOrderRateLimits(context.Background(), 0)
	if er != nil {
		t.Error("Binanceus GetOrderRateLimits() error", er)
	}
}

var testNewOrderResponseJSON = `{
	"symbol": "BTCUSDT",
	"orderId": 28,
	"orderListId": -1,
	"clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
	"transactTime": 1507725176595,
	"price": "0.00000000",
	"origQty": "10.00000000",
	"executedQty": "10.00000000",
	"cummulativeQuoteQty": "10.00000000",
	"status": "FILLED",
	"timeInForce": "GTC",
	"type": "MARKET",
	"side": "SELL"
  }`

func TestNewOrderTest(t *testing.T) {
	t.Parallel()
	var resp NewOrderResponse
	if er := json.Unmarshal([]byte(testNewOrderResponseJSON), &resp); er != nil {
		t.Error("Binanceus decerializing to Order error", er)
	}
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	req := &NewOrderRequest{
		Symbol:      currency.NewPair(currency.LTC, currency.BTC),
		Side:        order.Buy.String(),
		TradeType:   BinanceRequestParamsOrderLimit,
		Price:       0.0025,
		Quantity:    100000,
		TimeInForce: BinanceRequestParamsTimeGTC,
	}
	_, err := bi.NewOrderTest(context.Background(), req)
	if err != nil {
		t.Error("Binanceus NewOrderTest() error", err)
	}
	req = &NewOrderRequest{
		Symbol:        currency.NewPair(currency.LTC, currency.BTC),
		Side:          order.Sell.String(),
		TradeType:     BinanceRequestParamsOrderMarket,
		Price:         0.0045,
		QuoteOrderQty: 10,
	}
	_, err = bi.NewOrderTest(context.Background(), req)
	if err != nil {
		t.Error("NewOrderTest() error", err)
	}
}

func TestNewOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	req := &NewOrderRequest{
		Symbol:      currency.NewPair(currency.LTC, currency.BTC),
		Side:        order.Buy.String(),
		TradeType:   BinanceRequestParamsOrderLimit,
		Price:       0.0025,
		Quantity:    100000,
		TimeInForce: BinanceRequestParamsTimeGTC,
	}
	if _, err := bi.NewOrder(context.Background(), req); err != nil && !strings.Contains(err.Error(), "Account has insufficient balance for requested action") {
		t.Error("Binanceus NewOrder() error", err)
	}
}

func TestGetOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetOrder(context.Background(), &OrderRequestParams{})
	if !errors.Is(er, errIncompleteArguments) {
		t.Errorf("Binanceus GetOrder() error expecting %v, but found %v", errIncompleteArguments, er)
	}
	_, er = bi.GetOrder(context.Background(), &OrderRequestParams{
		Symbol:            "BTCUSDT",
		OrigClientOrderID: "something",
	})
	// You can check the existence of an order using a valid Symbol and OrigClient Order ID
	if er != nil && !strings.Contains(er.Error(), "Order does not exist.") {
		t.Error("Binanceus GetOrder() error", er)
	}
}

var openOrdersItemJSON = `{
    "symbol": "LTCBTC",
    "orderId": 1,
    "orderListId": -1,
    "clientOrderId": "myOrder1",
    "price": "0.1",
    "origQty": "1.0",
    "executedQty": "0.0",
    "cummulativeQuoteQty": "0.0",
    "status": "NEW",
    "timeInForce": "GTC",
    "type": "LIMIT",
    "side": "BUY",
    "stopPrice": "0.0",
    "icebergQty": "0.0",
    "time": 1499827319559,
    "updateTime": 1499827319559,
    "isWorking": true,
    "origQuoteOrderQty": "0.000000"
  }`

func TestGetAllOpenOrders(t *testing.T) {
	t.Parallel()
	var resp Order
	if er := json.Unmarshal([]byte(openOrdersItemJSON), &resp); er != nil {
		t.Error("Binanceus decerializing to Order error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetAllOpenOrders(context.Background(), "")
	if er != nil {
		t.Error("Binanceus GetAllOpenOrders() error", er)
	}
}

func TestCancelExistingOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.Skip("Binanceus CancelExistingOrder() skipping test, either api keys or canManipulateRealOrders isn't set")
	}
	_, er := bi.CancelExistingOrder(context.Background(), &CancelOrderRequestParams{Symbol: currency.NewPair(currency.BTC, currency.USDT)})
	if er != nil && !errors.Is(er, errEitherOrderIDOrClientOrderIDIsRequired) {
		t.Errorf("Binanceus CancelExistingOrder() error expecting %v, but found %v", errEitherOrderIDOrClientOrderIDIsRequired, er)
	}
	_, er = bi.CancelExistingOrder(context.Background(), &CancelOrderRequestParams{
		Symbol:                currency.NewPair(currency.BTC, currency.USDT),
		ClientSuppliedOrderID: "1234",
	})
	if er != nil && !strings.Contains(er.Error(), "Unknown order sent.") {
		t.Error("Binanceus CancelExistingorder() error", er)
	}
}

func TestCancelOpenOrdersForSymbol(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	_, er := bi.CancelOpenOrdersForSymbol(context.Background(), "")
	if !errors.Is(er, errMissingCurrencySymbol) {
		t.Errorf("Binanceus CancelOpenOrdersForSymbol() error expecting %v, but found %v", errIncompleteArguments, er)
	}
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.Skip("Binanceus CancelOpenOrdersForSymbol() skipping test, either api keys or canManipulateRealOrders isn't set")
	}
	_, er = bi.CancelOpenOrdersForSymbol(context.Background(), "BTCUSDT")
	if er != nil && !strings.Contains(er.Error(), "Unknown order sent") {
		t.Error("Binanceus CancelOpenOrdersForSymbol() error", er)
	}
}

// TestGetTrades test for fetching the list of
// trades attached with this account.
func TestGetTrades(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetTrades(context.Background(), &GetTradesParams{})
	if !errors.Is(er, errIncompleteArguments) {
		t.Errorf(" Binanceus GetTrades() expecting error %v, but found %v", errIncompleteArguments, er)
	}
	_, er = bi.GetTrades(context.Background(), &GetTradesParams{Symbol: "BTCUSDT"})
	if er != nil {
		t.Error("Binanceus GetTrades() error", er)
	}
}

func TestCreateNewOCOOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	_, er := bi.CreateNewOCOOrder(context.Background(),
		&OCOOrderInputParams{
			StopPrice: 1000,
			Side:      order.Buy.String(),
			Quantity:  0.0000001,
			Price:     1232334.00,
		})
	if !errors.Is(er, errIncompleteArguments) {
		t.Errorf("Binanceus CreatenewOCOOrder() error expected %v, but found %v", errIncompleteArguments, er)
	}
	_, er = bi.CreateNewOCOOrder(
		context.Background(),
		&OCOOrderInputParams{
			Symbol:               "XTZUSD",
			Price:                100,
			StopPrice:            3,
			StopLimitPrice:       2.5,
			Side:                 order.Buy.String(),
			Quantity:             1,
			StopLimitTimeInForce: "GTC",
			RecvWindow:           6000,
		})
	if er != nil && !strings.Contains(er.Error(), "Precision is over the maximum defined for this asset.") {
		t.Error("Binanceus CreateNewOCOOrder() error", er)
	}
}

var ocoOrderJSON = `{
	"orderListId": 27,
	"contingencyType": "OCO",
	"listStatusType": "EXEC_STARTED",
	"listOrderStatus": "EXECUTING",
	"listClientOrderId": "h2USkA5YQpaXHPIrkd96xE",
	"transactionTime": 1565245656253,
	"symbol": "LTCBTC",
	"orders": [
	  {
		"symbol": "LTCBTC",
		"orderId": 4,
		"clientOrderId": "qD1gy3kc3Gx0rihm9Y3xwS"
	  },
	  {
		"symbol": "LTCBTC",
		"orderId": 5,
		"clientOrderId": "ARzZ9I00CPM8i3NhmU9Ega"
	  }
	]
  }`

func TestGetOCOOrder(t *testing.T) {
	t.Parallel()
	var resp OCOOrderResponse
	if er := json.Unmarshal([]byte(ocoOrderJSON), &resp); er != nil {
		t.Error("Binanceus decerializing OCOOrderResponse error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetOCOOrder(context.Background(), &GetOCOOrderRequestParams{})
	if !errors.Is(er, errIncompleteArguments) {
		t.Errorf("Binanceus GetOCOOrder() error  expecting %v, but found %v", errIncompleteArguments, er)
	}
	_, er = bi.GetOCOOrder(context.Background(), &GetOCOOrderRequestParams{
		OrderListID: "123445",
	})
	if er != nil && !strings.Contains(er.Error(), "Order list does not exist.") {
		t.Error("Binanceus GetOCOOrder() error", er)
	}
}

func TestGetAllOCOOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetAllOCOOrder(context.Background(), &OCOOrdersRequestParams{})
	if er != nil {
		t.Error("Binanceus GetAllOCOOrder() error", er)
	}
}

func TestGetOpenOCOOrders(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetOpenOCOOrders(context.Background(), 0)
	if er != nil {
		t.Error("Binanceus GetOpenOCOOrders() error", er)
	}
}

func TestCancelOCOOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	_, er := bi.CancelOCOOrder(context.Background(), &OCOOrdersDeleteRequestParams{})
	if !errors.Is(er, errIncompleteArguments) {
		t.Errorf("Binanceus CancelOCOOrder() error expected %v, but found %v", errIncompleteArguments, er)
	}
}

// OTC end Points test code.
func TestGetSupportedCoinPairs(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetSupportedCoinPairs(context.Background(), currency.Pair{Base: currency.BTC, Quote: currency.USDT})
	if er != nil {
		t.Error("Binanceus GetSupportedCoinPairs() error", er)
	}
}

func TestRequestForQuote(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.RequestForQuote(context.Background(), &RequestQuoteParams{ToCoin: "BTC", RequestCoin: "USDT", RequestAmount: 1})
	if er != nil && !errors.Is(er, errMissingFromCoinName) {
		t.Errorf("Binanceus RequestForQuote() expecting %v, but found %v", errMissingFromCoinName, er)
	}
	_, er = bi.RequestForQuote(context.Background(), &RequestQuoteParams{FromCoin: "ETH", RequestCoin: "USDT", RequestAmount: 1})
	if er != nil && !errors.Is(er, errMissingToCoinName) {
		t.Errorf("Binanceus RequestForQuote() expecting %v, but found %v", errMissingToCoinName, er)
	}
	_, er = bi.RequestForQuote(context.Background(), &RequestQuoteParams{FromCoin: "ETH", ToCoin: "BTC", RequestCoin: "USDT"})
	if er != nil && !errors.Is(er, errMissingRequestAmount) {
		t.Errorf("Binanceus RequestForQuote() expecting %v, but found %v", errMissingRequestAmount, er)
	}
	_, er = bi.RequestForQuote(context.Background(), &RequestQuoteParams{FromCoin: "ETH", ToCoin: "BTC", RequestAmount: 1})
	if er != nil && !errors.Is(er, errMissingRequestCoin) {
		t.Errorf("Binanceus RequestForQuote() expecting %v, but found %v", errMissingRequestCoin, er)
	}
	_, er = bi.RequestForQuote(context.Background(), &RequestQuoteParams{FromCoin: "BTC", ToCoin: "USDT", RequestCoin: "BTC", RequestAmount: 1})
	if er != nil {
		t.Error("Binanceus RequestForQuote() error", er)
	}
}

var testPlaceOTCTradeOrderJSON = `{
    "orderId": "10002349",
    "createTime": 1641906714,
    "orderStatus": "PROCESS"
}`

func TestPlaceOTCTradeOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	var res OTCTradeOrderResponse
	er := json.Unmarshal([]byte(testPlaceOTCTradeOrderJSON), &res)
	if er != nil {
		t.Error("Binanceus PlaceOTCTradeOrder() error", er)
	}
	_, er = bi.PlaceOTCTradeOrder(context.Background(), "")
	if !errors.Is(er, errMissingQuoteID) {
		t.Errorf("Binanceus PlaceOTCTradeOrder()  expecting %v, but found %v", errMissingQuoteID, er)
	}
	_, er = bi.PlaceOTCTradeOrder(context.Background(), "15848701022")
	if er != nil && !strings.Contains(er.Error(), "-9000") {
		t.Error("Binanceus  PlaceOTCTradeOrder() error", er)
	}
}

var testGetOTCTradeOrderJSON = `{
    "quoteId": "4e5446f2cc6f44ab86ab02abf19a2fd2",
    "orderId": "10002349", 
    "orderStatus": "SUCCESS",
    "fromCoin": "BTC",
    "fromAmount": 1,
    "toCoin": "USDT",
    "toAmount": 50550.26,
    "ratio": 50550.26,
    "inverseRatio": 0.00001978,
    "createTime": 1641806714
}`

func TestGetOTCTradeOrder(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	var val OTCTradeOrder
	er := json.Unmarshal([]byte(testGetOTCTradeOrderJSON), &val)
	if er != nil {
		t.Error("Binanceus JSON GetOTCTradeOrder() error", er)
	}
	_, er = bi.GetOTCTradeOrder(context.Background(), 10002349)
	if er != nil && !strings.Contains(er.Error(), "status code: 400") {
		t.Error("Binanceus GetOTCTradeOrder() error ", er)
	}
}

var getAllOTCTradeOrders = `[
    {
        "quoteId": "4e5446f2cc6f44ab86ab02abf19a2fd2",
        "orderId": "10002349", 
        "orderStatus": "SUCCESS",
        "fromCoin": "BTC",
        "fromAmount": 1,
        "toCoin": "USDT",
        "toAmount": 50550.26,
        "ratio": 50550.26,
        "inverseRatio": 0.00001978,
        "createTime": 1641806714
    },
    {
        "quoteId": "15848645308",
        "orderId": "10002380", 
        "orderStatus": "PROCESS",
        "fromCoin": "SHIB",
        "fromAmount": 10000,
        "toCoin": "KSHIB",
        "toAmount": 10,
        "ratio": 0.001,
        "inverseRatio": 1000,
        "createTime": 1641916714
    }
]
`

func TestGetAllOTCTradeOrders(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	var orders []OTCTradeOrder
	er := json.Unmarshal([]byte(getAllOTCTradeOrders), &orders)
	if er != nil {
		t.Error(er)
	}
	_, er = bi.GetAllOTCTradeOrders(context.Background(), &OTCTradeOrderRequestParams{})
	if er != nil {
		t.Error("Binanceus GetAllOTCTradeOrders() error", er)
	}
}

var ocbsTradeOrderJSON = `
{
  "quoteId": "4e5446f2cc6f44ab86ab02abf19abvd",
  "orderId": "1000238000", 
  "orderStatus": "FAIL",
  "fromCoin": "USD",
  "fromAmount": 1000.5,
  "toCoin": "ETH",
  "toAmount": 0.5,
  "feeCoin": "USD",
  "feeAmount": 0.5,
  "ratio": 2000,
  "createTime": 1641916714
}`

func TestGetAllOCBSTradeOrders(t *testing.T) {
	t.Parallel()
	var orderDetail OCBSOrder
	if er := json.Unmarshal([]byte(ocbsTradeOrderJSON), &orderDetail); er != nil {
		t.Error("Binanceus decerializing to OCBSOrder error", er)
	}
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetAllOCBSTradeOrders(context.Background(), OCBSOrderRequestParams{}); er != nil {
		t.Error("Binanceus GetAllOCBSTradeOrders() error", er)
	}
}

func TestGetAssetFeesAndWalletStatus(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetAssetFeesAndWalletStatus(context.Background())
	if er != nil {
		t.Error("Binanceus GetAssetFeesAndWalletStatus()  error", er)
	}
}

func TestWithdrawCrypto(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() || !canManipulateRealOrders {
		t.SkipNow()
	}
	_, er := bi.WithdrawCrypto(context.Background(), &withdraw.Request{})
	if !errors.Is(er, errMissingRequiredArgumentCoin) {
		t.Errorf("Binanceus WithdrawCrypto() error expecting %v, but found %v", errMissingRequiredArgumentCoin, er)
	}
	if _, er = bi.WithdrawCrypto(context.Background(), &withdraw.Request{
		Currency: currency.BTC,
	}); !errors.Is(er, errMissingRequiredArgumentNetwork) {
		t.Errorf("Binanceus WithdrawCrypto() expecting %v, but found %v", errMissingRequiredArgumentNetwork, er)
	}
	params := &withdraw.Request{
		Currency: currency.BTC,
	}
	params.Crypto.Chain = "BSC"
	if _, er = bi.WithdrawCrypto(context.Background(), params); !errors.Is(er, errMissingRequiredParameterAddress) {
		t.Errorf("Binanceus WithdrawCrypto() expecting %v, but found %v", errMissingRequiredParameterAddress, er)
	}
	params.Crypto.Address = "1234567"
	if _, er = bi.WithdrawCrypto(context.Background(), params); !errors.Is(er, errAmountValueMustBeGreaterThan0) {
		t.Errorf("Binanceus WithdrawCrypto() expecting %v, but found %v", errAmountValueMustBeGreaterThan0, er)
	}
	params.Amount = 1
	if _, er = bi.WithdrawCrypto(context.Background(), params); er != nil && !strings.Contains(er.Error(), "You are not authorized to execute this request.") {
		t.Error("Binanceus WithdrawCrypto() error", er)
	}
}

func TestFiatWithdrawalHistory(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.FiatWithdrawalHistory(context.Background(), &FiatWithdrawalRequestParams{
		FiatCurrency: "USDT",
	})
	if er != nil {
		t.Errorf("%s FiatWithdrawalHistory() error %v", bi.Name, er)
	}
}

func TestDepositHistory(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.DepositHistory(context.Background(), currency.USD, 1, time.Time{}, time.Time{}, 0, 100)
	if er != nil {
		t.Error("Binanceus DepositHistory() error", er)
	}
}
func TestFiatDepositHistory(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.FiatDepositHistory(context.Background(), &FiatWithdrawalRequestParams{})
	if er != nil {
		t.Error("Binanceus FiatDepositHistory() error", er)
	}
}

// WEBSOCKET support testing
// Since both binance and Binance US has same websocket functions,
// the tests functions are also similar

// TestWebsocketStreamKey  this test mmethod handles the
// creating, updating, and deleting of user stream key or "listenKey"
// all the three methods in one test methods.
func TestWebsocketStreamKey(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	_, er := bi.GetWsAuthStreamKey(context.Background())
	if er != nil {
		t.Error("Binanceus GetWsAuthStreamKey() error", er)
	}
	er = bi.MaintainWsAuthStreamKey(context.Background())
	if er != nil {
		t.Error("Binanceus MaintainWsAuthStreamKey() error", er)
	}
	er = bi.CloseUserDataStream(context.Background())
	if er != nil {
		t.Error("Binanceus CloseUserDataStream() error", er)
	}
}

var subscriptionRequestString = `{
	"method": "SUBSCRIBE",
	"params": [
	  "btcusdt@aggTrade",
	  "btcusdt@depth"
	],
	"id": 1
  }`

func TestWebsocketSubscriptionHandling(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	rawData := []byte(subscriptionRequestString)
	err := bi.wsHandleData(rawData)
	if err != nil {
		t.Error("Binanceus wsHandleData() error", err)
	}
}

func TestWebsocketUnsubscriptionHandling(t *testing.T) {
	pressXToJSON := []byte(`{
	"method": "UNSUBSCRIBE",
	"params": [
		"btcusdt@depth"
	],
	"id": 312
	}`)
	err := bi.wsHandleData(pressXToJSON)
	if err != nil {
		t.Error(err)
	}
}

func TestGetSubscriptions(t *testing.T) {
	t.Parallel()
	if _, err := bi.GetSubscriptions(); err != nil {
		t.Error("Binanceus GetSubscriptions() error", err)
	}
}

var ticker24hourChangeStream = `{
	"stream":"btcusdt@ticker",
	"data" :{
		"e": "24hrTicker",  
		"E": 123456789,     
		"s": "BNBBTC",      
		"p": "0.0015",      
		"P": "250.00",      
		"w": "0.0018",      
		"x": "0.0009",      
		"c": "0.0025",      
		"Q": "10",          
		"b": "0.0024",       
		"B": "10",           
		"a": "0.0026",       
		"A": "100",          
		"o": "0.0010",      
		"h": "0.0025",      
		"l": "0.0010",      
		"v": "10000",        
		"q": "18",           
		"O": 0,             
		"C": 86400000,      
		"F": 0,             
		"L": 18150,         
		"n": 18151           
  }
}`

func TestWebsocketTickerUpdate(t *testing.T) {
	t.Parallel()
	if err := bi.wsHandleData([]byte(ticker24hourChangeStream)); err != nil {
		t.Error("Binanceus wsHandleData() for Ticker 24h Change Stream", err)
	}
}

func TestWebsocketKlineUpdate(t *testing.T) {
	t.Parallel()
	pressXToJSON := []byte(`
	{
		"stream":"btcusdt@kline_1m",
		"data":{
			"e": "kline",     
			"E": 123456789,   
			"s": "BNBBTC",    
			"k": {
				"t": 123400000, 
				"T": 123460000, 
				"s": "BNBBTC",  
				"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"   
	  			}
			}
		}`)
	if err := bi.wsHandleData(pressXToJSON); err != nil {
		t.Error("Binanceus wsHandleData() btcusdt@kline_1m stream data conversion ", err)
	}
}

func TestWebsocketStreamTradeUpdate(t *testing.T) {
	t.Parallel()
	pressXToJSON := []byte(`{"stream":"btcusdt@trade","data":{
	  "e": "trade",     
	  "E": 123456789,   
	  "s": "BNBBTC",    
	  "t": 12345,       
	  "p": "0.001",     
	  "q": "100",
	  "b": 88,        
	  "a": 50,          
	  "T": 123456785,
	  "m": true,        
	  "M": true         
	}}`)
	if err := bi.wsHandleData(pressXToJSON); err != nil {
		t.Error("Binanceus wsHandleData() error", err)
	}
}

// TestWsDepthUpdate copied from the Binance Test
func TestWebsocketOrderBookDepthDiffStream(t *testing.T) {
	binanceusOrderBookLock.Lock()
	defer binanceusOrderBookLock.Unlock()
	bi.setupOrderbookManager()
	seedLastUpdateID := int64(161)
	book := OrderBook{
		Asks: []OrderbookItem{
			{Price: 6621.80000000, Quantity: 0.00198100},
			{Price: 6622.14000000, Quantity: 4.00000000},
			{Price: 6622.46000000, Quantity: 2.30000000},
			{Price: 6622.47000000, Quantity: 1.18633300},
			{Price: 6622.64000000, Quantity: 4.00000000},
			{Price: 6622.73000000, Quantity: 0.02900000},
			{Price: 6622.76000000, Quantity: 0.12557700},
			{Price: 6622.81000000, Quantity: 2.08994200},
			{Price: 6622.82000000, Quantity: 0.01500000},
			{Price: 6623.17000000, Quantity: 0.16831300},
		},
		Bids: []OrderbookItem{
			{Price: 6621.55000000, Quantity: 0.16356700},
			{Price: 6621.45000000, Quantity: 0.16352600},
			{Price: 6621.41000000, Quantity: 0.86091200},
			{Price: 6621.25000000, Quantity: 0.16914100},
			{Price: 6621.23000000, Quantity: 0.09193600},
			{Price: 6621.22000000, Quantity: 0.00755100},
			{Price: 6621.13000000, Quantity: 0.08432000},
			{Price: 6621.03000000, Quantity: 0.00172000},
			{Price: 6620.94000000, Quantity: 0.30506700},
			{Price: 6620.93000000, Quantity: 0.00200000},
		},
		LastUpdateID: seedLastUpdateID,
	}
	update1 := []byte(`{"stream":"btcusdt@depth","data":{
	  "e": "depthUpdate", 
	  "E": 123456788,     
	  "s": "BTCUSDT",      
	  "U": 157,           
	  "u": 160,           
	  "b": [              
		["6621.45", "0.3"]
	  ],
	  "a": [              
		["6622.46", "1.5"]
	  ]
	}}`)

	p := currency.NewPairWithDelimiter("BTC", "USDT", "-")
	if err := bi.SeedLocalCacheWithBook(p, &book); err != nil {
		t.Error(err)
	}
	if err := bi.wsHandleData(update1); err != nil {
		t.Error(err)
	}
	bi.obm.state[currency.BTC][currency.USDT][asset.Spot].fetchingBook = false
	ob, err := bi.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": 123456789,     
			"s": "BTCUSDT",      
			"U": 161,           
			"u": 165,           
			"b": [           
				["6621.45", "0.163526"]
			],
			"a": [             
				["6622.46", "2.3"], 
				["6622.47", "1.9"]
			]
		}
	}`)
	if err = bi.wsHandleData(update2); err != nil {
		t.Error("Binanceus wshandlerData error", err)
	}
	ob, err = bi.Websocket.Orderbook.GetOrderbook(p, asset.Spot)
	if err != nil {
		t.Fatal("Binanceus GetOrderBook error", err)
	}
	if exp, got := int64(165), ob.LastUpdateID; got != exp {
		t.Fatalf("Binanceus 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("Binanceus Unexpected Ask amount. Exp: %f, got %f", exp, got)
	}
	if exp, got := 1.9, ob.Asks[3].Amount; got != exp {
		t.Fatalf("Binanceus Unexpected Ask amount. Exp: %f, got %f", exp, got)
	}
	if exp, got := 0.163526, ob.Bids[1].Amount; got != exp {
		t.Fatalf("Binanceus Unexpected Bid amount. Exp: %f, got %f", exp, got)
	}
	bi.obm.state[currency.BTC][currency.USDT][asset.Spot].lastUpdateID = 0
}

// TestWebsocketPartialOrderBookDepthStream copied from the Binance Test
func TestWebsocketPartialOrderBookDepthStream(t *testing.T) {
	t.Parallel()
	update1 := []byte(`{"stream":"btcusdt@depth5","data":
	{
		"lastUpdateId": 160,
		"bids": [           
		  [
			"0.0024",       
			"10"            
		  ]
		],
		"asks": [           
		  [
			"0.0026",       
			"100"           
		  ]
		]
	  }}`)
	var err error
	if err = bi.wsHandleData(update1); err != nil {
		t.Error("Binanceus Partial Order Book Depth Sream error", err)
	}
	update2 := []byte(`{
		"stream":"btcusdt@depth10",
		"data":{
			"lastUpdateId": 160, 
			"bids": [            
					[
						"0.0024",        
						"10"             
					]
			],
			"asks": [            
				[
					"0.0026",        
					"100"            
				]
			]
		}
	  }`)
	if err = bi.wsHandleData(update2); err != nil {
		t.Error("Binanceus Partial Order Book Depth Sream error", err)
	}
}

func TestWebsocketBookTicker(t *testing.T) {
	t.Parallel()
	var bookTickerJSON = []byte(
		`{
		"stream": "btcusdt@bookTicker",
		"data": {
			"u":400900217,   
			"s":"BNBUSDT",  
			"b":"25.35190000",
			"B":"31.21000000",
			"a":"25.36520000",
			"A":"40.66000000" 
		}
	  }`)
	if err := bi.wsHandleData(bookTickerJSON); err != nil {
		t.Error("Binanceus Book Ticker error", err)
	}
	var bookTickerForAllSymbols = []byte(`
	{
		"stream" : "!bookTicker",
		"data":{
			"u":400900217,    
			"s":"BNBUSDT",    
			"b":"25.35190000",
			"B":"31.21000000",
			"a":"25.36520000",
			"A":"40.66000000" 
		}
	}`)
	if err := bi.wsHandleData(bookTickerForAllSymbols); err != nil {
		t.Error("Binanceus Web socket Book ticker for all symbols error", err)
	}
}

func TestWebsocketAggTrade(t *testing.T) {
	t.Parallel()
	var aggTradejson = []byte(
		`{  
			"stream":"btcusdt@aggTrade", 
			"data": {
				"e": "aggTrade",  
				"E": 123456789,   
				"s": "BNBBTC",    
				"a": 12345,       
				"p": "0.001",     
				"q": "100",   
				"f": 100,     
				"l": 105,   
				"T": 123456785,
				"m": true,
				"M": true         
			}
	   }`)
	if err := bi.wsHandleData(aggTradejson); err != nil {
		t.Error("Binanceus Aggregated Trade Order Json() error", err)
	}
}

var balanceUpdateInputJSON = `
{
	"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc",
	"data":{
		"e": "balanceUpdate",         
		"E": 1573200697110,           
		"a": "BTC",                   
		"d": "100.00000000",          
		"T": 1573200697068            
  }
}`

func TestWebsocketBalanceUpdate(t *testing.T) {
	t.Parallel()
	thejson := []byte(balanceUpdateInputJSON)
	if err := bi.wsHandleData(thejson); err != nil {
		t.Error(err)
	}
}

var listStatusUserDataStreamPayload = `
{
	"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"
			}
		]
	}
}`

func TestWebsocketListStatus(t *testing.T) {
	t.Parallel()
	if err := bi.wsHandleData([]byte(listStatusUserDataStreamPayload)); err != nil {
		t.Error(err)
	}
}

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("Binanceus expected: %v, received: %v", testCases[i].Result, result)
		}
	}
}

var websocketDepthUpdate = []byte(
	`{
		"e": "depthUpdate",
		"E": 123456789,    
		"s": "BNBBTC",     
		"U": 157,          
		"u": 160,          
		"b": [             
		  [
			"0.0024",      
			"10"           
		  ]
		],
		"a": [             
		  [
			"0.0026",      
			"100"          
		  ]
		]
	  }
	`)

func TestProcessUpdate(t *testing.T) {
	t.Parallel()
	binanceusOrderBookLock.Lock()
	defer binanceusOrderBookLock.Unlock()
	p := currency.NewPair(currency.BTC, currency.USDT)
	var depth WebsocketDepthStream
	err := json.Unmarshal(websocketDepthUpdate, &depth)
	if err != nil {
		t.Fatal(err)
	}
	err = bi.obm.stageWsUpdate(&depth, p, asset.Spot)
	if err != nil {
		t.Fatal(err)
	}
	err = bi.obm.fetchBookViaREST(p)
	if err != nil {
		t.Fatal(err)
	}
	err = bi.obm.cleanup(p)
	if err != nil {
		t.Fatal(err)
	}
	bi.obm.state[currency.BTC][currency.USDT][asset.Spot].lastUpdateID = 0
}

func TestWebsocketOrderExecutionReport(t *testing.T) {
	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"}}`)
	expectedResult := order.Detail{
		Price:           52789.1,
		Amount:          0.00028400,
		RemainingAmount: 0.00028400,
		CostAsset:       currency.USDT,
		FeeAsset:        currency.BTC,
		Exchange:        "Binanceus",
		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.NewPair(currency.BTC, currency.USDT),
	}
	for len(bi.Websocket.DataHandler) > 0 {
		<-bi.Websocket.DataHandler
	}
	err := bi.wsHandleData(payload)
	if err != nil {
		t.Fatal(err)
	}
	res := <-bi.Websocket.DataHandler
	switch r := res.(type) {
	case *order.Detail:
		if !reflects.DeepEqual(expectedResult, *r) {
			t.Errorf("Binanceus Results do not match:\nexpected: %v\nreceived: %v", expectedResult, *r)
		}
	default:
		t.Fatalf("Binanceus 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"}}`)
	err = bi.wsHandleData(payload)
	if err != nil {
		t.Fatal("Binanceus OrderExecutionReport json conversion error", err)
	}
}

func TestWebsocketOutboundAccountPosition(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 := bi.wsHandleData(payload); err != nil {
		t.Fatal("Binanceus testing \"outboundAccountPosition\" data conversion error", err)
	}
}

func TestGetAvailableTransferChains(t *testing.T) {
	t.Parallel()
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetAvailableTransferChains(context.Background(), currency.BTC); er != nil {
		t.Error("Binanceus GetAvailableTransferChains() error", er)
	}
}

func TestQuickEnableCryptoWithdrawal(t *testing.T) {
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if er := bi.QuickEnableCryptoWithdrawal(context.Background()); er != nil && !strings.Contains(er.Error(), "unexpected end of JSON input") {
		t.Errorf("Binanceus QuickEnableCryptoWithdrawal() expecting %s, but found %v", "unexpected end of JSON input", er)
	}
}
func TestQuickDisableCryptoWithdrawal(t *testing.T) {
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if er := bi.QuickDisableCryptoWithdrawal(context.Background()); er != nil && !strings.Contains(er.Error(), "unexpected end of JSON input") {
		t.Errorf("Binanceus QuickDisableCryptoWithdrawal() expecting %s, but found %v", "unexpected end of JSON input", er)
	}
}

func TestGetUsersSpotAssetSnapshot(t *testing.T) {
	if !areTestAPIKeysSet() {
		t.SkipNow()
	}
	if _, er := bi.GetUsersSpotAssetSnapshot(context.Background(), time.Time{}, time.Time{}, 10, 6); er != nil {
		t.Error("Binanceus GetUsersSpotAssetSnapshot() error", er)
	}
}
