From 5a2c81346c61fad0d792aad8907b03347a67b720 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Thu, 18 Jan 2018 12:45:19 +1100 Subject: [PATCH] Added helper functions, exchange method to set currencies and bug fixes --- config/config.go | 14 +++-- config/config_test.go | 10 +++- currency/translation/translation.go | 1 + currency/translation/translation_test.go | 4 +- exchange.go | 3 +- exchanges/exchange.go | 27 ++++++++++ exchanges/exchange_test.go | 29 ++++++++++ exchanges/gemini/gemini.go | 8 ++- exchanges/gemini/gemini_types.go | 2 + exchanges/okcoin/okcoin.go | 2 +- helpers.go | 69 +++++++++++++++++++++++- main.go | 2 +- tools/portfolio/portfolio.go | 2 +- 13 files changed, 159 insertions(+), 14 deletions(-) diff --git a/config/config.go b/config/config.go index ba0af9dcb12..0ecf14a7e6c 100644 --- a/config/config.go +++ b/config/config.go @@ -327,14 +327,15 @@ func (c *Config) CheckWebserverConfigValues() error { // RetrieveConfigCurrencyPairs splits, assigns and verifies enabled currency // pairs either cryptoCurrencies or fiatCurrencies -func (c *Config) RetrieveConfigCurrencyPairs() error { +func (c *Config) RetrieveConfigCurrencyPairs(enabledOnly bool) error { cryptoCurrencies := common.SplitStrings(c.Cryptocurrencies, ",") fiatCurrencies := common.SplitStrings(currency.DefaultCurrencies, ",") for x := range c.Exchanges { - if !c.Exchanges[x].Enabled { + if !c.Exchanges[x].Enabled && enabledOnly { continue } + baseCurrencies := common.SplitStrings(c.Exchanges[x].BaseCurrencies, ",") for y := range baseCurrencies { if !common.DataContains(fiatCurrencies, baseCurrencies[y]) { @@ -344,11 +345,14 @@ func (c *Config) RetrieveConfigCurrencyPairs() error { } for x := range c.Exchanges { - if !c.Exchanges[x].Enabled { - continue + var pairs []pair.CurrencyPair + var err error + if !c.Exchanges[x].Enabled && enabledOnly { + pairs, err = c.GetEnabledPairs(c.Exchanges[x].Name) + } else { + pairs, err = c.GetAvailablePairs(c.Exchanges[x].Name) } - pairs, err := c.GetEnabledPairs(c.Exchanges[x].Name) if err != nil { return err } diff --git a/config/config_test.go b/config/config_test.go index e0645f97027..9ae21814db2 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -469,7 +469,15 @@ func TestRetrieveConfigCurrencyPairs(t *testing.T) { "Test failed. TestRetrieveConfigCurrencyPairs.LoadConfig: %s", err.Error(), ) } - err = cfg.RetrieveConfigCurrencyPairs() + err = cfg.RetrieveConfigCurrencyPairs(true) + if err != nil { + t.Errorf( + "Test failed. TestRetrieveConfigCurrencyPairs.RetrieveConfigCurrencyPairs: %s", + err.Error(), + ) + } + + err = cfg.RetrieveConfigCurrencyPairs(false) if err != nil { t.Errorf( "Test failed. TestRetrieveConfigCurrencyPairs.RetrieveConfigCurrencyPairs: %s", diff --git a/currency/translation/translation.go b/currency/translation/translation.go index decb9680a33..f3c2001a4a2 100644 --- a/currency/translation/translation.go +++ b/currency/translation/translation.go @@ -8,6 +8,7 @@ import ( var translations = map[pair.CurrencyItem]pair.CurrencyItem{ "BTC": "XBT", + "ETH": "XETH", "DOGE": "XDG", "USD": "USDT", } diff --git a/currency/translation/translation_test.go b/currency/translation/translation_test.go index d88d0f2c434..0fb327674b1 100644 --- a/currency/translation/translation_test.go +++ b/currency/translation/translation_test.go @@ -18,7 +18,7 @@ func TestGetTranslation(t *testing.T) { t.Error("GetTranslation: translation result was different to expected result") } - currencyPair.FirstCurrency = "ETH" + currencyPair.FirstCurrency = "NEO" _, err = GetTranslation(currencyPair.FirstCurrency) if err == nil { t.Error("GetTranslation: no error on non translatable currency") @@ -33,7 +33,7 @@ func TestHasTranslation(t *testing.T) { t.Error("HasTranslation: translation result was different to expected result") } - currencyPair.FirstCurrency = "ETH" + currencyPair.FirstCurrency = "NEO" expected = false actual = HasTranslation(currencyPair.FirstCurrency) if expected != actual { diff --git a/exchange.go b/exchange.go index 608426ac2bc..50a71e27ef7 100644 --- a/exchange.go +++ b/exchange.go @@ -14,6 +14,7 @@ import ( "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" @@ -140,7 +141,7 @@ func LoadExchange(name string) error { case "gdax": exch = new(gdax.GDAX) case "gemini": - exch = new(gdax.GDAX) + exch = new(gemini.Gemini) case "huobi": exch = new(huobi.HUOBI) case "itbit": diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 8648f49c4ba..7ca150c8d11 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -73,6 +73,7 @@ type IBotExchange interface { GetAvailableCurrencies() []pair.CurrencyPair GetExchangeAccountInfo() (AccountInfo, error) GetAuthenticatedAPISupport() bool + SetCurrencies(pairs []pair.CurrencyPair, enabledPairs bool) error } // SetAssetTypes checks the exchange asset types (whether it supports SPOT, @@ -295,6 +296,32 @@ func (e *Base) SetAPIKeys(APIKey, APISecret, ClientID string, b64Decode bool) { } } +// SetCurrencies sets the exchange currency pairs for either enabledPairs or +// availablePairs +func (e *Base) SetCurrencies(pairs []pair.CurrencyPair, enabledPairs bool) error { + cfg := config.GetConfig() + exchCfg, err := cfg.GetExchangeConfig(e.Name) + if err != nil { + return err + } + + var pairsStr []string + for x := range pairs { + pairsStr = append(pairsStr, pairs[x].Display(exchCfg.ConfigCurrencyPairFormat.Delimiter, + exchCfg.ConfigCurrencyPairFormat.Uppercase).String()) + } + + if enabledPairs { + exchCfg.EnabledPairs = common.JoinStrings(pairsStr, ",") + e.EnabledPairs = pairsStr + } else { + exchCfg.AvailablePairs = common.JoinStrings(pairsStr, ",") + e.AvailablePairs = pairsStr + } + + return cfg.UpdateExchangeConfig(exchCfg) +} + // UpdateEnabledCurrencies is a method that sets new pairs to the current // exchange. Setting force to true upgrades the enabled currencies func (e *Base) UpdateEnabledCurrencies(exchangeProducts []string, force bool) error { diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index 30958b247a0..495465a6406 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -484,6 +484,35 @@ func TestSetAPIKeys(t *testing.T) { SetAPIKeys.SetAPIKeys("RocketMan", "Digereedoo", "007", true) } +func TestSetCurrencies(t *testing.T) { + cfg := config.GetConfig() + err := cfg.LoadConfig(config.ConfigTestFile) + if err != nil { + t.Fatal("Test failed. TestSetCurrencies failed to load config") + } + + UAC := Base{Name: "ASDF"} + UAC.AvailablePairs = []string{"ETHLTC", "LTCBTC"} + UAC.EnabledPairs = []string{"ETHLTC"} + newPair := pair.NewCurrencyPair("ETH", "USDT") + + err = UAC.SetCurrencies([]pair.CurrencyPair{newPair}, true) + if err == nil { + t.Fatal("Test failed. TestSetCurrencies returned nil error on non-existant exchange") + } + + UAC.Name = "ANX" + UAC.SetCurrencies([]pair.CurrencyPair{newPair}, true) + if !pair.Contains(UAC.GetEnabledCurrencies(), newPair) { + t.Fatal("Test failed. TestSetCurrencies failed to set currencies") + } + + UAC.SetCurrencies([]pair.CurrencyPair{newPair}, false) + if !pair.Contains(UAC.GetAvailableCurrencies(), newPair) { + t.Fatal("Test failed. TestSetCurrencies failed to set currencies") + } +} + func TestUpdateEnabledCurrencies(t *testing.T) { cfg := config.GetConfig() err := cfg.LoadConfig(config.ConfigTestFile) diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index 2d3beb7aeeb..773ca233ad7 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -173,7 +173,13 @@ func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) { ticker.Last = resp.Last ticker.Volume.Currency, _ = strconv.ParseFloat(resp.Volume[currencyPair[0:3]].(string), 64) - ticker.Volume.USD, _ = strconv.ParseFloat(resp.Volume["USD"].(string), 64) + + if common.StringContains(currencyPair, "USD") { + ticker.Volume.USD, _ = strconv.ParseFloat(resp.Volume["USD"].(string), 64) + } else { + ticker.Volume.ETH, _ = strconv.ParseFloat(resp.Volume["ETH"].(string), 64) + ticker.Volume.BTC, _ = strconv.ParseFloat(resp.Volume["BTC"].(string), 64) + } time, _ := resp.Volume["timestamp"].(float64) ticker.Volume.Timestamp = int64(time) diff --git a/exchanges/gemini/gemini_types.go b/exchanges/gemini/gemini_types.go index dfa5c64b0f3..33fa1bd7f8c 100644 --- a/exchanges/gemini/gemini_types.go +++ b/exchanges/gemini/gemini_types.go @@ -8,6 +8,8 @@ type Ticker struct { Volume struct { Currency float64 USD float64 + BTC float64 + ETH float64 Timestamp int64 } } diff --git a/exchanges/okcoin/okcoin.go b/exchanges/okcoin/okcoin.go index ead489698c4..a366640b69e 100644 --- a/exchanges/okcoin/okcoin.go +++ b/exchanges/okcoin/okcoin.go @@ -101,12 +101,12 @@ func (o *OKCoin) SetDefaults() { o.APIUrl = OKCOIN_API_URL o.Name = "OKCOIN International" o.WebsocketURL = OKCOIN_WEBSOCKET_URL - okcoinDefaultsSet = true o.setCurrencyPairFormats() } else { o.APIUrl = OKCOIN_API_URL_CHINA o.Name = "OKCOIN China" o.WebsocketURL = OKCOIN_WEBSOCKET_URL_CHINA + okcoinDefaultsSet = true o.setCurrencyPairFormats() } } diff --git a/helpers.go b/helpers.go index cd27836d6fc..ab88e1c85bd 100644 --- a/helpers.go +++ b/helpers.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/translation" exchange "github.com/thrasher-/gocryptotrader/exchanges" @@ -12,6 +13,32 @@ import ( "github.com/thrasher-/gocryptotrader/exchanges/ticker" ) +// MapCurrenciesByExchange returns a list of currency pairs mapped to an +// exchange +func MapCurrenciesByExchange(p []pair.CurrencyPair) map[string][]pair.CurrencyPair { + currencyExchange := make(map[string][]pair.CurrencyPair) + for x := range p { + for y := range bot.config.Exchanges { + exchName := bot.config.Exchanges[y].Name + success, err := bot.config.SupportsPair(exchName, p[x]) + if err != nil || !success { + continue + } + + result, ok := currencyExchange[exchName] + if !ok { + var pairs []pair.CurrencyPair + pairs = append(pairs, p[x]) + currencyExchange[exchName] = pairs + } else { + result = append(result, p[x]) + currencyExchange[exchName] = result + } + } + } + return currencyExchange +} + // GetExchangeNamesByCurrency returns a list of exchanges supporting // a currency pair based on whether the exchange is enabled or not func GetExchangeNamesByCurrency(p pair.CurrencyPair, enabled bool) []string { @@ -34,8 +61,42 @@ func GetExchangeNamesByCurrency(p pair.CurrencyPair, enabled bool) []string { return exchanges } +// GetRelatableCryptocurrencies returns a list of currency pairs if it can find +// any relatable currencies (e.g ETHBTC -> ETHLTC -> ETHUSDT -> ETHREP) +// incOrig includes the supplied pair if desired +func GetRelatableCryptocurrencies(p pair.CurrencyPair) []pair.CurrencyPair { + var pairs []pair.CurrencyPair + cryptocurrencies := currency.CryptoCurrencies + + for x := range cryptocurrencies { + newPair := pair.NewCurrencyPair(p.FirstCurrency.String(), cryptocurrencies[x]) + if pair.Contains(pairs, newPair) { + continue + } + pairs = append(pairs, newPair) + } + return pairs +} + +// GetRelatableFiatCurrencies returns a list of currency pairs if it can find +// any relatable currencies (e.g ETHUSD -> ETHAUD -> ETHGBP -> ETHJPY) +// incOrig includes the supplied pair if desired +func GetRelatableFiatCurrencies(p pair.CurrencyPair) []pair.CurrencyPair { + var pairs []pair.CurrencyPair + fiatCurrencies := currency.BaseCurrencies + + for x := range fiatCurrencies { + newPair := pair.NewCurrencyPair(p.FirstCurrency.String(), fiatCurrencies[x]) + if pair.Contains(pairs, newPair) { + continue + } + pairs = append(pairs, newPair) + } + return pairs +} + // GetRelatableCurrencies returns a list of currency pairs if it can find -// any relatable currencies (e.g BTCUSD -> BTC USDT -> XBT USD) +// any relatable currencies (e.g BTCUSD -> BTC USDT -> XBT USDT -> XBT USD) // incOrig includes the supplied pair if desired func GetRelatableCurrencies(p pair.CurrencyPair, incOrig bool) []pair.CurrencyPair { var pairs []pair.CurrencyPair @@ -47,6 +108,12 @@ func GetRelatableCurrencies(p pair.CurrencyPair, incOrig bool) []pair.CurrencyPa if err == nil { pairs = append(pairs, pair.NewCurrencyPair(first.String(), p.SecondCurrency.String())) + + second, err := translation.GetTranslation(p.SecondCurrency) + if err == nil { + pairs = append(pairs, pair.NewCurrencyPair(first.String(), + second.String())) + } } second, err := translation.GetTranslation(p.SecondCurrency) diff --git a/main.go b/main.go index c348bd35e2d..1636db6d91a 100644 --- a/main.go +++ b/main.go @@ -96,7 +96,7 @@ func main() { } log.Printf("Currency exchange provider: %s.", bot.config.CurrencyExchangeProvider) - bot.config.RetrieveConfigCurrencyPairs() + bot.config.RetrieveConfigCurrencyPairs(true) err = currency.SeedCurrencyData(common.JoinStrings(currency.BaseCurrencies, ",")) if err != nil { currency.SwapProvider() diff --git a/tools/portfolio/portfolio.go b/tools/portfolio/portfolio.go index 509057e845a..7d7eca16cfc 100644 --- a/tools/portfolio/portfolio.go +++ b/tools/portfolio/portfolio.go @@ -82,7 +82,7 @@ func main() { Subtotal float64 } - cfg.RetrieveConfigCurrencyPairs() + cfg.RetrieveConfigCurrencyPairs(true) portfolioMap := make(map[string]PortfolioTemp) total := float64(0)