From b1e6534e7c58d99d4bf3503fd028cbc14cbdbfd4 Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 3 Jan 2019 13:15:07 +1100 Subject: [PATCH] Withdraw Crypto wrapper mapping (#226) * Initial commit * Updates signature for all withdrawal methods to use new withdrawRequest struct type * Implements crypto withdraw features & tests for Alphapoint, ANX, Binance, Bitfinex, Bitflyer, Bithumb, Bitmex, Bitstamp, Bittrex, BTCC, BTCmarkets, CoinbasePro, Coinut. Updates WithdrawRequest type with more members. Breaking change to update real order testing for increased code coverage * Updates all realOrder tests to run when no API key is present. Updates exchange functions to handle errors better * Implements crypto withdrawals for Exmo, GateIO, Gemini, HitBTC, Huobi, HuobiHadax, Kraken, LakeBTC, Liqui, Localbitcoins, OKCoin, OKEX, Poloniex, Wex, Yobit and ZB. Updates real order test formatting for all real order tests * Update alphapoint. Fixes anx typos. Adds function WithdrawFiatFundsToInternationalBank to exchange wrapper interface. Adds WithdrawFiatFundsToInternationalBank to alphapoint, bitmex, coinbasepro. Updates Kraken to use TradePassword property * Reverts alphapoint to use ErrNotYetImplemented * Fixes line spacing and removes unnecessary line --- exchanges/alphapoint/alphapoint_test.go | 65 ++++++++--- exchanges/alphapoint/alphapoint_wrapper.go | 10 +- exchanges/anx/anx_test.go | 61 +++++++--- exchanges/anx/anx_wrapper.go | 11 +- exchanges/binance/binance.go | 53 +++++++++ exchanges/binance/binance_test.go | 67 +++++++---- exchanges/binance/binance_types.go | 7 ++ exchanges/binance/binance_wrapper.go | 11 +- exchanges/bitfinex/bitfinex.go | 60 +++++++++- exchanges/bitfinex/bitfinex_test.go | 76 +++++++----- exchanges/bitfinex/bitfinex_wrapper.go | 22 +++- exchanges/bitflyer/bitflyer_test.go | 65 ++++++----- exchanges/bitflyer/bitflyer_wrapper.go | 6 +- exchanges/bithumb/bithumb.go | 4 +- exchanges/bithumb/bithumb_test.go | 64 +++++++--- exchanges/bithumb/bithumb_wrapper.go | 9 +- exchanges/bitmex/bitmex_parameters.go | 4 +- exchanges/bitmex/bitmex_test.go | 65 ++++++++--- exchanges/bitmex/bitmex_wrapper.go | 25 +++- exchanges/bitstamp/bitstamp.go | 27 ++--- exchanges/bitstamp/bitstamp_test.go | 64 +++++++--- exchanges/bitstamp/bitstamp_types.go | 5 + exchanges/bitstamp/bitstamp_wrapper.go | 16 ++- exchanges/bittrex/bittrex.go | 2 +- exchanges/bittrex/bittrex_test.go | 73 +++++++----- exchanges/bittrex/bittrex_wrapper.go | 10 +- exchanges/btcc/btcc_test.go | 60 ++++++---- exchanges/btcc/btcc_wrapper.go | 6 +- exchanges/btcmarkets/btcmarkets_test.go | 78 ++++++++----- exchanges/btcmarkets/btcmarkets_wrapper.go | 12 +- exchanges/coinbasepro/coinbasepro_test.go | 64 +++++++--- exchanges/coinbasepro/coinbasepro_wrapper.go | 13 ++- exchanges/coinut/coinut_test.go | 63 +++++++--- exchanges/coinut/coinut_wrapper.go | 12 +- exchanges/exchange.go | 28 ++++- exchanges/exmo/exmo.go | 43 +++++-- exchanges/exmo/exmo_test.go | 69 +++++++---- exchanges/exmo/exmo_wrapper.go | 10 +- exchanges/gateio/gateio.go | 26 +++++ exchanges/gateio/gateio_test.go | 58 ++++++--- exchanges/gateio/gateio_wrapper.go | 8 +- exchanges/gemini/gemini.go | 2 +- exchanges/gemini/gemini_test.go | 110 +++++++++++++----- exchanges/gemini/gemini_types.go | 2 + exchanges/gemini/gemini_wrapper.go | 17 ++- exchanges/hitbtc/hitbtc_test.go | 64 +++++++--- exchanges/hitbtc/hitbtc_wrapper.go | 10 +- exchanges/huobi/huobi.go | 9 +- exchanges/huobi/huobi_test.go | 71 ++++++++--- exchanges/huobi/huobi_types.go | 3 +- exchanges/huobi/huobi_wrapper.go | 13 ++- exchanges/huobihadax/huobihadax.go | 31 +++-- exchanges/huobihadax/huobihadax_test.go | 68 ++++++++--- exchanges/huobihadax/huobihadax_types.go | 3 +- exchanges/huobihadax/huobihadax_wrapper.go | 13 ++- exchanges/itbit/itbit_test.go | 63 +++++++--- exchanges/itbit/itbit_wrapper.go | 14 +-- exchanges/kraken/kraken.go | 19 +++ exchanges/kraken/kraken_test.go | 65 ++++++++--- exchanges/kraken/kraken_wrapper.go | 12 +- exchanges/lakebtc/lakebtc.go | 14 ++- exchanges/lakebtc/lakebtc_test.go | 75 +++++++----- exchanges/lakebtc/lakebtc_types.go | 1 + exchanges/lakebtc/lakebtc_wrapper.go | 19 ++- exchanges/liqui/liqui.go | 24 +++- exchanges/liqui/liqui_test.go | 69 +++++++---- exchanges/liqui/liqui_wrapper.go | 17 ++- exchanges/localbitcoins/localbitcoins.go | 4 +- exchanges/localbitcoins/localbitcoins_test.go | 64 +++++++--- .../localbitcoins/localbitcoins_wrapper.go | 9 +- exchanges/okcoin/okcoin.go | 2 +- exchanges/okcoin/okcoin_test.go | 68 ++++++++--- exchanges/okcoin/okcoin_types.go | 5 +- exchanges/okcoin/okcoin_wrapper.go | 17 +-- exchanges/okex/okex.go | 28 ++++- exchanges/okex/okex_test.go | 66 ++++++++--- exchanges/okex/okex_types.go | 6 + exchanges/okex/okex_wrapper.go | 9 +- exchanges/poloniex/poloniex_test.go | 64 +++++++--- exchanges/poloniex/poloniex_wrapper.go | 9 +- exchanges/wex/wex_test.go | 64 +++++++--- exchanges/wex/wex_wrapper.go | 9 +- exchanges/yobit/yobit_test.go | 64 +++++++--- exchanges/yobit/yobit_wrapper.go | 16 ++- exchanges/zb/zb.go | 31 +++++ exchanges/zb/zb_test.go | 63 +++++++--- exchanges/zb/zb_wrapper.go | 8 +- tools/exchange_template/wrapper_file.tmpl | 6 +- 88 files changed, 2050 insertions(+), 802 deletions(-) diff --git a/exchanges/alphapoint/alphapoint_test.go b/exchanges/alphapoint/alphapoint_test.go index beba68aa..e7a825f1 100644 --- a/exchanges/alphapoint/alphapoint_test.go +++ b/exchanges/alphapoint/alphapoint_test.go @@ -495,21 +495,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled(a *Alphapoint) bool { - if a.APIKey == "" || a.APISecret == "" || - a.APIKey == "Key" || a.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet(a *Alphapoint) bool { + if a.APIKey != "" && a.APIKey != "Key" && + a.APISecret != "" && a.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { a := &Alphapoint{} a.SetDefaults() - if !isRealOrderTestEnabled(a) { - t.Skip() + if areTestAPIKeysSet(a) && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ Delimiter: "_", @@ -517,8 +516,15 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := a.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { - t.Errorf("Order failed to be placed: %v", err) + if !areTestAPIKeysSet(a) && err == nil { + t.Errorf("Expecting an error when no keys are set: %v", err) + } + if areTestAPIKeysSet(a) && err != nil { + t.Errorf("Withdraw failed to be placed: %v", err) + + if !response.IsOrderPlaced { + t.Errorf("Order failed to be placed: %v", err) + } } } @@ -527,8 +533,8 @@ func TestCancelExchangeOrder(t *testing.T) { a := &Alphapoint{} a.SetDefaults() - if !isRealOrderTestEnabled(a) { - t.Skip() + if areTestAPIKeysSet(a) && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC) @@ -543,8 +549,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := a.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Test Failed - ANX CancelOrder() error: %s", err) + if !areTestAPIKeysSet(a) && err == nil { + t.Errorf("Expecting an error when no keys are set: %v", err) + } + if areTestAPIKeysSet(a) && err != nil { + t.Errorf("Withdraw failed to be placed: %v", err) } } @@ -553,8 +562,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { a := &Alphapoint{} a.SetDefaults() - if !isRealOrderTestEnabled(a) { - t.Skip() + if areTestAPIKeysSet(a) && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC) @@ -569,8 +578,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := a.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + if !areTestAPIKeysSet(a) && err == nil { + t.Errorf("Expecting an error when no keys are set: %v", err) + } + if areTestAPIKeysSet(a) && err != nil { + t.Errorf("Withdraw failed to be placed: %v", err) } if len(resp.OrderStatus) > 0 { @@ -587,3 +599,20 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + a := &Alphapoint{} + a.SetDefaults() + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + AddressTag: "0123456789", + } + + _, err := a.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not implemented', recieved %v", err) + } +} diff --git a/exchanges/alphapoint/alphapoint_wrapper.go b/exchanges/alphapoint/alphapoint_wrapper.go index e14cc136..d14f27ee 100644 --- a/exchanges/alphapoint/alphapoint_wrapper.go +++ b/exchanges/alphapoint/alphapoint_wrapper.go @@ -180,12 +180,18 @@ func (a *Alphapoint) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (a *Alphapoint) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { +func (a *Alphapoint) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFunds returns a withdrawal ID when a withdrawal is submitted -func (a *Alphapoint) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (a *Alphapoint) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrNotYetImplemented +} + +// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is +// submitted +func (a *Alphapoint) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/anx/anx_test.go b/exchanges/anx/anx_test.go index 5127dff6..55263f31 100644 --- a/exchanges/anx/anx_test.go +++ b/exchanges/anx/anx_test.go @@ -230,21 +230,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if a.APIKey == "" || a.APISecret == "" || - a.APIKey == "Key" || a.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if a.APIKey != "" && a.APIKey != "Key" && + a.APISecret != "" && a.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { a.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ Delimiter: "_", @@ -252,8 +251,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := a.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -262,8 +263,8 @@ func TestCancelExchangeOrder(t *testing.T) { a.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC) @@ -278,8 +279,10 @@ func TestCancelExchangeOrder(t *testing.T) { err := a.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Test Failed - ANX CancelOrder() error: %s", err) + if areTestAPIKeysSet() && err != nil { + t.Errorf("Could not cancel order: %s", err) + } else if !areTestAPIKeysSet() && err == nil { + t.Errorf("Expecting an error when no keys are set: %v", err) } } @@ -288,8 +291,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { a.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC) @@ -304,8 +307,10 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := a.CancelAllOrders(orderCancellation) // Assert - if err != nil { + if areTestAPIKeysSet() && err != nil { t.Errorf("Could not cancel order: %s", err) + } else if !areTestAPIKeysSet() && err == nil { + t.Errorf("Expecting an error when no keys are set: %v", err) } if len(resp.OrderStatus) > 0 { @@ -333,3 +338,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + a.SetDefaults() + TestSetup(t) + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + AddressTag: "0123456789", + } + + _, err := a.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if areTestAPIKeysSet() && err != nil { + t.Errorf("Withdraw failed to be placed: %v", err) + } else if !areTestAPIKeysSet() && err == nil { + t.Error("Expecting an error when no keys are set") + } +} diff --git a/exchanges/anx/anx_wrapper.go b/exchanges/anx/anx_wrapper.go index 13710a73..1484e705 100644 --- a/exchanges/anx/anx_wrapper.go +++ b/exchanges/anx/anx_wrapper.go @@ -1,6 +1,7 @@ package anx import ( + "fmt" "log" "strconv" "sync" @@ -310,19 +311,21 @@ func (a *ANX) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, error // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (a *ANX) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (a *ANX) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return a.Send(withdrawRequest.Currency.String(), withdrawRequest.Address, "", fmt.Sprintf("%v", withdrawRequest.Amount)) } // WithdrawFiatFunds returns a withdrawal ID when a withdrawal is // submitted -func (a *ANX) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (a *ANX) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + // Fiat withdrawals available via website return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is // submitted -func (a *ANX) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (a *ANX) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { + // Fiat withdrawals available via website return "", common.ErrNotYetImplemented } diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index 92a50727..e9408af5 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -51,6 +51,17 @@ const ( openOrders = "/api/v3/openOrders" allOrders = "/api/v3/allOrders" + // Withdraw API endpoints + withdraw = "/wapi/v3/withdraw.html" + depositHistory = "/wapi/v3/depositHistory.html" + withdrawalHistory = "/wapi/v3/withdrawHistory.html" + depositAddress = "/wapi/v3/depositAddress.html" + accountStatus = "/wapi/v3/accountStatus.html" + systemStatus = "/wapi/v3/systemStatus.html" + dustLog = "/wapi/v3/userAssetDribbletLog.html" + tradeFee = "/wapi/v3/tradeFee.html" + assetDetail = "/wapi/v3/assetDetail.html" + // binance authenticated and unauthenticated limit rates // to-do binanceAuthRate = 0 @@ -702,3 +713,45 @@ func calculateTradingFee(purchasePrice, amount, multiplier float64) float64 { func getCryptocurrencyWithdrawalFee(currency string, purchasePrice, amount float64) float64 { return WithdrawalFees[currency] } + +// WithdrawCrypto sends cryptocurrency to the address of your choosing +func (b *Binance) WithdrawCrypto(asset, address, addressTag, name, amount string) (int64, error) { + var resp WithdrawResponse + path := fmt.Sprintf("%s%s", b.APIUrl, withdraw) + + params := url.Values{} + params.Set("asset", asset) + params.Set("address", string(address)) + params.Set("amount", string(amount)) + if len(name) > 0 { + params.Set("name", string(name)) + } + if len(addressTag) > 0 { + params.Set("addressTag", string(addressTag)) + } + + if err := b.SendAuthHTTPRequest("POST", path, params, &resp); err != nil { + return -1, err + } + + if !resp.Success { + return resp.ID, errors.New(resp.Msg) + } + + return resp.ID, nil +} + + +//GetDepositAddressForCurrency retrieves the wallet address for a given currency +func (b *Binance) GetDepositAddressForCurrency(currency string) error { + path := fmt.Sprintf("%s%s", b.APIUrl, depositAddress) + var resp interface{} + params := url.Values{} + params.Set("asset", currency) + + if err := b.SendAuthHTTPRequest("GET", path, params, &resp); err != nil { + return err + } + + return nil +} diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index cd3f683b..2fecc28b 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -334,31 +334,28 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ----------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() - } - var p = pair.CurrencyPair{ Delimiter: "", FirstCurrency: symbol.LTC, SecondCurrency: symbol.BTC, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -367,10 +364,6 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() - } - currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) var orderCancellation = exchange.OrderCancellation{ @@ -384,8 +377,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -394,10 +390,6 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() - } - currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) var orderCancellation = exchange.OrderCancellation{ @@ -411,8 +403,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 order: %v", err) } if len(resp.OrderStatus) > 0 { @@ -421,6 +416,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { } func TestGetAccountInfo(t *testing.T) { + b.SetDefaults() + TestSetup(t) if testAPIKey == "" || testAPISecret == "" { t.Skip() } @@ -437,3 +434,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + _, err := b.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) + } +} diff --git a/exchanges/binance/binance_types.go b/exchanges/binance/binance_types.go index dafa9679..f9f22c26 100644 --- a/exchanges/binance/binance_types.go +++ b/exchanges/binance/binance_types.go @@ -616,3 +616,10 @@ var WithdrawalFees = map[string]float64{ symbol.APPC: 12.4, symbol.PIVX: 0.02, } + +// WithdrawResponse contains status of withdrawal request +type WithdrawResponse struct { + Success bool `json:"success"` + Msg string `json:"msg"` + ID int64 `json:"id"` +} diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index a9a46775..716f2d2b 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -270,19 +270,22 @@ func (b *Binance) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, e // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Binance) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Binance) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + amountStr := strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64) + id, err := b.WithdrawCrypto(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Description, amountStr) + + return strconv.FormatInt(id, 10), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Binance) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Binance) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Binance) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Binance) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bitfinex/bitfinex.go b/exchanges/bitfinex/bitfinex.go index 5e5f4e42..16014669 100644 --- a/exchanges/bitfinex/bitfinex.go +++ b/exchanges/bitfinex/bitfinex.go @@ -11,6 +11,7 @@ import ( "github.com/gorilla/websocket" "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/request" "github.com/thrasher-/gocryptotrader/exchanges/ticker" @@ -582,15 +583,18 @@ func (b *Bitfinex) WalletTransfer(amount float64, currency, walletFrom, walletTo b.SendAuthenticatedHTTPRequest("POST", bitfinexTransfer, request, &response) } -// Withdrawal requests a withdrawal from one of your wallets. -// Major Upgrade needed on this function to include all query params -func (b *Bitfinex) Withdrawal(withdrawType, wallet, address string, amount float64) ([]Withdrawal, error) { +// WithdrawCryptocurrency requests a withdrawal from one of your wallets. +// For FIAT, use WithdrawFIAT +func (b *Bitfinex) WithdrawCryptocurrency(withdrawType, wallet, address, currency, paymentID string, amount float64) ([]Withdrawal, error) { response := []Withdrawal{} request := make(map[string]interface{}) - request["withdrawal_type"] = withdrawType + request["withdraw_type"] = withdrawType request["walletselected"] = wallet request["amount"] = strconv.FormatFloat(amount, 'f', -1, 64) request["address"] = address + if currency == symbol.XMR { + request["paymend_id"] = paymentID + } return response, b.SendAuthenticatedHTTPRequest("POST", bitfinexWithdrawal, request, &response) @@ -999,3 +1003,51 @@ func (b *Bitfinex) CalculateTradingFee(accountInfos []AccountInfo, purchasePrice } return (fee / 100) * purchasePrice * amount, err } + +// ConvertSymbolToWithdrawalType You need to have specific withdrawal types to withdraw from Bitfinex +func (b *Bitfinex) ConvertSymbolToWithdrawalType(currency string) string { + switch currency { + case symbol.BTC: + return "bitcoin" + case symbol.LTC: + return "litecoin" + case symbol.ETH: + return "ethereum" + case symbol.ETC: + return "ethereumc" + case symbol.USDT: + return "tetheruso" + case "Wire": + return "wire" + case symbol.ZEC: + return "zcash" + case symbol.XMR: + return "monero" + case symbol.DSH: + return "dash" + case symbol.XRP: + return "ripple" + case symbol.SAN: + return "santiment" + case symbol.OMG: + return "omisego" + case symbol.BCH: + return "bcash" + case symbol.ETP: + return "metaverse" + case symbol.AVT: + return "aventus" + case symbol.EDO: + return "eidoo" + case symbol.BTG: + return "bgold" + case symbol.DATA: + return "datacoin" + case symbol.GNT: + return "golem" + case symbol.SNT: + return "status" + default: + return common.StringToLower(currency) + } +} diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index 989f3c4d..06329f62 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -336,18 +336,6 @@ func TestWalletTransfer(t *testing.T) { } } -func TestWithdrawal(t *testing.T) { - if b.APIKey == "" || b.APISecret == "" { - t.SkipNow() - } - t.Parallel() - - _, err := b.Withdrawal("LITECOIN", "deposit", "1000", 0.01) - if err == nil { - t.Error("Test Failed - Withdrawal() error") - } -} - func TestNewOrder(t *testing.T) { if b.APIKey == "" || b.APISecret == "" { t.SkipNow() @@ -722,21 +710,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ Delimiter: "", @@ -744,8 +731,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.BTC, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -754,8 +743,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -771,8 +760,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -781,8 +773,8 @@ func TestCancelAllExchangeOrdera(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -798,8 +790,11 @@ func TestCancelAllExchangeOrdera(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -813,3 +808,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + _, err := b.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) + } +} diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 8bf37569..e0012d91 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -1,6 +1,7 @@ package bitfinex import ( + "errors" "fmt" "log" "net/url" @@ -233,19 +234,32 @@ func (b *Bitfinex) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, } // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is submitted -func (b *Bitfinex) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Bitfinex) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + withdrawalType := b.ConvertSymbolToWithdrawalType(withdrawRequest.Currency.String()) + // Bitfinex has support for three types, exchange, margin and deposit + // As this is for trading, I've made the wrapper default 'exchange' + // TODO: Discover an automated way to make the decision for wallet type to withdraw from + walletType := "exchange" + resp, err := b.WithdrawCryptocurrency(withdrawalType, walletType, withdrawRequest.Address, withdrawRequest.Currency.String(), withdrawRequest.Description, withdrawRequest.Amount) + if err != nil { + return "", err + } + if len(resp) == 0 { + return "", errors.New("No withdrawID returned. Check order status") + } + + return fmt.Sprintf("%v", resp[0].WithdrawalID), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitfinex) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitfinex) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitfinex) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitfinex) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bitflyer/bitflyer_test.go b/exchanges/bitflyer/bitflyer_test.go index 817e64aa..be4eb24b 100644 --- a/exchanges/bitflyer/bitflyer_test.go +++ b/exchanges/bitflyer/bitflyer_test.go @@ -4,6 +4,7 @@ import ( "log" "testing" + "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/currency/symbol" "github.com/thrasher-/gocryptotrader/exchanges" @@ -250,30 +251,30 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } + var p = pair.CurrencyPair{ Delimiter: "", FirstCurrency: symbol.LTC, SecondCurrency: symbol.BTC, } - response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { - t.Errorf("Order failed to be placed: %v", err) + _, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } @@ -282,12 +283,11 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -297,10 +297,9 @@ func TestCancelExchangeOrder(t *testing.T) { // Act err := b.CancelOrder(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } @@ -309,12 +308,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -323,15 +321,30 @@ func TestCancelAllExchangeOrders(t *testing.T) { } // Act - resp, err := b.CancelAllOrders(orderCancellation) - + _, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) + } +} + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", } - if len(resp.OrderStatus) > 0 { - t.Errorf("%v orders failed to cancel", len(resp.OrderStatus)) + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := b.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index bcfdb9eb..7d525cb4 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -190,19 +190,19 @@ func (b *Bitflyer) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bitflyer) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitflyer) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitflyer) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitflyer) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitflyer) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitflyer) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bithumb/bithumb.go b/exchanges/bithumb/bithumb.go index b1a2db05..7f99e362 100644 --- a/exchanges/bithumb/bithumb.go +++ b/exchanges/bithumb/bithumb.go @@ -447,7 +447,9 @@ func (b *Bithumb) WithdrawCrypto(address, destination, currency string, units fl params := url.Values{} params.Set("address", address) - params.Set("destination", destination) + if len(destination) > 0 { + params.Set("destination", destination) + } params.Set("currency", common.StringToUpper(currency)) params.Set("units", strconv.FormatFloat(units, 'f', -1, 64)) diff --git a/exchanges/bithumb/bithumb_test.go b/exchanges/bithumb/bithumb_test.go index c08de81c..44a4c334 100644 --- a/exchanges/bithumb/bithumb_test.go +++ b/exchanges/bithumb/bithumb_test.go @@ -289,21 +289,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -312,8 +311,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.LTC, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -322,8 +323,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -339,8 +340,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 order: %v", err) } } @@ -349,8 +353,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -366,8 +370,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 order: %v", err) } if len(resp.OrderStatus) > 0 { @@ -401,3 +408,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test Failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + _, err := b.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) + } +} diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 2fcdb69d..670bfcf7 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -250,19 +250,20 @@ func (b *Bithumb) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, e // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bithumb) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Bithumb) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + _, err := b.WithdrawCrypto(withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Currency.String(), withdrawRequest.Amount) + return "", err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Bithumb) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bithumb) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Bithumb) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bithumb) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bitmex/bitmex_parameters.go b/exchanges/bitmex/bitmex_parameters.go index 2216a01b..e5155c66 100644 --- a/exchanges/bitmex/bitmex_parameters.go +++ b/exchanges/bitmex/bitmex_parameters.go @@ -1089,7 +1089,7 @@ type UserRequestWithdrawalParams struct { Address string `json:"address,omitempty"` // Amount - Amount of withdrawal currency. - Amount int64 `json:"amount,omitempty"` + Amount float64 `json:"amount,omitempty"` // Currency - Currency you're withdrawing. Options: `XBt` Currency string `json:"currency,omitempty"` @@ -1100,7 +1100,7 @@ type UserRequestWithdrawalParams struct { Fee float64 `json:"fee,omitempty"` // OtpToken - 2FA token. Required if 2FA is enabled on your account. - OtpToken string `json:"otpToken,omitempty"` + OtpToken int64 `json:"otpToken,omitempty"` } // VerifyData verifies outgoing data sets diff --git a/exchanges/bitmex/bitmex_test.go b/exchanges/bitmex/bitmex_test.go index 9bc60779..692c677b 100644 --- a/exchanges/bitmex/bitmex_test.go +++ b/exchanges/bitmex/bitmex_test.go @@ -467,21 +467,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -490,8 +489,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -500,8 +501,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -517,8 +518,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -527,8 +531,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -544,8 +548,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -573,3 +580,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test Failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: "XBt", + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + OneTimePassword: 000000, + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := b.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) + } +} diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 58c5bba9..f26f3c2b 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -256,19 +256,34 @@ func (b *Bitmex) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bitmex) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Bitmex) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + var request = UserRequestWithdrawalParams{ + Address: withdrawRequest.Address, + Amount: withdrawRequest.Amount, + Currency: withdrawRequest.Currency.String(), + OtpToken: withdrawRequest.OneTimePassword, + } + if withdrawRequest.FeeAmount > 0 { + request.Fee = withdrawRequest.FeeAmount + } + + resp, err := b.UserRequestWithdrawal(request) + if err != nil { + return "", err + } + + return resp.TransactID, nil } // WithdrawFiatFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bitmex) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitmex) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } -// WithdrawExchangeFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is +// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is // submitted -func (b *Bitmex) WithdrawExchangeFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitmex) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bitstamp/bitstamp.go b/exchanges/bitstamp/bitstamp.go index 613f82c2..460977ad 100644 --- a/exchanges/bitstamp/bitstamp.go +++ b/exchanges/bitstamp/bitstamp.go @@ -483,15 +483,12 @@ func (b *Bitstamp) GetWithdrawalRequests(timedelta int64) ([]WithdrawalRequests, // symbol - the type of crypto ie "ltc", "btc", "eth" // destTag - only for XRP default to "" // instant - only for bitcoins -func (b *Bitstamp) CryptoWithdrawal(amount float64, address, symbol, destTag string, instant bool) (string, error) { +func (b *Bitstamp) CryptoWithdrawal(amount float64, address, symbol, destTag string, instant bool) (CryptoWithdrawalResponse, error) { var req = url.Values{} req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64)) req.Add("address", address) - - type response struct { - ID string `json:"id"` - } - resp := response{} + resp := CryptoWithdrawalResponse{} + var endpoint string switch common.StringToLower(symbol) { case "btc": @@ -500,23 +497,21 @@ func (b *Bitstamp) CryptoWithdrawal(amount float64, address, symbol, destTag str } else { req.Add("instant", "0") } - return resp.ID, - b.SendAuthenticatedHTTPRequest(bitstampAPIBitcoinWithdrawal, false, req, &resp) + endpoint = bitstampAPIBitcoinWithdrawal case "ltc": - return resp.ID, - b.SendAuthenticatedHTTPRequest(bitstampAPILTCWithdrawal, true, req, &resp) + endpoint = bitstampAPILTCWithdrawal case "eth": - return resp.ID, - b.SendAuthenticatedHTTPRequest(bitstampAPIETHWithdrawal, true, req, &resp) + endpoint = bitstampAPIETHWithdrawal case "xrp": if destTag != "" { req.Add("destination_tag", destTag) } - return resp.ID, - b.SendAuthenticatedHTTPRequest(bitstampAPIXrpWithdrawal, true, req, &resp) + endpoint = bitstampAPIXrpWithdrawal + default: + return resp, errors.New("incorrect symbol") } - return resp.ID, - errors.New("incorrect symbol") + + return resp, b.SendAuthenticatedHTTPRequest(endpoint, false, req, &resp) } // GetCryptoDepositAddress returns a depositing address by crypto diff --git a/exchanges/bitstamp/bitstamp_test.go b/exchanges/bitstamp/bitstamp_test.go index 8ae193a1..2af8e59b 100644 --- a/exchanges/bitstamp/bitstamp_test.go +++ b/exchanges/bitstamp/bitstamp_test.go @@ -370,21 +370,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -393,8 +392,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -403,8 +404,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -420,8 +421,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -430,8 +434,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -447,8 +451,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -462,3 +469,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.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 := b.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) + } +} diff --git a/exchanges/bitstamp/bitstamp_types.go b/exchanges/bitstamp/bitstamp_types.go index af376d78..68b19b99 100644 --- a/exchanges/bitstamp/bitstamp_types.go +++ b/exchanges/bitstamp/bitstamp_types.go @@ -122,6 +122,11 @@ type WithdrawalRequests struct { TransactionID string `json:"transaction_id"` // Bitcoin withdrawals only } +type CryptoWithdrawalResponse struct { + ID string `json:"id"` + Error string `json:"error"` +} + // UnconfirmedBTCTransactions holds address information about unconfirmed // transactions type UnconfirmedBTCTransactions struct { diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 257a1633..b59d0432 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -225,19 +225,27 @@ func (b *Bitstamp) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bitstamp) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Bitstamp) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := b.CryptoWithdrawal(withdrawRequest.Amount, withdrawRequest.Address, withdrawRequest.Currency.String(), withdrawRequest.AddressTag, true) + if err != nil { + return "", err + } + if resp.Error != "" { + return "", errors.New(resp.Error) + } + + return resp.ID, nil } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitstamp) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitstamp) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Bitstamp) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bitstamp) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/bittrex/bittrex.go b/exchanges/bittrex/bittrex.go index 77c3304c..0b5eafa8 100644 --- a/exchanges/bittrex/bittrex.go +++ b/exchanges/bittrex/bittrex.go @@ -390,7 +390,7 @@ func (b *Bittrex) Withdraw(currency, paymentID, address string, quantity float64 var id UUID values := url.Values{} values.Set("currency", currency) - values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64)) + values.Set("quantity", fmt.Sprintf("%v", quantity)) values.Set("address", address) path := fmt.Sprintf("%s/%s", b.APIUrl, bittrexAPIWithdraw) diff --git a/exchanges/bittrex/bittrex_test.go b/exchanges/bittrex/bittrex_test.go index 1718456d..89eba6ea 100644 --- a/exchanges/bittrex/bittrex_test.go +++ b/exchanges/bittrex/bittrex_test.go @@ -176,15 +176,6 @@ func TestGetDepositAddress(t *testing.T) { } } -func TestWithdraw(t *testing.T) { - t.Parallel() - - _, err := b.Withdraw("btc", "something", "someplace", 1) - if err == nil { - t.Error("Test Failed - Bittrex - Withdraw() error") - } -} - func TestGetOrder(t *testing.T) { t.Parallel() @@ -335,21 +326,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -358,8 +348,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.LTC, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -368,8 +360,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -385,8 +377,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -395,8 +390,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -412,8 +407,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -427,3 +425,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := b.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) + } +} diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 316cc0a6..12534372 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -2,6 +2,7 @@ package bittrex import ( "errors" + "fmt" "log" "sync" @@ -242,19 +243,20 @@ func (b *Bittrex) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, e // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *Bittrex) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (b *Bittrex) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + uuid, err := b.Withdraw(withdrawRequest.Currency.String(), withdrawRequest.AddressTag, withdrawRequest.Address, withdrawRequest.Amount) + return fmt.Sprintf("%v", uuid), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *Bittrex) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bittrex) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *Bittrex) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *Bittrex) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/btcc/btcc_test.go b/exchanges/btcc/btcc_test.go index 16fcf02a..d5a1f041 100644 --- a/exchanges/btcc/btcc_test.go +++ b/exchanges/btcc/btcc_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" @@ -173,21 +174,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -195,9 +195,9 @@ func TestSubmitOrder(t *testing.T) { FirstCurrency: symbol.BTC, SecondCurrency: symbol.LTC, } - response, err := b.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { - t.Errorf("Order failed to be placed: %v", err) + _, err := b.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } @@ -206,8 +206,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -223,8 +223,8 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } @@ -233,8 +233,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -247,15 +247,31 @@ func TestCancelAllExchangeOrders(t *testing.T) { } // Act - resp, err := b.CancelAllOrders(orderCancellation) + _, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) + } +} + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", } - if len(resp.OrderStatus) > 0 { - t.Errorf("%v orders failed to cancel", len(resp.OrderStatus)) + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := b.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if err != common.ErrNotYetImplemented { + t.Errorf("Expected 'Not Yet Implemented', recieved %v", err) } } diff --git a/exchanges/btcc/btcc_wrapper.go b/exchanges/btcc/btcc_wrapper.go index 9a9e4dea..14c7fad4 100644 --- a/exchanges/btcc/btcc_wrapper.go +++ b/exchanges/btcc/btcc_wrapper.go @@ -186,19 +186,19 @@ func (b *BTCC) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, erro // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (b *BTCC) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { +func (b *BTCC) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *BTCC) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *BTCC) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *BTCC) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *BTCC) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index 19b1a00b..62fd8ef1 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -169,20 +169,6 @@ func TestGetOrderInfo(t *testing.T) { } } -func TestWithdrawCryptocurrencyFunds(t *testing.T) { - _, err := b.WithdrawCryptocurrencyFunds("someaddress", "ltc", 0) - if err == nil { - t.Error("Test failed - WithdrawExchangeFunds() error", err) - } -} - -func TestWithdrawFiatFunds(t *testing.T) { - _, err := b.WithdrawFiatFunds("AUD", 0) - if err == nil { - t.Error("Test failed - WithdrawFiatFunds() error", err) - } -} - func setFeeBuilder() exchange.FeeBuilder { return exchange.FeeBuilder{ Amount: 1, @@ -292,21 +278,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if b.APIKey == "" || b.APISecret == "" || - b.APIKey == "Key" || b.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if b.APIKey != "" && b.APIKey != "Key" && + b.APISecret != "" && b.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -315,8 +300,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.LTC, } response, err := b.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -325,8 +312,8 @@ func TestCancelExchangeOrder(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -342,8 +329,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := b.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -352,8 +342,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { b.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -369,8 +359,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := b.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -384,3 +377,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + b.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := b.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) + } +} diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index c7fc7bab..6cb47d9b 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -261,23 +261,23 @@ func (b *BTCMarkets) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string } // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is submitted -func (b *BTCMarkets) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return b.WithdrawCrypto(amount, cryptocurrency.String(), address) +func (b *BTCMarkets) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return b.WithdrawCrypto(withdrawRequest.Amount, withdrawRequest.Currency.String(), withdrawRequest.Address) } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (b *BTCMarkets) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { - bd, err := b.GetClientBankAccounts(b.Name, currency.Upper().String()) +func (b *BTCMarkets) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + bd, err := b.GetClientBankAccounts(b.Name, withdrawRequest.Currency.Upper().String()) if err != nil { return "", err } - return b.WithdrawAUD(bd.AccountName, bd.AccountNumber, bd.BankName, bd.BSBNumber, amount) + return b.WithdrawAUD(bd.AccountName, bd.AccountNumber, bd.BankName, bd.BSBNumber, withdrawRequest.Amount) } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (b *BTCMarkets) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (b *BTCMarkets) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 8836ad33..672d1b71 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -409,21 +409,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if c.APIKey == "" || c.APISecret == "" || - c.APIKey == "Key" || c.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if c.APIKey != "" && c.APIKey != "Key" && + c.APISecret != "" && c.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -432,8 +431,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.LTC, } response, err := c.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 1, "clientId") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -442,8 +443,8 @@ func TestCancelExchangeOrder(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -459,8 +460,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := c.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -469,8 +473,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -486,8 +490,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := c.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -501,3 +508,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + c.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := c.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) + } +} diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index 247aef2c..a09a5cad 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -199,13 +199,20 @@ func (c *CoinbasePro) GetDepositAddress(cryptocurrency pair.CurrencyItem) (strin // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (c *CoinbasePro) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (c *CoinbasePro) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := c.WithdrawCrypto(withdrawRequest.Amount, withdrawRequest.Currency.String(), withdrawRequest.Address) + return resp.ID, err } // WithdrawFiatFunds returns a withdrawal ID when a withdrawal is // submitted -func (c *CoinbasePro) WithdrawFiatFunds(cryptocurrency pair.CurrencyItem, amount float64) (string, error) { +func (c *CoinbasePro) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrNotYetImplemented +} + +// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a +// withdrawal is submitted +func (c *CoinbasePro) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/coinut/coinut_test.go b/exchanges/coinut/coinut_test.go index 4ecbff10..b993695b 100644 --- a/exchanges/coinut/coinut_test.go +++ b/exchanges/coinut/coinut_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" @@ -194,22 +195,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - - if c.APIKey == "" || - c.APIKey == "Key" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if c.APIKey != "" && c.APIKey != "Key" && + c.APISecret != "" && c.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -218,8 +217,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := c.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 10, "1234234") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -228,8 +229,8 @@ func TestCancelExchangeOrder(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -245,8 +246,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := c.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -255,8 +259,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { c.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -272,8 +276,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := c.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -301,3 +308,23 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + c.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := c.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if err != common.ErrFunctionNotSupported { + t.Errorf("Expected 'Not supported', recieved %v", err) + } +} diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index 8455bee4..67548468 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -352,20 +352,20 @@ func (c *COINUT) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (c *COINUT) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (c *COINUT) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (c *COINUT) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (c *COINUT) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (c *COINUT) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (c *COINUT) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // GetWebsocket returns a pointer to the exchange websocket diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 069aa737..4fe99ba6 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -98,6 +98,29 @@ type OrderCancellation struct { Side OrderSide } +// WithdrawRequest used for wrapper crypto and FIAT withdraw methods +type WithdrawRequest struct { + // Exchange related information + Description string + OneTimePassword int64 + AccountID string + PIN int64 + TradePassword string + // Crypto related information + Currency pair.CurrencyItem + Address string + AddressTag string + Amount float64 + FeeAmount float64 + // FIAT related information + BankName string + BankAddress string + BankCity string + BankCountry string + SwiftCode string + WireCurrency string +} + // Definitions for each type of withdrawal method for a given exchange const ( // No withdraw @@ -268,8 +291,9 @@ type IBotExchange interface { GetOrderInfo(orderID int64) (OrderDetail, error) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, error) - WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) - WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) + WithdrawCryptocurrencyFunds(wtihdrawRequest WithdrawRequest) (string, error) + WithdrawFiatFunds(wtihdrawRequest WithdrawRequest) (string, error) + WithdrawFiatFundsToInternationalBank(wtihdrawRequest WithdrawRequest) (string, error) GetWebsocket() (*Websocket, error) } diff --git a/exchanges/exmo/exmo.go b/exchanges/exmo/exmo.go index a93562e3..e29cb30f 100644 --- a/exchanges/exmo/exmo.go +++ b/exchanges/exmo/exmo.go @@ -1,6 +1,7 @@ package exmo import ( + "errors" "fmt" "log" "net/url" @@ -171,7 +172,9 @@ func (e *EXMO) GetUserInfo() (UserInfo, error) { // Type can be buy, sell, market_buy, market_sell, market_buy_total and market_sell_total func (e *EXMO) CreateOrder(pair, orderType string, price, amount float64) (int64, error) { type response struct { - OrderID int64 `json:"order_id"` + OrderID int64 `json:"order_id"` + Result bool `json:"result"` + Error string `json:"error"` } v := url.Values{} @@ -180,17 +183,28 @@ func (e *EXMO) CreateOrder(pair, orderType string, price, amount float64) (int64 v.Set("price", strconv.FormatFloat(price, 'f', -1, 64)) v.Set("quantity", strconv.FormatFloat(amount, 'f', -1, 64)) - var result response - err := e.SendAuthenticatedHTTPRequest("POST", exmoOrderCreate, v, &result) - return result.OrderID, err + var resp response + err := e.SendAuthenticatedHTTPRequest("POST", exmoOrderCreate, v, &resp) + if !resp.Result { + return -1, errors.New(resp.Error) + } + return resp.OrderID, err } // CancelExistingOrder cancels an order by the orderID func (e *EXMO) CancelExistingOrder(orderID int64) error { v := url.Values{} v.Set("order_id", strconv.FormatInt(orderID, 10)) - var result interface{} - return e.SendAuthenticatedHTTPRequest("POST", exmoOrderCancel, v, &result) + type response struct { + Result bool `json:"result"` + Error string `json:"error"` + } + var resp response + err := e.SendAuthenticatedHTTPRequest("POST", exmoOrderCancel, v, &resp) + if !resp.Result { + return errors.New(resp.Error) + } + return err } // GetOpenOrders returns the users open orders @@ -268,7 +282,10 @@ func (e *EXMO) GetCryptoDepositAddress() (map[string]string, error) { // NOTE: This API function is available only after request to their tech support team func (e *EXMO) WithdrawCryptocurrency(currency, address, invoice string, amount float64) (int64, error) { type response struct { - TaskID int64 `json:"task_id,string"` + TaskID int64 `json:"task_id,string"` + Result bool `json:"result"` + Error string `json:"error"` + Success int64 `json:"success"` } v := url.Values{} @@ -280,9 +297,15 @@ func (e *EXMO) WithdrawCryptocurrency(currency, address, invoice string, amount } v.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64)) - var result response - err := e.SendAuthenticatedHTTPRequest("POST", exmoWithdrawCrypt, v, &result) - return result.TaskID, err + var resp response + err := e.SendAuthenticatedHTTPRequest("POST", exmoWithdrawCrypt, v, &resp) + if err != nil { + return -1, err + } + if resp.Success == 0 || !resp.Result { + return -1, errors.New(resp.Error) + } + return resp.TaskID, err } // GetWithdrawTXID gets the result of a withdrawal request diff --git a/exchanges/exmo/exmo_test.go b/exchanges/exmo/exmo_test.go index 9fbc91bc..be0b4ccd 100644 --- a/exchanges/exmo/exmo_test.go +++ b/exchanges/exmo/exmo_test.go @@ -250,21 +250,19 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if e.APIKey == "" || e.APISecret == "" || - e.APIKey == "Key" || e.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if e.APIKey != "" && e.APIKey != "Key" && + e.APISecret != "" && e.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { e.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -273,8 +271,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := e.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -282,9 +282,8 @@ func TestCancelExchangeOrder(t *testing.T) { // Arrange e.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -298,10 +297,12 @@ func TestCancelExchangeOrder(t *testing.T) { // Act err := e.CancelOrder(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -310,12 +311,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { e.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -325,10 +325,12 @@ func TestCancelAllExchangeOrders(t *testing.T) { // Act resp, err := e.CancelAllOrders(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -342,3 +344,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + e.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := e.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) + } +} diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index 536809c8..364cce71 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -255,19 +255,21 @@ func (e *EXMO) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, erro // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (e *EXMO) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (e *EXMO) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := e.WithdrawCryptocurrency(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Amount) + + return fmt.Sprintf("%v", resp), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (e *EXMO) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (e *EXMO) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (e *EXMO) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (e *EXMO) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/gateio/gateio.go b/exchanges/gateio/gateio.go index e69b600c..d17af1d0 100644 --- a/exchanges/gateio/gateio.go +++ b/exchanges/gateio/gateio.go @@ -28,6 +28,7 @@ const ( gateioBalances = "private/balances" gateioCancelOrder = "private/cancelOrder" gateioCancelAllOrders = "private/cancelAllOrders" + gateioWithdraw = "private/withdraw" gateioOpenOrders = "private/openOrders" gateioTicker = "ticker" gateioTickers = "tickers" @@ -508,3 +509,28 @@ func calculateTradingFee(feeForPair, purchasePrice, amount float64) float64 { func getCryptocurrencyWithdrawalFee(currency string) float64 { return WithdrawalFees[currency] } + +// WithdrawCrypto withdraws cryptocurrency to your selected wallet +func (g *Gateio) WithdrawCrypto(currency, address string, amount float64) (string, error) { + type response struct { + Result bool `json:"result"` + Message string `json:"message"` + Code int `json:"code"` + } + + var result response + params := fmt.Sprintf("currency=%v&amount=%v&address=%v", + currency, + address, + amount, + ) + err := g.SendAuthenticatedHTTPRequest("POST", gateioWithdraw, params, &result) + if err != nil { + return "", err + } + if !result.Result { + return "", fmt.Errorf("code:%d message:%s", result.Code, result.Message) + } + + return "", nil +} diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index 78c484a2..401494ef 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -252,20 +252,19 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if g.APIKey == "" || g.APISecret == "" || - g.APIKey == "Key" || g.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if g.APIKey != "" && g.APIKey != "Key" && + g.APISecret != "" && g.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { g.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip() } @@ -275,8 +274,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.BTC, } response, err := g.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -285,7 +286,7 @@ func TestCancelExchangeOrder(t *testing.T) { g.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip() } @@ -302,8 +303,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := g.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -312,7 +316,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { g.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip() } @@ -329,8 +333,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := g.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -358,3 +365,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + g.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := g.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) + } +} diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index cd1e9666..912ac275 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -268,19 +268,19 @@ func (g *Gateio) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (g *Gateio) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (g *Gateio) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return g.WithdrawCrypto(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.Amount) } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (g *Gateio) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (g *Gateio) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (g *Gateio) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (g *Gateio) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index 99d98695..2aaee6a5 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -436,7 +436,7 @@ func (g *Gemini) WithdrawCrypto(address, currency string, amount float64) (Withd request["address"] = address request["amount"] = strconv.FormatFloat(amount, 'f', -1, 64) - err := g.SendAuthenticatedHTTPRequest("POST", geminiWithdraw+currency, nil, &response) + err := g.SendAuthenticatedHTTPRequest("POST", geminiWithdraw+common.StringToLower(currency), request, &response) if err != nil { return response, err } diff --git a/exchanges/gemini/gemini_test.go b/exchanges/gemini/gemini_test.go index e983234b..18dbbf85 100644 --- a/exchanges/gemini/gemini_test.go +++ b/exchanges/gemini/gemini_test.go @@ -23,23 +23,28 @@ const ( apiKeyRole2 = "" sessionHeartBeat2 = false - canManipulateRealOrders = false + canManipulateRealOrders = !false ) func TestAddSession(t *testing.T) { var g1 Gemini - err := AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false) - if err != nil { - t.Error("Test failed - AddSession() error") + if Session[1] == nil { + err := AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false) + if err != nil { + t.Error("Test failed - AddSession() error", err) + } + err = AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false) + if err == nil { + t.Error("Test failed - AddSession() error", err) + } } - err = AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, false) - if err == nil { - t.Error("Test failed - AddSession() error") - } - var g2 Gemini - err = AddSession(&g2, 2, apiKey2, apiSecret2, apiKeyRole2, false, true) - if err != nil { - t.Error("Test failed - AddSession() error") + + if len(Session) <= 1 { + var g2 Gemini + err := AddSession(&g2, 2, apiKey2, apiSecret2, apiKeyRole2, false, true) + if err != nil { + t.Error("Test failed - AddSession() error", err) + } } } @@ -61,6 +66,13 @@ func TestSetup(t *testing.T) { Session[1].Setup(geminiConfig) Session[2].Setup(geminiConfig) + + Session[1].APIKey = apiKey1 + Session[1].APISecret = apiSecret1 + + Session[2].APIKey = apiKey2 + Session[2].APISecret = apiSecret2 + } func TestGetSymbols(t *testing.T) { @@ -326,21 +338,21 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if Session[1].APIKey == "" || Session[1].APISecret == "" || - Session[1].APIKey == "Key" || Session[1].APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if Session[1].APIKey != "" && Session[1].APIKey != "Key" && + Session[1].APISecret != "" && Session[1].APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { - Session[1].SetDefaults() + TestAddSession(t) + TestSetDefaults(t) TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -349,18 +361,21 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.BTC, } response, err := Session[1].SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") - if err != nil || !response.IsOrderPlaced { + 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 - Session[1].SetDefaults() + TestAddSession(t) + TestSetDefaults(t) TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -376,18 +391,22 @@ func TestCancelExchangeOrder(t *testing.T) { err := Session[1].CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 - Session[1].SetDefaults() + TestAddSession(t) + TestSetDefaults(t) TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -403,8 +422,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := Session[1].CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -418,3 +440,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + TestAddSession(t) + TestSetDefaults(t) + 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 := Session[1].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) + } +} diff --git a/exchanges/gemini/gemini_types.go b/exchanges/gemini/gemini_types.go index 79ddcfb4..f31d20ea 100644 --- a/exchanges/gemini/gemini_types.go +++ b/exchanges/gemini/gemini_types.go @@ -179,6 +179,8 @@ type WithdrawalAddress struct { Amount float64 `json:"amount"` TXHash string `json:"txHash"` Message string `json:"message"` + Result string `json:"result"` + Reason string `json:"reason"` } // ErrorCapture is a generlized error response from the server diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index 49a561d2..bfe7273d 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -1,6 +1,7 @@ package gemini import ( + "errors" "fmt" "log" "net/url" @@ -191,19 +192,27 @@ func (g *Gemini) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (g *Gemini) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (g *Gemini) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := g.WithdrawCrypto(withdrawRequest.Address, withdrawRequest.Currency.String(), withdrawRequest.Amount) + if err != nil { + return "", err + } + if resp.Result == "error" { + return "", errors.New(resp.Message) + } + + return resp.TXHash, err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (g *Gemini) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (g *Gemini) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (g *Gemini) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (g *Gemini) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/hitbtc/hitbtc_test.go b/exchanges/hitbtc/hitbtc_test.go index 968d4590..82cc8a27 100644 --- a/exchanges/hitbtc/hitbtc_test.go +++ b/exchanges/hitbtc/hitbtc_test.go @@ -177,21 +177,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if h.APIKey == "" || h.APISecret == "" || - h.APIKey == "Key" || h.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if h.APIKey != "" && h.APIKey != "Key" && + h.APISecret != "" && h.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -200,8 +199,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.BTC, } response, err := h.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "1234234") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -210,8 +211,8 @@ func TestCancelExchangeOrder(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -227,8 +228,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := h.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -237,8 +241,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -254,8 +258,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := h.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -269,3 +276,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + h.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + 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) + } +} diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index da7d0c58..5162969f 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -220,19 +220,21 @@ func (h *HitBTC) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (h *HitBTC) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (h *HitBTC) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + _, err := h.Withdraw(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.Amount) + + return "", err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (h *HitBTC) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HitBTC) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (h *HitBTC) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HitBTC) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/huobi/huobi.go b/exchanges/huobi/huobi.go index c2a6671b..b478ede8 100644 --- a/exchanges/huobi/huobi.go +++ b/exchanges/huobi/huobi.go @@ -20,6 +20,7 @@ import ( "github.com/gorilla/websocket" "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/symbol" exchange "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/request" "github.com/thrasher-/gocryptotrader/exchanges/ticker" @@ -778,19 +779,19 @@ func (h *HUOBI) Withdraw(address, currency, addrTag string, amount, fee float64) Address string `json:"address"` Amount string `json:"amount"` Currency string `json:"currency"` - Fee string `json:"fee"` - AddrTag string `json:"addr-tag"` + Fee string `json:"fee,omitempty"` + AddrTag string `json:"addr-tag,omitempty"` }{ Address: address, Currency: currency, Amount: strconv.FormatFloat(amount, 'f', -1, 64), } - if fee != 0 { + if fee > 0 { data.Fee = strconv.FormatFloat(fee, 'f', -1, 64) } - if currency == "XRP" { + if currency == symbol.XRP { data.AddrTag = addrTag } diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index 179cb62a..3d32073e 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -398,20 +398,24 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if h.APIKey == "" || h.APISecret == "" || - h.APIKey == "Key" || h.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if h.APIKey != "" && h.APIKey != "Key" && + h.APISecret != "" && h.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + 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() } @@ -420,14 +424,17 @@ func TestSubmitOrder(t *testing.T) { 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 err != nil || !response.IsOrderPlaced { + 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") } } @@ -436,8 +443,8 @@ func TestCancelExchangeOrder(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -453,8 +460,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := h.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -462,13 +472,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { // Arrange h.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -478,10 +486,12 @@ func TestCancelAllExchangeOrders(t *testing.T) { // Act resp, err := h.CancelAllOrders(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -509,3 +519,26 @@ func TestModifyOrder(t *testing.T) { 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) + } +} diff --git a/exchanges/huobi/huobi_types.go b/exchanges/huobi/huobi_types.go index 714cc2d1..e131190d 100644 --- a/exchanges/huobi/huobi_types.go +++ b/exchanges/huobi/huobi_types.go @@ -28,7 +28,8 @@ type CancelOpenOrdersBatch struct { NextID int `json:"next-id"` SuccessCount int `json:"success-count"` } `json:"data"` - Status string `json:"status"` + Status string `json:"status"` + ErrorMessage string `json:"err-msg"` } // DetailMerged stores the ticker detail merged data diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 8f8ed65d..768e050c 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -314,6 +314,10 @@ func (h *HUOBI) CancelAllOrders(orderCancellation exchange.OrderCancellation) (e if resp.Data.FailedCount > 0 { return cancelAllOrdersResponse, fmt.Errorf("%v orders failed to cancel", resp.Data.FailedCount) } + + if resp.Status == "error" { + return cancelAllOrdersResponse, errors.New(resp.ErrorMessage) + } } return cancelAllOrdersResponse, nil @@ -332,19 +336,20 @@ func (h *HUOBI) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, err // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (h *HUOBI) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (h *HUOBI) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := h.Withdraw(withdrawRequest.Address, withdrawRequest.Currency.Lower().String(), withdrawRequest.AddressTag, withdrawRequest.Amount, withdrawRequest.FeeAmount) + return fmt.Sprintf("%v", resp), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (h *HUOBI) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HUOBI) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (h *HUOBI) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HUOBI) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/huobihadax/huobihadax.go b/exchanges/huobihadax/huobihadax.go index bb941dda..c4a75794 100644 --- a/exchanges/huobihadax/huobihadax.go +++ b/exchanges/huobihadax/huobihadax.go @@ -12,6 +12,7 @@ import ( "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" + "github.com/thrasher-/gocryptotrader/currency/symbol" "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/request" "github.com/thrasher-/gocryptotrader/exchanges/ticker" @@ -755,22 +756,30 @@ func (h *HUOBIHADAX) Withdraw(address, currency, addrTag string, amount, fee flo Response WithdrawID int64 `json:"data"` } - - vals := url.Values{} - vals.Set("address", address) - vals.Set("currency", currency) - vals.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64)) - - if fee != 0 { - vals.Set("fee", strconv.FormatFloat(fee, 'f', -1, 64)) + data := struct { + Address string `json:"address"` + Amount string `json:"amount"` + Currency string `json:"currency"` + Fee string `json:"fee,omitempty"` + AddrTag string `json:"addr-tag,omitempty"` + }{ + Address: address, + Currency: currency, + Amount: strconv.FormatFloat(amount, 'f', -1, 64), } - if currency == "XRP" { - vals.Set("addr-tag", addrTag) + if fee > 0 { + data.Fee = strconv.FormatFloat(fee, 'f', -1, 64) + } + + if currency == symbol.XRP { + data.AddrTag = addrTag } var result response - err := h.SendAuthenticatedHTTPRequest("POST", huobihadaxWithdrawCreate, vals, &result) + bytesParams, _ := common.JSONEncode(data) + postBodyParams := string(bytesParams) + err := h.SendAuthenticatedHTTPPostRequest("POST", huobihadaxWithdrawCreate, postBodyParams, &result) if result.ErrorMessage != "" { return 0, errors.New(result.ErrorMessage) diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index 91ee5a82..5956c5a5 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -377,20 +377,24 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if h.APIKey == "" || h.APISecret == "" || - h.APIKey == "Key" || h.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if h.APIKey != "" && h.APIKey != "Key" && + h.APISecret != "" && h.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + 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() } @@ -406,18 +410,21 @@ func TestSubmitOrder(t *testing.T) { } response, err := h.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 10, strconv.FormatInt(accounts[0].ID, 10)) - if err != nil || !response.IsOrderPlaced { + 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 !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -433,8 +440,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := h.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -443,8 +453,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { h.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -460,8 +470,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := h.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -489,3 +502,26 @@ func TestModifyOrder(t *testing.T) { 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) + } +} diff --git a/exchanges/huobihadax/huobihadax_types.go b/exchanges/huobihadax/huobihadax_types.go index f8c3df88..c4059aec 100644 --- a/exchanges/huobihadax/huobihadax_types.go +++ b/exchanges/huobihadax/huobihadax_types.go @@ -53,7 +53,8 @@ type CancelOpenOrdersBatch struct { NextID int `json:"next-id"` SuccessCount int `json:"success-count"` } `json:"data"` - Status string `json:"status"` + Status string `json:"status"` + ErrorMessage string `json:"err-msg"` } // TradeHistory stores the the trade history data diff --git a/exchanges/huobihadax/huobihadax_wrapper.go b/exchanges/huobihadax/huobihadax_wrapper.go index 94ecfc58..4d00b134 100644 --- a/exchanges/huobihadax/huobihadax_wrapper.go +++ b/exchanges/huobihadax/huobihadax_wrapper.go @@ -279,6 +279,10 @@ func (h *HUOBIHADAX) CancelAllOrders(orderCancellation exchange.OrderCancellatio if resp.Data.FailedCount > 0 { return cancelAllOrdersResponse, fmt.Errorf("%v orders failed to cancel", resp.Data.FailedCount) } + + if resp.Status == "error" { + return cancelAllOrdersResponse, errors.New(resp.ErrorMessage) + } } return cancelAllOrdersResponse, nil @@ -297,19 +301,20 @@ func (h *HUOBIHADAX) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (h *HUOBIHADAX) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (h *HUOBIHADAX) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := h.Withdraw(withdrawRequest.Address, withdrawRequest.Currency.Lower().String(), withdrawRequest.AddressTag, withdrawRequest.Amount, withdrawRequest.FeeAmount) + return fmt.Sprintf("%v", resp), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (h *HUOBIHADAX) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HUOBIHADAX) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (h *HUOBIHADAX) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (h *HUOBIHADAX) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/itbit/itbit_test.go b/exchanges/itbit/itbit_test.go index bd2ce04c..90f96a2f 100644 --- a/exchanges/itbit/itbit_test.go +++ b/exchanges/itbit/itbit_test.go @@ -4,6 +4,7 @@ import ( "net/url" "testing" + "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/symbol" @@ -246,21 +247,19 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if i.APIKey == "" || i.APISecret == "" || - i.APIKey == "Key" || i.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if i.APIKey != "" && i.APIKey != "Key" && + i.APISecret != "" && i.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { i.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -269,8 +268,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USDT, } response, err := i.SubmitOrder(p, exchange.Buy, exchange.Limit, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -279,8 +280,8 @@ func TestCancelExchangeOrder(t *testing.T) { i.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -296,8 +297,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := i.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -306,8 +310,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { i.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -323,8 +327,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := i.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -347,3 +354,23 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + i.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := i.WithdrawCryptocurrencyFunds(withdrawCryptoRequest) + if err != common.ErrFunctionNotSupported { + t.Errorf("Expected 'Not supported', recieved %v", err) + } +} diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index e0f8c9d4..56b8961a 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -168,7 +168,7 @@ func (i *ItBit) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderT var submitOrderResponse exchange.SubmitOrderResponse var wallet string - wallets, err := i.GetWallets(nil) + wallets, err := i.GetWallets(url.Values{}) if err != nil { return submitOrderResponse, err } @@ -243,20 +243,20 @@ func (i *ItBit) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, err // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (i *ItBit) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (i *ItBit) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (i *ItBit) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (i *ItBit) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (i *ItBit) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (i *ItBit) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // GetWebsocket returns a pointer to the exchange websocket diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index 4a8389f2..e6897c40 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -40,6 +40,7 @@ const ( krakenOrderCancel = "CancelOrder" krakenOrderPlace = "AddOrder" krakenWithdrawInfo = "WithdrawInfo" + krakenWithdraw = "Withdraw" krakenDepositMethods = "DepositMethods" krakenAuthRate = 0 @@ -469,6 +470,24 @@ func (k *Kraken) GetWithdrawInfo(currency string, amount float64) (WithdrawInfor return response.Result, GetError(response.Error) } +// Withdraw withdraws funds +func (k *Kraken) Withdraw(asset, key string, amount float64) (string, error) { + var response struct { + Error []string `json:"error"` + ReferenceID string `json:"refid"` + } + params := url.Values{} + params.Set("asset", asset) + params.Set("key", key) + params.Set("amount", fmt.Sprintf("%f", amount)) + + if err := k.SendAuthenticatedHTTPRequest(krakenWithdraw, params, &response); err != nil { + return response.ReferenceID, err + } + + return response.ReferenceID, GetError(response.Error) +} + // GetDepositMethods gets withdrawal fees func (k *Kraken) GetDepositMethods(currency string) ([]DepositMethods, error) { var response struct { diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index bf1681cc..9e6ec5cb 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -332,21 +332,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if k.APIKey == "" || k.APISecret == "" || - k.APIKey == "Key" || k.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if k.APIKey != "" && k.APIKey != "Key" && + k.APISecret != "" && k.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { k.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -355,8 +354,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.CAD, } response, err := k.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -365,8 +366,8 @@ func TestCancelExchangeOrder(t *testing.T) { k.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -382,8 +383,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := k.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -392,8 +396,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { k.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -409,8 +413,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := k.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -438,3 +445,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + k.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.XXBT, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "donation", + TradePassword: "Key", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := k.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) + } +} diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index d7d47116..7fbded3f 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -240,21 +240,21 @@ func (k *Kraken) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er return "", common.ErrNotYetImplemented } -// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is -// submitted -func (k *Kraken) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal +// Populate exchange.WithdrawRequest.TradePassword with withdrawal key name, as set up on your account +func (k *Kraken) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return k.Withdraw(withdrawRequest.Currency.String(), withdrawRequest.TradePassword, withdrawRequest.Amount) } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (k *Kraken) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (k *Kraken) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (k *Kraken) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (k *Kraken) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go index cea4b98e..ce8c5243 100644 --- a/exchanges/lakebtc/lakebtc.go +++ b/exchanges/lakebtc/lakebtc.go @@ -317,11 +317,19 @@ func (l *LakeBTC) GetExternalAccounts() ([]ExternalAccounts, error) { // CreateWithdraw allows your to withdraw to external account WARNING: Only for // BTC! -func (l *LakeBTC) CreateWithdraw(amount float64, accountID int64) (Withdraw, error) { +func (l *LakeBTC) CreateWithdraw(amount float64, accountID string) (Withdraw, error) { resp := Withdraw{} - params := strconv.FormatFloat(amount, 'f', -1, 64) + ",btc," + strconv.FormatInt(accountID, 10) + params := strconv.FormatFloat(amount, 'f', -1, 64) + ",btc," + accountID - return resp, l.SendAuthenticatedHTTPRequest(lakeBTCCreateWithdraw, params, &resp) + err := l.SendAuthenticatedHTTPRequest(lakeBTCCreateWithdraw, params, &resp) + if err != nil { + return Withdraw{}, err + } + if len(resp.Error) > 0 { + return resp, errors.New(resp.Error) + } + + return resp, nil } // SendHTTPRequest sends an unauthenticated http request diff --git a/exchanges/lakebtc/lakebtc_test.go b/exchanges/lakebtc/lakebtc_test.go index b9d92947..e04d6378 100644 --- a/exchanges/lakebtc/lakebtc_test.go +++ b/exchanges/lakebtc/lakebtc_test.go @@ -135,17 +135,6 @@ func TestGetExternalAccounts(t *testing.T) { } } -func TestCreateWithdraw(t *testing.T) { - t.Parallel() - if l.APIKey == "" || l.APISecret == "" { - t.Skip() - } - _, err := l.CreateWithdraw(0, 1337) - if err == nil { - t.Error("Test Failed - CreateWithdraw() error", err) - } -} - func setFeeBuilder() exchange.FeeBuilder { return exchange.FeeBuilder{ Amount: 1, @@ -250,21 +239,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if l.APIKey == "" || l.APISecret == "" || - l.APIKey == "Key" || l.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if l.APIKey != "" && l.APIKey != "Key" && + l.APISecret != "" && l.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -273,8 +261,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.EUR, } response, err := l.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -283,8 +273,8 @@ func TestCancelExchangeOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -300,8 +290,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := l.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -310,8 +303,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -327,8 +320,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := l.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -342,3 +338,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + l.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "7860767916", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := l.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) + } +} diff --git a/exchanges/lakebtc/lakebtc_types.go b/exchanges/lakebtc/lakebtc_types.go index ffbf6fd1..dd890073 100644 --- a/exchanges/lakebtc/lakebtc_types.go +++ b/exchanges/lakebtc/lakebtc_types.go @@ -110,4 +110,5 @@ type Withdraw struct { Source string `json:"source"` ExternalAccountID int64 `json:"external_account_id,string"` At int64 `json:"at"` + Error string `json:"error"` } diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go index 8d788ae7..24601a9f 100644 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ b/exchanges/lakebtc/lakebtc_wrapper.go @@ -1,6 +1,7 @@ package lakebtc import ( + "errors" "fmt" "log" "strconv" @@ -8,6 +9,7 @@ import ( "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/currency/pair" + "github.com/thrasher-/gocryptotrader/currency/symbol" "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/orderbook" "github.com/thrasher-/gocryptotrader/exchanges/ticker" @@ -205,19 +207,28 @@ func (l *LakeBTC) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, e // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (l *LakeBTC) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (l *LakeBTC) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + if withdrawRequest.Currency.String() != symbol.BTC { + return "", errors.New("Only BTC supported for withdrawals") + } + + resp, err := l.CreateWithdraw(withdrawRequest.Amount, withdrawRequest.Description) + if err != nil { + return "", err + } + + return fmt.Sprintf("%v", resp.ID), nil } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (l *LakeBTC) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (l *LakeBTC) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (l *LakeBTC) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (l *LakeBTC) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/liqui/liqui.go b/exchanges/liqui/liqui.go index 3cac5ee5..c6e82816 100644 --- a/exchanges/liqui/liqui.go +++ b/exchanges/liqui/liqui.go @@ -1,6 +1,7 @@ package liqui import ( + "errors" "fmt" "log" "net/url" @@ -201,10 +202,13 @@ func (l *Liqui) Trade(pair, orderType string, amount, price float64) (float64, e req.Add("type", orderType) req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64)) req.Add("rate", strconv.FormatFloat(price, 'f', -1, 64)) - var result Trade - return result.OrderID, l.SendAuthenticatedHTTPRequest(liquiTrade, req, &result) + err := l.SendAuthenticatedHTTPRequest(liquiTrade, req, &result) + if result.Success == 0 { + return -1, errors.New(result.Error) + } + return result.OrderID, err } // GetActiveOrders returns the list of your active orders. @@ -233,7 +237,11 @@ func (l *Liqui) CancelExistingOrder(OrderID int64) error { req.Add("order_id", strconv.FormatInt(OrderID, 10)) var result CancelOrder - return l.SendAuthenticatedHTTPRequest(liquiCancelOrder, req, &result) + err := l.SendAuthenticatedHTTPRequest(liquiCancelOrder, req, &result) + if result.Success == 0 { + return errors.New(result.Error) + } + return err } // GetTradeHistory returns trade history @@ -257,7 +265,15 @@ func (l *Liqui) WithdrawCoins(coin string, amount float64, address string) (With req.Add("address", address) var result WithdrawCoins - return result, l.SendAuthenticatedHTTPRequest(liquiWithdrawCoin, req, &result) + err := l.SendAuthenticatedHTTPRequest(liquiWithdrawCoin, req, &result) + if err != nil { + return WithdrawCoins{}, err + } + if len(result.Error) > 0 { + return result, errors.New(result.Error) + } + + return result, nil } // SendHTTPRequest sends an unauthenticated HTTP request diff --git a/exchanges/liqui/liqui_test.go b/exchanges/liqui/liqui_test.go index e4ce3347..3c62866f 100644 --- a/exchanges/liqui/liqui_test.go +++ b/exchanges/liqui/liqui_test.go @@ -235,21 +235,19 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if l.APIKey == "" || l.APISecret == "" || - l.APIKey == "Key" || l.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if l.APIKey != "" && l.APIKey != "Key" && + l.APISecret != "" && l.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -258,8 +256,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.EUR, } response, err := l.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -268,12 +268,11 @@ func TestCancelExchangeOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -283,10 +282,12 @@ func TestCancelExchangeOrder(t *testing.T) { // Act err := l.CancelOrder(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -295,12 +296,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + 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", @@ -310,10 +310,12 @@ func TestCancelAllExchangeOrders(t *testing.T) { // Act resp, err := l.CancelAllOrders(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -327,3 +329,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + l.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := l.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) + } +} diff --git a/exchanges/liqui/liqui_wrapper.go b/exchanges/liqui/liqui_wrapper.go index 1751b93b..ad6729b0 100644 --- a/exchanges/liqui/liqui_wrapper.go +++ b/exchanges/liqui/liqui_wrapper.go @@ -220,20 +220,25 @@ func (l *Liqui) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, err // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (l *Liqui) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (l *Liqui) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := l.WithdrawCoins(withdrawRequest.Currency.String(), withdrawRequest.Amount, withdrawRequest.Address) + if err != nil { + return "", err + } + + return fmt.Sprintf("%v", resp.TID), nil } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (l *Liqui) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (l *Liqui) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (l *Liqui) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (l *Liqui) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { + return "", common.ErrFunctionNotSupported } // GetWebsocket returns a pointer to the exchange websocket diff --git a/exchanges/localbitcoins/localbitcoins.go b/exchanges/localbitcoins/localbitcoins.go index cc45dfa8..86a01006 100644 --- a/exchanges/localbitcoins/localbitcoins.go +++ b/exchanges/localbitcoins/localbitcoins.go @@ -560,14 +560,14 @@ func (l *LocalBitcoins) GetWalletBalance() (WalletBalanceInfo, error) { // On success, the response returns a message indicating success. It is highly // recommended to minimize the lifetime of access tokens with the money // permission. Use Logout() to make the current token expire instantly. -func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int) (bool, error) { +func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int64) (bool, error) { values := url.Values{} values.Set("address", address) values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64)) path := localbitcoinsAPIWalletSend if pin > 0 { - values.Set("pincode", strconv.Itoa(pin)) + values.Set("pincode", fmt.Sprintf("%v", pin)) path = localbitcoinsAPIWalletSendPin } diff --git a/exchanges/localbitcoins/localbitcoins_test.go b/exchanges/localbitcoins/localbitcoins_test.go index 7570562d..4246cd6d 100644 --- a/exchanges/localbitcoins/localbitcoins_test.go +++ b/exchanges/localbitcoins/localbitcoins_test.go @@ -200,21 +200,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if l.APIKey == "" || l.APISecret == "" || - l.APIKey == "Key" || l.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if l.APIKey != "" && l.APIKey != "Key" && + l.APISecret != "" && l.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -223,8 +222,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.EUR, } response, err := l.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -233,8 +234,8 @@ func TestCancelExchangeOrder(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -250,8 +251,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := l.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -260,8 +264,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { l.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -277,8 +281,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := l.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -292,3 +299,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + l.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := l.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) + } +} diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index d5765117..2f9032b9 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -252,19 +252,20 @@ func (l *LocalBitcoins) GetDepositAddress(cryptocurrency pair.CurrencyItem) (str // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (l *LocalBitcoins) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (l *LocalBitcoins) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + _, err := l.WalletSend(withdrawRequest.Address, withdrawRequest.Amount, withdrawRequest.PIN) + return "", err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (l *LocalBitcoins) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (l *LocalBitcoins) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (l *LocalBitcoins) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (l *LocalBitcoins) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/okcoin/okcoin.go b/exchanges/okcoin/okcoin.go index 0eb3a1b2..8cf0fe72 100644 --- a/exchanges/okcoin/okcoin.go +++ b/exchanges/okcoin/okcoin.go @@ -558,10 +558,10 @@ func (o *OKCoin) Withdrawal(symbol string, fee float64, tradePWD, address string v.Set("trade_pwd", tradePWD) v.Set("withdraw_address", address) v.Set("withdraw_amount", strconv.FormatFloat(amount, 'f', -1, 64)) + v.Set("target", "address") result := WithdrawalResponse{} err := o.SendAuthenticatedHTTPRequest(okcoinWithdraw, v, &result) - if err != nil { return 0, err } diff --git a/exchanges/okcoin/okcoin_test.go b/exchanges/okcoin/okcoin_test.go index 71d29f5e..28f384f5 100644 --- a/exchanges/okcoin/okcoin_test.go +++ b/exchanges/okcoin/okcoin_test.go @@ -150,21 +150,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if o.APIKey == "" || o.APISecret == "" || - o.APIKey == "Key" || o.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if o.APIKey != "" && o.APIKey != "Key" && + o.APISecret != "" && o.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { o.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -173,8 +172,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.EUR, } response, err := o.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -182,9 +183,8 @@ func TestCancelExchangeOrder(t *testing.T) { // Arrange o.SetDefaults() TestSetup(t) - - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -198,10 +198,12 @@ func TestCancelExchangeOrder(t *testing.T) { // Act err := o.CancelOrder(orderCancellation) - // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -210,8 +212,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { o.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -227,8 +229,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := o.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -242,3 +247,28 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + o.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: "btc_usd", + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + TradePassword: "Password", + FeeAmount: 1, + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := o.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) + } +} diff --git a/exchanges/okcoin/okcoin_types.go b/exchanges/okcoin/okcoin_types.go index d50ff0c4..337390eb 100644 --- a/exchanges/okcoin/okcoin_types.go +++ b/exchanges/okcoin/okcoin_types.go @@ -197,8 +197,9 @@ type BatchTrade struct { // CancelOrderResponse is a response type for a cancelled order type CancelOrderResponse struct { - Success string - Error string + Success string + ErrorCode string `json:"error_code"` + Result bool `json:"result"` } // OrderInfo holds data on an order diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index 1ae773d8..20a27c30 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -240,8 +240,10 @@ func (o *OKCoin) CancelOrder(order exchange.OrderCancellation) error { return err } - _, err = o.CancelExistingOrder(orders, exchange.FormatExchangeCurrency(o.Name, order.CurrencyPair).String()) - + resp, err := o.CancelExistingOrder(orders, exchange.FormatExchangeCurrency(o.Name, order.CurrencyPair).String()) + if !resp.Result { + return errors.New(resp.ErrorCode) + } return err } @@ -266,7 +268,7 @@ func (o *OKCoin) CancelAllOrders(orderCancellation exchange.OrderCancellation) ( return cancelAllOrdersResponse, err } - for _, order := range common.SplitStrings(resp.Error, ",") { + for _, order := range common.SplitStrings(resp.ErrorCode, ",") { if err != nil { cancelAllOrdersResponse.OrderStatus[order] = "Order could not be cancelled" } @@ -289,19 +291,20 @@ func (o *OKCoin) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, er // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (o *OKCoin) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (o *OKCoin) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := o.Withdrawal(withdrawRequest.Currency.String(), withdrawRequest.FeeAmount, withdrawRequest.TradePassword, withdrawRequest.Address, withdrawRequest.Amount) + return fmt.Sprintf("%v", resp), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (o *OKCoin) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (o *OKCoin) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (o *OKCoin) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (o *OKCoin) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/okex/okex.go b/exchanges/okex/okex.go index 96cc904e..06b2e01d 100644 --- a/exchanges/okex/okex.go +++ b/exchanges/okex/okex.go @@ -66,7 +66,7 @@ const ( spotCancelTrade = "cancel_order" spotOrderInfo = "order_info" spotMultiOrderInfo = "orders_info" - spotWithdraw = "withdraw" + spotWithdraw = "withdraw.do" spotCancelWithdraw = "cancel_withdraw" spotWithdrawInfo = "withdraw_info" spotAccountRecords = "account_records" @@ -1225,3 +1225,29 @@ func (o *OKEX) GetBalance() ([]FullBalance, error) { return balances, nil } + +// Withdrawal withdraws a cryptocurrency to a supplied address +func (o *OKEX) Withdrawal(symbol string, fee float64, tradePWD, address string, amount float64) (int, error) { + v := url.Values{} + v.Set("symbol", symbol) + + if fee != 0 { + v.Set("chargefee", strconv.FormatFloat(fee, 'f', -1, 64)) + } + v.Set("trade_pwd", tradePWD) + v.Set("withdraw_address", address) + v.Set("withdraw_amount", strconv.FormatFloat(amount, 'f', -1, 64)) + v.Set("target", "address") + resp := WithdrawalResponse{} + + err := o.SendAuthenticatedHTTPRequest(spotWithdraw, v, &resp) + if err != nil { + return 0, err + } + + if !resp.Result { + return 0, errors.New("unable to process withdrawal request") + } + + return resp.WithdrawID, nil +} diff --git a/exchanges/okex/okex_test.go b/exchanges/okex/okex_test.go index 9418be0f..129d91b1 100644 --- a/exchanges/okex/okex_test.go +++ b/exchanges/okex/okex_test.go @@ -399,21 +399,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if o.APIKey == "" || o.APISecret == "" || - o.APIKey == "Key" || o.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if o.APIKey != "" && o.APIKey != "Key" && + o.APISecret != "" && o.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { o.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var p = pair.CurrencyPair{ @@ -422,8 +421,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.EUR, } response, err := o.SubmitOrder(p, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -432,8 +433,8 @@ func TestCancelExchangeOrder(t *testing.T) { o.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -449,8 +450,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := o.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -459,8 +463,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { o.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -476,8 +480,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := o.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -505,3 +512,28 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + o.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: "btc_usd", + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + TradePassword: "Password", + FeeAmount: 1, + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := o.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) + } +} diff --git a/exchanges/okex/okex_types.go b/exchanges/okex/okex_types.go index 1d750509..197644e7 100644 --- a/exchanges/okex/okex_types.go +++ b/exchanges/okex/okex_types.go @@ -463,3 +463,9 @@ type Balance struct { } `json:"funds"` } `json:"info"` } + +// WithdrawalResponse is a response type for withdrawal +type WithdrawalResponse struct { + WithdrawID int `json:"withdraw_id"` + Result bool `json:"result"` +} diff --git a/exchanges/okex/okex_wrapper.go b/exchanges/okex/okex_wrapper.go index 311b33d6..76ce66e6 100644 --- a/exchanges/okex/okex_wrapper.go +++ b/exchanges/okex/okex_wrapper.go @@ -288,19 +288,20 @@ func (o *OKEX) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, erro // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (o *OKEX) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (o *OKEX) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := o.Withdrawal(withdrawRequest.Currency.String(), withdrawRequest.FeeAmount, withdrawRequest.TradePassword, withdrawRequest.Address, withdrawRequest.Amount) + return fmt.Sprintf("%v", resp), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (o *OKEX) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (o *OKEX) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (o *OKEX) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (o *OKEX) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/poloniex/poloniex_test.go b/exchanges/poloniex/poloniex_test.go index c1a82bff..fc7f92ea 100644 --- a/exchanges/poloniex/poloniex_test.go +++ b/exchanges/poloniex/poloniex_test.go @@ -195,21 +195,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if p.APIKey == "" || p.APISecret == "" || - p.APIKey == "Key" || p.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if p.APIKey != "" && p.APIKey != "Key" && + p.APISecret != "" && p.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { p.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var pair = pair.CurrencyPair{ @@ -218,8 +217,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.LTC, } response, err := p.SubmitOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -228,8 +229,8 @@ func TestCancelExchangeOrder(t *testing.T) { p.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -245,8 +246,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := p.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -255,8 +259,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { p.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -272,8 +276,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := p.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -287,3 +294,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test Failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + p.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := p.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) + } +} diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index e53b9dd4..727a31f8 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -241,19 +241,20 @@ func (p *Poloniex) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (p *Poloniex) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (p *Poloniex) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + _, err := p.Withdraw(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.Amount) + return "", err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (p *Poloniex) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (p *Poloniex) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (p *Poloniex) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (p *Poloniex) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/wex/wex_test.go b/exchanges/wex/wex_test.go index 038773fc..4726b90c 100644 --- a/exchanges/wex/wex_test.go +++ b/exchanges/wex/wex_test.go @@ -325,13 +325,12 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if w.APIKey == "" || w.APISecret == "" || - w.APIKey == "Key" || w.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if w.APIKey != "" && w.APIKey != "Key" && + w.APISecret != "" && w.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { @@ -341,8 +340,8 @@ func TestSubmitOrder(t *testing.T) { w.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var pair = pair.CurrencyPair{ @@ -351,8 +350,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := w.SubmitOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -364,8 +365,8 @@ func TestCancelExchangeOrder(t *testing.T) { w.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -381,8 +382,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := w.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -394,8 +398,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { w.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -411,8 +415,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := w.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -426,3 +433,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + w.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := w.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) + } +} diff --git a/exchanges/wex/wex_wrapper.go b/exchanges/wex/wex_wrapper.go index ed399284..3df63ef9 100644 --- a/exchanges/wex/wex_wrapper.go +++ b/exchanges/wex/wex_wrapper.go @@ -238,19 +238,20 @@ func (w *WEX) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, error // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (w *WEX) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (w *WEX) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := w.WithdrawCoins(withdrawRequest.Currency.String(), withdrawRequest.Amount, withdrawRequest.Address) + return fmt.Sprintf("%v", resp.TID), err } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (w *WEX) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (w *WEX) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (w *WEX) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (w *WEX) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/yobit/yobit_test.go b/exchanges/yobit/yobit_test.go index 6c2c9ecd..67b46b7c 100644 --- a/exchanges/yobit/yobit_test.go +++ b/exchanges/yobit/yobit_test.go @@ -314,21 +314,20 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if y.APIKey == "" || y.APISecret == "" || - y.APIKey == "Key" || y.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if y.APIKey != "" && y.APIKey != "Key" && + y.APISecret != "" && y.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { y.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var pair = pair.CurrencyPair{ @@ -337,8 +336,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USD, } response, err := y.SubmitOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -347,8 +348,8 @@ func TestCancelExchangeOrder(t *testing.T) { y.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -364,8 +365,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := y.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -374,8 +378,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { y.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -391,8 +395,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := y.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -406,3 +413,26 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + y.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.LTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := y.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) + } +} diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index fff8f446..b23f8710 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -1,6 +1,7 @@ package yobit import ( + "errors" "fmt" "log" "strconv" @@ -219,19 +220,26 @@ func (y *Yobit) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, err // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (y *Yobit) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (y *Yobit) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + resp, err := y.WithdrawCoinsToAddress(withdrawRequest.Currency.String(), withdrawRequest.Amount, withdrawRequest.Address) + if err != nil { + return "", err + } + if len(resp.Error) > 0 { + return "", errors.New(resp.Error) + } + return "", nil } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (y *Yobit) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (y *Yobit) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (y *Yobit) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (y *Yobit) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/exchanges/zb/zb.go b/exchanges/zb/zb.go index ecccfba8..db84d80d 100644 --- a/exchanges/zb/zb.go +++ b/exchanges/zb/zb.go @@ -31,6 +31,7 @@ const ( zbTickers = "allTicker" zbDepth = "depth" zbUnfinishedOrdersIgnoreTradeType = "getUnfinishedOrdersIgnoreTradeType" + zbWithdraw = "withdraw" zbAuthRate = 100 zbUnauthRate = 100 @@ -440,3 +441,33 @@ var errorCode = map[int64]string{ 4001: "API interface is locked", 4002: "Request too frequently", } + +// Withdraw transfers funds +func (z *ZB) Withdraw(currency, address, safepassword string, amount, fees float64, itransfer bool) (string, error) { + type response struct { + Code int `json:"code"` // Result code + Message string `json:"message"` // Result Message + ID string `json:"id"` // Withdrawal ID + } + + vals := url.Values{} + vals.Set("accesskey", z.APIKey) + vals.Set("amount", fmt.Sprintf("%v", amount)) + vals.Set("currency", currency) + vals.Set("fees", fmt.Sprintf("%v", fees)) + vals.Set("itransfer", fmt.Sprintf("%v", itransfer)) + vals.Set("method", "withdraw") + vals.Set("recieveAddr", address) + vals.Set("safePwd", safepassword) + + var resp response + err := z.SendAuthenticatedHTTPRequest("GET", zbWithdraw, vals, &resp) + if err != nil { + return "", err + } + if resp.Code != 1000 { + return "", errors.New(resp.Message) + } + + return resp.ID, nil +} diff --git a/exchanges/zb/zb_test.go b/exchanges/zb/zb_test.go index aa39e821..7635af07 100644 --- a/exchanges/zb/zb_test.go +++ b/exchanges/zb/zb_test.go @@ -232,20 +232,19 @@ func TestFormatWithdrawPermissions(t *testing.T) { // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- -func isRealOrderTestEnabled() bool { - if z.APIKey == "" || z.APISecret == "" || - z.APIKey == "Key" || z.APISecret == "Secret" || - !canManipulateRealOrders { - return false +func areTestAPIKeysSet() bool { + if z.APIKey != "" && z.APIKey != "Key" && + z.APISecret != "" && z.APISecret != "Secret" { + return true } - return true + return false } func TestSubmitOrder(t *testing.T) { z.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { + if areTestAPIKeysSet() && !canManipulateRealOrders { t.Skip(fmt.Sprintf("ApiKey: %s. Can place orders: %v", z.APIKey, canManipulateRealOrders)) } var pair = pair.CurrencyPair{ @@ -254,8 +253,10 @@ func TestSubmitOrder(t *testing.T) { SecondCurrency: symbol.USDT, } response, err := z.SubmitOrder(pair, exchange.Buy, exchange.Market, 1, 10, "hi") - if err != nil || !response.IsOrderPlaced { + 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") } } @@ -264,8 +265,8 @@ func TestCancelExchangeOrder(t *testing.T) { z.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -281,8 +282,11 @@ func TestCancelExchangeOrder(t *testing.T) { err := z.CancelOrder(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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) } } @@ -291,8 +295,8 @@ func TestCancelAllExchangeOrders(t *testing.T) { z.SetDefaults() TestSetup(t) - if !isRealOrderTestEnabled() { - t.Skip() + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") } currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC) @@ -308,8 +312,11 @@ func TestCancelAllExchangeOrders(t *testing.T) { resp, err := z.CancelAllOrders(orderCancellation) // Assert - if err != nil { - t.Errorf("Could not cancel order: %s", err) + 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 { @@ -337,3 +344,27 @@ func TestModifyOrder(t *testing.T) { t.Error("Test failed - ModifyOrder() error") } } + +func TestWithdraw(t *testing.T) { + z.SetDefaults() + TestSetup(t) + var withdrawCryptoRequest = exchange.WithdrawRequest{ + Amount: 100, + Currency: symbol.BTC, + Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", + Description: "WITHDRAW IT ALL", + FeeAmount: 1, + } + + if areTestAPIKeysSet() && !canManipulateRealOrders { + t.Skip("API keys set, canManipulateRealOrders false, skipping test") + } + + _, err := z.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) + } +} diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index e6e31651..af3a36a5 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -249,19 +249,19 @@ func (z *ZB) GetDepositAddress(cryptocurrency pair.CurrencyItem) (string, error) // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func (z *ZB) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { - return "", common.ErrNotYetImplemented +func (z *ZB) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { + return z.Withdraw(withdrawRequest.Currency.Lower().String(), withdrawRequest.Address, withdrawRequest.TradePassword, withdrawRequest.Amount, withdrawRequest.FeeAmount, false) } // WithdrawFiatFunds returns a withdrawal ID when a // withdrawal is submitted -func (z *ZB) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func (z *ZB) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a // withdrawal is submitted -func (z *ZB) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func (z *ZB) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } diff --git a/tools/exchange_template/wrapper_file.tmpl b/tools/exchange_template/wrapper_file.tmpl index ec5531b2..528f5ce0 100644 --- a/tools/exchange_template/wrapper_file.tmpl +++ b/tools/exchange_template/wrapper_file.tmpl @@ -154,19 +154,19 @@ func ({{.Variable}} *{{.CapitalName}}) GetDepositAddress(cryptocurrency pair.Cur // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted -func ({{.Variable}} *{{.CapitalName}}) WithdrawCryptocurrencyFunds(address string, cryptocurrency pair.CurrencyItem, amount float64) (string, error) { +func ({{.Variable}} *{{.CapitalName}}) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFunds returns a withdrawal ID when a withdrawal is // submitted -func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFunds(currency pair.CurrencyItem, amount float64) (string, error) { +func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented } // WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is // submitted -func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) { +func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) { return "", common.ErrNotYetImplemented }