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

Commit

Permalink
better error handling in networking layer, add ccxt-kraken as read-on…
Browse files Browse the repository at this point in the history
…ly integration (trading disable until fully tested)
  • Loading branch information
nikhilsaraf committed Feb 27, 2019
1 parent 015fd5c commit 796ae59
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 30 deletions.
20 changes: 17 additions & 3 deletions plugins/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,22 @@ var exchanges = map[string]ExchangeContainer{
return makeKrakenExchange(exchangeFactoryData.apiKeys, exchangeFactoryData.simMode)
},
},
"ccxt-binance": ExchangeContainer{
"ccxt-kraken": ExchangeContainer{
SortOrder: 1,
Description: "Kraken is a popular centralized cryptocurrency exchange (via ccxt-rest)",
TradeEnabled: false,
makeFn: func(exchangeFactoryData exchangeFactoryData) (api.Exchange, error) {
return makeCcxtExchange(
"http://localhost:3000",
"kraken",
nil,
exchangeFactoryData.apiKeys,
exchangeFactoryData.simMode,
)
},
},
"ccxt-binance": ExchangeContainer{
SortOrder: 2,
Description: "Binance is a popular centralized cryptocurrency exchange (via ccxt-rest)",
TradeEnabled: true,
makeFn: func(exchangeFactoryData exchangeFactoryData) (api.Exchange, error) {
Expand All @@ -183,7 +197,7 @@ var exchanges = map[string]ExchangeContainer{
},
},
"ccxt-poloniex": ExchangeContainer{
SortOrder: 2,
SortOrder: 3,
Description: "Poloniex is a popular centralized cryptocurrency exchange (via ccxt-rest)",
TradeEnabled: false,
makeFn: func(exchangeFactoryData exchangeFactoryData) (api.Exchange, error) {
Expand All @@ -197,7 +211,7 @@ var exchanges = map[string]ExchangeContainer{
},
},
"ccxt-bittrex": ExchangeContainer{
SortOrder: 3,
SortOrder: 4,
Description: "Bittrex is a popular centralized cryptocurrency exchange (via ccxt-rest)",
TradeEnabled: false,
makeFn: func(exchangeFactoryData exchangeFactoryData) (api.Exchange, error) {
Expand Down
17 changes: 14 additions & 3 deletions support/networking/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func JSONRequest(
data string,
headers map[string]string,
responseData interface{}, // the passed in responseData should be a pointer
errorKey string,
) error {
// create http request
req, e := http.NewRequest(method, reqURL, strings.NewReader(data))
Expand Down Expand Up @@ -52,9 +53,19 @@ func JSONRequest(
return fmt.Errorf("invalid 'Content-Type' header in http response ('%s'), expecting 'application/json', response body: %s", contentType, bodyString)
}

// TODO move this out of this low-level layer
if strings.Contains(bodyString, "error") {
return fmt.Errorf("error in response: %s", bodyString)
if errorKey != "" {
var errorResponse interface{}
e = json.Unmarshal(body, &errorResponse)
if e != nil {
return fmt.Errorf("could not unmarshall response body to check for an error response: %s | bodyString: %s", e, bodyString)
}

switch er := errorResponse.(type) {
case map[string]interface{}:
if _, ok := er[errorKey]; ok {
return fmt.Errorf("error in response, bodyString: %s", bodyString)
}
}
}

if responseData != nil {
Expand Down
28 changes: 14 additions & 14 deletions support/sdk/ccxt.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func MakeInitializedCcxtExchange(ccxtBaseURL string, exchangeName string, apiKey
func (c *Ccxt) init(apiKey api.ExchangeAPIKey) error {
// get exchange list
var exchangeList []string
e := networking.JSONRequest(c.httpClient, "GET", c.ccxtBaseURL+pathExchanges, "", map[string]string{}, &exchangeList)
e := networking.JSONRequest(c.httpClient, "GET", c.ccxtBaseURL+pathExchanges, "", map[string]string{}, &exchangeList, "error")
if e != nil {
return fmt.Errorf("error getting list of supported exchanges by CCXT: %s", e)
}
Expand All @@ -87,12 +87,12 @@ func (c *Ccxt) init(apiKey api.ExchangeAPIKey) error {
}
}
if !exchangeListed {
return fmt.Errorf("exchange name '%s' is not in the list of %d exchanges available", c.exchangeName, len(exchangeList))
return fmt.Errorf("exchange name '%s' is not in the list of %d exchanges available: %v", c.exchangeName, len(exchangeList), exchangeList)
}

// list all the instances of the exchange
var instanceList []string
e = networking.JSONRequest(c.httpClient, "GET", c.ccxtBaseURL+pathExchanges+"/"+c.exchangeName, "", map[string]string{}, &instanceList)
e = networking.JSONRequest(c.httpClient, "GET", c.ccxtBaseURL+pathExchanges+"/"+c.exchangeName, "", map[string]string{}, &instanceList, "error")
if e != nil {
return fmt.Errorf("error getting list of exchange instances for exchange '%s': %s", c.exchangeName, e)
}
Expand All @@ -111,7 +111,7 @@ func (c *Ccxt) init(apiKey api.ExchangeAPIKey) error {
// load markets to populate fields related to markets
var marketsResponse interface{}
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/loadMarkets"
e = networking.JSONRequest(c.httpClient, "POST", url, "", map[string]string{}, &marketsResponse)
e = networking.JSONRequest(c.httpClient, "POST", url, "", map[string]string{}, &marketsResponse, "error")
if e != nil {
return fmt.Errorf("error loading markets for exchange instance (exchange=%s, instanceName=%s): %s", c.exchangeName, c.instanceName, e)
}
Expand Down Expand Up @@ -171,7 +171,7 @@ func (c *Ccxt) newInstance(apiKey api.ExchangeAPIKey) error {
}

var newInstance map[string]interface{}
e = networking.JSONRequest(c.httpClient, "POST", c.ccxtBaseURL+pathExchanges+"/"+c.exchangeName, string(data), map[string]string{}, &newInstance)
e = networking.JSONRequest(c.httpClient, "POST", c.ccxtBaseURL+pathExchanges+"/"+c.exchangeName, string(data), map[string]string{}, &newInstance, "error")
if e != nil {
return fmt.Errorf("error in web request when creating new exchange instance for exchange '%s': %s", c.exchangeName, e)
}
Expand All @@ -188,7 +188,7 @@ func (c *Ccxt) symbolExists(tradingPair string) error {
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var exchangeOutput interface{}
e := networking.JSONRequest(c.httpClient, "GET", url, "", map[string]string{}, &exchangeOutput)
e := networking.JSONRequest(c.httpClient, "GET", url, "", map[string]string{}, &exchangeOutput, "error")
if e != nil {
return fmt.Errorf("error fetching details of exchange instance (exchange=%s, instanceName=%s): %s", c.exchangeName, c.instanceName, e)
}
Expand Down Expand Up @@ -234,7 +234,7 @@ func (c *Ccxt) FetchTicker(tradingPair string) (map[string]interface{}, error) {
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchTicker"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching tickers for trading pair '%s': %s", tradingPair, e)
}
Expand Down Expand Up @@ -274,7 +274,7 @@ func (c *Ccxt) FetchOrderBook(tradingPair string, limit *int) (map[string][]Ccxt
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchOrderBook"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching orderbook for trading pair '%s': %s", tradingPair, e)
}
Expand Down Expand Up @@ -331,7 +331,7 @@ func (c *Ccxt) FetchTrades(tradingPair string) ([]CcxtTrade, error) {
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchTrades"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
output := []CcxtTrade{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching trades for trading pair '%s': %s", tradingPair, e)
}
Expand All @@ -353,7 +353,7 @@ func (c *Ccxt) FetchMyTrades(tradingPair string) ([]CcxtTrade, error) {
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchMyTrades"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
output := []CcxtTrade{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching trades for trading pair '%s': %s", tradingPair, e)
}
Expand All @@ -372,7 +372,7 @@ func (c *Ccxt) FetchBalance() (map[string]CcxtBalance, error) {
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchBalance"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e := networking.JSONRequest(c.httpClient, "POST", url, "", map[string]string{}, &output)
e := networking.JSONRequest(c.httpClient, "POST", url, "", map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching balance: %s", e)
}
Expand Down Expand Up @@ -438,7 +438,7 @@ func (c *Ccxt) FetchOpenOrders(tradingPairs []string) (map[string][]CcxtOpenOrde
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/fetchOpenOrders"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error fetching open orders: %s", e)
}
Expand Down Expand Up @@ -494,7 +494,7 @@ func (c *Ccxt) CreateLimitOrder(tradingPair string, side string, amount float64,
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/createOrder"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error creating order: %s", e)
}
Expand Down Expand Up @@ -533,7 +533,7 @@ func (c *Ccxt) CancelOrder(orderID string, tradingPair string) (*CcxtOpenOrder,
url := c.ccxtBaseURL + pathExchanges + "/" + c.exchangeName + "/" + c.instanceName + "/cancelOrder"
// decode generic data (see "https://blog.golang.org/json-and-go#TOC_4.")
var output interface{}
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output)
e = networking.JSONRequest(c.httpClient, "POST", url, string(data), map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("error canceling order: %s", e)
}
Expand Down
22 changes: 12 additions & 10 deletions support/sdk/ccxt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,18 @@ func TestFetchOrderBook(t *testing.T) {
limit2 := 2
for _, k := range []orderbookTest{
{
exchangeName: "poloniex",
tradingPair: "BTC/USDT",
exchangeName: "kraken",
tradingPair: "BTC/USD",
limit: nil,
expectError: false,
}, {
exchangeName: "poloniex",
tradingPair: "BTC/USDT",
exchangeName: "kraken",
tradingPair: "BTC/USD",
limit: &limit5,
expectError: false,
}, {
exchangeName: "poloniex",
tradingPair: "BTC/USDT",
exchangeName: "kraken",
tradingPair: "BTC/USD",
limit: &limit2,
expectError: false,
}, {
Expand All @@ -152,8 +152,8 @@ func TestFetchOrderBook(t *testing.T) {
limit: &limit2,
expectError: true,
}, {
exchangeName: "poloniex",
tradingPair: "XLM/USDT",
exchangeName: "kraken",
tradingPair: "XLM/USD",
limit: &limit2,
expectError: false,
},
Expand Down Expand Up @@ -253,7 +253,8 @@ func TestFetchTrades(t *testing.T) {
expectedFields: bittrexFields,
},
} {
t.Run(k.exchangeName, func(t *testing.T) {
tradingPairString := strings.Replace(k.tradingPair, "/", "_", -1)
t.Run(fmt.Sprintf("%s-%s", k.exchangeName, tradingPairString), func(t *testing.T) {
c, e := MakeInitializedCcxtExchange("http://localhost:3000", k.exchangeName, api.ExchangeAPIKey{})
if e != nil {
assert.Fail(t, fmt.Sprintf("error when making ccxt exchange: %s", e))
Expand Down Expand Up @@ -303,7 +304,8 @@ func TestFetchMyTrades(t *testing.T) {
apiKey: api.ExchangeAPIKey{},
},
} {
t.Run(k.exchangeName, func(t *testing.T) {
tradingPairString := strings.Replace(k.tradingPair, "/", "_", -1)
t.Run(fmt.Sprintf("%s-%s", k.exchangeName, tradingPairString), func(t *testing.T) {
c, e := MakeInitializedCcxtExchange("http://localhost:3000", k.exchangeName, k.apiKey)
if e != nil {
assert.Fail(t, fmt.Sprintf("error when making ccxt exchange: %s", e))
Expand Down

0 comments on commit 796ae59

Please sign in to comment.