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

Commit

Permalink
lazy-load ccxt exchange list, breaking hard dependency on ccxt-rest, c…
Browse files Browse the repository at this point in the history
…loses #126 (#128)
  • Loading branch information
nikhilsaraf authored Mar 19, 2019
1 parent 09f76e8 commit 40c5641
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 16 deletions.
3 changes: 3 additions & 0 deletions cmd/exchanges.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/stellar/kelp/plugins"
"github.com/stellar/kelp/support/sdk"

"github.com/spf13/cobra"
)
Expand All @@ -15,6 +16,8 @@ var exchanagesCmd = &cobra.Command{

func init() {
exchanagesCmd.Run = func(ccmd *cobra.Command, args []string) {
// call sdk.GetExchangeList() here so we pre-load exchanges before displaying the table
sdk.GetExchangeList()
fmt.Printf(" Exchange\t\t\tTested\t\tTrading\t\tDescription\n")
fmt.Printf(" --------------------------------------------------------------------------------\n")
exchanges := plugins.Exchanges()
Expand Down
26 changes: 17 additions & 9 deletions plugins/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,23 @@ type ExchangeContainer struct {
}

// exchanges is a map of all the exchange integrations available
var exchanges map[string]ExchangeContainer
var exchanges *map[string]ExchangeContainer

func init() {
// getExchanges returns a map of all the exchange integrations available
func getExchanges() map[string]ExchangeContainer {
if exchanges == nil {
loadExchanges()
}
return *exchanges
}

func loadExchanges() {
// marked as tested if key exists in this map (regardless of bool value)
testedCcxtExchanges := map[string]bool{
"binance": true,
}

exchanges = map[string]ExchangeContainer{
exchanges = &map[string]ExchangeContainer{
"kraken": ExchangeContainer{
SortOrder: 0,
Description: "Kraken is a popular centralized cryptocurrency exchange",
Expand All @@ -186,13 +194,13 @@ func init() {
}

// add all CCXT exchanges
sortOrderOffset := len(exchanges)
for i, exchangeName := range sdk.ExchangeList {
sortOrderOffset := len(*exchanges)
for i, exchangeName := range sdk.GetExchangeList() {
key := fmt.Sprintf("ccxt-%s", exchangeName)
_, tested := testedCcxtExchanges[exchangeName]
boundExchangeName := exchangeName

exchanges[key] = ExchangeContainer{
(*exchanges)[key] = ExchangeContainer{
SortOrder: uint16(i + sortOrderOffset),
Description: exchangeName + " is automatically added via ccxt-rest",
TradeEnabled: true,
Expand All @@ -211,7 +219,7 @@ func init() {

// MakeExchange is a factory method to make an exchange based on a given type
func MakeExchange(exchangeType string, simMode bool) (api.Exchange, error) {
if exchange, ok := exchanges[exchangeType]; ok {
if exchange, ok := getExchanges()[exchangeType]; ok {
exchangeAPIKey := api.ExchangeAPIKey{Key: "", Secret: ""}
x, e := exchange.makeFn(exchangeFactoryData{
simMode: simMode,
Expand All @@ -228,7 +236,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) {
if exchange, ok := exchanges[exchangeType]; ok {
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,5 +260,5 @@ func MakeTradingExchange(exchangeType string, apiKeys []api.ExchangeAPIKey, simM

// Exchanges returns the list of exchanges
func Exchanges() map[string]ExchangeContainer {
return exchanges
return getExchanges()
}
32 changes: 25 additions & 7 deletions support/sdk/ccxt.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,27 +75,45 @@ func MakeInitializedCcxtExchange(exchangeName string, apiKey api.ExchangeAPIKey)
return c, nil
}

// ExchangeList contains a list of supported exchanges
var ExchangeList []string
// exchangeList contains a list of supported exchanges
var exchangeList *[]string

func init() {
e := networking.JSONRequest(http.DefaultClient, "GET", ccxtBaseURL+pathExchanges, "", map[string]string{}, &ExchangeList, "error")
// GetExchangeList gets a list of all supported exchanges
func GetExchangeList() []string {
if exchangeList == nil {
loadExchangeList()
}
return *exchangeList
}

func loadExchangeList() {
var output []string
e := networking.JSONRequest(http.DefaultClient, "GET", ccxtBaseURL+pathExchanges, "", map[string]string{}, &output, "error")
if e != nil {
panic(fmt.Errorf("error getting list of supported exchanges by CCXT: %s", e))
eMsg1 := strings.Contains(e.Error(), "could not execute http request")
eMsg2 := strings.Contains(e.Error(), "http://localhost:3000/exchanges: dial tcp")
eMsg3 := strings.Contains(e.Error(), "connection refused")
if eMsg1 && eMsg2 && eMsg3 {
log.Printf("ccxt-rest is not running on port 3000 so we cannot include those exchanges")
} else {
panic(fmt.Errorf("error getting list of supported exchanges by CCXT: %s", e))
}
}
exchangeList = &output
}

func (c *Ccxt) initialize(apiKey api.ExchangeAPIKey) error {
// validate that exchange name is in the exchange list
exchangeListed := false
for _, name := range ExchangeList {
el := GetExchangeList()
for _, name := range el {
if name == c.exchangeName {
exchangeListed = true
break
}
}
if !exchangeListed {
return fmt.Errorf("exchange name '%s' is not in the list of %d exchanges available: %v", c.exchangeName, len(ExchangeList), ExchangeList)
return fmt.Errorf("exchange name '%s' is not in the list of %d exchanges available: %v", c.exchangeName, len(el), el)
}

// list all the instances of the exchange
Expand Down

0 comments on commit 40c5641

Please sign in to comment.