Calculating each exchange's fees (#188)

* Adds some constants for fee types
Adds some fee calculation in an attempt to be generic
Adds fee stuff to Bittrex
Adds fee stuff to bitstamp

* Fixes bitstamp fee calculation

* Tests
Tests all scenarios for GetFeeByType

* Adds method to wrapper
Adds err to response
Checks for err

* Adds support for Bittrex fees

* Adds maker/taker dynamic to fees
Updates tests
Adds bitmex fee support
Removes unused switch case scenarios to not waste space

* Adds bithumb support for fee calculation

* Adds Bitfinex fee support
Adds list of currencies as const strings
Sets up bitflyer

* Fixes arguments

* Greatly expands symbols
Adds Binance fee calculation support
Cleans up previous exchanges

* Fixes errors for fee calculations

* Adds ANX fee support

* Adds btcc fee support
Adds alphapoint fee wrapper support
Renames method to match "enum"
Uses symbols in tests, not inline strings

* Adds support for BTCMarkets fee calculation
Adds new method to retrieve fee amount from BTCMarkets
Adds new fee type struct: FeeBuilder
Updates ANX and BTCMarkets to use new FeeBuilder type struct
Standardises the tests to run when it comes to fee calculation

* Migrates all existing exchange fee to use new feebuilder type struct
Uses standard testing model

* Fixes unit tests

* Updates maker taker fees in test config

* Removes parallel from fee testing

* Removes more parallel from tests

* Adds coinbasepro fee support

* Adds Coinut fee support

* Adds Exmo fee support
Adds maker fee support to coinut
Introduces a type for fees and bank transfers to prevent random strings being used

* Adds partial bitflyer support
Moves bitflyer to feeBuilder struct

* Adds gateio fee support

* Adds Gemini fee support

* Adds hitbtc fee support

* Adds huobi fee support

* Adds HuobiHadax fee support

* Adds itbit fee support

* Adds partial kraken fee support with trading fees

* Finishes basic Kraken fee support

* Adds basic LakeBTC fee support

* Adds basic liqui fee support

* Adds localbitcoins fee support.......

* Adds basic okcoin fee support

* Adds simple OKEX fee support
Adds many new currency symbols
Fixes liqui's fees

* Adds poloniex fee support

* Adds fee support for Yobit

* Adds WEX fee support

* Adds ZB fee support

* Removes bad reference

* Improves accuracy of variable name

* trading fee method names are now consistent

(cherry picked from commit 21c82e8b90cae590cfd73d365d7be39e1a00e973)

* Fixes rebasing issues

* Fixes issues from rebase
Removes "IsTaker" as IsMaker bool can imply taker
Updates tests to actually work.

* Adds a zero to the test

* Fixes bitfinex api endpoints and fixes fee calculations

* Updates btcmarkets trading fee calculation

* Verifies tests with apis for all exchanges except coinbasepro, itbit and bitflyer
Removes taker fee test as taker is default

* Removes redundant all exchange wrapper error checks due to the error checks being redundant

* Addresses review comments:
- Renames variables
- Changes how functions return data
- Fixes typo
This commit is contained in:
Scott
2018-10-29 12:32:46 +11:00
committed by Adrian Gallagher
parent 83263f3245
commit e4c443b901
108 changed files with 8468 additions and 538 deletions

View File

@@ -652,3 +652,48 @@ func (b *Binance) SetValues() {
TimeIntervalMonth,
}
}
// GetFee returns an estimate of fee based on type of transaction
func (b *Binance) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
var fee float64
switch feeBuilder.FeeType {
case exchange.CryptocurrencyTradeFee:
multiplier, err := b.getMultiplier(feeBuilder.IsMaker)
if err != nil {
return 0, err
}
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, multiplier)
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency, feeBuilder.PurchasePrice, feeBuilder.Amount)
}
if fee < 0 {
fee = 0
}
return fee, nil
}
// getMultiplier retrieves account based taker/maker fees
func (b *Binance) getMultiplier(isMaker bool) (float64, error) {
var multiplier float64
account, err := b.GetAccount()
if err != nil {
return 0, err
}
if isMaker {
multiplier = float64(account.MakerCommission)
} else {
multiplier = float64(account.TakerCommission)
}
return multiplier, nil
}
// calculateTradingFee returns the fee for trading any currency on Bittrex
func calculateTradingFee(purchasePrice, amount, multiplier float64) float64 {
return (multiplier / 100) * purchasePrice * amount
}
// getCryptocurrencyWithdrawalFee returns the fee for withdrawing from the exchange
func getCryptocurrencyWithdrawalFee(currency string, purchasePrice, amount float64) float64 {
return WithdrawalFees[currency]
}

View File

@@ -3,7 +3,10 @@ package binance
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
// Please supply your own keys here for due diligence testing
@@ -29,7 +32,6 @@ func TestSetup(t *testing.T) {
binanceConfig.AuthenticatedAPISupport = true
binanceConfig.APIKey = testAPIKey
binanceConfig.APISecret = testAPISecret
b.Setup(binanceConfig)
}
@@ -205,3 +207,112 @@ func TestAllOrders(t *testing.T) {
t.Error("Test Failed - Binance AllOrders() error", err)
}
}
func TestGetAccount(t *testing.T) {
if testAPIKey == "" || testAPISecret == "" {
t.Skip()
}
t.Parallel()
b.SetDefaults()
TestSetup(t)
account, err := b.GetAccount()
if err != nil {
t.Fatal("Test Failed - Binance GetAccount() error", err)
}
if account.MakerCommission <= 0 {
t.Fatalf("Test Failed. Expected > 0, Recieved %d", account.MakerCommission)
}
if account.TakerCommission <= 0 {
t.Fatalf("Test Failed. Expected > 0, Recieved %d", account.TakerCommission)
}
t.Logf("Current makerFee: %d", account.MakerCommission)
t.Logf("Current takerFee: %d", account.TakerCommission)
}
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
}
}
func TestGetFee(t *testing.T) {
b.SetDefaults()
TestSetup(t)
var feeBuilder = setFeeBuilder()
if testAPIKey != "" || testAPISecret != "" {
// CryptocurrencyTradeFee Basic
if resp, err := b.GetFee(feeBuilder); resp != float64(0.1) || err != nil {
t.Error(err)
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0), resp)
}
// CryptocurrencyTradeFee High quantity
feeBuilder = setFeeBuilder()
feeBuilder.Amount = 1000
feeBuilder.PurchasePrice = 1000
if resp, err := b.GetFee(feeBuilder); resp != float64(100000) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(100000), resp)
t.Error(err)
}
// CryptocurrencyTradeFee IsMaker
feeBuilder = setFeeBuilder()
feeBuilder.IsMaker = true
if resp, err := b.GetFee(feeBuilder); resp != float64(0.1) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0.1), resp)
t.Error(err)
}
// CryptocurrencyTradeFee Negative purchase price
feeBuilder = setFeeBuilder()
feeBuilder.PurchasePrice = -1000
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0), resp)
t.Error(err)
}
}
// CryptocurrencyWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0005) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0.0005), resp)
t.Error(err)
}
// CyptocurrencyDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Recieved: %f", float64(0), resp)
t.Error(err)
}
}

View File

@@ -2,6 +2,8 @@ package binance
import (
"encoding/json"
"github.com/thrasher-/gocryptotrader/currency/symbol"
)
// Response holds basic binance api response data
@@ -432,3 +434,172 @@ var (
TimeIntervalWeek = TimeInterval("1w")
TimeIntervalMonth = TimeInterval("1M")
)
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.BNB: 0.13,
symbol.BTC: 0.0005,
symbol.NEO: 0,
symbol.ETH: 0.01,
symbol.LTC: 0.001,
symbol.QTUM: 0.01,
symbol.EOS: 0.1,
symbol.SNT: 35,
symbol.BNT: 1,
symbol.GAS: 0,
symbol.BCC: 0.001,
symbol.BTM: 5,
symbol.USDT: 3.4,
symbol.HCC: 0.0005,
symbol.OAX: 6.5,
symbol.DNT: 54,
symbol.MCO: 0.31,
symbol.ICN: 3.5,
symbol.ZRX: 1.9,
symbol.OMG: 0.4,
symbol.WTC: 0.5,
symbol.LRC: 12.3,
symbol.LLT: 67.8,
symbol.YOYO: 1,
symbol.TRX: 1,
symbol.STRAT: 0.1,
symbol.SNGLS: 54,
symbol.BQX: 3.9,
symbol.KNC: 3.5,
symbol.SNM: 25,
symbol.FUN: 86,
symbol.LINK: 4,
symbol.XVG: 0.1,
symbol.CTR: 35,
symbol.SALT: 2.3,
symbol.MDA: 2.3,
symbol.IOTA: 0.5,
symbol.SUB: 11.4,
symbol.ETC: 0.01,
symbol.MTL: 2,
symbol.MTH: 45,
symbol.ENG: 2.2,
symbol.AST: 14.4,
symbol.DASH: 0.002,
symbol.BTG: 0.001,
symbol.EVX: 2.8,
symbol.REQ: 29.9,
symbol.VIB: 30,
symbol.POWR: 8.2,
symbol.ARK: 0.2,
symbol.XRP: 0.25,
symbol.MOD: 2,
symbol.ENJ: 26,
symbol.STORJ: 5.1,
symbol.KMD: 0.002,
symbol.RCN: 47,
symbol.NULS: 0.01,
symbol.RDN: 2.5,
symbol.XMR: 0.04,
symbol.DLT: 19.8,
symbol.AMB: 8.9,
symbol.BAT: 8,
symbol.ZEC: 0.005,
symbol.BCPT: 14.5,
symbol.ARN: 3,
symbol.GVT: 0.13,
symbol.CDT: 81,
symbol.GXS: 0.3,
symbol.POE: 134,
symbol.QSP: 36,
symbol.BTS: 1,
symbol.XZC: 0.02,
symbol.LSK: 0.1,
symbol.TNT: 47,
symbol.FUEL: 79,
symbol.MANA: 18,
symbol.BCD: 0.01,
symbol.DGD: 0.04,
symbol.ADX: 6.3,
symbol.ADA: 1,
symbol.PPT: 0.41,
symbol.CMT: 12,
symbol.XLM: 0.01,
symbol.CND: 58,
symbol.LEND: 84,
symbol.WABI: 6.6,
symbol.SBTC: 0.0005,
symbol.BCX: 0.5,
symbol.WAVES: 0.002,
symbol.TNB: 139,
symbol.GTO: 20,
symbol.ICX: 0.02,
symbol.OST: 32,
symbol.ELF: 3.9,
symbol.AION: 3.2,
symbol.CVC: 10.9,
symbol.REP: 0.2,
symbol.GNT: 8.9,
symbol.DATA: 37,
symbol.ETF: 1,
symbol.BRD: 3.8,
symbol.NEBL: 0.01,
symbol.VIBE: 17.3,
symbol.LUN: 0.36,
symbol.CHAT: 60.7,
symbol.RLC: 3.4,
symbol.INS: 3.5,
symbol.IOST: 105.6,
symbol.STEEM: 0.01,
symbol.NANO: 0.01,
symbol.AE: 1.3,
symbol.VIA: 0.01,
symbol.BLZ: 10.3,
symbol.SYS: 1,
symbol.NCASH: 247.6,
symbol.POA: 0.01,
symbol.ONT: 1,
symbol.ZIL: 37.2,
symbol.STORM: 152,
symbol.XEM: 4,
symbol.WAN: 0.1,
symbol.WPR: 43.4,
symbol.QLC: 1,
symbol.GRS: 0.2,
symbol.CLOAK: 0.02,
symbol.LOOM: 11.9,
symbol.BCN: 1,
symbol.TUSD: 1.35,
symbol.ZEN: 0.002,
symbol.SKY: 0.01,
symbol.THETA: 24,
symbol.IOTX: 90.5,
symbol.QKC: 24.6,
symbol.AGI: 29.81,
symbol.NXS: 0.02,
symbol.SC: 0.1,
symbol.EON: 10,
symbol.NPXS: 897,
symbol.KEY: 223,
symbol.NAS: 0.1,
symbol.ADD: 100,
symbol.MEETONE: 300,
symbol.ATD: 100,
symbol.MFT: 175,
symbol.EOP: 5,
symbol.DENT: 596,
symbol.IQ: 50,
symbol.ARDR: 2,
symbol.HOT: 1210,
symbol.VET: 100,
symbol.DOCK: 68,
symbol.POLY: 7,
symbol.VTHO: 21,
symbol.ONG: 0.1,
symbol.PHX: 1,
symbol.HC: 0.005,
symbol.GO: 0.01,
symbol.PAX: 1.4,
symbol.EDO: 1.3,
symbol.WINGS: 8.9,
symbol.NAV: 0.2,
symbol.TRIG: 49.1,
symbol.APPC: 12.4,
symbol.PIVX: 0.02,
}

View File

@@ -194,3 +194,8 @@ func (b *Binance) WithdrawFiatExchangeFundsToInternationalBank(currency pair.Cur
func (b *Binance) GetWebsocket() (*exchange.Websocket, error) {
return b.Websocket, nil
}
// GetFeeByType returns an estimate of fee based on type of transaction
func (b *Binance) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, error) {
return b.GetFee(feeBuilder)
}