Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Enable additional ccxt params and http headers (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reidmcc authored and nikhilsaraf committed Apr 12, 2019
1 parent 860d76b commit e7c76fe
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 54 deletions.
12 changes: 12 additions & 0 deletions api/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ type ExchangeAPIKey struct {
Secret string
}

// ExchangeParam specifies an additional parameter to be sent when initializing the exchange
type ExchangeParam struct {
Param string
Value string
}

// ExchangeHeader specifies additional HTTP headers
type ExchangeHeader struct {
Header string
Value string
}

// Account allows you to access key account functions
type Account interface {
GetAccountBalances(assetList []interface{}) (map[interface{}]model.Number, error)
Expand Down
18 changes: 17 additions & 1 deletion cmd/trade.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,24 @@ func makeExchangeShimSdex(
})
}

exchangeParams := []api.ExchangeParam{}
for _, param := range botConfig.ExchangeParams {
exchangeParams = append(exchangeParams, api.ExchangeParam{
Param: param.Param,
Value: param.Value,
})
}

exchangeHeaders := []api.ExchangeHeader{}
for _, header := range botConfig.ExchangeHeaders {
exchangeHeaders = append(exchangeHeaders, api.ExchangeHeader{
Header: header.Header,
Value: header.Value,
})
}

var exchangeAPI api.Exchange
exchangeAPI, e = plugins.MakeTradingExchange(botConfig.TradingExchange, exchangeAPIKeys, *options.simMode)
exchangeAPI, e = plugins.MakeTradingExchange(botConfig.TradingExchange, exchangeAPIKeys, exchangeParams, exchangeHeaders, *options.simMode)
if e != nil {
logger.Fatal(l, fmt.Errorf("unable to make trading exchange: %s", e))
return nil, nil
Expand Down
12 changes: 11 additions & 1 deletion examples/configs/trader/sample_mirror.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,14 @@ PER_LEVEL_SPREAD=0.005
# you can use multiple API keys to overcome rate limit concerns
#[[EXCHANGE_API_KEYS]]
#KEY=""
#SECRET=""
#SECRET=""

# if your exchange requires additional parameters, list them here with the the necessary values (only ccxt supported currently)
#[[EXCHANGE_PARAMS]]
#PARAM=""
#VALUE=""

# if your exchange requires additional headers, list them here with the the necessary values (only ccxt supported currently)
#[[EXCHANGE_HEADERS]]
#HEADER=""
#VALUE=""
17 changes: 17 additions & 0 deletions examples/configs/trader/sample_trader.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,20 @@ MAX_OP_FEE_STROOPS=5000
#[[EXCHANGE_API_KEYS]]
#KEY=""
#SECRET=""

# if your exchange requires additional parameters during initialization, list them here (only ccxt supported currently)
# Note that some CCXT exchanges require additional parameters, e.g. coinbase pro requires a "password"
#[[EXCHANGE_PARAMS]]
#PARAM=""
#VALUE=""
#[[EXCHANGE_PARAMS]]
#PARAM=""
#VALUE=""

# if your exchange requires additional parameters as http headers, list them here (only ccxt supported currently)
#[[EXCHANGE_HEADERS]]
#HEADER=""
#VALUE=""
#[[EXCHANGE_HEADERS]]
#HEADER=""
#VALUE=""
4 changes: 3 additions & 1 deletion plugins/ccxtExchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func makeCcxtExchange(
exchangeName string,
orderConstraintOverrides map[model.TradingPair]model.OrderConstraints,
apiKeys []api.ExchangeAPIKey,
exchangeParams []api.ExchangeParam,
headers []api.ExchangeHeader,
simMode bool,
) (api.Exchange, error) {
if len(apiKeys) == 0 {
Expand All @@ -42,7 +44,7 @@ func makeCcxtExchange(
return nil, fmt.Errorf("need exactly 1 ExchangeAPIKey")
}

c, e := sdk.MakeInitializedCcxtExchange(exchangeName, apiKeys[0])
c, e := sdk.MakeInitializedCcxtExchange(exchangeName, apiKeys[0], exchangeParams, headers)
if e != nil {
return nil, fmt.Errorf("error making a ccxt exchange: %s", e)
}
Expand Down
22 changes: 12 additions & 10 deletions plugins/ccxtExchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

var supportedExchanges = []string{"binance"}
var emptyAPIKey = api.ExchangeAPIKey{}
var emptyParams = api.ExchangeParam{}
var supportedTradingExchanges = map[string]api.ExchangeAPIKey{
"binance": {},
}
Expand All @@ -30,7 +31,7 @@ func TestGetTickerPrice_Ccxt(t *testing.T) {

for _, exchangeName := range supportedExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand All @@ -57,7 +58,7 @@ func TestGetOrderBook_Ccxt(t *testing.T) {

for _, exchangeName := range supportedExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -90,7 +91,7 @@ func TestGetTrades_Ccxt(t *testing.T) {

for _, exchangeName := range supportedExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{emptyAPIKey}, []api.ExchangeParam{}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand All @@ -115,7 +116,7 @@ func TestGetTradeHistory_Ccxt(t *testing.T) {

for exchangeName, apiKey := range supportedTradingExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -173,7 +174,7 @@ func validateTrades(t *testing.T, pair model.TradingPair, trades []model.Trade)
func TestGetLatestTradeCursor_Ccxt(t *testing.T) {
for exchangeName, apiKey := range supportedTradingExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -212,7 +213,7 @@ func TestGetAccountBalances_Ccxt(t *testing.T) {

for exchangeName, apiKey := range supportedTradingExchanges {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -257,7 +258,7 @@ func TestGetOpenOrders_Ccxt(t *testing.T) {
for exchangeName, apiKey := range supportedTradingExchanges {
for _, pair := range tradingPairs {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -372,7 +373,7 @@ func TestAddOrder_Ccxt(t *testing.T) {
},
} {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down Expand Up @@ -422,7 +423,7 @@ func TestCancelOrder_Ccxt(t *testing.T) {
},
} {
t.Run(exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, false)
testCcxtExchange, e := makeCcxtExchange(exchangeName, testOrderConstraints, []api.ExchangeAPIKey{apiKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand All @@ -442,6 +443,7 @@ func TestCancelOrder_Ccxt(t *testing.T) {
}

func TestGetOrderConstraints_Ccxt_Precision(t *testing.T) {
// coinbasepro gives incorrect precision values so we do not test it here
testCases := []struct {
exchangeName string
pair *model.TradingPair
Expand Down Expand Up @@ -473,7 +475,7 @@ func TestGetOrderConstraints_Ccxt_Precision(t *testing.T) {

for _, kase := range testCases {
t.Run(kase.exchangeName, func(t *testing.T) {
testCcxtExchange, e := makeCcxtExchange(kase.exchangeName, nil, []api.ExchangeAPIKey{emptyAPIKey}, false)
testCcxtExchange, e := makeCcxtExchange(kase.exchangeName, nil, []api.ExchangeAPIKey{emptyAPIKey}, []api.ExchangeParam{emptyParams}, []api.ExchangeHeader{}, false)
if !assert.NoError(t, e) {
return
}
Expand Down
16 changes: 11 additions & 5 deletions plugins/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,10 @@ func Strategies() map[string]StrategyContainer {

// exchangeFactoryData is a data container that has all the information needed to make an exchange
type exchangeFactoryData struct {
simMode bool
apiKeys []api.ExchangeAPIKey
simMode bool
apiKeys []api.ExchangeAPIKey
exchangeParams []api.ExchangeParam
headers []api.ExchangeHeader
}

// ExchangeContainer contains the exchange factory method along with some metadata
Expand Down Expand Up @@ -214,6 +216,8 @@ func loadExchanges() {
boundExchangeName,
nil,
exchangeFactoryData.apiKeys,
exchangeFactoryData.exchangeParams,
exchangeFactoryData.headers,
exchangeFactoryData.simMode,
)
},
Expand Down Expand Up @@ -241,7 +245,7 @@ func MakeExchange(exchangeType string, simMode bool) (api.Exchange, error) {
}

// MakeTradingExchange is a factory method to make an exchange based on a given type
func MakeTradingExchange(exchangeType string, apiKeys []api.ExchangeAPIKey, simMode bool) (api.Exchange, error) {
func MakeTradingExchange(exchangeType string, apiKeys []api.ExchangeAPIKey, exchangeParams []api.ExchangeParam, headers []api.ExchangeHeader, simMode bool) (api.Exchange, error) {
if exchange, ok := getExchanges()[exchangeType]; ok {
if !exchange.TradeEnabled {
return nil, fmt.Errorf("trading is not enabled on this exchange: %s", exchangeType)
Expand All @@ -252,8 +256,10 @@ func MakeTradingExchange(exchangeType string, apiKeys []api.ExchangeAPIKey, simM
}

x, e := exchange.makeFn(exchangeFactoryData{
simMode: simMode,
apiKeys: apiKeys,
simMode: simMode,
apiKeys: apiKeys,
exchangeParams: exchangeParams,
headers: headers,
})
if e != nil {
return nil, fmt.Errorf("error when making the '%s' exchange: %s", exchangeType, e)
Expand Down
40 changes: 39 additions & 1 deletion plugins/mirrorStrategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,38 @@ func (t *exchangeAPIKeysToml) toExchangeAPIKeys() []api.ExchangeAPIKey {
return apiKeys
}

type exchangeParamsToml []struct {
Param string `valid:"-" toml:"PARAM"`
Value string `valid:"-" toml:"VALUE"`
}

func (t *exchangeParamsToml) toExchangeParams() []api.ExchangeParam {
exchangeParams := []api.ExchangeParam{}
for _, param := range *t {
exchangeParams = append(exchangeParams, api.ExchangeParam{
Param: param.Param,
Value: param.Value,
})
}
return exchangeParams
}

type exchangeHeadersToml []struct {
Header string `valid:"-" toml:"HEADER"`
Value string `valid:"-" toml:"VALUE"`
}

func (t *exchangeHeadersToml) toExchangeHeaders() []api.ExchangeHeader {
apiHeaders := []api.ExchangeHeader{}
for _, header := range *t {
apiHeaders = append(apiHeaders, api.ExchangeHeader{
Header: header.Header,
Value: header.Value,
})
}
return apiHeaders
}

// mirrorConfig contains the configuration params for this strategy
type mirrorConfig struct {
Exchange string `valid:"-" toml:"EXCHANGE"`
Expand All @@ -42,12 +74,16 @@ type mirrorConfig struct {
MinQuoteVolumeOverride *float64 `valid:"-" toml:"MIN_QUOTE_VOLUME_OVERRIDE"`
OffsetTrades bool `valid:"-" toml:"OFFSET_TRADES"`
ExchangeAPIKeys exchangeAPIKeysToml `valid:"-" toml:"EXCHANGE_API_KEYS"`
ExchangeParams exchangeParamsToml `valid:"-" toml:"EXCHANGE_PARAMS"`
ExchangeHeaders exchangeHeadersToml `valid:"-" toml:"EXCHANGE_HEADERS"`
}

// String impl.
func (c mirrorConfig) String() string {
return utils.StructString(c, map[string]func(interface{}) interface{}{
"EXCHANGE_API_KEYS": utils.Hide,
"EXCHANGE_PARAMS": utils.Hide,
"EXCHANGE_HEADERS": utils.Hide,
"PRICE_PRECISION_OVERRIDE": utils.UnwrapInt8Pointer,
"VOLUME_PRECISION_OVERRIDE": utils.UnwrapInt8Pointer,
"MIN_BASE_VOLUME_OVERRIDE": utils.UnwrapFloat64Pointer,
Expand Down Expand Up @@ -104,7 +140,9 @@ func makeMirrorStrategy(sdex *SDEX, ieif *IEIF, pair *model.TradingPair, baseAss
var e error
if config.OffsetTrades {
exchangeAPIKeys := config.ExchangeAPIKeys.toExchangeAPIKeys()
exchange, e = MakeTradingExchange(config.Exchange, exchangeAPIKeys, simMode)
exchangeParams := config.ExchangeParams.toExchangeParams()
exchangeHeaders := config.ExchangeHeaders.toExchangeHeaders()
exchange, e = MakeTradingExchange(config.Exchange, exchangeAPIKeys, exchangeParams, exchangeHeaders, simMode)
if e != nil {
return nil, e
}
Expand Down
Loading

0 comments on commit e7c76fe

Please sign in to comment.