package huobi import ( "crypto/ecdsa" "crypto/rand" "crypto/x509" "encoding/pem" "io/ioutil" "strconv" "strings" "testing" "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" ) // Please supply you own test keys here for due diligence testing. const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false ) var h HUOBI // getDefaultConfig returns a default huobi config func getDefaultConfig() config.ExchangeConfig { return config.ExchangeConfig{ Name: "Huobi", Enabled: true, Verbose: true, Websocket: false, UseSandbox: false, RESTPollingDelay: 10, HTTPTimeout: 15000000000, AuthenticatedAPISupport: true, APIKey: "", APISecret: "", ClientID: "", AvailablePairs: "BTC-USDT,BCH-USDT", EnabledPairs: "BTC-USDT", BaseCurrencies: "USD", AssetTypes: "SPOT", SupportsAutoPairUpdates: false, ConfigCurrencyPairFormat: &config.CurrencyPairFormatConfig{ Uppercase: true, Delimiter: "-", }, RequestCurrencyPairFormat: &config.CurrencyPairFormatConfig{ Uppercase: false, }, } } func TestSetDefaults(t *testing.T) { h.SetDefaults() } func TestSetup(t *testing.T) { cfg := config.GetConfig() cfg.LoadConfig("../../testdata/configtest.json") hConfig, err := cfg.GetExchangeConfig("Huobi") if err != nil { t.Error("Test Failed - Huobi Setup() init error") } hConfig.AuthenticatedAPISupport = true hConfig.APIKey = apiKey hConfig.APISecret = apiSecret h.Setup(hConfig) } func TestGetSpotKline(t *testing.T) { t.Parallel() _, err := h.GetSpotKline(KlinesRequestParams{ Symbol: "btcusdt", Period: TimeIntervalHour, Size: 0, }) if err != nil { t.Errorf("Test failed - Huobi TestGetSpotKline: %s", err) } } func TestGetMarketDetailMerged(t *testing.T) { t.Parallel() _, err := h.GetMarketDetailMerged("btcusdt") if err != nil { t.Errorf("Test failed - Huobi TestGetMarketDetailMerged: %s", err) } } func TestGetDepth(t *testing.T) { t.Parallel() _, err := h.GetDepth(OrderBookDataRequestParams{ Symbol: "btcusdt", Type: OrderBookDataRequestParamsTypeStep1, }) if err != nil { t.Errorf("Test failed - Huobi TestGetDepth: %s", err) } } func TestGetTrades(t *testing.T) { t.Parallel() _, err := h.GetTrades("btcusdt") if err != nil { t.Errorf("Test failed - Huobi TestGetTrades: %s", err) } } func TestGetLatestSpotPrice(t *testing.T) { t.Parallel() _, err := h.GetLatestSpotPrice("btcusdt") if err != nil { t.Errorf("Test failed - Huobi GetLatestSpotPrice: %s", err) } } func TestGetTradeHistory(t *testing.T) { t.Parallel() _, err := h.GetTradeHistory("btcusdt", "50") if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } } func TestGetMarketDetail(t *testing.T) { t.Parallel() _, err := h.GetMarketDetail("btcusdt") if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } } func TestGetSymbols(t *testing.T) { t.Parallel() _, err := h.GetSymbols() if err != nil { t.Errorf("Test failed - Huobi TestGetSymbols: %s", err) } } func TestGetCurrencies(t *testing.T) { t.Parallel() _, err := h.GetCurrencies() if err != nil { t.Errorf("Test failed - Huobi TestGetCurrencies: %s", err) } } func TestGetTimestamp(t *testing.T) { t.Parallel() _, err := h.GetTimestamp() if err != nil { t.Errorf("Test failed - Huobi TestGetTimestamp: %s", err) } } func TestGetAccounts(t *testing.T) { t.Parallel() if h.APIKey == "" || h.APISecret == "" || h.APIAuthPEMKey == "" { t.Skip() } _, err := h.GetAccounts() if err != nil { t.Errorf("Test failed - Huobi GetAccounts: %s", err) } } func TestGetAccountBalance(t *testing.T) { t.Parallel() if h.APIKey == "" || h.APISecret == "" || h.APIAuthPEMKey == "" { t.Skip() } result, err := h.GetAccounts() if err != nil { t.Errorf("Test failed - Huobi GetAccounts: %s", err) } userID := strconv.FormatInt(result[0].ID, 10) _, err = h.GetAccountBalance(userID) if err != nil { t.Errorf("Test failed - Huobi GetAccountBalance: %s", err) } } func TestSpotNewOrder(t *testing.T) { t.Parallel() if h.APIKey == "" || h.APISecret == "" || h.APIAuthPEMKey == "" { t.Skip() } arg := SpotNewOrderRequestParams{ Symbol: "btcusdt", AccountID: 1, Amount: 0.01, Price: 10.1, Type: SpotNewOrderRequestTypeBuyLimit, } _, err := h.SpotNewOrder(arg) if err != nil { t.Errorf("Test failed - Huobi SpotNewOrder: %s", err) } } func TestCancelExistingOrder(t *testing.T) { t.Parallel() _, err := h.CancelExistingOrder(1337) if err == nil { t.Error("Test failed - Huobi TestCancelExistingOrder: Invalid orderID returned true") } } func TestGetOrder(t *testing.T) { t.Parallel() _, err := h.GetOrder(1337) if err == nil { t.Error("Test failed - Huobi TestCancelOrder: Invalid orderID returned true") } } func TestGetMarginLoanOrders(t *testing.T) { t.Parallel() if h.APIKey == "" || h.APISecret == "" || h.APIAuthPEMKey == "" { t.Skip() } _, err := h.GetMarginLoanOrders("btcusdt", "", "", "", "", "", "", "") if err != nil { t.Errorf("Test failed - Huobi TestGetMarginLoanOrders: %s", err) } } func TestGetMarginAccountBalance(t *testing.T) { t.Parallel() if h.APIKey == "" || h.APISecret == "" || h.APIAuthPEMKey == "" { t.Skip() } _, err := h.GetMarginAccountBalance("btcusdt") if err != nil { t.Errorf("Test failed - Huobi TestGetMarginAccountBalance: %s", err) } } func TestCancelWithdraw(t *testing.T) { t.Parallel() _, err := h.CancelWithdraw(1337) if err == nil { t.Error("Test failed - Huobi TestCancelWithdraw: Invalid withdraw-ID was valid") } } func TestPEMLoadAndSign(t *testing.T) { t.Parallel() pemKey := strings.NewReader(h.APIAuthPEMKey) pemBytes, err := ioutil.ReadAll(pemKey) if err != nil { t.Fatalf("Test Failed. TestPEMLoadAndSign Unable to ioutil.ReadAll PEM key: %s", err) } block, _ := pem.Decode(pemBytes) if block == nil { t.Fatalf("Test Failed. TestPEMLoadAndSign Block is nil") } x509Encoded := block.Bytes privKey, err := x509.ParseECPrivateKey(x509Encoded) if err != nil { t.Fatalf("Test Failed. TestPEMLoadAndSign Unable to ParseECPrivKey: %s", err) } _, _, err = ecdsa.Sign(rand.Reader, privKey, common.GetSHA256([]byte("test"))) if err != nil { t.Fatalf("Test Failed. TestPEMLoadAndSign Unable to sign: %s", err) } } func setFeeBuilder() exchange.FeeBuilder { return exchange.FeeBuilder{ Amount: 1, Delimiter: "_", FeeType: exchange.CryptocurrencyTradeFee, FirstCurrency: symbol.BTC, SecondCurrency: symbol.LTC, IsMaker: false, PurchasePrice: 1, CurrencyItem: symbol.USD, BankTransactionType: exchange.WireTransfer, } } func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() // CryptocurrencyTradeFee Basic if resp, err := h.GetFee(feeBuilder); resp != float64(0.002) || err != nil { t.Error(err) t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.002), resp) } // CryptocurrencyTradeFee High quantity feeBuilder = setFeeBuilder() feeBuilder.Amount = 1000 feeBuilder.PurchasePrice = 1000 if resp, err := h.GetFee(feeBuilder); resp != float64(2000) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(2000), resp) t.Error(err) } // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true if resp, err := h.GetFee(feeBuilder); resp != float64(0.002) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.002), resp) t.Error(err) } // CryptocurrencyTradeFee Negative purchase price feeBuilder = setFeeBuilder() feeBuilder.PurchasePrice = -1000 if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } // CryptocurrencyWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } // CryptocurrencyWithdrawalFee Invalid currency feeBuilder = setFeeBuilder() feeBuilder.FirstCurrency = "hello" feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } // CyptocurrencyDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CyptocurrencyDepositFee if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } // InternationalBankDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankDepositFee if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } // InternationalBankWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee feeBuilder.CurrencyItem = symbol.USD if resp, err := h.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) t.Error(err) } } func TestFormatWithdrawPermissions(t *testing.T) { // Arrange h.SetDefaults() expectedResult := exchange.AutoWithdrawCryptoWithSetupText // Act withdrawPermissions := h.FormatWithdrawPermissions() // Assert if withdrawPermissions != expectedResult { t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions) } } // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- func areTestAPIKeysSet() bool { if h.APIKey != "" && h.APIKey != "Key" && h.APISecret != "" && h.APISecret != "Secret" { return true } return false } func TestSubmitOrder(t *testing.T) { h.SetDefaults() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } if (h.APIKey == "" || h.APIKey == "Key") && (h.APISecret == "" || h.APISecret == "Secret") { t.Skip() } var p = pair.CurrencyPair{ Delimiter: "", FirstCurrency: symbol.BTC, SecondCurrency: symbol.USDT, } accounts, err := h.GetAccounts() if err != nil { t.Errorf("Failed to get accounts. Err: %s", err) } response, err := h.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 10, strconv.FormatInt(accounts[0].ID, 10)) if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) { t.Errorf("Order failed to be placed: %v", err) } else if !areTestAPIKeysSet() && err == nil { t.Error("Expecting an error when no keys are set") } } func TestCancelExchangeOrder(t *testing.T) { // Arrange h.SetDefaults() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) var orderCancellation = exchange.OrderCancellation{ OrderID: "1", WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", AccountID: "1", CurrencyPair: currencyPair, } // Act err := h.CancelOrder(orderCancellation) // Assert if !areTestAPIKeysSet() && err == nil { t.Errorf("Expecting an error when no keys are set: %v", err) } if areTestAPIKeysSet() && err != nil { t.Errorf("Could not cancel orders: %v", err) } } func TestCancelAllExchangeOrders(t *testing.T) { // Arrange h.SetDefaults() TestSetup(t) if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) var orderCancellation = exchange.OrderCancellation{ OrderID: "1", WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", AccountID: "1", CurrencyPair: currencyPair, } // Act resp, err := h.CancelAllOrders(orderCancellation) // Assert if !areTestAPIKeysSet() && err == nil { t.Errorf("Expecting an error when no keys are set: %v", err) } if areTestAPIKeysSet() && err != nil { t.Errorf("Could not cancel orders: %v", err) } if len(resp.OrderStatus) > 0 { t.Errorf("%v orders failed to cancel", len(resp.OrderStatus)) } } func TestGetAccountInfo(t *testing.T) { if apiKey == "" || apiSecret == "" { _, err := h.GetAccountInfo() if err == nil { t.Error("Test Failed - GetAccountInfo() error") } } else { _, err := h.GetAccountInfo() if err != nil { t.Error("Test Failed - GetAccountInfo() error", err) } } } func TestModifyOrder(t *testing.T) { _, err := h.ModifyOrder(exchange.ModifyOrder{}) if err == nil { t.Error("Test failed - ModifyOrder() error") } } func TestWithdraw(t *testing.T) { h.SetDefaults() TestSetup(t) var withdrawCryptoRequest = exchange.WithdrawRequest{ Amount: 100, Currency: symbol.BTC, Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", Description: "WITHDRAW IT ALL", } if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } _, err := h.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) if !areTestAPIKeysSet() && err == nil { t.Errorf("Expecting an error when no keys are set: %v", err) } if areTestAPIKeysSet() && err != nil { t.Errorf("Withdraw failed to be placed: %v", err) } }