Files
gocryptotrader/exchanges/binanceus/binanceus_test.go
Ryan O'Hara-Reid d31fa3ff3d types: Add Time type from Gateio and share across codebase (#1648)
* consolidate type to types package and share across code base

* rm convert type and convert codebase

* rm irrelavant test cases

* Fix tests

* glorious nits

* Update exchanges/gateio/gateio_types.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* thrasher: nits

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
2024-10-01 10:46:55 +10:00

1826 lines
58 KiB
Go

package binanceus
import (
"context"
"encoding/json"
"errors"
"log"
"os"
reflects "reflect"
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"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"
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
"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()
os.Exit(m.Run())
}
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
if _, err := bi.FetchAccountInfo(context.Background(), asset.Spot); err != nil {
t.Error("Binanceus FetchAccountInfo() error", err)
}
}
func TestUpdateAccountInfo(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, bi, canManipulateRealOrders)
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 sharedtestvalues.AreAPICredentialsSet(bi) && err != nil && strings.Contains(err.Error(), "{\"code\":-1013,\"msg\":\"Market is closed.\""):
t.Skip("Binanceus SubmitOrder() Market is Closed")
case sharedtestvalues.AreAPICredentialsSet(bi) && err != nil:
t.Errorf("Binanceus SubmitOrder() Could not place order: %v", err)
case sharedtestvalues.AreAPICredentialsSet(bi) && response.Status != order.Filled:
t.Error("Binanceus SubmitOrder() Order not placed")
case !sharedtestvalues.AreAPICredentialsSet(bi) && err == nil:
t.Error("Binanceus SubmitOrder() Expecting an error when no keys are set")
}
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, bi, canManipulateRealOrders)
_, err := bi.GetWithdrawalsHistory(context.Background(), currency.ETH, asset.Spot)
switch {
case sharedtestvalues.AreAPICredentialsSet(bi) && err != nil:
t.Error("Binanceus GetWithdrawalsHistory() error", err)
case !sharedtestvalues.AreAPICredentialsSet(bi) && err == nil:
t.Error("Binanceus GetWithdrawalsHistory() expecting an error when no keys are set")
}
}
func TestWithdrawFiat(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
var getOrdersRequest = order.MultiOrderRequest{
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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 !sharedtestvalues.AreAPICredentialsSet(bi) && 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetAccount(context.Background())
if er != nil {
t.Error("Binanceus GetAccount() error", er)
}
}
func TestGetUserAccountStatus(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetUserAccountStatus(context.Background(), 3000)
if er != nil {
t.Error("Binanceus GetUserAccountStatus() error", er)
}
}
func TestGetUserAPITradingStatus(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetUserAPITradingStatus(context.Background(), 3000)
if er != nil {
t.Error("Binanceus GetUserAPITradingStatus() error", er)
}
}
func TestGetTradeFee(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetTradeFee(context.Background(), 3000, "BTC-USDT")
if er != nil {
t.Error("Binanceus GetTradeFee() error", er)
}
}
func TestGetAssetDistributionHistory(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetAssetDistributionHistory(context.Background(), "", 0, 0, 3000)
if er != nil {
t.Error("Binanceus GetAssetDistributionHistory() error", er)
}
}
func TestGetMasterAccountTotalUSDValue(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetAllOpenOrders(context.Background(), "")
if er != nil {
t.Error("Binanceus GetAllOpenOrders() error", er)
}
}
func TestCancelExistingOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, er := bi.CancelOpenOrdersForSymbol(context.Background(), "")
if !errors.Is(er, errMissingCurrencySymbol) {
t.Errorf("Binanceus CancelOpenOrdersForSymbol() error expecting %v, but found %v", errIncompleteArguments, er)
}
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetAllOCOOrder(context.Background(), &OCOOrdersRequestParams{})
if er != nil {
t.Error("Binanceus GetAllOCOOrder() error", er)
}
}
func TestGetOpenOCOOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetOpenOCOOrders(context.Background(), 0)
if er != nil {
t.Error("Binanceus GetOpenOCOOrders() error", er)
}
}
func TestCancelOCOOrder(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
if _, er := bi.GetAllOCBSTradeOrders(context.Background(), OCBSOrderRequestParams{}); er != nil {
t.Error("Binanceus GetAllOCBSTradeOrders() error", er)
}
}
func TestGetAssetFeesAndWalletStatus(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, er := bi.GetAssetFeesAndWalletStatus(context.Background())
if er != nil {
t.Error("Binanceus GetAssetFeesAndWalletStatus() error", er)
}
}
func TestWithdrawCrypto(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi, canManipulateRealOrders)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
_, 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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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": 1234567891,
"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": 8640000011,
"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": 1234567891,
"s": "BNBBTC",
"k": {
"t": 1234000001,
"T": 1234600001,
"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": 1234567891,
"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.Fatal(err)
}
if err := bi.wsHandleData(update1); err != nil {
t.Fatal(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": 1234567892,
"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": 12345678911,
"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()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
if _, er := bi.GetAvailableTransferChains(context.Background(), currency.BTC); er != nil {
t.Error("Binanceus GetAvailableTransferChains() error", er)
}
}
func TestQuickEnableCryptoWithdrawal(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
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) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, bi)
if _, er := bi.GetUsersSpotAssetSnapshot(context.Background(), time.Time{}, time.Time{}, 10, 6); er != nil {
t.Error("Binanceus GetUsersSpotAssetSnapshot() error", er)
}
}
func TestGetCurrencyTradeURL(t *testing.T) {
t.Parallel()
testexch.UpdatePairsOnce(t, bi)
for _, a := range bi.GetAssetTypes(false) {
pairs, err := bi.CurrencyPairs.GetPairs(a, false)
require.NoError(t, err, "cannot get pairs for %s", a)
require.NotEmpty(t, pairs, "no pairs for %s", a)
resp, err := bi.GetCurrencyTradeURL(context.Background(), a, pairs[0])
require.NoError(t, err)
assert.NotEmpty(t, resp)
}
}