From e56fc26d93d55d707d24f128ea15216919d078de Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 9 Apr 2019 19:38:31 +1000 Subject: [PATCH] Offline worst case trade fees (#274) * Really basic getSimulated fee function everywhere * Worst case fees for all exchanges * Adds tests, fixes comment spacing. Adds wrapper logic. Makes test api key var name consistent. Removes some okcoin ETT tests * Removes redundant functions * linting issues. Fixes introduces huobi issues * More linting * Stops trying to hide ETT problems, uses iota * Skips ETT tests for now --- exchanges/alphapoint/alphapoint_test.go | 10 +-- exchanges/anx/anx.go | 7 ++ exchanges/anx/anx_test.go | 25 +++++-- exchanges/anx/anx_wrapper.go | 4 ++ exchanges/binance/binance.go | 7 ++ exchanges/binance/binance_test.go | 39 ++++++---- exchanges/binance/binance_wrapper.go | 4 ++ exchanges/bitfinex/bitfinex.go | 8 +++ exchanges/bitfinex/bitfinex_test.go | 25 +++++-- exchanges/bitfinex/bitfinex_wrapper.go | 4 ++ exchanges/bitflyer/bitflyer.go | 7 +- exchanges/bitflyer/bitflyer_test.go | 25 +++++-- exchanges/bitflyer/bitflyer_wrapper.go | 4 ++ exchanges/bithumb/bithumb.go | 5 +- exchanges/bithumb/bithumb_test.go | 45 ++++++++---- exchanges/bithumb/bithumb_wrapper.go | 4 ++ exchanges/bitmex/bitmex.go | 12 +++- exchanges/bitmex/bitmex_test.go | 26 +++++-- exchanges/bitmex/bitmex_wrapper.go | 4 ++ exchanges/bitstamp/bitstamp.go | 7 ++ exchanges/bitstamp/bitstamp_test.go | 15 ++++ exchanges/bitstamp/bitstamp_wrapper.go | 4 ++ exchanges/bittrex/bittrex.go | 8 ++- exchanges/bittrex/bittrex_test.go | 15 ++++ exchanges/bittrex/bittrex_wrapper.go | 4 ++ exchanges/btcc/btcc.go | 7 ++ exchanges/btcc/btcc_test.go | 15 ++++ exchanges/btcc/btcc_wrapper.go | 4 ++ exchanges/btcmarkets/btcmarkets.go | 7 ++ exchanges/btcmarkets/btcmarkets_test.go | 15 ++++ exchanges/btcmarkets/btcmarkets_wrapper.go | 4 ++ exchanges/btse/btse.go | 7 ++ exchanges/btse/btse_test.go | 21 ++++++ exchanges/btse/btse_wrapper.go | 4 ++ exchanges/coinbasepro/coinbasepro.go | 7 ++ exchanges/coinbasepro/coinbasepro_test.go | 15 ++++ exchanges/coinbasepro/coinbasepro_wrapper.go | 4 ++ exchanges/coinut/coinut.go | 10 +++ exchanges/coinut/coinut_test.go | 15 ++++ exchanges/coinut/coinut_wrapper.go | 4 ++ exchanges/exchange.go | 72 +++++++++---------- exchanges/exmo/exmo.go | 14 ++-- exchanges/exmo/exmo_test.go | 15 ++++ exchanges/exmo/exmo_wrapper.go | 4 ++ exchanges/gateio/gateio.go | 7 ++ exchanges/gateio/gateio_test.go | 15 ++++ exchanges/gateio/gateio_wrapper.go | 4 ++ exchanges/gemini/gemini.go | 7 ++ exchanges/gemini/gemini_test.go | 20 +++++- exchanges/gemini/gemini_wrapper.go | 4 ++ exchanges/hitbtc/hitbtc.go | 10 +++ exchanges/hitbtc/hitbtc_test.go | 15 ++++ exchanges/hitbtc/hitbtc_wrapper.go | 4 ++ exchanges/huobi/huobi.go | 12 ++-- exchanges/huobi/huobi_test.go | 15 ++++ exchanges/huobi/huobi_wrapper.go | 4 ++ exchanges/huobihadax/huobihadax.go | 12 ++-- exchanges/huobihadax/huobihadax_test.go | 15 ++++ exchanges/huobihadax/huobihadax_wrapper.go | 4 ++ exchanges/itbit/itbit.go | 11 ++- exchanges/itbit/itbit_test.go | 23 ++++-- exchanges/itbit/itbit_wrapper.go | 4 ++ exchanges/kraken/kraken.go | 7 ++ exchanges/kraken/kraken_test.go | 16 +++++ exchanges/kraken/kraken_wrapper.go | 4 ++ exchanges/lakebtc/lakebtc.go | 7 ++ exchanges/lakebtc/lakebtc_test.go | 15 ++++ exchanges/lakebtc/lakebtc_wrapper.go | 4 ++ exchanges/localbitcoins/localbitcoins_test.go | 15 ++++ .../localbitcoins/localbitcoins_wrapper.go | 4 ++ exchanges/okcoin/okcoin_test.go | 17 ++++- exchanges/okex/okex_test.go | 22 +++++- exchanges/okgroup/okgroup.go | 9 ++- exchanges/okgroup/okgroup_wrapper.go | 4 ++ exchanges/poloniex/poloniex.go | 7 ++ exchanges/poloniex/poloniex_test.go | 15 ++++ exchanges/poloniex/poloniex_wrapper.go | 4 ++ exchanges/yobit/yobit.go | 7 +- exchanges/yobit/yobit_test.go | 15 ++++ exchanges/yobit/yobit_wrapper.go | 4 ++ exchanges/zb/zb.go | 7 ++ exchanges/zb/zb_test.go | 15 ++++ exchanges/zb/zb_wrapper.go | 4 ++ 83 files changed, 814 insertions(+), 136 deletions(-) diff --git a/exchanges/alphapoint/alphapoint_test.go b/exchanges/alphapoint/alphapoint_test.go index 561ee315..04c6d004 100644 --- a/exchanges/alphapoint/alphapoint_test.go +++ b/exchanges/alphapoint/alphapoint_test.go @@ -10,8 +10,8 @@ import ( const ( onlineTest = false - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -29,13 +29,13 @@ func TestSetDefaults(t *testing.T) { } func testSetAPIKey(a *Alphapoint) { - a.APIKey = testAPIKey - a.APISecret = testAPISecret + a.APIKey = apiKey + a.APISecret = apiSecret a.AuthenticatedAPISupport = true } func testIsAPIKeysSet(a *Alphapoint) bool { - if testAPIKey != "" && testAPISecret != "" && a.AuthenticatedAPISupport { + if apiKey != "" && apiSecret != "" && a.AuthenticatedAPISupport { return true } return false diff --git a/exchanges/anx/anx.go b/exchanges/anx/anx.go index c6dc4e15..7eccd54f 100644 --- a/exchanges/anx/anx.go +++ b/exchanges/anx/anx.go @@ -454,6 +454,8 @@ func (a *ANX) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -461,6 +463,11 @@ func (a *ANX) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func (a *ANX) calculateTradingFee(purchasePrice, amount float64, isMaker bool) float64 { var fee float64 diff --git a/exchanges/anx/anx_test.go b/exchanges/anx/anx_test.go index fe28dba8..8d11f22c 100644 --- a/exchanges/anx/anx_test.go +++ b/exchanges/anx/anx_test.go @@ -11,8 +11,8 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -54,8 +54,8 @@ func TestSetup(t *testing.T) { t.Error("Test Failed - ANX Setup() init error") } a.Setup(&anxConfig) - a.APIKey = testAPIKey - a.APISecret = testAPISecret + a.APIKey = apiKey + a.APISecret = apiSecret a.AuthenticatedAPISupport = true if !a.Enabled { @@ -138,6 +138,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + a.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { a.SetDefaults() TestSetup(t) @@ -341,7 +356,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { } func TestGetAccountInfo(t *testing.T) { - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { _, err := a.GetAccountInfo() if err != nil { t.Error("test failed - GetAccountInfo() error:", err) diff --git a/exchanges/anx/anx_wrapper.go b/exchanges/anx/anx_wrapper.go index 6a62cbb1..acc8198d 100644 --- a/exchanges/anx/anx_wrapper.go +++ b/exchanges/anx/anx_wrapper.go @@ -367,6 +367,10 @@ func (a *ANX) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (a *ANX) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (a.APIKey == "" || a.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return a.GetFee(feeBuilder) } diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index b66c9092..e0328799 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -710,6 +710,8 @@ func (b *Binance) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, multiplier) case exchange.CryptocurrencyWithdrawalFee: fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -717,6 +719,11 @@ func (b *Binance) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + // getMultiplier retrieves account based taker/maker fees func (b *Binance) getMultiplier(isMaker bool) (float64, error) { var multiplier float64 diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index 20a7addc..4ffd1559 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -11,8 +11,8 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -31,8 +31,8 @@ func TestSetup(t *testing.T) { } binanceConfig.AuthenticatedAPISupport = true - binanceConfig.APIKey = testAPIKey - binanceConfig.APISecret = testAPISecret + binanceConfig.APIKey = apiKey + binanceConfig.APISecret = apiSecret b.Setup(&binanceConfig) } @@ -140,7 +140,7 @@ func TestGetBestPrice(t *testing.T) { func TestNewOrder(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } _, err := b.NewOrder(&NewOrderRequest{ @@ -160,7 +160,7 @@ func TestNewOrder(t *testing.T) { func TestCancelExistingOrder(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -173,7 +173,7 @@ func TestCancelExistingOrder(t *testing.T) { func TestQueryOrder(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -186,7 +186,7 @@ func TestQueryOrder(t *testing.T) { func TestOpenOrders(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -199,7 +199,7 @@ func TestOpenOrders(t *testing.T) { func TestAllOrders(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -210,7 +210,7 @@ func TestAllOrders(t *testing.T) { } func TestGetAccount(t *testing.T) { - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } t.Parallel() @@ -240,13 +240,28 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) var feeBuilder = setFeeBuilder() - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { // CryptocurrencyTradeFee Basic if resp, err := b.GetFee(feeBuilder); resp != float64(0.1) || err != nil { t.Error(err) @@ -455,7 +470,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { func TestGetAccountInfo(t *testing.T) { b.SetDefaults() TestSetup(t) - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 55a7956f..d7554163 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -324,6 +324,10 @@ func (b *Binance) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *Binance) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bitfinex/bitfinex.go b/exchanges/bitfinex/bitfinex.go index 505f8916..04567178 100644 --- a/exchanges/bitfinex/bitfinex.go +++ b/exchanges/bitfinex/bitfinex.go @@ -1086,6 +1086,8 @@ func (b *Bitfinex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankDepositFee(feeBuilder.Amount) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -1093,6 +1095,12 @@ func (b *Bitfinex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +// does not require an API request, requires manual updating +func getOfflineTradeFee(price, amount float64) float64 { + return 0.001 * price * amount +} + // GetCryptocurrencyWithdrawalFee returns an estimate of fee based on type of transaction func (b *Bitfinex) GetCryptocurrencyWithdrawalFee(c currency.Code, accountFees AccountFees) (fee float64, err error) { switch result := accountFees.Withdraw[c.String()].(type) { diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index b52a51da..ae3ec8d1 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -14,8 +14,8 @@ import ( // Please supply your own keys here to do better tests const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -30,8 +30,8 @@ func TestSetup(t *testing.T) { t.Error("Test Failed - Bitfinex Setup() init error") } b.Setup(&bfxConfig) - b.APIKey = testAPIKey - b.APISecret = testAPISecret + b.APIKey = apiKey + b.APISecret = apiSecret if !b.Enabled || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) || b.Verbose || b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 || len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 { @@ -619,12 +619,27 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) var feeBuilder = setFeeBuilder() - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { // CryptocurrencyTradeFee Basic if resp, err := b.GetFee(feeBuilder); resp != float64(0.002) || err != nil { t.Error(err) diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 5cfe0425..b77d6aaa 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -329,6 +329,10 @@ func (b *Bitfinex) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitfinex) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bitflyer/bitflyer.go b/exchanges/bitflyer/bitflyer.go index 2d286a23..3aadf5d1 100644 --- a/exchanges/bitflyer/bitflyer.go +++ b/exchanges/bitflyer/bitflyer.go @@ -403,6 +403,8 @@ func (b *Bitflyer) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getDepositFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency) case exchange.InternationalBankWithdrawalFee: fee = getWithdrawalFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency, feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -411,10 +413,9 @@ func (b *Bitflyer) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { } // calculateTradingFee returns fee when performing a trade -func calculateTradingFee(purchasePrice, amount float64) float64 { - fee := 0.0015 +func calculateTradingFee(price, amount float64) float64 { // bitflyer has fee tiers, but does not disclose them via API, so the largest has to be assumed - return fee * amount * purchasePrice + return 0.0012 * price * amount } func getDepositFee(bankTransactionType exchange.InternationalBankTransactionType, c currency.Code) (fee float64) { diff --git a/exchanges/bitflyer/bitflyer_test.go b/exchanges/bitflyer/bitflyer_test.go index 0692dd4f..ecaf050c 100644 --- a/exchanges/bitflyer/bitflyer_test.go +++ b/exchanges/bitflyer/bitflyer_test.go @@ -12,8 +12,8 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -32,8 +32,8 @@ func TestSetup(t *testing.T) { } bitflyerConfig.AuthenticatedAPISupport = true - bitflyerConfig.APIKey = testAPIKey - bitflyerConfig.APISecret = testAPISecret + bitflyerConfig.APIKey = apiKey + bitflyerConfig.APISecret = apiSecret b.Setup(&bitflyerConfig) } @@ -159,12 +159,27 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) var feeBuilder = setFeeBuilder() - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { // CryptocurrencyTradeFee Basic if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { t.Error(err) diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index a403aded..2feb7560 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -236,5 +236,9 @@ func (b *Bitflyer) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) // GetFeeByType returns an estimate of fee based on the type of transaction func (b *Bitflyer) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bithumb/bithumb.go b/exchanges/bithumb/bithumb.go index d8f26aec..4b97a987 100644 --- a/exchanges/bithumb/bithumb.go +++ b/exchanges/bithumb/bithumb.go @@ -619,6 +619,8 @@ func (b *Bithumb) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getWithdrawalFee(feeBuilder.Pair.Base) case exchange.InternationalBankWithdrawalFee: fee = getWithdrawalFee(feeBuilder.FiatCurrency) + case exchange.OfflineTradeFee: + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -628,8 +630,7 @@ func (b *Bithumb) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { // calculateTradingFee returns fee when performing a trade func calculateTradingFee(purchasePrice, amount float64) float64 { - fee := 0.0015 - return fee * amount * purchasePrice + return 0.0025 * amount * purchasePrice } // getDepositFee returns fee on a currency when depositing small amounts to bithumb diff --git a/exchanges/bithumb/bithumb_test.go b/exchanges/bithumb/bithumb_test.go index 2d866fc7..e8264566 100644 --- a/exchanges/bithumb/bithumb_test.go +++ b/exchanges/bithumb/bithumb_test.go @@ -11,8 +11,8 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -31,8 +31,8 @@ func TestSetup(t *testing.T) { } bitConfig.AuthenticatedAPISupport = true - bitConfig.APIKey = testAPIKey - bitConfig.APISecret = testAPISecret + bitConfig.APIKey = apiKey + bitConfig.APISecret = apiSecret b.Setup(&bitConfig) } @@ -79,7 +79,7 @@ func TestGetTransactionHistory(t *testing.T) { func TestGetAccountBalance(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -90,7 +90,7 @@ func TestGetAccountBalance(t *testing.T) { } func TestGetWalletAddress(t *testing.T) { - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } @@ -159,7 +159,7 @@ func TestWithdrawCrypto(t *testing.T) { func TestRequestKRWDepositDetails(t *testing.T) { t.Parallel() - if testAPIKey == "" || testAPISecret == "" { + if apiKey == "" || apiSecret == "" { t.Skip() } _, err := b.RequestKRWDepositDetails() @@ -201,31 +201,46 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) var feeBuilder = setFeeBuilder() // CryptocurrencyTradeFee Basic - if resp, err := b.GetFee(feeBuilder); resp != float64(0.0015) || err != nil { + if resp, err := b.GetFee(feeBuilder); resp != float64(0.0025) || err != nil { t.Error(err) - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0015), resp) + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0025), resp) } // CryptocurrencyTradeFee High quantity feeBuilder = setFeeBuilder() feeBuilder.Amount = 1000 feeBuilder.PurchasePrice = 1000 - if resp, err := b.GetFee(feeBuilder); resp != float64(1500) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(1500), resp) + if resp, err := b.GetFee(feeBuilder); resp != float64(2500) || err != nil { + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(2500), resp) t.Error(err) } // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true - if resp, err := b.GetFee(feeBuilder); resp != float64(0.0015) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0015), resp) + if resp, err := b.GetFee(feeBuilder); resp != float64(0.0025) || err != nil { + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0025), resp) t.Error(err) } @@ -406,7 +421,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { func TestGetAccountInfo(t *testing.T) { t.Parallel() - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { _, err := b.GetAccountInfo() if err != nil { t.Error("test failed - Bithumb GetAccountInfo() error", err) @@ -505,7 +520,7 @@ func TestWithdrawInternationalBank(t *testing.T) { } func TestGetDepositAddress(t *testing.T) { - if testAPIKey != "" && testAPISecret != "" { + if apiKey != "" && apiSecret != "" { _, err := b.GetDepositAddress(currency.BTC, "") if err != nil { t.Error("Test Failed - GetDepositAddress() error", err) diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 2f14b342..1bac973d 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -326,6 +326,10 @@ func (b *Bithumb) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bithumb) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bitmex/bitmex.go b/exchanges/bitmex/bitmex.go index fcb39222..ff9c6113 100644 --- a/exchanges/bitmex/bitmex.go +++ b/exchanges/bitmex/bitmex.go @@ -938,9 +938,11 @@ func (b *Bitmex) CaptureError(resp, reType interface{}) error { func (b *Bitmex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { var fee float64 var err error - - if feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + switch feeBuilder.FeeType { + case exchange.CryptocurrencyTradeFee: fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -948,10 +950,14 @@ func (b *Bitmex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, err } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.000750 * price * amount +} + // calculateTradingFee returns the fee for trading any currency on Bittrex func calculateTradingFee(purchasePrice, amount float64, isMaker bool) float64 { var fee = 0.000750 - if isMaker { fee -= 0.000250 } diff --git a/exchanges/bitmex/bitmex_test.go b/exchanges/bitmex/bitmex_test.go index 3b3256e5..8a231924 100644 --- a/exchanges/bitmex/bitmex_test.go +++ b/exchanges/bitmex/bitmex_test.go @@ -13,8 +13,8 @@ import ( // Please supply your own keys here for due diligence testing const ( - testAPIKey = "" - testAPISecret = "" + apiKey = "" + apiSecret = "" canManipulateRealOrders = false ) @@ -32,8 +32,8 @@ func TestSetup(t *testing.T) { t.Error("Test Failed - Bitmex Setup() init error") } bitmexConfig.AuthenticatedAPISupport = true - bitmexConfig.APIKey = testAPIKey - bitmexConfig.APISecret = testAPISecret + bitmexConfig.APIKey = apiKey + bitmexConfig.APISecret = apiSecret b.Setup(&bitmexConfig) } @@ -369,12 +369,26 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) var feeBuilder = setFeeBuilder() - // CryptocurrencyTradeFee Basic if resp, err := b.GetFee(feeBuilder); resp != float64(0.00075) || err != nil { t.Error(err) @@ -576,7 +590,7 @@ func TestCancelAllExchangeOrders(t *testing.T) { } func TestGetAccountInfo(t *testing.T) { - if testAPIKey != "" || testAPISecret != "" { + if apiKey != "" || apiSecret != "" { _, err := b.GetAccountInfo() if err != nil { t.Error("Test Failed - GetAccountInfo() error", err) diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 7c2b5ee2..dc23c46c 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -305,6 +305,10 @@ func (b *Bitmex) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitmex) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bitstamp/bitstamp.go b/exchanges/bitstamp/bitstamp.go index efcde3e1..498e4010 100644 --- a/exchanges/bitstamp/bitstamp.go +++ b/exchanges/bitstamp/bitstamp.go @@ -164,6 +164,8 @@ func (b *Bitstamp) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankDepositFee(feeBuilder.Amount) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -171,6 +173,11 @@ func (b *Bitstamp) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0025 * price * amount +} + // getInternationalBankWithdrawalFee returns international withdrawal fee func getInternationalBankWithdrawalFee(amount float64) float64 { fee := amount * 0.0009 diff --git a/exchanges/bitstamp/bitstamp_test.go b/exchanges/bitstamp/bitstamp_test.go index a2420a5d..c2414521 100644 --- a/exchanges/bitstamp/bitstamp_test.go +++ b/exchanges/bitstamp/bitstamp_test.go @@ -70,6 +70,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 96175161..54b86831 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -94,6 +94,10 @@ func (b *Bitstamp) GetTickerPrice(p currency.Pair, assetType string) (ticker.Pri // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitstamp) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/bittrex/bittrex.go b/exchanges/bittrex/bittrex.go index 4aeecbc8..2527132d 100644 --- a/exchanges/bittrex/bittrex.go +++ b/exchanges/bittrex/bittrex.go @@ -530,6 +530,8 @@ func (b *Bittrex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) case exchange.CryptocurrencyWithdrawalFee: fee, err = b.GetWithdrawalFee(feeBuilder.Pair.Base) + case exchange.OfflineTradeFee: + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -554,7 +556,7 @@ func (b *Bittrex) GetWithdrawalFee(c currency.Code) (float64, error) { } // calculateTradingFee returns the fee for trading any currency on Bittrex -func calculateTradingFee(purchasePrice, amount float64) float64 { - var fee = 0.0025 - return fee * purchasePrice * amount +func calculateTradingFee(price, amount float64) float64 { + return 0.0025 * price * amount + } diff --git a/exchanges/bittrex/bittrex_test.go b/exchanges/bittrex/bittrex_test.go index 4fd51faa..37d29260 100644 --- a/exchanges/bittrex/bittrex_test.go +++ b/exchanges/bittrex/bittrex_test.go @@ -228,6 +228,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 530a452c..f4bd0fee 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -300,6 +300,10 @@ func (b *Bittrex) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bittrex) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/btcc/btcc.go b/exchanges/btcc/btcc.go index 4d3858d5..a0a25a0c 100644 --- a/exchanges/btcc/btcc.go +++ b/exchanges/btcc/btcc.go @@ -104,6 +104,8 @@ func (b *BTCC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -111,6 +113,11 @@ func (b *BTCC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.001 * price * amount +} + func getCryptocurrencyWithdrawalFee(c currency.Code) float64 { return WithdrawalFees[c] } diff --git a/exchanges/btcc/btcc_test.go b/exchanges/btcc/btcc_test.go index 14534de7..6b81eba6 100644 --- a/exchanges/btcc/btcc_test.go +++ b/exchanges/btcc/btcc_test.go @@ -84,6 +84,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) diff --git a/exchanges/btcc/btcc_wrapper.go b/exchanges/btcc/btcc_wrapper.go index 84f15728..2f15dd3f 100644 --- a/exchanges/btcc/btcc_wrapper.go +++ b/exchanges/btcc/btcc_wrapper.go @@ -158,6 +158,10 @@ func (b *BTCC) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *BTCC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/btcmarkets/btcmarkets.go b/exchanges/btcmarkets/btcmarkets.go index d571774f..7212af90 100644 --- a/exchanges/btcmarkets/btcmarkets.go +++ b/exchanges/btcmarkets/btcmarkets.go @@ -506,6 +506,8 @@ func (b *BTCMarkets) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -513,6 +515,11 @@ func (b *BTCMarkets) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0085 * price * amount +} + func calculateTradingFee(tradingFee TradingFee, purchasePrice, amount float64) (fee float64) { fee = tradingFee.TradingFeeRate / 100000000 return fee * amount * purchasePrice diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index 6dd37fac..795458fd 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -174,6 +174,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 4e949bee..04733c98 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -332,6 +332,10 @@ func (b *BTCMarkets) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (b *BTCMarkets) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/btse/btse.go b/exchanges/btse/btse.go index 0e377ebe..b99687b3 100644 --- a/exchanges/btse/btse.go +++ b/exchanges/btse/btse.go @@ -298,10 +298,17 @@ func (b *BTSE) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankDepositFee(feeBuilder.Amount) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0015 * price * amount +} + // getInternationalBankDepositFee returns international deposit fee // Only when the initial deposit amount is less than $1000 or equivalent, // BTSE will charge a small fee (0.25% or $3 USD equivalent, whichever is greater). diff --git a/exchanges/btse/btse_test.go b/exchanges/btse/btse_test.go index 2875e025..f7673d41 100644 --- a/exchanges/btse/btse_test.go +++ b/exchanges/btse/btse_test.go @@ -140,6 +140,27 @@ func TestFormatWithdrawPermissions(t *testing.T) { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + feeBuilder := &exchange.FeeBuilder{ + FeeType: exchange.CryptocurrencyTradeFee, + Pair: currency.NewPair(currency.BTC, currency.USD), + IsMaker: true, + Amount: 1000, + } + + b.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { b.SetDefaults() TestSetup(t) diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index beb304d5..75ba4409 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -348,5 +348,9 @@ func (b *BTSE) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]e // GetFeeByType returns an estimate of fee based on type of transaction func (b *BTSE) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return b.GetFee(feeBuilder) } diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index 8d150706..c5a671cd 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -854,6 +854,8 @@ func (c *CoinbasePro) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency) case exchange.InternationalBankDepositFee: fee = getInternationalBankDepositFee(feeBuilder.FiatCurrency) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -863,6 +865,11 @@ func (c *CoinbasePro) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0025 * price * amount +} + func (c *CoinbasePro) calculateTradingFee(trailingVolume []Volume, base, quote currency.Code, delimiter string, purchasePrice, amount float64, isMaker bool) float64 { var fee float64 for _, i := range trailingVolume { diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 7936b720..46cb5d4a 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -230,6 +230,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + c.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { c.SetDefaults() TestSetup(t) diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index fc7d4c5c..d0f5499a 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -288,6 +288,10 @@ func (c *CoinbasePro) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (c *CoinbasePro) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (c.APIKey == "" || c.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return c.GetFee(feeBuilder) } diff --git a/exchanges/coinut/coinut.go b/exchanges/coinut/coinut.go index fc96dcc2..aee0fc90 100644 --- a/exchanges/coinut/coinut.go +++ b/exchanges/coinut/coinut.go @@ -409,6 +409,8 @@ func (c *COINUT) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { case exchange.InternationalBankDepositFee: fee = getInternationalBankDepositFee(feeBuilder.FiatCurrency, feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.Pair, feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -418,6 +420,14 @@ func (c *COINUT) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(c currency.Pair, price, amount float64) float64 { + if c.IsCryptoFiatPair() { + return 0.0035 * price * amount + } + return 0.002 * price * amount +} + func (c *COINUT) calculateTradingFee(base, quote currency.Code, purchasePrice, amount float64, isMaker bool) float64 { var fee float64 diff --git a/exchanges/coinut/coinut_test.go b/exchanges/coinut/coinut_test.go index e1e4a059..755748d2 100644 --- a/exchanges/coinut/coinut_test.go +++ b/exchanges/coinut/coinut_test.go @@ -59,6 +59,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + c.GetFeeByType(feeBuilder) + if apiKey == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { c.SetDefaults() TestSetup(t) diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index b5a32fec..96760af5 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -383,6 +383,10 @@ func (c *COINUT) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (c *COINUT) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if c.APIKey == "" && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return c.GetFee(feeBuilder) } diff --git a/exchanges/exchange.go b/exchanges/exchange.go index e695ef8c..090a54b2 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -31,41 +31,42 @@ const ( ) // FeeType custom type for calculating fees based on method -type FeeType string - -// InternationalBankTransactionType custom type for calculating fees based on fiat transaction types -type InternationalBankTransactionType string +type FeeType uint8 // Const declarations for fee types const ( - BankFee FeeType = "bankFee" - InternationalBankDepositFee FeeType = "internationalBankDepositFee" - InternationalBankWithdrawalFee FeeType = "internationalBankWithdrawalFee" - CryptocurrencyTradeFee FeeType = "cryptocurrencyTradeFee" - CyptocurrencyDepositFee FeeType = "cyptocurrencyDepositFee" - CryptocurrencyWithdrawalFee FeeType = "cryptocurrencyWithdrawalFee" + BankFee FeeType = iota + InternationalBankDepositFee + InternationalBankWithdrawalFee + CryptocurrencyTradeFee + CyptocurrencyDepositFee + CryptocurrencyWithdrawalFee + OfflineTradeFee ) +// InternationalBankTransactionType custom type for calculating fees based on fiat transaction types +type InternationalBankTransactionType uint8 + // Const declarations for international transaction types const ( - WireTransfer InternationalBankTransactionType = "wireTransfer" - PerfectMoney InternationalBankTransactionType = "perfectMoney" - Neteller InternationalBankTransactionType = "neteller" - AdvCash InternationalBankTransactionType = "advCash" - Payeer InternationalBankTransactionType = "payeer" - Skrill InternationalBankTransactionType = "skrill" - Simplex InternationalBankTransactionType = "simplex" - SEPA InternationalBankTransactionType = "sepa" - Swift InternationalBankTransactionType = "swift" - RapidTransfer InternationalBankTransactionType = "rapidTransfer" - MisterTangoSEPA InternationalBankTransactionType = "misterTangoSepa" - Qiwi InternationalBankTransactionType = "qiwi" - VisaMastercard InternationalBankTransactionType = "visaMastercard" - WebMoney InternationalBankTransactionType = "webMoney" - Capitalist InternationalBankTransactionType = "capitalist" - WesternUnion InternationalBankTransactionType = "westernUnion" - MoneyGram InternationalBankTransactionType = "moneyGram" - Contact InternationalBankTransactionType = "contact" + WireTransfer InternationalBankTransactionType = iota + PerfectMoney + Neteller + AdvCash + Payeer + Skrill + Simplex + SEPA + Swift + RapidTransfer + MisterTangoSEPA + Qiwi + VisaMastercard + WebMoney + Capitalist + WesternUnion + MoneyGram + Contact ) // SubmitOrderResponse is what is returned after submitting an order to an @@ -78,25 +79,22 @@ type SubmitOrderResponse struct { // FeeBuilder is the type which holds all parameters required to calculate a fee // for an exchange type FeeBuilder struct { - FeeType FeeType - // Used for calculating crypto trading fees, deposits & withdrawals - Pair currency.Pair - IsMaker bool - // Fiat currency used for bank deposits & withdrawals + IsMaker bool + PurchasePrice float64 + Amount float64 + FeeType FeeType FiatCurrency currency.Code BankTransactionType InternationalBankTransactionType - // Used to multiply for fee calculations - PurchasePrice float64 - Amount float64 + Pair currency.Pair } // OrderCancellation type required when requesting to cancel an order type OrderCancellation struct { AccountID string OrderID string - CurrencyPair currency.Pair WalletAddress string Side OrderSide + CurrencyPair currency.Pair } // WithdrawRequest used for wrapper crypto and FIAT withdraw methods diff --git a/exchanges/exmo/exmo.go b/exchanges/exmo/exmo.go index 2250bf67..182b96d2 100644 --- a/exchanges/exmo/exmo.go +++ b/exchanges/exmo/exmo.go @@ -421,7 +421,7 @@ func (e *EXMO) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { var fee float64 switch feeBuilder.FeeType { case exchange.CryptocurrencyTradeFee: - fee = e.calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) case exchange.CryptocurrencyWithdrawalFee: fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) case exchange.InternationalBankWithdrawalFee: @@ -432,6 +432,8 @@ func (e *EXMO) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankDepositFee(feeBuilder.FiatCurrency, feeBuilder.Amount, feeBuilder.BankTransactionType) + case exchange.OfflineTradeFee: + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -445,14 +447,8 @@ func getCryptocurrencyWithdrawalFee(c currency.Code) float64 { return WithdrawalFees[c] } -func (e *EXMO) calculateTradingFee(purchasePrice, amount float64) float64 { - fee := 0.002 - return fee * amount * purchasePrice -} - -func calculateTradingFee(purchasePrice, amount float64) float64 { - fee := 0.002 - return fee * amount * purchasePrice +func calculateTradingFee(price, amount float64) float64 { + return 0.002 * price * amount } func getInternationalBankWithdrawalFee(c currency.Code, amount float64, bankTransactionType exchange.InternationalBankTransactionType) float64 { diff --git a/exchanges/exmo/exmo_test.go b/exchanges/exmo/exmo_test.go index 24189feb..2c624f14 100644 --- a/exchanges/exmo/exmo_test.go +++ b/exchanges/exmo/exmo_test.go @@ -116,6 +116,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + e.GetFeeByType(feeBuilder) + if APIKey == "" || APISecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { e.SetDefaults() TestSetup(t) diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index a6219095..dc2e2e09 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -316,6 +316,10 @@ func (e *EXMO) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (e *EXMO) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (e.APIKey == "" || e.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return e.GetFee(feeBuilder) } diff --git a/exchanges/gateio/gateio.go b/exchanges/gateio/gateio.go index b8f41470..2c1c6f32 100644 --- a/exchanges/gateio/gateio.go +++ b/exchanges/gateio/gateio.go @@ -538,6 +538,8 @@ func (g *Gateio) GetFee(feeBuilder *exchange.FeeBuilder) (fee float64, err error case exchange.CryptocurrencyWithdrawalFee: fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -547,6 +549,11 @@ func (g *Gateio) GetFee(feeBuilder *exchange.FeeBuilder) (fee float64, err error return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func calculateTradingFee(feeForPair, purchasePrice, amount float64) float64 { return (feeForPair / 100) * purchasePrice * amount } diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index 4ef3923f..38184e48 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -156,6 +156,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + g.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { g.SetDefaults() TestSetup(t) diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index a0c1f563..f4f681a9 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -332,6 +332,10 @@ func (g *Gateio) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (g *Gateio) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (g.APIKey == "" || g.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return g.GetFee(feeBuilder) } diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index 4f933cff..228b998a 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -546,6 +546,8 @@ func (g *Gemini) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { // Could do via trade history, but would require analysis of response and dates to determine level of fee case exchange.InternationalBankWithdrawalFee: fee = 0 + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -554,6 +556,11 @@ func (g *Gemini) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.01 * price * amount +} + func calculateTradingFee(notionVolume *NotionalVolume, purchasePrice, amount float64, isMaker bool) float64 { var volumeFee float64 if isMaker { diff --git a/exchanges/gemini/gemini_test.go b/exchanges/gemini/gemini_test.go index 0037befb..1620e60e 100644 --- a/exchanges/gemini/gemini_test.go +++ b/exchanges/gemini/gemini_test.go @@ -247,6 +247,24 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + TestAddSession(t) + TestSetDefaults(t) + TestSetup(t) + var feeBuilder = setFeeBuilder() + Session[1].GetFeeByType(feeBuilder) + if apiKey1 == "" || apiSecret1 == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { var feeBuilder = setFeeBuilder() if apiKey1 != "" && apiSecret1 != "" { @@ -342,7 +360,6 @@ func TestGetActiveOrders(t *testing.T) { TestAddSession(t) TestSetDefaults(t) TestSetup(t) - Session[1].Verbose = true var getOrdersRequest = exchange.GetOrdersRequest{ OrderType: exchange.AnyOrderType, @@ -361,7 +378,6 @@ func TestGetOrderHistory(t *testing.T) { TestAddSession(t) TestSetDefaults(t) TestSetup(t) - Session[1].Verbose = true var getOrdersRequest = exchange.GetOrdersRequest{ OrderType: exchange.AnyOrderType, diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index 606be83f..3ea4c1e5 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -259,6 +259,10 @@ func (g *Gemini) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (g *Gemini) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (g.APIKey == "" || g.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return g.GetFee(feeBuilder) } diff --git a/exchanges/hitbtc/hitbtc.go b/exchanges/hitbtc/hitbtc.go index fc8c1a5a..038d897a 100644 --- a/exchanges/hitbtc/hitbtc.go +++ b/exchanges/hitbtc/hitbtc.go @@ -641,11 +641,21 @@ func (h *HitBTC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { case exchange.CyptocurrencyDepositFee: fee = calculateCryptocurrencyDepositFee(feeBuilder.Pair.Base, feeBuilder.Amount) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) + } + if fee < 0 { + fee = 0 } return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func calculateCryptocurrencyDepositFee(c currency.Code, amount float64) float64 { var fee float64 if c == currency.BTC { diff --git a/exchanges/hitbtc/hitbtc_test.go b/exchanges/hitbtc/hitbtc_test.go index a0a23aeb..52b0082b 100644 --- a/exchanges/hitbtc/hitbtc_test.go +++ b/exchanges/hitbtc/hitbtc_test.go @@ -75,6 +75,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + h.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { h.SetDefaults() TestSetup(t) diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index 278fa89a..5c1f3bc9 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -286,6 +286,10 @@ func (h *HitBTC) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (h *HitBTC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (h.APIKey == "" || h.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return h.GetFee(feeBuilder) } diff --git a/exchanges/huobi/huobi.go b/exchanges/huobi/huobi.go index 439fcd06..02f17d0b 100644 --- a/exchanges/huobi/huobi.go +++ b/exchanges/huobi/huobi.go @@ -914,8 +914,8 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url // GetFee returns an estimate of fee based on type of transaction func (h *HUOBI) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { var fee float64 - if feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { - fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) + if feeBuilder.FeeType == exchange.OfflineTradeFee || feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + fee = calculateTradingFee(feeBuilder.Pair, feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -924,7 +924,9 @@ func (h *HUOBI) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } -func calculateTradingFee(purchasePrice, amount float64) float64 { - feePercent := 0.002 - return feePercent * purchasePrice * amount +func calculateTradingFee(c currency.Pair, price, amount float64) float64 { + if c.IsCryptoFiatPair() { + return 0.001 * price * amount + } + return 0.002 * price * amount } diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index 156b316f..a7081a28 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -305,6 +305,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + h.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 50573bb0..eac670e7 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -393,6 +393,10 @@ func (h *HUOBI) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (h *HUOBI) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (h.APIKey == "" || h.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return h.GetFee(feeBuilder) } diff --git a/exchanges/huobihadax/huobihadax.go b/exchanges/huobihadax/huobihadax.go index 9a5f1b44..788b038c 100644 --- a/exchanges/huobihadax/huobihadax.go +++ b/exchanges/huobihadax/huobihadax.go @@ -885,8 +885,8 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPRequest(method, endpoint string, value // GetFee returns an estimate of fee based on type of transaction func (h *HUOBIHADAX) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { var fee float64 - if feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { - fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) + if feeBuilder.FeeType == exchange.OfflineTradeFee || feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + fee = calculateTradingFee(feeBuilder.Pair, feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -895,9 +895,11 @@ func (h *HUOBIHADAX) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } -func calculateTradingFee(purchasePrice, amount float64) float64 { - feePercent := 0.002 - return feePercent * purchasePrice * amount +func calculateTradingFee(c currency.Pair, price, amount float64) float64 { + if c.IsCryptoFiatPair() { + return 0.001 * price * amount + } + return 0.002 * price * amount } // GetDepositWithdrawalHistory returns deposit or withdrawal data diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index b7af942c..505dfaf6 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -285,6 +285,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + h.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() diff --git a/exchanges/huobihadax/huobihadax_wrapper.go b/exchanges/huobihadax/huobihadax_wrapper.go index c975ae82..c1071852 100644 --- a/exchanges/huobihadax/huobihadax_wrapper.go +++ b/exchanges/huobihadax/huobihadax_wrapper.go @@ -349,6 +349,10 @@ func (h *HUOBIHADAX) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (h *HUOBIHADAX) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (h.APIKey == "" || h.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return h.GetFee(feeBuilder) } diff --git a/exchanges/itbit/itbit.go b/exchanges/itbit/itbit.go index 1cd836ef..87795d43 100644 --- a/exchanges/itbit/itbit.go +++ b/exchanges/itbit/itbit.go @@ -428,6 +428,8 @@ func (i *ItBit) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker) case exchange.InternationalBankWithdrawalFee: fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.BankTransactionType) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -437,12 +439,17 @@ func (i *ItBit) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0035 * price * amount +} + func calculateTradingFee(purchasePrice, amount float64, isMaker bool) float64 { // TODO: Itbit has volume discounts, but not API endpoint to get the exact volume numbers // When support is added, this needs to be updated to calculate the accurate volume fee - feePercent := 0.0025 + feePercent := 0.0035 if isMaker { - feePercent = 0 + feePercent = -0.0003 } return feePercent * purchasePrice * amount } diff --git a/exchanges/itbit/itbit_test.go b/exchanges/itbit/itbit_test.go index 87f1aacf..93f5dd26 100644 --- a/exchanges/itbit/itbit_test.go +++ b/exchanges/itbit/itbit_test.go @@ -154,21 +154,36 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + i.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() // CryptocurrencyTradeFee Basic - if resp, err := i.GetFee(feeBuilder); resp != float64(0.0025) || err != nil { + if resp, err := i.GetFee(feeBuilder); resp != float64(0.0035) || err != nil { t.Error(err) - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.002), resp) + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0035), resp) } // CryptocurrencyTradeFee High quantity feeBuilder = setFeeBuilder() feeBuilder.Amount = 1000 feeBuilder.PurchasePrice = 1000 - if resp, err := i.GetFee(feeBuilder); resp != float64(2500) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(2500), resp) + if resp, err := i.GetFee(feeBuilder); resp != float64(3500) || err != nil { + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(3500), resp) t.Error(err) } diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index 9663b542..deeff7ff 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -301,6 +301,10 @@ func (i *ItBit) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (i *ItBit) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (i.APIKey == "" || i.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return i.GetFee(feeBuilder) } diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index 1df51b07..ca16fa6c 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -1020,6 +1020,8 @@ func (k *Kraken) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { case exchange.InternationalBankWithdrawalFee: fee = getWithdrawalFee(feeBuilder.FiatCurrency) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -1028,6 +1030,11 @@ func (k *Kraken) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0016 * price * amount +} + func getWithdrawalFee(c currency.Code) float64 { return WithdrawalFees[c] } diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index b34ad7c8..64a57e5e 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -256,6 +256,22 @@ func setFeeBuilder() *exchange.FeeBuilder { } // TestGetFee logic test + +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + k.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { k.SetDefaults() TestSetup(t) diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 27a6ab4e..fc9937e8 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -312,6 +312,10 @@ func (k *Kraken) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (k *Kraken) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (k.APIKey == "" || k.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return k.GetFee(feeBuilder) } diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go index 11fe0d0f..80452e18 100644 --- a/exchanges/lakebtc/lakebtc.go +++ b/exchanges/lakebtc/lakebtc.go @@ -388,6 +388,8 @@ func (l *LakeBTC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { // fees for withdrawals are dynamic. They cannot be calculated in // advance as they are manually performed via the website, it can only // be determined when submitting the request + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { @@ -397,6 +399,11 @@ func (l *LakeBTC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func calculateTradingFee(purchasePrice, amount float64, isMaker bool) (fee float64) { if isMaker { // TODO: Volume based fee calculation diff --git a/exchanges/lakebtc/lakebtc_test.go b/exchanges/lakebtc/lakebtc_test.go index 3d037a85..7b067abf 100644 --- a/exchanges/lakebtc/lakebtc_test.go +++ b/exchanges/lakebtc/lakebtc_test.go @@ -148,6 +148,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + l.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go index 271e3270..b57823c4 100644 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ b/exchanges/lakebtc/lakebtc_wrapper.go @@ -276,6 +276,10 @@ func (l *LakeBTC) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (l *LakeBTC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (l.APIKey == "" || l.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return l.GetFee(feeBuilder) } diff --git a/exchanges/localbitcoins/localbitcoins_test.go b/exchanges/localbitcoins/localbitcoins_test.go index 57d7636c..12f5d17c 100644 --- a/exchanges/localbitcoins/localbitcoins_test.go +++ b/exchanges/localbitcoins/localbitcoins_test.go @@ -108,6 +108,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + l.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { l.SetDefaults() var feeBuilder = setFeeBuilder() diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index 5e448850..ff9f962e 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -303,6 +303,10 @@ func (l *LocalBitcoins) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (l *LocalBitcoins) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (l.APIKey == "" || l.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return l.GetFee(feeBuilder) } diff --git a/exchanges/okcoin/okcoin_test.go b/exchanges/okcoin/okcoin_test.go index 5ddba65a..0fa413a5 100644 --- a/exchanges/okcoin/okcoin_test.go +++ b/exchanges/okcoin/okcoin_test.go @@ -1040,6 +1040,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + o.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { TestSetDefaults(t) var feeBuilder = setFeeBuilder() @@ -1059,7 +1074,7 @@ func TestGetFee(t *testing.T) { // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true - if resp, err := o.GetFee(feeBuilder); resp != float64(0.00100) || err != nil { + if resp, err := o.GetFee(feeBuilder); resp != float64(0.0005) || err != nil { t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0005), resp) t.Error(err) } diff --git a/exchanges/okex/okex_test.go b/exchanges/okex/okex_test.go index 2021c02f..be3dd882 100644 --- a/exchanges/okex/okex_test.go +++ b/exchanges/okex/okex_test.go @@ -1553,6 +1553,7 @@ func TestGetETTOrderDetails(t *testing.T) { // TestGetETTConstituents API endpoint test func TestGetETTConstituents(t *testing.T) { + t.Skip("ETT currently unavailable") TestSetDefaults(t) t.Parallel() _, err := o.GetETTConstituents("OK06ETT") @@ -1563,6 +1564,7 @@ func TestGetETTConstituents(t *testing.T) { // TestGetETTSettlementPriceHistory API endpoint test func TestGetETTSettlementPriceHistory(t *testing.T) { + t.Skip("ETT currently unavailable") TestSetDefaults(t) t.Parallel() _, err := o.GetETTSettlementPriceHistory("OK06ETT") @@ -1810,7 +1812,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } -// TestGetFee fee calcuation test +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + o.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { TestSetDefaults(t) t.Parallel() @@ -1833,8 +1849,8 @@ func TestGetFee(t *testing.T) { // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true - if resp, err := o.GetFee(feeBuilder); resp != float64(0.001) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp) + if resp, err := o.GetFee(feeBuilder); resp != float64(0.0005) || err != nil { + t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0005), resp) t.Error(err) } diff --git a/exchanges/okgroup/okgroup.go b/exchanges/okgroup/okgroup.go index dfbec673..e454435e 100644 --- a/exchanges/okgroup/okgroup.go +++ b/exchanges/okgroup/okgroup.go @@ -680,6 +680,8 @@ func (o *OKGroup) GetFee(feeBuilder *exchange.FeeBuilder) (fee float64, _ error) break } } + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -688,10 +690,15 @@ func (o *OKGroup) GetFee(feeBuilder *exchange.FeeBuilder) (fee float64, _ error) return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.0015 * price * amount +} + func calculateTradingFee(purchasePrice, amount float64, isMaker bool) (fee float64) { // TODO volume based fees if isMaker { - fee = 0.001 + fee = 0.0005 } else { fee = 0.0015 } diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index bd8124d6..8d0d3194 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -414,6 +414,10 @@ func (o *OKGroup) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (o *OKGroup) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (o.APIKey == "" || o.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return o.GetFee(feeBuilder) } diff --git a/exchanges/poloniex/poloniex.go b/exchanges/poloniex/poloniex.go index 689ad54e..21c24ca8 100644 --- a/exchanges/poloniex/poloniex.go +++ b/exchanges/poloniex/poloniex.go @@ -914,6 +914,8 @@ func (p *Poloniex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { case exchange.CryptocurrencyWithdrawalFee: fee = getWithdrawalFee(feeBuilder.Pair.Base) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -922,6 +924,11 @@ func (p *Poloniex) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func calculateTradingFee(feeInfo Fee, purchasePrice, amount float64, isMaker bool) (fee float64) { if isMaker { fee = feeInfo.MakerFee diff --git a/exchanges/poloniex/poloniex_test.go b/exchanges/poloniex/poloniex_test.go index e18be2c3..bb273932 100644 --- a/exchanges/poloniex/poloniex_test.go +++ b/exchanges/poloniex/poloniex_test.go @@ -99,6 +99,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + p.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { p.SetDefaults() TestSetup(t) diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index 87c4987c..aa98b2cf 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -310,6 +310,10 @@ func (p *Poloniex) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (p *Poloniex) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (p.APIKey == "" || p.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return p.GetFee(feeBuilder) } diff --git a/exchanges/yobit/yobit.go b/exchanges/yobit/yobit.go index 40694725..ba472d13 100644 --- a/exchanges/yobit/yobit.go +++ b/exchanges/yobit/yobit.go @@ -399,6 +399,8 @@ func (y *Yobit) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount, feeBuilder.BankTransactionType) + case exchange.OfflineTradeFee: + fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -407,9 +409,8 @@ func (y *Yobit) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } -func calculateTradingFee(purchasePrice, amount float64) (fee float64) { - fee = 0.002 - return fee * amount * purchasePrice +func calculateTradingFee(price, amount float64) (fee float64) { + return 0.002 * price * amount } func getWithdrawalFee(c currency.Code) float64 { diff --git a/exchanges/yobit/yobit_test.go b/exchanges/yobit/yobit_test.go index 269f5835..a6c48978 100644 --- a/exchanges/yobit/yobit_test.go +++ b/exchanges/yobit/yobit_test.go @@ -147,6 +147,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + y.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { y.SetDefaults() TestSetup(t) diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index c783c1cf..eef57754 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -280,6 +280,10 @@ func (y *Yobit) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (y *Yobit) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (y.APIKey == "" || y.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return y.GetFee(feeBuilder) } diff --git a/exchanges/zb/zb.go b/exchanges/zb/zb.go index 193e2d5f..dbbb9229 100644 --- a/exchanges/zb/zb.go +++ b/exchanges/zb/zb.go @@ -422,6 +422,8 @@ func (z *ZB) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount) case exchange.CryptocurrencyWithdrawalFee: fee = getWithdrawalFee(feeBuilder.Pair.Base) + case exchange.OfflineTradeFee: + fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) } if fee < 0 { fee = 0 @@ -430,6 +432,11 @@ func (z *ZB) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { return fee, nil } +// getOfflineTradeFee calculates the worst case-scenario trading fee +func getOfflineTradeFee(price, amount float64) float64 { + return 0.002 * price * amount +} + func calculateTradingFee(purchasePrice, amount float64) (fee float64) { fee = 0.002 return fee * amount * purchasePrice diff --git a/exchanges/zb/zb_test.go b/exchanges/zb/zb_test.go index 707f94f8..a60b042a 100644 --- a/exchanges/zb/zb_test.go +++ b/exchanges/zb/zb_test.go @@ -138,6 +138,21 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +// TestGetFeeByTypeOfflineTradeFee logic test +func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { + var feeBuilder = setFeeBuilder() + z.GetFeeByType(feeBuilder) + if apiKey == "" || apiSecret == "" { + if feeBuilder.FeeType != exchange.OfflineTradeFee { + t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) + } + } else { + if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { + t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) + } + } +} + func TestGetFee(t *testing.T) { z.SetDefaults() TestSetup(t) diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index abbea0cc..5cfc81a5 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -307,6 +307,10 @@ func (z *ZB) GetWebsocket() (*exchange.Websocket, error) { // GetFeeByType returns an estimate of fee based on type of transaction func (z *ZB) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { + if (z.APIKey == "" || z.APISecret == "") && // Todo check connection status + feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { + feeBuilder.FeeType = exchange.OfflineTradeFee + } return z.GetFee(feeBuilder) }