From 4d4c85f458ea285feee7ec1876b65d7f900e0b15 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Tue, 16 Jan 2018 12:05:30 +1100 Subject: [PATCH] Add dynamic loading/unloading and reloading of exchanges --- exchange.go | 224 +++++++++++++++++++++++++++++++++++++ exchange_test.go | 138 +++++++++++++++++++++++ exchanges/exchange.go | 1 + exchanges/okcoin/okcoin.go | 2 +- helpers.go | 27 ++--- main.go | 106 +----------------- restful_server.go | 2 + routines.go | 117 ++++++++++--------- testdata/configtest.json | 31 ++++- websocket.go | 2 +- 10 files changed, 467 insertions(+), 183 deletions(-) create mode 100644 exchange.go create mode 100644 exchange_test.go diff --git a/exchange.go b/exchange.go new file mode 100644 index 00000000000..640fc0fee53 --- /dev/null +++ b/exchange.go @@ -0,0 +1,224 @@ +package main + +import ( + "errors" + "log" + + "github.com/thrasher-/gocryptotrader/common" + exchange "github.com/thrasher-/gocryptotrader/exchanges" + "github.com/thrasher-/gocryptotrader/exchanges/anx" + "github.com/thrasher-/gocryptotrader/exchanges/bitfinex" + "github.com/thrasher-/gocryptotrader/exchanges/bitstamp" + "github.com/thrasher-/gocryptotrader/exchanges/bittrex" + "github.com/thrasher-/gocryptotrader/exchanges/btcc" + "github.com/thrasher-/gocryptotrader/exchanges/btcmarkets" + "github.com/thrasher-/gocryptotrader/exchanges/coinut" + "github.com/thrasher-/gocryptotrader/exchanges/gdax" + "github.com/thrasher-/gocryptotrader/exchanges/huobi" + "github.com/thrasher-/gocryptotrader/exchanges/itbit" + "github.com/thrasher-/gocryptotrader/exchanges/kraken" + "github.com/thrasher-/gocryptotrader/exchanges/lakebtc" + "github.com/thrasher-/gocryptotrader/exchanges/liqui" + "github.com/thrasher-/gocryptotrader/exchanges/localbitcoins" + "github.com/thrasher-/gocryptotrader/exchanges/okcoin" + "github.com/thrasher-/gocryptotrader/exchanges/poloniex" + "github.com/thrasher-/gocryptotrader/exchanges/wex" +) + +// vars related to exchange functions +var ( + ErrNoExchangesLoaded = errors.New("no exchanges have been loaded") + ErrExchangeNotFound = errors.New("exchange not found") + ErrExchangeAlreadyLoaded = errors.New("exchange already loaded") + ErrExchangeFailedToLoad = errors.New("exchange failed to load") +) + +// CheckExchangeExists returns true whether or not an exchange has already +// been loaded +func CheckExchangeExists(exchName string) bool { + for x := range bot.exchanges { + if common.StringToLower(bot.exchanges[x].GetName()) == common.StringToLower(exchName) { + return true + } + } + return false +} + +// GetExchangeByName returns an exchange given an exchange name +func GetExchangeByName(exchName string) exchange.IBotExchange { + for x := range bot.exchanges { + if common.StringToLower(bot.exchanges[x].GetName()) == common.StringToLower(exchName) { + return bot.exchanges[x] + } + } + return nil +} + +// ReloadExchange loads an exchange config by name +func ReloadExchange(name string) error { + nameLower := common.StringToLower(name) + + if len(bot.exchanges) == 0 { + return ErrNoExchangesLoaded + } + + if !CheckExchangeExists(nameLower) { + return ErrExchangeNotFound + } + + exchCfg, err := bot.config.GetExchangeConfig(name) + if err != nil { + return err + } + + e := GetExchangeByName(nameLower) + e.Setup(exchCfg) + log.Printf("%s exchange reloaded successfully.\n", name) + return nil +} + +// UnloadExchange unloads an exchange by +func UnloadExchange(name string) error { + nameLower := common.StringToLower(name) + + if len(bot.exchanges) == 0 { + return ErrNoExchangesLoaded + } + + if !CheckExchangeExists(nameLower) { + return ErrExchangeNotFound + } + + exchCfg, err := bot.config.GetExchangeConfig(name) + if err != nil { + return err + } + + exchCfg.Enabled = false + err = bot.config.UpdateExchangeConfig(exchCfg) + if err != nil { + return err + } + + for x := range bot.exchanges { + if bot.exchanges[x].GetName() == name { + bot.exchanges[x].SetEnabled(false) + bot.exchanges = append(bot.exchanges[:x], bot.exchanges[x+1:]...) + return nil + } + } + + return ErrExchangeNotFound +} + +// LoadExchange loads an exchange by name +func LoadExchange(name string) error { + nameLower := common.StringToLower(name) + var exch exchange.IBotExchange + + if len(bot.exchanges) > 0 { + if CheckExchangeExists(nameLower) { + return ErrExchangeAlreadyLoaded + } + } + + switch nameLower { + case "anx": + exch = new(anx.ANX) + case "bitfinex": + exch = new(bitfinex.Bitfinex) + case "bitstamp": + exch = new(bitstamp.Bitstamp) + case "bittrex": + exch = new(bittrex.Bittrex) + case "btcc": + exch = new(btcc.BTCC) + case "btc markets": + exch = new(btcmarkets.BTCMarkets) + case "coinut": + exch = new(coinut.COINUT) + case "gdax": + exch = new(gdax.GDAX) + case "gemini": + exch = new(gdax.GDAX) + case "huobi": + exch = new(huobi.HUOBI) + case "itbit": + exch = new(itbit.ItBit) + case "kraken": + exch = new(kraken.Kraken) + case "lakebtc": + exch = new(lakebtc.LakeBTC) + case "liqui": + exch = new(liqui.Liqui) + case "localbitcoins": + exch = new(localbitcoins.LocalBitcoins) + case "okcoin china": + exch = new(okcoin.OKCoin) + case "okcoin international": + exch = new(okcoin.OKCoin) + case "poloniex": + exch = new(poloniex.Poloniex) + case "wex": + exch = new(wex.WEX) + default: + return ErrExchangeNotFound + } + + if exch == nil { + return ErrExchangeFailedToLoad + } + + exch.SetDefaults() + bot.exchanges = append(bot.exchanges, exch) + exchCfg, err := bot.config.GetExchangeConfig(name) + if err != nil { + return err + } + + exchCfg.Enabled = true + exch.Setup(exchCfg) + return nil +} + +// SetupExchanges sets up the exchanges used by the bot +func SetupExchanges() { + for _, exch := range bot.config.Exchanges { + if CheckExchangeExists(exch.Name) { + e := GetExchangeByName(exch.Name) + if e == nil { + log.Println(ErrExchangeNotFound) + continue + } + + err := ReloadExchange(exch.Name) + if err != nil { + log.Printf("ReloadExchange %s failed: %s", exch.Name, err) + continue + } + + if !e.IsEnabled() { + UnloadExchange(exch.Name) + continue + } + return + + } + if !exch.Enabled { + log.Printf("%s: Exchange support: Disabled", exch.Name) + continue + } else { + err := LoadExchange(exch.Name) + if err != nil { + log.Printf("LoadExchange %s failed: %s", exch.Name, err) + continue + } + } + log.Printf( + "%s: Exchange support: Enabled (Authenticated API support: %s - Verbose mode: %s).\n", + exch.Name, + common.IsEnabled(exch.AuthenticatedAPISupport), + common.IsEnabled(exch.Verbose), + ) + } +} diff --git a/exchange_test.go b/exchange_test.go new file mode 100644 index 00000000000..339d56241c0 --- /dev/null +++ b/exchange_test.go @@ -0,0 +1,138 @@ +package main + +import ( + "testing" + + "github.com/thrasher-/gocryptotrader/config" +) + +var testSetup = false + +func SetupTest(t *testing.T) { + if !testSetup { + bot.config = &config.Cfg + err := bot.config.LoadConfig("./testdata/configtest.json") + if err != nil { + t.Fatalf("Test failed. SetupTest: Failed to load config: %s", err) + } + testSetup = true + } + + if CheckExchangeExists("Bitfinex") { + return + } + err := LoadExchange("Bitfinex") + if err != nil { + t.Errorf("Test failed. SetupTest: Failed to load exchange: %s", err) + } +} + +func CleanupTest(t *testing.T) { + if !CheckExchangeExists("Bitfinex") { + return + } + + err := UnloadExchange("Bitfinex") + if err != nil { + t.Fatalf("Test failed. CleanupTest: Failed to unload exchange: %s", + err) + } +} + +func TestCheckExchangeExists(t *testing.T) { + SetupTest(t) + + if !CheckExchangeExists("Bitfinex") { + t.Errorf("Test failed. TestGetExchangeExists: Unable to find exchange") + } + + if CheckExchangeExists("Asdsad") { + t.Errorf("Test failed. TestGetExchangeExists: Non-existant exchange found") + } + + CleanupTest(t) +} + +func TestGetExchangeByName(t *testing.T) { + SetupTest(t) + + exch := GetExchangeByName("Bitfinex") + if exch == nil { + t.Errorf("Test failed. TestGetExchangeByName: Failed to get exchange") + } + + if !exch.IsEnabled() { + t.Errorf("Test failed. TestGetExchangeByName: Unexpected result") + } + + exch.SetEnabled(false) + bfx := GetExchangeByName("Bitfinex") + if bfx.IsEnabled() { + t.Errorf("Test failed. TestGetExchangeByName: Unexpected result") + } + + if exch.GetName() != "Bitfinex" { + t.Errorf("Test failed. TestGetExchangeByName: Unexpected result") + } + + exch = GetExchangeByName("Asdasd") + if exch != nil { + t.Errorf("Test failed. TestGetExchangeByName: Non-existant exchange found") + } + + CleanupTest(t) +} + +func TestReloadExchange(t *testing.T) { + SetupTest(t) + + err := ReloadExchange("asdf") + if err != ErrExchangeNotFound { + t.Errorf("Test failed. TestReloadExchange: Incorrect result: %s", + err) + } + + err = ReloadExchange("Bitfinex") + if err != nil { + t.Errorf("Test failed. TestReloadExchange: Incorrect result: %s", + err) + } + + CleanupTest(t) + + err = ReloadExchange("asdf") + if err != ErrNoExchangesLoaded { + t.Errorf("Test failed. TestReloadExchange: Incorrect result: %s", + err) + } +} + +func TestUnloadExchange(t *testing.T) { + SetupTest(t) + + err := UnloadExchange("asdf") + if err != ErrExchangeNotFound { + t.Errorf("Test failed. TestUnloadExchange: Incorrect result: %s", + err) + } + + err = UnloadExchange("Bitfinex") + if err != nil { + t.Errorf("Test failed. TestUnloadExchange: Failed to get exchange. %s", + err) + } + + err = UnloadExchange("asdf") + if err != ErrNoExchangesLoaded { + t.Errorf("Test failed. TestUnloadExchange: Incorrect result: %s", + err) + } + + CleanupTest(t) +} + +func TestSetupExchanges(t *testing.T) { + SetupTest(t) + SetupExchanges() + CleanupTest(t) +} diff --git a/exchanges/exchange.go b/exchanges/exchange.go index d197e3d0db4..1e42bbeb2f0 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -64,6 +64,7 @@ type IBotExchange interface { SetDefaults() GetName() string IsEnabled() bool + SetEnabled(bool) GetTickerPrice(currency pair.CurrencyPair, assetType string) (ticker.Price, error) UpdateTicker(currency pair.CurrencyPair, assetType string) (ticker.Price, error) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (orderbook.Base, error) diff --git a/exchanges/okcoin/okcoin.go b/exchanges/okcoin/okcoin.go index 12466207c1a..ead489698c4 100644 --- a/exchanges/okcoin/okcoin.go +++ b/exchanges/okcoin/okcoin.go @@ -96,7 +96,7 @@ func (o *OKCoin) SetDefaults() { o.FuturesValues = []string{"this_week", "next_week", "quarter"} o.AssetTypes = []string{ticker.Spot} - if !okcoinDefaultsSet { + if okcoinDefaultsSet { o.AssetTypes = append(o.AssetTypes, o.FuturesValues...) o.APIUrl = OKCOIN_API_URL o.Name = "OKCOIN International" diff --git a/helpers.go b/helpers.go index 080cff09dc8..4f472772c25 100644 --- a/helpers.go +++ b/helpers.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" - "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/translation" exchange "github.com/thrasher-/gocryptotrader/exchanges" @@ -31,25 +30,15 @@ func GetRelatableCurrencies(p pair.CurrencyPair) []pair.CurrencyPair { return pairs } -// GetExchangeByName returns an exchange given an exchange name -func GetExchangeByName(exchName string) exchange.IBotExchange { - for x := range bot.exchanges { - if common.StringToLower(bot.exchanges[x].GetName()) == common.StringToLower(exchName) { - return bot.exchanges[x] - } - } - return nil -} - // GetSpecificOrderbook returns a specific orderbook given the currency, // exchangeName and assetType func GetSpecificOrderbook(currency, exchangeName, assetType string) (orderbook.Base, error) { var specificOrderbook orderbook.Base var err error - for i := 0; i < len(bot.exchanges); i++ { - if bot.exchanges[i] != nil { - if bot.exchanges[i].IsEnabled() && bot.exchanges[i].GetName() == exchangeName { - specificOrderbook, err = bot.exchanges[i].GetOrderbookEx( + for x := range bot.exchanges { + if bot.exchanges[x] != nil { + if bot.exchanges[x].GetName() == exchangeName { + specificOrderbook, err = bot.exchanges[x].GetOrderbookEx( pair.NewCurrencyPairFromString(currency), assetType, ) @@ -65,10 +54,10 @@ func GetSpecificOrderbook(currency, exchangeName, assetType string) (orderbook.B func GetSpecificTicker(currency, exchangeName, assetType string) (ticker.Price, error) { var specificTicker ticker.Price var err error - for i := 0; i < len(bot.exchanges); i++ { - if bot.exchanges[i] != nil { - if bot.exchanges[i].IsEnabled() && bot.exchanges[i].GetName() == exchangeName { - specificTicker, err = bot.exchanges[i].GetTickerPrice( + for x := range bot.exchanges { + if bot.exchanges[x] != nil { + if bot.exchanges[x].GetName() == exchangeName { + specificTicker, err = bot.exchanges[x].GetTickerPrice( pair.NewCurrencyPairFromString(currency), assetType, ) diff --git a/main.go b/main.go index 7d6dc1a59cc..b7c8c9a3742 100644 --- a/main.go +++ b/main.go @@ -14,93 +14,23 @@ import ( "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/exchanges" - "github.com/thrasher-/gocryptotrader/exchanges/anx" - "github.com/thrasher-/gocryptotrader/exchanges/bitfinex" - "github.com/thrasher-/gocryptotrader/exchanges/bitstamp" - "github.com/thrasher-/gocryptotrader/exchanges/bittrex" - "github.com/thrasher-/gocryptotrader/exchanges/btcc" - "github.com/thrasher-/gocryptotrader/exchanges/btcmarkets" - "github.com/thrasher-/gocryptotrader/exchanges/coinut" - "github.com/thrasher-/gocryptotrader/exchanges/gdax" - "github.com/thrasher-/gocryptotrader/exchanges/gemini" - "github.com/thrasher-/gocryptotrader/exchanges/huobi" - "github.com/thrasher-/gocryptotrader/exchanges/itbit" - "github.com/thrasher-/gocryptotrader/exchanges/kraken" - "github.com/thrasher-/gocryptotrader/exchanges/lakebtc" - "github.com/thrasher-/gocryptotrader/exchanges/liqui" - "github.com/thrasher-/gocryptotrader/exchanges/localbitcoins" - "github.com/thrasher-/gocryptotrader/exchanges/okcoin" - "github.com/thrasher-/gocryptotrader/exchanges/poloniex" - "github.com/thrasher-/gocryptotrader/exchanges/ticker" - "github.com/thrasher-/gocryptotrader/exchanges/wex" "github.com/thrasher-/gocryptotrader/portfolio" "github.com/thrasher-/gocryptotrader/smsglobal" ) -// ExchangeMain contains all the necessary exchange packages -type ExchangeMain struct { - anx anx.ANX - btcc btcc.BTCC - bitstamp bitstamp.Bitstamp - bitfinex bitfinex.Bitfinex - bittrex bittrex.Bittrex - wex wex.WEX - btcmarkets btcmarkets.BTCMarkets - coinut coinut.COINUT - gdax gdax.GDAX - gemini gemini.Gemini - okcoinChina okcoin.OKCoin - okcoinIntl okcoin.OKCoin - itbit itbit.ItBit - lakebtc lakebtc.LakeBTC - liqui liqui.Liqui - localbitcoins localbitcoins.LocalBitcoins - poloniex poloniex.Poloniex - huobi huobi.HUOBI - kraken kraken.Kraken -} - // Bot contains configuration, portfolio, exchange & ticker data and is the // overarching type across this code base. type Bot struct { config *config.Config smsglobal *smsglobal.Base portfolio *portfolio.Base - exchange ExchangeMain exchanges []exchange.IBotExchange - tickers []ticker.Ticker shutdown chan bool configFile string } var bot Bot -func setupBotExchanges() { - for _, exch := range bot.config.Exchanges { - for i := 0; i < len(bot.exchanges); i++ { - if bot.exchanges[i] != nil { - if bot.exchanges[i].GetName() == exch.Name { - bot.exchanges[i].Setup(exch) - if bot.exchanges[i].IsEnabled() { - log.Printf( - "%s: Exchange support: %s (Authenticated API support: %s - Verbose mode: %s).\n", - exch.Name, common.IsEnabled(exch.Enabled), - common.IsEnabled(exch.AuthenticatedAPISupport), - common.IsEnabled(exch.Verbose), - ) - bot.exchanges[i].Start() - } else { - log.Printf( - "%s: Exchange support: %s\n", exch.Name, - common.IsEnabled(exch.Enabled), - ) - } - } - } - } - } -} - func main() { HandleInterrupt() @@ -135,42 +65,12 @@ func main() { "Available Exchanges: %d. Enabled Exchanges: %d.\n", len(bot.config.Exchanges), bot.config.GetConfigEnabledExchanges(), ) - log.Println("Bot Exchange support:") - - bot.exchanges = []exchange.IBotExchange{ - new(anx.ANX), - new(kraken.Kraken), - new(btcc.BTCC), - new(bitstamp.Bitstamp), - new(bitfinex.Bitfinex), - new(bittrex.Bittrex), - new(wex.WEX), - new(btcmarkets.BTCMarkets), - new(coinut.COINUT), - new(gdax.GDAX), - new(gemini.Gemini), - new(okcoin.OKCoin), - new(okcoin.OKCoin), - new(itbit.ItBit), - new(lakebtc.LakeBTC), - new(liqui.Liqui), - new(localbitcoins.LocalBitcoins), - new(poloniex.Poloniex), - new(huobi.HUOBI), - } - for i := 0; i < len(bot.exchanges); i++ { - if bot.exchanges[i] != nil { - bot.exchanges[i].SetDefaults() - log.Printf( - "Exchange %s successfully set default settings.\n", - bot.exchanges[i].GetName(), - ) - } + SetupExchanges() + if len(bot.exchanges) == 0 { + log.Fatalf("No exchanges were able to be loaded. Exiting") } - setupBotExchanges() - if bot.config.CurrencyExchangeProvider == "yahoo" { currency.SetProvider(true) } else { diff --git a/restful_server.go b/restful_server.go index f51032274b5..f0462c4095f 100644 --- a/restful_server.go +++ b/restful_server.go @@ -86,6 +86,8 @@ func RESTSaveAllSettings(w http.ResponseWriter, r *http.Request) { if err != nil { RESTfulError(r.Method, err) } + + SetupExchanges() } // RESTGetOrderbook returns orderbook info for a given currency, exchange and diff --git a/routines.go b/routines.go index 5c32b6b0322..2523cee9cfe 100644 --- a/routines.go +++ b/routines.go @@ -173,44 +173,47 @@ func relayWebsocketEvent(result interface{}, event, assetType, exchangeName stri } } +// TickerUpdaterRoutine fetches and updates the ticker for all enabled +// currency pairs and exchanges func TickerUpdaterRoutine() { log.Println("Starting ticker updater routine") for { for x := range bot.exchanges { - if bot.exchanges[x].IsEnabled() { - exchangeName := bot.exchanges[x].GetName() - enabledCurrencies := bot.exchanges[x].GetEnabledCurrencies() + if bot.exchanges[x] == nil { + continue + } + exchangeName := bot.exchanges[x].GetName() + enabledCurrencies := bot.exchanges[x].GetEnabledCurrencies() - var result ticker.Price - var err error - var assetTypes []string + var result ticker.Price + var err error + var assetTypes []string - assetTypes, err = exchange.GetExchangeAssetTypes(exchangeName) - if err != nil { - log.Printf("failed to get %s exchange asset types. Error: %s", - exchangeName, err) - } + assetTypes, err = exchange.GetExchangeAssetTypes(exchangeName) + if err != nil { + log.Printf("failed to get %s exchange asset types. Error: %s", + exchangeName, err) + } - for y := range enabledCurrencies { - currency := enabledCurrencies[y] + for y := range enabledCurrencies { + currency := enabledCurrencies[y] - if len(assetTypes) > 1 { - for z := range assetTypes { - result, err = bot.exchanges[x].UpdateTicker(currency, - assetTypes[z]) - printSummary(result, currency, assetTypes[z], exchangeName, err) - if err == nil { - relayWebsocketEvent(result, "ticker_update", assetTypes[z], exchangeName) - } - } - } else { + if len(assetTypes) > 1 { + for z := range assetTypes { result, err = bot.exchanges[x].UpdateTicker(currency, - assetTypes[0]) - printSummary(result, currency, assetTypes[0], exchangeName, err) + assetTypes[z]) + printSummary(result, currency, assetTypes[z], exchangeName, err) if err == nil { - relayWebsocketEvent(result, "ticker_update", assetTypes[0], exchangeName) + relayWebsocketEvent(result, "ticker_update", assetTypes[z], exchangeName) } } + } else { + result, err = bot.exchanges[x].UpdateTicker(currency, + assetTypes[0]) + printSummary(result, currency, assetTypes[0], exchangeName, err) + if err == nil { + relayWebsocketEvent(result, "ticker_update", assetTypes[0], exchangeName) + } } } } @@ -218,47 +221,51 @@ func TickerUpdaterRoutine() { } } +// OrderbookUpdaterRoutine fetches and updates the orderbooks for all enabled +// currency pairs and exchanges func OrderbookUpdaterRoutine() { log.Println("Starting orderbook updater routine") for { for x := range bot.exchanges { - if bot.exchanges[x].IsEnabled() { - if bot.exchanges[x].GetName() == "ANX" { - continue - } + if bot.exchanges[x] == nil { + continue + } - exchangeName := bot.exchanges[x].GetName() - enabledCurrencies := bot.exchanges[x].GetEnabledCurrencies() - var result orderbook.Base - var err error - var assetTypes []string + if bot.exchanges[x].GetName() == "ANX" { + continue + } - assetTypes, err = exchange.GetExchangeAssetTypes(exchangeName) - if err != nil { - log.Printf("failed to get %s exchange asset types. Error: %s", - exchangeName, err) - } + exchangeName := bot.exchanges[x].GetName() + enabledCurrencies := bot.exchanges[x].GetEnabledCurrencies() + var result orderbook.Base + var err error + var assetTypes []string + + assetTypes, err = exchange.GetExchangeAssetTypes(exchangeName) + if err != nil { + log.Printf("failed to get %s exchange asset types. Error: %s", + exchangeName, err) + } - for y := range enabledCurrencies { - currency := enabledCurrencies[y] + for y := range enabledCurrencies { + currency := enabledCurrencies[y] - if len(assetTypes) > 1 { - for z := range assetTypes { - result, err = bot.exchanges[x].UpdateOrderbook(currency, - assetTypes[z]) - printOrderbookSummary(result, currency, assetTypes[z], exchangeName, err) - if err == nil { - relayWebsocketEvent(result, "orderbook_update", assetTypes[z], exchangeName) - } - } - } else { + if len(assetTypes) > 1 { + for z := range assetTypes { result, err = bot.exchanges[x].UpdateOrderbook(currency, - assetTypes[0]) - printOrderbookSummary(result, currency, assetTypes[0], exchangeName, err) + assetTypes[z]) + printOrderbookSummary(result, currency, assetTypes[z], exchangeName, err) if err == nil { - relayWebsocketEvent(result, "orderbook_update", assetTypes[0], exchangeName) + relayWebsocketEvent(result, "orderbook_update", assetTypes[z], exchangeName) } } + } else { + result, err = bot.exchanges[x].UpdateOrderbook(currency, + assetTypes[0]) + printOrderbookSummary(result, currency, assetTypes[0], exchangeName, err) + if err == nil { + relayWebsocketEvent(result, "orderbook_update", assetTypes[0], exchangeName) + } } } } diff --git a/testdata/configtest.json b/testdata/configtest.json index 79c8ac014a8..231c6ba9812 100644 --- a/testdata/configtest.json +++ b/testdata/configtest.json @@ -13,19 +13,19 @@ { "Address": "1JCe8z4jJVNXSjohjM4i9Hh813dLCNx2Sy", "CoinType": "BTC", - "Balance": 124178.00647714, + "Balance": 124178.00354266, "Description": "" }, { "Address": "3Nxwenay9Z8Lc9JBiywExpnEFiLp6Afp8v", "CoinType": "BTC", - "Balance": 107843.84030984, + "Balance": 123439.8370977, "Description": "" }, { "Address": "LgY8ahfHRhvjVQC1zJnBhFMG5pCTMuKRqh", "CoinType": "LTC", - "Balance": 100000.052, + "Balance": 0.03665026, "Description": "" }, { @@ -211,6 +211,28 @@ "Uppercase": true } }, + { + "Name": "COINUT", + "Enabled": true, + "Verbose": false, + "Websocket": false, + "UseSandbox": false, + "RESTPollingDelay": 10, + "AuthenticatedAPISupport": false, + "APIKey": "Key", + "APISecret": "Secret", + "ClientID": "ClientID", + "AvailablePairs": "LTCBTC,ETCBTC,ETHBTC", + "EnabledPairs": "LTCBTC,ETCBTC,ETHBTC", + "BaseCurrencies": "USD", + "AssetTypes": "SPOT", + "ConfigCurrencyPairFormat": { + "Uppercase": true + }, + "RequestCurrencyPairFormat": { + "Uppercase": true + } + }, { "Name": "GDAX", "Enabled": true, @@ -313,7 +335,8 @@ "BaseCurrencies": "EUR,USD,CAD,GBP,JPY", "AssetTypes": "SPOT", "ConfigCurrencyPairFormat": { - "Uppercase": true + "Uppercase": true, + "Delimiter": "-" }, "RequestCurrencyPairFormat": { "Uppercase": true, diff --git a/websocket.go b/websocket.go index 0d93dc56bfe..51a4b4fea41 100644 --- a/websocket.go +++ b/websocket.go @@ -174,7 +174,7 @@ func wsSaveConfig(wsClient *websocket.Conn, data interface{}) error { } } - setupBotExchanges() + SetupExchanges() wsResp.Data = WebsocketResponseSuccess return wsClient.WriteJSON(wsResp) }