From 69aa445a3a08b8fe344553f50c1cbac2e9a9cc1d Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 4 Sep 2017 11:31:13 +1000 Subject: [PATCH] Refactor stats and link up to ticker routine --- currency/pair/pair.go | 9 ++ currency/pair/pair_test.go | 24 +++++ exchanges/btce/btce_wrapper.go | 2 - exchanges/stats/stats.go | 141 +++++++++++++++-------------- exchanges/stats/stats_test.go | 156 +++++++++++++++++++-------------- routines.go | 5 +- 6 files changed, 204 insertions(+), 133 deletions(-) diff --git a/currency/pair/pair.go b/currency/pair/pair.go index 3b105ba0..a0ca789c 100644 --- a/currency/pair/pair.go +++ b/currency/pair/pair.go @@ -62,6 +62,15 @@ func (c CurrencyPair) Display(delimiter string, uppercase bool) CurrencyItem { return pair.Lower() } +// Equal compares two currency pairs and returns whether or not they are equal +func (c CurrencyPair) Equal(p CurrencyPair) bool { + if c.FirstCurrency.Upper() == p.FirstCurrency.Upper() && + c.SecondCurrency.Upper() == p.SecondCurrency.Upper() { + return true + } + return false +} + // NewCurrencyPairDelimiter splits the desired currency string at delimeter, // the returns a CurrencyPair struct func NewCurrencyPairDelimiter(currency, delimiter string) CurrencyPair { diff --git a/currency/pair/pair_test.go b/currency/pair/pair_test.go index 736abd01..c8f6fcd0 100644 --- a/currency/pair/pair_test.go +++ b/currency/pair/pair_test.go @@ -105,6 +105,30 @@ func TestDisplay(t *testing.T) { } } +func TestEqual(t *testing.T) { + t.Parallel() + pair := NewCurrencyPair("BTC", "USD") + secondPair := NewCurrencyPair("btc", "uSd") + actual := pair.Equal(secondPair) + expected := true + if actual != expected { + t.Errorf( + "Test failed. Equal(): %v was not equal to expected value: %v", + actual, expected, + ) + } + + secondPair.SecondCurrency = "ETH" + actual = pair.Equal(secondPair) + expected = false + if actual != expected { + t.Errorf( + "Test failed. Equal(): %v was not equal to expected value: %v", + actual, expected, + ) + } +} + func TestNewCurrencyPair(t *testing.T) { t.Parallel() pair := NewCurrencyPair("BTC", "USD") diff --git a/exchanges/btce/btce_wrapper.go b/exchanges/btce/btce_wrapper.go index ff180858..282f9a38 100644 --- a/exchanges/btce/btce_wrapper.go +++ b/exchanges/btce/btce_wrapper.go @@ -9,7 +9,6 @@ import ( "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/orderbook" - "github.com/thrasher-/gocryptotrader/exchanges/stats" "github.com/thrasher-/gocryptotrader/exchanges/ticker" ) @@ -45,7 +44,6 @@ func (b *BTCE) Run() { x = common.StringToUpper(x[0:3] + x[4:]) log.Printf("BTC-e %s: Last %f High %f Low %f Volume %f\n", x, y.Last, y.High, y.Low, y.Vol_cur) b.Ticker[x] = y - stats.AddExchangeInfo(b.GetName(), common.StringToUpper(x[0:3]), common.StringToUpper(x[4:]), y.Last, y.Vol_cur) } }() time.Sleep(time.Second * b.RESTPollingDelay) diff --git a/exchanges/stats/stats.go b/exchanges/stats/stats.go index 5d477e62..0b003e2f 100644 --- a/exchanges/stats/stats.go +++ b/exchanges/stats/stats.go @@ -3,113 +3,124 @@ package stats import ( "sort" - "github.com/thrasher-/gocryptotrader/currency" + "github.com/thrasher-/gocryptotrader/currency/pair" ) -type ExchangeInfo struct { - Exchange string - FirstCurrency string - FiatCurrency string - Price float64 - Volume float64 +// Item holds various fields for storing currency pair stats +type Item struct { + Exchange string + Pair pair.CurrencyPair + AssetType string + Price float64 + Volume float64 } -var ExchInfo []ExchangeInfo +// Items var array +var Items []Item -type ByPrice []ExchangeInfo +// ByPrice allows sorting by price +type ByPrice []Item -func (this ByPrice) Len() int { - return len(this) +func (b ByPrice) Len() int { + return len(b) } -func (this ByPrice) Less(i, j int) bool { - return this[i].Price < this[j].Price +func (b ByPrice) Less(i, j int) bool { + return b[i].Price < b[j].Price } -func (this ByPrice) Swap(i, j int) { - this[i], this[j] = this[j], this[i] +func (b ByPrice) Swap(i, j int) { + b[i], b[j] = b[j], b[i] } -type ByVolume []ExchangeInfo +// ByVolume allows sorting by volume +type ByVolume []Item -func (this ByVolume) Len() int { - return len(this) +func (b ByVolume) Len() int { + return len(b) } -func (this ByVolume) Less(i, j int) bool { - return this[i].Volume < this[j].Volume +func (b ByVolume) Less(i, j int) bool { + return b[i].Volume < b[j].Volume } -func (this ByVolume) Swap(i, j int) { - this[i], this[j] = this[j], this[i] +func (b ByVolume) Swap(i, j int) { + b[i], b[j] = b[j], b[i] } -func AddExchangeInfo(exchange, crypto, fiat string, price, volume float64) { - if currency.BaseCurrencies == "" { - currency.BaseCurrencies = currency.DefaultCurrencies - } - - if !currency.IsFiatCurrency(fiat) { - return - } - AppendExchangeInfo(exchange, crypto, fiat, price, volume) - -} - -func AppendExchangeInfo(exchange, crypto, fiat string, price, volume float64) { - if ExchangeInfoAlreadyExists(exchange, crypto, fiat, price, volume) { +// Add adds or updates the item stats +func Add(exchange string, p pair.CurrencyPair, assetType string, price, volume float64) { + if exchange == "" || assetType == "" || price == 0 || volume == 0 || p.FirstCurrency == "" || p.SecondCurrency == "" { return } - exch := ExchangeInfo{} - exch.Exchange = exchange - exch.FirstCurrency = crypto - exch.FiatCurrency = fiat - exch.Price = price - exch.Volume = volume - ExchInfo = append(ExchInfo, exch) + Append(exchange, p, assetType, price, volume) } -func ExchangeInfoAlreadyExists(exchange, crypto, fiat string, price, volume float64) bool { - for i := range ExchInfo { - if ExchInfo[i].Exchange == exchange && ExchInfo[i].FirstCurrency == crypto && ExchInfo[i].FiatCurrency == fiat { - ExchInfo[i].Price, ExchInfo[i].Volume = price, volume +// Append adds or updates the item stats for a specific +// currency pair and asset type +func Append(exchange string, p pair.CurrencyPair, assetType string, price, volume float64) { + if AlreadyExists(exchange, p, assetType, price, volume) { + return + } + + i := Item{ + Exchange: exchange, + Pair: p, + AssetType: assetType, + Price: price, + Volume: volume, + } + + Items = append(Items, i) +} + +// AlreadyExists checks to see if item info already exists +// for a specific currency pair and asset type +func AlreadyExists(exchange string, p pair.CurrencyPair, assetType string, price, volume float64) bool { + for i := range Items { + if Items[i].Exchange == exchange && Items[i].Pair.Equal(p) && Items[i].AssetType == assetType { + Items[i].Price, Items[i].Volume = price, volume return true } } return false } -func SortExchangesByVolume(crypto, fiat string, reverse bool) []ExchangeInfo { - info := []ExchangeInfo{} - - for _, x := range ExchInfo { - if x.FirstCurrency == crypto && x.FiatCurrency == fiat { - info = append(info, x) +// SortExchangesByVolume sorts item info by volume for a specific +// currency pair and asset type. Reverse will reverse the order from lowest to +// highest +func SortExchangesByVolume(p pair.CurrencyPair, assetType string, reverse bool) []Item { + var result []Item + for x := range Items { + if Items[x].Pair.Equal(p) && Items[x].AssetType == assetType { + result = append(result, Items[x]) } } if reverse { - sort.Sort(sort.Reverse(ByVolume(info))) + sort.Sort(sort.Reverse(ByVolume(result))) } else { - sort.Sort(ByVolume(info)) + sort.Sort(ByVolume(result)) } - return info + return result } -func SortExchangesByPrice(crypto, fiat string, reverse bool) []ExchangeInfo { - info := []ExchangeInfo{} - - for _, x := range ExchInfo { - if x.FirstCurrency == crypto && x.FiatCurrency == fiat { - info = append(info, x) +// SortExchangesByPrice sorts item info by volume for a specific +// currency pair and asset type. Reverse will reverse the order from lowest to +// highest +func SortExchangesByPrice(p pair.CurrencyPair, assetType string, reverse bool) []Item { + var result []Item + for x := range Items { + if Items[x].Pair.Equal(p) && Items[x].AssetType == assetType { + result = append(result, Items[x]) } } if reverse { - sort.Sort(sort.Reverse(ByPrice(info))) + sort.Sort(sort.Reverse(ByPrice(result))) } else { - sort.Sort(ByPrice(info)) + sort.Sort(ByPrice(result)) } - return info + return result } diff --git a/exchanges/stats/stats_test.go b/exchanges/stats/stats_test.go index 812823ef..3cefd2b9 100644 --- a/exchanges/stats/stats_test.go +++ b/exchanges/stats/stats_test.go @@ -2,138 +2,166 @@ package stats import ( "testing" + + "github.com/thrasher-/gocryptotrader/currency/pair" ) func TestLenByPrice(t *testing.T) { - exchangeInfo := ExchangeInfo{ - Exchange: "ANX", - FirstCurrency: "BTC", - FiatCurrency: "USD", - Price: 1200, - Volume: 5, + p := pair.NewCurrencyPair("BTC", "USD") + i := Item{ + Exchange: "ANX", + Pair: p, + AssetType: "SPOT", + Price: 1200, + Volume: 5, } - ExchInfo = append(ExchInfo, exchangeInfo) - if ByPrice.Len(ExchInfo) < 1 { + Items = append(Items, i) + if ByPrice.Len(Items) < 1 { t.Error("Test Failed - stats LenByPrice() length not correct.") } } func TestLessByPrice(t *testing.T) { - exchangeInfo := ExchangeInfo{ - Exchange: "alphapoint", - FirstCurrency: "BTC", - FiatCurrency: "USD", - Price: 1200, - Volume: 5, + p := pair.NewCurrencyPair("BTC", "USD") + i := Item{ + Exchange: "alphapoint", + Pair: p, + AssetType: "SPOT", + Price: 1200, + Volume: 5, } - exchangeInfo2 := ExchangeInfo{ - Exchange: "bitfinex", - FirstCurrency: "BTC", - FiatCurrency: "USD", - Price: 1198, - Volume: 20, + i2 := Item{ + Exchange: "bitfinex", + Pair: p, + AssetType: "SPOT", + Price: 1198, + Volume: 20, } - ExchInfo = append(ExchInfo, exchangeInfo) - ExchInfo = append(ExchInfo, exchangeInfo2) + Items = append(Items, i) + Items = append(Items, i2) - if !ByPrice.Less(ExchInfo, 2, 1) { + if !ByPrice.Less(Items, 2, 1) { t.Error("Test Failed - stats LessByPrice() incorrect return.") } - if ByPrice.Less(ExchInfo, 1, 2) { + if ByPrice.Less(Items, 1, 2) { t.Error("Test Failed - stats LessByPrice() incorrect return.") } } func TestSwapByPrice(t *testing.T) { - exchangeInfo := ExchangeInfo{ - Exchange: "bitstamp", - FirstCurrency: "BTC", - FiatCurrency: "USD", - Price: 1324, - Volume: 5, + p := pair.NewCurrencyPair("BTC", "USD") + i := Item{ + Exchange: "bitstamp", + Pair: p, + AssetType: "SPOT", + Price: 1324, + Volume: 5, } - exchangeInfo2 := ExchangeInfo{ - Exchange: "btcc", - FirstCurrency: "BTC", - FiatCurrency: "USD", - Price: 7863, - Volume: 20, + i2 := Item{ + Exchange: "btcc", + Pair: p, + AssetType: "SPOT", + Price: 7863, + Volume: 20, } - ExchInfo = append(ExchInfo, exchangeInfo) - ExchInfo = append(ExchInfo, exchangeInfo2) - ByPrice.Swap(ExchInfo, 3, 4) - if ExchInfo[3].Exchange != "btcc" || ExchInfo[4].Exchange != "bitstamp" { + Items = append(Items, i) + Items = append(Items, i2) + ByPrice.Swap(Items, 3, 4) + if Items[3].Exchange != "btcc" || Items[4].Exchange != "bitstamp" { t.Error("Test Failed - stats SwapByPrice did not swap values.") } } func TestLenByVolume(t *testing.T) { - if ByVolume.Len(ExchInfo) != 5 { + if ByVolume.Len(Items) != 5 { t.Error("Test Failed - stats lenByVolume did not swap values.") } } func TestLessByVolume(t *testing.T) { - if !ByVolume.Less(ExchInfo, 1, 2) { + if !ByVolume.Less(Items, 1, 2) { t.Error("Test Failed - stats LessByVolume() incorrect return.") } - if ByVolume.Less(ExchInfo, 2, 1) { + if ByVolume.Less(Items, 2, 1) { t.Error("Test Failed - stats LessByVolume() incorrect return.") } } func TestSwapByVolume(t *testing.T) { - ByPrice.Swap(ExchInfo, 3, 4) + ByPrice.Swap(Items, 3, 4) - if ExchInfo[4].Exchange != "btcc" || ExchInfo[3].Exchange != "bitstamp" { + if Items[4].Exchange != "btcc" || Items[3].Exchange != "bitstamp" { t.Error("Test Failed - stats SwapByVolume did not swap values.") } } -func TestAddExchangeInfo(t *testing.T) { - ExchInfo = ExchInfo[:0] - AddExchangeInfo("ANX", "BTC", "USD", 1200, 42) +func TestAdd(t *testing.T) { + Items = Items[:0] + p := pair.NewCurrencyPair("BTC", "USD") + Add("ANX", p, "SPOT", 1200, 42) - if len(ExchInfo) < 1 { - t.Error("Test Failed - stats AddExchangeInfo did not add exchange info.") + if len(Items) < 1 { + t.Error("Test Failed - stats Add did not add exchange info.") + } + + Add("", p, "", 0, 0) + + if len(Items) != 1 { + t.Error("Test Failed - stats Add did not add exchange info.") } } -func TestAppendExchangeInfo(t *testing.T) { - AppendExchangeInfo("sillyexchange", "BTC", "USD", 1234, 45) - if len(ExchInfo) < 2 { - t.Error("Test Failed - stats AppendExchangeInfo did not add exchange values.") +func TestAppend(t *testing.T) { + p := pair.NewCurrencyPair("BTC", "USD") + Append("sillyexchange", p, "SPOT", 1234, 45) + if len(Items) < 2 { + t.Error("Test Failed - stats Append did not add exchange values.") } - AppendExchangeInfo("sillyexchange", "BTC", "USD", 1234, 45) - if len(ExchInfo) == 3 { - t.Error("Test Failed - stats AppendExchangeInfo added exchange values") + + Append("sillyexchange", p, "SPOT", 1234, 45) + if len(Items) == 3 { + t.Error("Test Failed - stats Append added exchange values") } } -func TestExchangeInfoAlreadyExists(t *testing.T) { - if !ExchangeInfoAlreadyExists("ANX", "BTC", "USD", 1200, 42) { - t.Error("Test Failed - stats ExchangeInfoAlreadyExists exchange does not exist.") +func TestAlreadyExists(t *testing.T) { + p := pair.NewCurrencyPair("BTC", "USD") + if !AlreadyExists("ANX", p, "SPOT", 1200, 42) { + t.Error("Test Failed - stats AlreadyExists exchange does not exist.") } - if ExchangeInfoAlreadyExists("bla", "dii", "USD", 1234, 123) { - t.Error("Test Failed - stats ExchangeInfoAlreadyExists found incorrect exchange.") + p.FirstCurrency = "dii" + if AlreadyExists("bla", p, "SPOT", 1234, 123) { + t.Error("Test Failed - stats AlreadyExists found incorrect exchange.") } } func TestSortExchangesByVolume(t *testing.T) { - topVolume := SortExchangesByVolume("BTC", "USD", true) + p := pair.NewCurrencyPair("BTC", "USD") + topVolume := SortExchangesByVolume(p, "SPOT", true) if topVolume[0].Exchange != "sillyexchange" { t.Error("Test Failed - stats SortExchangesByVolume incorrectly sorted values.") } + + topVolume = SortExchangesByVolume(p, "SPOT", false) + if topVolume[0].Exchange != "ANX" { + t.Error("Test Failed - stats SortExchangesByVolume incorrectly sorted values.") + } } func TestSortExchangesByPrice(t *testing.T) { - topPrice := SortExchangesByPrice("BTC", "USD", true) + p := pair.NewCurrencyPair("BTC", "USD") + topPrice := SortExchangesByPrice(p, "SPOT", true) if topPrice[0].Exchange != "sillyexchange" { t.Error("Test Failed - stats SortExchangesByPrice incorrectly sorted values.") } + + topPrice = SortExchangesByPrice(p, "SPOT", false) + if topPrice[0].Exchange != "ANX" { + t.Error("Test Failed - stats SortExchangesByPrice incorrectly sorted values.") + } } diff --git a/routines.go b/routines.go index 3a20b24b..ae9f7c9d 100644 --- a/routines.go +++ b/routines.go @@ -5,10 +5,10 @@ import ( "log" "time" - "github.com/thrasher-/gocryptotrader/exchanges/orderbook" - "github.com/thrasher-/gocryptotrader/currency/pair" exchange "github.com/thrasher-/gocryptotrader/exchanges" + "github.com/thrasher-/gocryptotrader/exchanges/orderbook" + "github.com/thrasher-/gocryptotrader/exchanges/stats" "github.com/thrasher-/gocryptotrader/exchanges/ticker" ) @@ -21,6 +21,7 @@ func printSummary(result ticker.Price, p pair.CurrencyPair, assetType, exchangeN return } + stats.Add(exchangeName, p, assetType, result.Last, result.Volume) log.Printf("%s %s %s: Last %.8f Ask %.8f Bid %.8f High %.8f Low %.8f Volume %.8f", exchangeName, exchange.FormatCurrency(p).String(),