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 }