From 416fbbd5ae3c4365b60d7bf15c4a0a75953917cd Mon Sep 17 00:00:00 2001 From: Shogin Michael Date: Thu, 30 May 2019 05:35:22 +0200 Subject: [PATCH 1/5] Unit tests for communication/base package (#312) * Added tests * Added tests communications base * Removed unnecessary field * Review corrections: linter * Review corrections: typo --- communications/base/base_interface.go | 1 + communications/base/base_test.go | 147 +++++++++++++++++++++++++- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/communications/base/base_interface.go b/communications/base/base_interface.go index ae8f0ab1..1ed3633d 100644 --- a/communications/base/base_interface.go +++ b/communications/base/base_interface.go @@ -54,6 +54,7 @@ func (c IComm) PushEvent(event Event) { // GetEnabledCommunicationMediums prints out enabled and connected communication // packages +// (#debug output only) func (c IComm) GetEnabledCommunicationMediums() { var count int for i := range c { diff --git a/communications/base/base_test.go b/communications/base/base_test.go index e8133f47..3dc5d0e7 100644 --- a/communications/base/base_test.go +++ b/communications/base/base_test.go @@ -2,6 +2,9 @@ package base import ( "testing" + + "github.com/thrasher-/gocryptotrader/exchanges/orderbook" + "github.com/thrasher-/gocryptotrader/exchanges/ticker" ) var ( @@ -71,14 +74,150 @@ func TestGetStatus(t *testing.T) { } } +type CommunicationProvider struct { + ICommunicate + + isEnabled bool + isConnected bool + ConnectCalled bool + PushEventCalled bool +} + +func (p *CommunicationProvider) IsEnabled() bool { + return p.isEnabled +} + +func (p *CommunicationProvider) IsConnected() bool { + return p.isConnected +} + +func (p *CommunicationProvider) Connect() error { + p.ConnectCalled = true + return nil +} + +func (p *CommunicationProvider) PushEvent(e Event) error { + p.PushEventCalled = true + return nil +} + +func (p *CommunicationProvider) GetName() string { + return "someTestProvider" +} + func TestSetup(t *testing.T) { - i.Setup() + var ic IComm + testConfigs := []struct { + isEnabled bool + isConnected bool + shouldConnectCalled bool + provider ICommunicate + }{ + {false, true, false, nil}, + {false, false, false, nil}, + {true, true, false, nil}, + {true, false, true, nil}, + } + for _, config := range testConfigs { + config.provider = &CommunicationProvider{ + isEnabled: config.isEnabled, + isConnected: config.isConnected} + ic = append(ic, config.provider) + } + + ic.Setup() + + for idx, provider := range ic { + exp := testConfigs[idx].shouldConnectCalled + act := provider.(*CommunicationProvider).ConnectCalled + if exp != act { + t.Fatalf("provider should be enabled and not be connected: exp=%v, act=%v", exp, act) + } + } } func TestPushEvent(t *testing.T) { - i.PushEvent(Event{}) + var ic IComm + testConfigs := []struct { + Enabled bool + Connected bool + PushEventCalled bool + provider ICommunicate + }{ + {false, true, false, nil}, + {false, false, false, nil}, + {true, false, false, nil}, + {true, true, true, nil}, + } + for _, config := range testConfigs { + config.provider = &CommunicationProvider{ + isEnabled: config.Enabled, + isConnected: config.Connected} + ic = append(ic, config.provider) + } + + ic.PushEvent(Event{}) + + for idx, provider := range ic { + exp := testConfigs[idx].PushEventCalled + act := provider.(*CommunicationProvider).PushEventCalled + if exp != act { + t.Fatalf("provider should be enabled and connected: exp=%v, act=%v", exp, act) + } + } } -func TestGetEnabledCommunicationMediums(t *testing.T) { - i.GetEnabledCommunicationMediums() +func TestStageTickerData(t *testing.T) { + _, ok := TickerStaged["bitstamp"]["someAsset"]["BTCUSD"] + if ok { + t.Fatalf("key should not exists") + } + + price := ticker.Price{} + var i IComm + i.Setup() + + i.StageTickerData("bitstamp", "someAsset", &price) + + _, ok = TickerStaged["bitstamp"]["someAsset"][price.Pair.String()] + if !ok { + t.Fatalf("key should exists") + } +} + +func TestOrderbookData(t *testing.T) { + _, ok := OrderbookStaged["bitstamp"]["someAsset"]["someOrderbook"] + if ok { + t.Fatal("key should not exists") + } + + ob := orderbook.Base{ + Asks: []orderbook.Item{ + {Amount: 1, Price: 2, ID: 3}, + {Amount: 4, Price: 5, ID: 6}, + }, + } + var i IComm + i.Setup() + + i.StageOrderbookData("bitstamp", "someAsset", &ob) + + orderbook, ok := OrderbookStaged["bitstamp"]["someAsset"][ob.Pair.String()] + if !ok { + t.Fatal("key should exists") + } + + if ob.Pair.String() != orderbook.CurrencyPair { + t.Fatal("currency missmatched") + } + + _, totalAsks := ob.TotalAsksAmount() + if totalAsks != orderbook.TotalAsks { + t.Fatal("total asks missmatched") + } + + _, totalBids := ob.TotalBidsAmount() + if totalBids != orderbook.TotalBids { + t.Fatal("total bids missmatched") + } } From a80acb16dea7d110663de5b2b4de317cae3b0b45 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 31 May 2019 16:06:10 +1000 Subject: [PATCH 2/5] General fixes for CancelAllOrders exchange wrapper function (#313) * General fixes for CancelAllOrders * Fix error shadowing issue * Initialise order status map and rm reduntant initialisations --- exchanges/alphapoint/alphapoint_wrapper.go | 3 ++- exchanges/bithumb/bithumb_wrapper.go | 2 +- exchanges/bitmex/bitmex_wrapper.go | 4 +++- exchanges/bitstamp/bitstamp_wrapper.go | 7 +++++-- exchanges/btse/btse_wrapper.go | 4 ++-- exchanges/exmo/exmo_wrapper.go | 8 ++++++-- exchanges/gateio/gateio_wrapper.go | 8 ++++---- exchanges/gemini/gemini.go | 2 +- exchanges/hitbtc/hitbtc_wrapper.go | 8 +++++++- exchanges/huobi/huobi_wrapper.go | 4 +--- exchanges/huobihadax/huobihadax_wrapper.go | 4 +--- exchanges/kraken/kraken_wrapper.go | 10 ++++------ exchanges/lakebtc/lakebtc_wrapper.go | 7 ++----- exchanges/localbitcoins/localbitcoins_wrapper.go | 2 +- exchanges/okgroup/okgroup_wrapper.go | 10 ++++++---- exchanges/poloniex/poloniex.go | 9 ++++----- exchanges/poloniex/poloniex_wrapper.go | 7 ++----- exchanges/yobit/yobit_wrapper.go | 3 ++- exchanges/zb/zb_wrapper.go | 2 -- 19 files changed, 54 insertions(+), 50 deletions(-) diff --git a/exchanges/alphapoint/alphapoint_wrapper.go b/exchanges/alphapoint/alphapoint_wrapper.go index 204cf01c..954e9ffe 100644 --- a/exchanges/alphapoint/alphapoint_wrapper.go +++ b/exchanges/alphapoint/alphapoint_wrapper.go @@ -170,7 +170,8 @@ func (a *Alphapoint) CancelOrder(order *exchange.OrderCancellation) error { // CancelAllOrders cancels all orders for a given account func (a *Alphapoint) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - return exchange.CancelAllOrdersResponse{}, a.CancelAllExistingOrders(orderCancellation.AccountID) + return exchange.CancelAllOrdersResponse{}, + a.CancelAllExistingOrders(orderCancellation.AccountID) } // GetOrderInfo returns information on a current open order diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 245022d4..6717b52e 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -242,8 +242,8 @@ func (b *Bithumb) CancelAllOrders(orderCancellation *exchange.OrderCancellation) cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ OrderStatus: make(map[string]string), } - var allOrders []OrderData + var allOrders []OrderData for _, currency := range b.GetEnabledCurrencies() { orders, err := b.GetOrders("", orderCancellation.Side.ToString(), diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index b7a06a75..539a0871 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -247,7 +247,9 @@ func (b *Bitmex) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel } for i := range orders { - cancelAllOrdersResponse.OrderStatus[orders[i].OrderID] = orders[i].OrdRejReason + if orders[i].OrdRejReason != "" { + cancelAllOrdersResponse.OrderStatus[orders[i].OrderID] = orders[i].OrdRejReason + } } return cancelAllOrdersResponse, nil diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 00183ac3..9526d874 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -232,8 +232,11 @@ func (b *Bitstamp) CancelOrder(order *exchange.OrderCancellation) error { // CancelAllOrders cancels all orders associated with a currency pair func (b *Bitstamp) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - isCancelAllSuccessful, err := b.CancelAllExistingOrders() - if !isCancelAllSuccessful { + success, err := b.CancelAllExistingOrders() + if err != nil { + return exchange.CancelAllOrdersResponse{}, err + } + if !success { err = errors.New("cancel all orders failed. Bitstamp provides no further information. Check order status to verify") } diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 3cd625e0..22d1be50 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -187,13 +187,13 @@ func (b *BTSE) CancelOrder(order *exchange.OrderCancellation) error { // If product ID is sent, all orders of that specified market will be cancelled // If not specified, all orders of all markets will be cancelled func (b *BTSE) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { + var resp exchange.CancelAllOrdersResponse r, err := b.CancelOrders(exchange.FormatExchangeCurrency(b.Name, orderCancellation.CurrencyPair).String()) if err != nil { - return exchange.CancelAllOrdersResponse{}, err + return resp, err } - var resp exchange.CancelAllOrdersResponse switch r.Code { case -1: return resp, errors.New("order cancellation unsuccessful") diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index 0f1d8cc0..a97e01ae 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -240,7 +240,6 @@ func (e *EXMO) ModifyOrder(action *exchange.ModifyOrder) (string, error) { // CancelOrder cancels an order by its corresponding ID number func (e *EXMO) CancelOrder(order *exchange.OrderCancellation) error { orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64) - if err != nil { return err } @@ -253,6 +252,7 @@ func (e *EXMO) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAl cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ OrderStatus: make(map[string]string), } + openOrders, err := e.GetOpenOrders() if err != nil { return cancelAllOrdersResponse, err @@ -292,7 +292,10 @@ func (e *EXMO) GetDepositAddress(cryptocurrency currency.Code, _ string) (string // WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is // submitted func (e *EXMO) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.WithdrawRequest) (string, error) { - resp, err := e.WithdrawCryptocurrency(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Amount) + resp, err := e.WithdrawCryptocurrency(withdrawRequest.Currency.String(), + withdrawRequest.Address, + withdrawRequest.AddressTag, + withdrawRequest.Amount) return fmt.Sprintf("%v", resp), err } @@ -329,6 +332,7 @@ func (e *EXMO) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]e if err != nil { return nil, err } + var orders []exchange.OrderDetail for _, order := range resp { symbol := currency.NewPairDelimiter(order.Pair, "_") diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index b7e91baa..f05d2c4e 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -266,15 +266,15 @@ func (g *Gateio) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel return cancelAllOrdersResponse, err } - uniqueSymbols := make(map[string]string) + uniqueSymbols := make(map[string]int) for i := range openOrders.Orders { - uniqueSymbols[openOrders.Orders[i].CurrencyPair] = openOrders.Orders[i].CurrencyPair + uniqueSymbols[openOrders.Orders[i].CurrencyPair]++ } for unique := range uniqueSymbols { - err = g.CancelAllExistingOrders(-1, uniqueSymbols[unique]) + err = g.CancelAllExistingOrders(-1, unique) if err != nil { - return cancelAllOrdersResponse, err + cancelAllOrdersResponse.OrderStatus[unique] = err.Error() } } diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index cc9a0811..e2c61ccb 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -342,12 +342,12 @@ func (g *Gemini) CancelExistingOrder(orderID int64) (Order, error) { // the UI. If sessions = true will only cancel the order that is called on this // session asssociated with the APIKEY func (g *Gemini) CancelExistingOrders(cancelBySession bool) (OrderResult, error) { - response := OrderResult{} path := geminiOrderCancelAll if cancelBySession { path = geminiOrderCancelSession } + var response OrderResult err := g.SendAuthenticatedHTTPRequest(http.MethodPost, path, nil, &response) if err != nil { return response, err diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index ec149444..9460ef1f 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -231,13 +231,19 @@ func (h *HitBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ OrderStatus: make(map[string]string), } + resp, err := h.CancelAllExistingOrders() if err != nil { return cancelAllOrdersResponse, err } for i := range resp { - cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(resp[i].ID, 10)] = fmt.Sprintf("Could not cancel order %v. Status: %v", resp[i].ID, resp[i].Status) + if resp[i].Status != "canceled" { + cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(resp[i].ID, 10)] = + fmt.Sprintf("Could not cancel order %v. Status: %v", + resp[i].ID, + resp[i].Status) + } } return cancelAllOrdersResponse, nil diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 79b9eca2..ce5739d2 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -335,9 +335,7 @@ func (h *HUOBI) CancelOrder(order *exchange.OrderCancellation) error { // CancelAllOrders cancels all orders associated with a currency pair func (h *HUOBI) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ - OrderStatus: make(map[string]string), - } + var cancelAllOrdersResponse exchange.CancelAllOrdersResponse for _, currency := range h.GetEnabledCurrencies() { resp, err := h.CancelOpenOrdersBatch(orderCancellation.AccountID, exchange.FormatExchangeCurrency(h.Name, currency).String()) if err != nil { diff --git a/exchanges/huobihadax/huobihadax_wrapper.go b/exchanges/huobihadax/huobihadax_wrapper.go index 190ac046..59ea1c10 100644 --- a/exchanges/huobihadax/huobihadax_wrapper.go +++ b/exchanges/huobihadax/huobihadax_wrapper.go @@ -291,9 +291,7 @@ func (h *HUOBIHADAX) CancelOrder(order *exchange.OrderCancellation) error { // CancelAllOrders cancels all orders associated with a currency pair func (h *HUOBIHADAX) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ - OrderStatus: make(map[string]string), - } + var cancelAllOrdersResponse exchange.CancelAllOrdersResponse for _, currency := range h.GetEnabledCurrencies() { resp, err := h.CancelOpenOrdersBatch(orderCancellation.AccountID, exchange.FormatExchangeCurrency(h.Name, currency).String()) if err != nil { diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index c3f8fd72..c359427e 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -251,12 +251,10 @@ func (k *Kraken) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel return cancelAllOrdersResponse, err } - if openOrders.Count > 0 { - for orderID := range openOrders.Open { - _, err = k.CancelExistingOrder(orderID) - if err != nil { - cancelAllOrdersResponse.OrderStatus[orderID] = err.Error() - } + for orderID := range openOrders.Open { + _, err = k.CancelExistingOrder(orderID) + if err != nil { + cancelAllOrdersResponse.OrderStatus[orderID] = err.Error() } } diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go index dac301be..33061c81 100644 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ b/exchanges/lakebtc/lakebtc_wrapper.go @@ -202,9 +202,7 @@ func (l *LakeBTC) CancelOrder(order *exchange.OrderCancellation) error { // CancelAllOrders cancels all orders associated with a currency pair func (l *LakeBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{ - OrderStatus: make(map[string]string), - } + var cancelAllOrdersResponse exchange.CancelAllOrdersResponse openOrders, err := l.GetOpenOrders() if err != nil { return cancelAllOrdersResponse, err @@ -212,8 +210,7 @@ func (l *LakeBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cance var ordersToCancel []string for _, order := range openOrders { - orderIDString := strconv.FormatInt(order.ID, 10) - ordersToCancel = append(ordersToCancel, orderIDString) + ordersToCancel = append(ordersToCancel, strconv.FormatInt(order.ID, 10)) } return cancelAllOrdersResponse, l.CancelExistingOrders(ordersToCancel) diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index 73b0e534..8f27977a 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -253,7 +253,7 @@ func (l *LocalBitcoins) CancelAllOrders(_ *exchange.OrderCancellation) (exchange adIDString := strconv.FormatInt(ads.AdList[i].Data.AdID, 10) err = l.DeleteAd(adIDString) if err != nil { - cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(ads.AdList[i].Data.AdID, 10)] = err.Error() + cancelAllOrdersResponse.OrderStatus[adIDString] = err.Error() } } diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index b74cf7fd..b0ceb467 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -264,13 +264,15 @@ func (o *OKGroup) CancelOrder(orderCancellation *exchange.OrderCancellation) (er } // CancelAllOrders cancels all orders associated with a currency pair -func (o *OKGroup) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (resp exchange.CancelAllOrdersResponse, _ error) { +func (o *OKGroup) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (resp exchange.CancelAllOrdersResponse, err error) { orderIDs := strings.Split(orderCancellation.OrderID, ",") + resp.OrderStatus = make(map[string]string) var orderIDNumbers []int64 for _, i := range orderIDs { - orderIDNumber, err := strconv.ParseInt(i, 10, 64) - if err != nil { - return resp, err + orderIDNumber, strConvErr := strconv.ParseInt(i, 10, 64) + if strConvErr != nil { + resp.OrderStatus[i] = strConvErr.Error() + continue } orderIDNumbers = append(orderIDNumbers, orderIDNumber) } diff --git a/exchanges/poloniex/poloniex.go b/exchanges/poloniex/poloniex.go index 3d0b8e0d..9a2cf9fa 100644 --- a/exchanges/poloniex/poloniex.go +++ b/exchanges/poloniex/poloniex.go @@ -533,22 +533,21 @@ func (p *Poloniex) PlaceOrder(currency string, rate, amount float64, immediate, } // CancelExistingOrder cancels and order by orderID -func (p *Poloniex) CancelExistingOrder(orderID int64) (bool, error) { +func (p *Poloniex) CancelExistingOrder(orderID int64) error { result := GenericResponse{} values := url.Values{} values.Set("orderNumber", strconv.FormatInt(orderID, 10)) err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexOrderCancel, values, &result) - if err != nil { - return false, err + return err } if result.Success != 1 { - return false, errors.New(result.Error) + return errors.New(result.Error) } - return true, nil + return nil } // MoveOrder moves an order diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index 5e93a95a..11629b61 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -230,14 +230,11 @@ func (p *Poloniex) ModifyOrder(action *exchange.ModifyOrder) (string, error) { // CancelOrder cancels an order by its corresponding ID number func (p *Poloniex) CancelOrder(order *exchange.OrderCancellation) error { orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64) - if err != nil { return err } - _, err = p.CancelExistingOrder(orderIDInt) - - return err + return p.CancelExistingOrder(orderIDInt) } // CancelAllOrders cancels all orders associated with a currency pair @@ -252,7 +249,7 @@ func (p *Poloniex) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Canc for _, openOrderPerCurrency := range openOrders.Data { for _, openOrder := range openOrderPerCurrency { - _, err = p.CancelExistingOrder(openOrder.OrderNumber) + err = p.CancelExistingOrder(openOrder.OrderNumber) if err != nil { cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(openOrder.OrderNumber, 10)] = err.Error() } diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 6a541c0c..3279a93f 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -219,7 +219,8 @@ func (y *Yobit) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelA for key := range activeOrders { orderIDInt, err := strconv.ParseInt(key, 10, 64) if err != nil { - return cancelAllOrdersResponse, err + cancelAllOrdersResponse.OrderStatus[key] = err.Error() + continue } _, err = y.CancelExistingOrder(orderIDInt) diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index cbf1bb9d..0d36862f 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -239,7 +239,6 @@ func (z *ZB) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllO } var allOpenOrders []Order for _, currency := range z.GetEnabledCurrencies() { - var pageNumber int64 // Limiting to 10 pages for i := 0; i < 10; i++ { openOrders, err := z.GetUnfinishedOrdersIgnoreTradeType(exchange.FormatExchangeCurrency(z.Name, currency).String(), 1, 10) @@ -252,7 +251,6 @@ func (z *ZB) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllO } allOpenOrders = append(allOpenOrders, openOrders...) - pageNumber++ } } From 94ac7c917df2ec325578838bd385e876114fd22b Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 3 Jun 2019 17:00:34 +1000 Subject: [PATCH 3/5] Huobi/Hadax: Update test symbol to fix tests --- exchanges/huobi/huobi_test.go | 21 +++++++++++---------- exchanges/huobihadax/huobihadax_test.go | 21 +++++++++++---------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index a7081a28..e53fcd3d 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -21,6 +21,7 @@ const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false + testSymbol = "btcusdt" ) var h HUOBI @@ -75,7 +76,7 @@ func TestSetup(t *testing.T) { func TestGetSpotKline(t *testing.T) { t.Parallel() _, err := h.GetSpotKline(KlinesRequestParams{ - Symbol: "btcusdt", + Symbol: testSymbol, Period: TimeIntervalHour, Size: 0, }) @@ -86,7 +87,7 @@ func TestGetSpotKline(t *testing.T) { func TestGetMarketDetailMerged(t *testing.T) { t.Parallel() - _, err := h.GetMarketDetailMerged("btcusdt") + _, err := h.GetMarketDetailMerged(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetMarketDetailMerged: %s", err) } @@ -95,7 +96,7 @@ func TestGetMarketDetailMerged(t *testing.T) { func TestGetDepth(t *testing.T) { t.Parallel() _, err := h.GetDepth(OrderBookDataRequestParams{ - Symbol: "btcusdt", + Symbol: testSymbol, Type: OrderBookDataRequestParamsTypeStep1, }) @@ -106,7 +107,7 @@ func TestGetDepth(t *testing.T) { func TestGetTrades(t *testing.T) { t.Parallel() - _, err := h.GetTrades("btcusdt") + _, err := h.GetTrades(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetTrades: %s", err) } @@ -114,7 +115,7 @@ func TestGetTrades(t *testing.T) { func TestGetLatestSpotPrice(t *testing.T) { t.Parallel() - _, err := h.GetLatestSpotPrice("btcusdt") + _, err := h.GetLatestSpotPrice(testSymbol) if err != nil { t.Errorf("Test failed - Huobi GetLatestSpotPrice: %s", err) } @@ -122,7 +123,7 @@ func TestGetLatestSpotPrice(t *testing.T) { func TestGetTradeHistory(t *testing.T) { t.Parallel() - _, err := h.GetTradeHistory("btcusdt", "50") + _, err := h.GetTradeHistory(testSymbol, "50") if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } @@ -130,7 +131,7 @@ func TestGetTradeHistory(t *testing.T) { func TestGetMarketDetail(t *testing.T) { t.Parallel() - _, err := h.GetMarketDetail("btcusdt") + _, err := h.GetMarketDetail(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } @@ -200,7 +201,7 @@ func TestSpotNewOrder(t *testing.T) { } arg := SpotNewOrderRequestParams{ - Symbol: "btcusdt", + Symbol: testSymbol, AccountID: 1, Amount: 0.01, Price: 10.1, @@ -238,7 +239,7 @@ func TestGetMarginLoanOrders(t *testing.T) { t.Skip() } - _, err := h.GetMarginLoanOrders("btcusdt", "", "", "", "", "", "", "") + _, err := h.GetMarginLoanOrders(testSymbol, "", "", "", "", "", "", "") if err != nil { t.Errorf("Test failed - Huobi TestGetMarginLoanOrders: %s", err) } @@ -251,7 +252,7 @@ func TestGetMarginAccountBalance(t *testing.T) { t.Skip() } - _, err := h.GetMarginAccountBalance("btcusdt") + _, err := h.GetMarginAccountBalance(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetMarginAccountBalance: %s", err) } diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index 505dfaf6..bd4dad0e 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -17,6 +17,7 @@ const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false + testSymbol = "btcusdt" ) var h HUOBIHADAX @@ -71,7 +72,7 @@ func TestSetup(t *testing.T) { func TestGetSpotKline(t *testing.T) { t.Parallel() _, err := h.GetSpotKline(KlinesRequestParams{ - Symbol: "hptusdt", + Symbol: testSymbol, Period: TimeIntervalHour, Size: 0, }) @@ -82,7 +83,7 @@ func TestGetSpotKline(t *testing.T) { func TestGetMarketDetailMerged(t *testing.T) { t.Parallel() - _, err := h.GetMarketDetailMerged("hptusdt") + _, err := h.GetMarketDetailMerged(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetMarketDetailMerged: %s", err) } @@ -90,7 +91,7 @@ func TestGetMarketDetailMerged(t *testing.T) { func TestGetDepth(t *testing.T) { t.Parallel() - _, err := h.GetDepth("hptusdt", "step1") + _, err := h.GetDepth(testSymbol, "step1") if err != nil { t.Errorf("Test failed - Huobi TestGetDepth: %s", err) } @@ -98,7 +99,7 @@ func TestGetDepth(t *testing.T) { func TestGetTrades(t *testing.T) { t.Parallel() - _, err := h.GetTrades("hptusdt") + _, err := h.GetTrades(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetTrades: %s", err) } @@ -106,7 +107,7 @@ func TestGetTrades(t *testing.T) { func TestGetLatestSpotPrice(t *testing.T) { t.Parallel() - _, err := h.GetLatestSpotPrice("hptusdt") + _, err := h.GetLatestSpotPrice(testSymbol) if err != nil { t.Errorf("Test failed - Huobi GetLatestSpotPrice: %s", err) } @@ -114,7 +115,7 @@ func TestGetLatestSpotPrice(t *testing.T) { func TestGetTradeHistory(t *testing.T) { t.Parallel() - _, err := h.GetTradeHistory("hptusdt", "50") + _, err := h.GetTradeHistory(testSymbol, "50") if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } @@ -122,7 +123,7 @@ func TestGetTradeHistory(t *testing.T) { func TestGetMarketDetail(t *testing.T) { t.Parallel() - _, err := h.GetMarketDetail("hptusdt") + _, err := h.GetMarketDetail(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err) } @@ -192,7 +193,7 @@ func TestSpotNewOrder(t *testing.T) { } arg := SpotNewOrderRequestParams{ - Symbol: "hptusdt", + Symbol: testSymbol, AccountID: 000000, Amount: 0.01, Price: 10.1, @@ -240,7 +241,7 @@ func TestGetMarginLoanOrders(t *testing.T) { t.Skip() } - _, err := h.GetMarginLoanOrders("hptusdt", "", "", "", "", "", "", "") + _, err := h.GetMarginLoanOrders(testSymbol, "", "", "", "", "", "", "") if err != nil { t.Errorf("Test failed - Huobi TestGetMarginLoanOrders: %s", err) } @@ -253,7 +254,7 @@ func TestGetMarginAccountBalance(t *testing.T) { t.Skip() } - _, err := h.GetMarginAccountBalance("hptusdt") + _, err := h.GetMarginAccountBalance(testSymbol) if err != nil { t.Errorf("Test failed - Huobi TestGetMarginAccountBalance: %s", err) } From 8048962b608f021e36cef510f4d1cbf23b60b14d Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 3 Jun 2019 17:17:17 +1000 Subject: [PATCH 4/5] Remove BTCC exchange --- README.md | 1 - config/config_test.go | 2 +- config_example.json | 40 -- exchange.go | 3 - exchanges/btcc/README.md | 141 ----- exchanges/btcc/btcc.go | 136 ----- exchanges/btcc/btcc_test.go | 350 ------------ exchanges/btcc/btcc_types.go | 98 ---- exchanges/btcc/btcc_websocket.go | 539 ------------------ exchanges/btcc/btcc_wrapper.go | 191 ------- exchanges/stats/stats_test.go | 6 +- exchanges/ticker/ticker_test.go | 13 +- testdata/configtest.json | 40 -- tools/documentation/documentation.go | 2 - .../exchanges_templates/btcc.tmpl | 106 ---- .../root_templates/root_readme.tmpl | 1 - 16 files changed, 11 insertions(+), 1658 deletions(-) delete mode 100644 exchanges/btcc/README.md delete mode 100644 exchanges/btcc/btcc.go delete mode 100644 exchanges/btcc/btcc_test.go delete mode 100644 exchanges/btcc/btcc_types.go delete mode 100644 exchanges/btcc/btcc_websocket.go delete mode 100644 exchanges/btcc/btcc_wrapper.go delete mode 100644 tools/documentation/exchanges_templates/btcc.tmpl diff --git a/README.md b/README.md index dfff73c2..bed3517c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader | BitMEX | Yes | Yes | NA | | Bitstamp | Yes | Yes | No | | Bittrex | Yes | No | NA | -| BTCC | Yes | Yes | No | | BTCMarkets | Yes | No | NA | | BTSE | Yes | Yes | NA | | COINUT | Yes | Yes | NA | diff --git a/config/config_test.go b/config/config_test.go index b7c7a0f7..33e7b31e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -13,7 +13,7 @@ import ( const ( // Default number of enabled exchanges. Modify this whenever an exchange is // added or removed - defaultEnabledExchanges = 28 + defaultEnabledExchanges = 27 ) func TestGetCurrencyConfig(t *testing.T) { diff --git a/config_example.json b/config_example.json index 5fd0b85f..7fae4881 100644 --- a/config_example.json +++ b/config_example.json @@ -491,46 +491,6 @@ } ] }, - { - "name": "BTCC", - "enabled": true, - "verbose": false, - "websocket": false, - "useSandbox": false, - "restPollingDelay": 10, - "httpTimeout": 15000000000, - "httpUserAgent": "", - "httpDebugging": false, - "authenticatedApiSupport": false, - "apiKey": "Key", - "apiSecret": "Secret", - "apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "proxyAddress": "", - "websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API", - "availablePairs": "BTCUSD", - "enabledPairs": "BTCUSD", - "baseCurrencies": "USD", - "assetTypes": "SPOT", - "supportsAutoPairUpdates": true, - "configCurrencyPairFormat": { - "uppercase": true - }, - "requestCurrencyPairFormat": { - "uppercase": true - }, - "bankAccounts": [ - { - "bankName": "", - "bankAddress": "", - "accountName": "", - "accountNumber": "", - "swiftCode": "", - "iban": "", - "supportedCurrencies": "" - } - ] - }, { "name": "BTSE", "enabled": true, diff --git a/exchange.go b/exchange.go index 1825af82..6d34a38f 100644 --- a/exchange.go +++ b/exchange.go @@ -15,7 +15,6 @@ import ( "github.com/thrasher-/gocryptotrader/exchanges/bitmex" "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/btse" "github.com/thrasher-/gocryptotrader/exchanges/coinbasepro" @@ -148,8 +147,6 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error { exch = new(bitstamp.Bitstamp) case "bittrex": exch = new(bittrex.Bittrex) - case "btcc": - exch = new(btcc.BTCC) case "btc markets": exch = new(btcmarkets.BTCMarkets) case "btse": diff --git a/exchanges/btcc/README.md b/exchanges/btcc/README.md deleted file mode 100644 index df3e7678..00000000 --- a/exchanges/btcc/README.md +++ /dev/null @@ -1,141 +0,0 @@ -# GoCryptoTrader package Btcc - - - - -[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader) -[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE) -[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/btcc) -[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master) -[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader) - - -This btcc package is part of the GoCryptoTrader codebase. - -## This is still in active development - -You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader). - -Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY) - -## BTCC Exchange - -### Current Features - -+ REST Support -+ Websocket Support - -### How to enable - -+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example) - -+ Individual package example below: - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### How to do REST public/private calls - -+ If enabled via "configuration".json file the exchange will be added to the -IBotExchange array in the ```go var bot Bot``` and you will only be able to use -the wrapper interface functions for accessing exchange data. View routines.go -for an example of integration usage with GoCryptoTrader. Rudimentary example -below: - -main.go -```go -var b exchange.IBotExchange - -for i := range bot.exchanges { - if bot.exchanges[i].GetName() == "BTCC" { - b = bot.exchanges[i] - } -} - -// Public calls - wrapper functions - -// Fetches current ticker information -tick, err := b.GetTickerPrice() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := b.GetOrderbookEx() -if err != nil { - // Handle error -} - -// Private calls - wrapper functions - make sure your APIKEY and APISECRET are -// set and AuthenticatedAPISupport is set to true - -// Fetches current account information -accountInfo, err := b.GetAccountInfo() -if err != nil { - // Handle error -} -``` - -+ If enabled via individually importing package, rudimentary example below: - -```go -// Public calls - -// Fetches current ticker information -ticker, err := b.GetTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := b.GetOrderBook() -if err != nil { - // Handle error -} - -// Private calls - make sure your APIKEY and APISECRET are set and -// AuthenticatedAPISupport is set to true - -// GetUserInfo returns account info -accountInfo, err := b.GetUserInfo(...) -if err != nil { - // Handle error -} - -// Submits an order and the exchange and returns its tradeID -tradeID, err := b.Trade(...) -if err != nil { - // Handle error -} -``` - -### How to do Websocket public/private calls - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### Please click GoDocs chevron above to view current GoDoc information for this package - -## Contribution - -Please feel free to submit any pull requests or suggest any desired features to be added. - -When submitting a PR, please abide by our coding guidelines: - -+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). -+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. -+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md). -+ Pull requests need to be based on and opened against the `master` branch. - -## Donations - - - -If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to: - -***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB*** - diff --git a/exchanges/btcc/btcc.go b/exchanges/btcc/btcc.go deleted file mode 100644 index 06dfd718..00000000 --- a/exchanges/btcc/btcc.go +++ /dev/null @@ -1,136 +0,0 @@ -package btcc - -import ( - "sync" - "time" - - "github.com/gorilla/websocket" - "github.com/thrasher-/gocryptotrader/common" - "github.com/thrasher-/gocryptotrader/config" - "github.com/thrasher-/gocryptotrader/currency" - exchange "github.com/thrasher-/gocryptotrader/exchanges" - "github.com/thrasher-/gocryptotrader/exchanges/request" - "github.com/thrasher-/gocryptotrader/exchanges/ticker" - log "github.com/thrasher-/gocryptotrader/logger" -) - -const ( - btccAuthRate = 0 - btccUnauthRate = 0 -) - -// BTCC is the main overaching type across the BTCC package -// NOTE this package is websocket connection dependant, the REST endpoints have -// been dropped -type BTCC struct { - exchange.Base - Conn *websocket.Conn - wsRequestMtx sync.Mutex -} - -// SetDefaults sets default values for the exchange -func (b *BTCC) SetDefaults() { - b.Name = "BTCC" - b.Enabled = false - b.Fee = 0 - b.Verbose = false - b.RESTPollingDelay = 10 - b.APIWithdrawPermissions = exchange.NoAPIWithdrawalMethods - b.RequestCurrencyPairFormat.Delimiter = "" - b.RequestCurrencyPairFormat.Uppercase = true - b.ConfigCurrencyPairFormat.Delimiter = "" - b.ConfigCurrencyPairFormat.Uppercase = true - b.AssetTypes = []string{ticker.Spot} - b.SupportsAutoPairUpdating = true - b.SupportsRESTTickerBatching = false - b.Requester = request.New(b.Name, - request.NewRateLimit(time.Second, btccAuthRate), - request.NewRateLimit(time.Second, btccUnauthRate), - common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout)) - b.WebsocketInit() - b.Websocket.Functionality = - exchange.WebsocketSubscribeSupported | - exchange.WebsocketUnsubscribeSupported -} - -// Setup is run on startup to setup exchange with config values -func (b *BTCC) Setup(exch *config.ExchangeConfig) { - if !exch.Enabled { - b.SetEnabled(false) - } else { - b.Enabled = true - b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport - b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false) - b.SetHTTPClientTimeout(exch.HTTPTimeout) - b.SetHTTPClientUserAgent(exch.HTTPUserAgent) - b.RESTPollingDelay = exch.RESTPollingDelay - b.Verbose = exch.Verbose - b.HTTPDebugging = exch.HTTPDebugging - b.Websocket.SetWsStatusAndConnection(exch.Websocket) - b.BaseCurrencies = exch.BaseCurrencies - b.AvailablePairs = exch.AvailablePairs - b.EnabledPairs = exch.EnabledPairs - err := b.SetCurrencyPairFormat() - if err != nil { - log.Fatal(err) - } - err = b.SetAssetTypes() - if err != nil { - log.Fatal(err) - } - err = b.SetAutoPairDefaults() - if err != nil { - log.Fatal(err) - } - err = b.SetAPIURL(exch) - if err != nil { - log.Fatal(err) - } - err = b.SetClientProxyAddress(exch.ProxyAddress) - if err != nil { - log.Fatal(err) - } - err = b.WebsocketSetup(b.WsConnect, - b.Subscribe, - b.Unsubscribe, - exch.Name, - exch.Websocket, - exch.Verbose, - btccSocketioAddress, - exch.WebsocketURL) - if err != nil { - log.Fatal(err) - } - } -} - -// GetFee returns an estimate of fee based on type of transaction -func (b *BTCC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { - var fee float64 - - switch feeBuilder.FeeType { - case exchange.CryptocurrencyWithdrawalFee: - fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) - case exchange.InternationalBankWithdrawalFee: - fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount) - case exchange.OfflineTradeFee: - fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) - } - if fee < 0 { - fee = 0 - } - return fee, nil -} - -// getOfflineTradeFee calculates the worst case-scenario trading fee -func getOfflineTradeFee(price, amount float64) float64 { - return 0.001 * price * amount -} - -func getCryptocurrencyWithdrawalFee(c currency.Code) float64 { - return WithdrawalFees[c] -} - -func getInternationalBankWithdrawalFee(c currency.Code, amount float64) float64 { - return WithdrawalFees[c] * amount -} diff --git a/exchanges/btcc/btcc_test.go b/exchanges/btcc/btcc_test.go deleted file mode 100644 index 6b81eba6..00000000 --- a/exchanges/btcc/btcc_test.go +++ /dev/null @@ -1,350 +0,0 @@ -package btcc - -import ( - "testing" - "time" - - "github.com/thrasher-/gocryptotrader/common" - "github.com/thrasher-/gocryptotrader/config" - "github.com/thrasher-/gocryptotrader/currency" - exchange "github.com/thrasher-/gocryptotrader/exchanges" -) - -// Please supply your own APIkeys here to do better tests -const ( - apiKey = "" - apiSecret = "" - canManipulateRealOrders = false -) - -var b BTCC - -func TestSetDefaults(t *testing.T) { - b.SetDefaults() -} - -func TestSetup(t *testing.T) { - cfg := config.GetConfig() - cfg.LoadConfig("../../testdata/configtest.json") - bConfig, err := cfg.GetExchangeConfig("BTCC") - if err != nil { - t.Error("Test Failed - BTCC Setup() init error") - } - b.Setup(&bConfig) - - if !b.IsEnabled() || b.AuthenticatedAPISupport || - b.RESTPollingDelay != time.Duration(10) || b.Verbose || - b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 || - len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 { - t.Error("Test Failed - BTCC Setup values not set correctly") - } -} - -// func TestGetTicker(t *testing.T) { -// t.Skip() -// _, err := b.GetTicker("BTCUSD") -// if err != nil { -// t.Error("Test failed - GetTicker() error", err) -// } -// } - -// func TestGetTradeHistory(t *testing.T) { -// t.Skip() -// _, err := b.GetTradeHistory("BTCUSD", 0, 0, time.Time{}) -// if err != nil { -// t.Error("Test failed - GetTradeHistory() error", err) -// } -// } - -// func TestGetOrderBook(t *testing.T) { -// t.Skip() -// _, err := b.GetOrderBook("BTCUSD", 100) -// if err != nil { -// t.Error("Test failed - GetOrderBook() error", err) -// } -// _, err = b.GetOrderBook("BTCUSD", 0) -// if err != nil { -// t.Error("Test failed - GetOrderBook() error", err) -// } -// } - -// func TestGetAccountInfo(t *testing.T) { -// t.Skip() -// err := b.GetAccountInfo("") -// if err == nil { -// t.Error("Test failed - GetAccountInfo() error", err) -// } -// } -func setFeeBuilder() *exchange.FeeBuilder { - return &exchange.FeeBuilder{ - Amount: 1, - FeeType: exchange.CryptocurrencyTradeFee, - Pair: currency.NewPair(currency.BTC, currency.LTC), - PurchasePrice: 1, - } -} - -// TestGetFeeByTypeOfflineTradeFee logic test -func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { - var feeBuilder = setFeeBuilder() - b.GetFeeByType(feeBuilder) - if apiKey == "" || apiSecret == "" { - if feeBuilder.FeeType != exchange.OfflineTradeFee { - t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) - } - } else { - if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { - t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) - } - } -} - -func TestGetFee(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - var feeBuilder = setFeeBuilder() - - // CryptocurrencyTradeFee Basic - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Error(err) - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - } - - // CryptocurrencyTradeFee High quantity - feeBuilder = setFeeBuilder() - feeBuilder.Amount = 1000 - feeBuilder.PurchasePrice = 1000 - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - t.Error(err) - } - - // CryptocurrencyTradeFee IsMaker - feeBuilder = setFeeBuilder() - feeBuilder.IsMaker = true - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - t.Error(err) - } - - // CryptocurrencyTradeFee Negative purchase price - feeBuilder = setFeeBuilder() - feeBuilder.PurchasePrice = -1000 - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - t.Error(err) - } - - // CryptocurrencyWithdrawalFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee - if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp) - t.Error(err) - } - - // CyptocurrencyDepositFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.CyptocurrencyDepositFee - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - t.Error(err) - } - - // InternationalBankDepositFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.InternationalBankDepositFee - feeBuilder.FiatCurrency = currency.USD - if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp) - t.Error(err) - } - - // InternationalBankWithdrawalFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee - feeBuilder.FiatCurrency = currency.USD - if resp, err := b.GetFee(feeBuilder); resp != float64(0.005) || err != nil { - t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.005), resp) - t.Error(err) - } -} - -func TestFormatWithdrawPermissions(t *testing.T) { - b.SetDefaults() - expectedResult := exchange.NoAPIWithdrawalMethodsText - - withdrawPermissions := b.FormatWithdrawPermissions() - - if withdrawPermissions != expectedResult { - t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions) - } -} - -func TestGetActiveOrders(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - var getOrdersRequest = exchange.GetOrdersRequest{ - OrderType: exchange.AnyOrderType, - } - - _, err := b.GetActiveOrders(&getOrdersRequest) - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not get open orders: %s", err) - } else if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } -} - -func TestGetOrderHistory(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - var getOrdersRequest = exchange.GetOrdersRequest{ - OrderType: exchange.AnyOrderType, - } - - _, err := b.GetOrderHistory(&getOrdersRequest) - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not get order history: %s", err) - } else if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } -} - -// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them -// ---------------------------------------------------------------------------------------------------------------------------- -func areTestAPIKeysSet() bool { - if b.APIKey != "" && b.APIKey != "Key" && - b.APISecret != "" && b.APISecret != "Secret" { - return true - } - return false -} - -func TestSubmitOrder(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var p = currency.Pair{ - Delimiter: "-", - Base: currency.BTC, - Quote: currency.LTC, - } - _, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId") - if err != common.ErrNotYetImplemented { - t.Errorf("Expected 'Not Yet Implemented', received %v", err) - } -} - -func TestCancelExchangeOrder(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - currencyPair := currency.NewPair(currency.LTC, currency.BTC) - - var orderCancellation = &exchange.OrderCancellation{ - OrderID: "1", - WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", - AccountID: "1", - CurrencyPair: currencyPair, - } - - err := b.CancelOrder(orderCancellation) - if err != common.ErrNotYetImplemented { - t.Errorf("Expected 'Not Yet Implemented', received %v", err) - } -} - -func TestCancelAllExchangeOrders(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - currencyPair := currency.NewPair(currency.LTC, currency.BTC) - - var orderCancellation = &exchange.OrderCancellation{ - OrderID: "1", - WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", - AccountID: "1", - CurrencyPair: currencyPair, - } - - _, err := b.CancelAllOrders(orderCancellation) - - if err != common.ErrNotYetImplemented { - t.Errorf("Expected 'Not Yet Implemented', received %v", err) - } -} - -func TestWithdraw(t *testing.T) { - b.SetDefaults() - TestSetup(t) - var withdrawCryptoRequest = exchange.WithdrawRequest{ - Amount: 100, - Currency: currency.LTC, - Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB", - Description: "WITHDRAW IT ALL", - } - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - _, err := b.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest) - if err != common.ErrFunctionNotSupported { - t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) - } -} - -func TestModifyOrder(t *testing.T) { - _, err := b.ModifyOrder(&exchange.ModifyOrder{}) - if err == nil { - t.Error("Test failed - ModifyOrder() error") - } -} - -func TestWithdrawFiat(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var withdrawFiatRequest = exchange.WithdrawRequest{} - - _, err := b.WithdrawFiatFunds(&withdrawFiatRequest) - if err != common.ErrFunctionNotSupported { - t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) - } -} - -func TestWithdrawInternationalBank(t *testing.T) { - b.SetDefaults() - TestSetup(t) - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var withdrawFiatRequest = exchange.WithdrawRequest{} - - _, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest) - if err != common.ErrFunctionNotSupported { - t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) - } -} diff --git a/exchanges/btcc/btcc_types.go b/exchanges/btcc/btcc_types.go deleted file mode 100644 index af1fbaf0..00000000 --- a/exchanges/btcc/btcc_types.go +++ /dev/null @@ -1,98 +0,0 @@ -package btcc - -import ( - "encoding/json" - - "github.com/thrasher-/gocryptotrader/currency" -) - -// WsAllTickerData defines multiple ticker data -type WsAllTickerData []WsTicker - -// WsOutgoing defines outgoing JSON -type WsOutgoing struct { - Action string `json:"action"` - Symbol string `json:"symbol,omitempty"` - Count int `json:"count,omitempty"` - Len int `json:"len,omitempty"` -} - -// WsResponseMain defines the main websocket response -type WsResponseMain struct { - MsgType string `json:"MsgType"` - CRID string `json:"CRID"` - RC interface{} `json:"RC"` - Reason string `json:"Reason"` - Data json.RawMessage `json:"data"` -} - -// WsOrderbookSnapshot defines an orderbook from the websocket -type WsOrderbookSnapshot struct { - Timestamp int64 `json:"Timestamp"` - Symbol string `json:"Symbol"` - Version int64 `json:"Version"` - Type string `json:"Type"` - Content string `json:"Content"` - List []struct { - Side string `json:"Side"` - Size interface{} `json:"Size"` - Price float64 `json:"Price"` - } `json:"List"` - MsgType string `json:"MsgType"` -} - -// WsOrderbookSnapshotOld defines an old orderbook from the websocket connection -type WsOrderbookSnapshotOld struct { - MsgType string `json:"MsgType"` - Symbol string `json:"Symbol"` - Data map[string][]interface{} `json:"Data"` - Timestamp int64 `json:"Timestamp"` -} - -// WsTrades defines trading data from the websocket -type WsTrades struct { - Trades []struct { - TID int64 `json:"TID"` - Timestamp int64 `json:"Timestamp"` - Symbol string `json:"Symbol"` - Side string `json:"Side"` - Size float64 `json:"Size"` - Price float64 `json:"Price"` - MsgType string `json:"MsgType"` - } `json:"Trades"` - RC int64 `json:"RC"` - CRID string `json:"CRID"` - Reason string `json:"Reason"` - MsgType string `json:"MsgType"` -} - -// WsTicker defines ticker data from the websocket -type WsTicker struct { - Symbol string `json:"Symbol"` - BidPrice float64 `json:"BidPrice"` - AskPrice float64 `json:"AskPrice"` - Open float64 `json:"Open"` - High float64 `json:"High"` - Low float64 `json:"Low"` - Last float64 `json:"Last"` - LastQuantity float64 `json:"LastQuantity"` - PrevCls float64 `json:"PrevCls"` - Volume float64 `json:"Volume"` - Volume24H float64 `json:"Volume24H"` - Timestamp int64 `json:"Timestamp"` - ExecutionLimitDown float64 `json:"ExecutionLimitDown"` - ExecutionLimitUp float64 `json:"ExecutionLimitUp"` - MsgType string `json:"MsgType"` -} - -// WithdrawalFees the large list of predefined withdrawal fees -// Prone to change -var WithdrawalFees = map[currency.Code]float64{ - currency.USD: 0.005, - currency.USDT: 10, - currency.BTC: 0.001, - currency.ETH: 0.01, - currency.BCH: 0.0001, - currency.LTC: 0.001, - currency.DASH: 0.002, -} diff --git a/exchanges/btcc/btcc_websocket.go b/exchanges/btcc/btcc_websocket.go deleted file mode 100644 index 7c5ac45a..00000000 --- a/exchanges/btcc/btcc_websocket.go +++ /dev/null @@ -1,539 +0,0 @@ -package btcc - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "strconv" - "sync" - "time" - - "github.com/gorilla/websocket" - "github.com/thrasher-/gocryptotrader/common" - "github.com/thrasher-/gocryptotrader/currency" - exchange "github.com/thrasher-/gocryptotrader/exchanges" - "github.com/thrasher-/gocryptotrader/exchanges/orderbook" - log "github.com/thrasher-/gocryptotrader/logger" -) - -const ( - btccSocketioAddress = "wss://ws.btcc.com" - - msgTypeHeartBeat = "Heartbeat" - msgTypeGetActiveContracts = "GetActiveContractsResponse" - msgTypeQuote = "QuoteResponse" - msgTypeLogin = "LoginResponse" - msgTypeAccountInfo = "AccountInfo" - msgTypeExecReport = "ExecReport" - msgTypePlaceOrder = "PlaceOrderResponse" - msgTypeCancelAllOrders = "CancelAllOrdersResponse" - msgTypeCancelOrder = "CancelOrderResponse" - msgTypeCancelReplaceOrder = "CancelReplaceOrderResponse" - msgTypeGetAccountInfo = "GetAccountInfoResponse" - msgTypeRetrieveOrder = "RetrieveOrderResponse" - msgTypeGetTrades = "GetTradesResponse" - - msgTypeAllTickers = "AllTickersResponse" -) - -var ( - mtx sync.Mutex -) - -// WsConnect initiates a websocket client connection -func (b *BTCC) WsConnect() error { - if !b.Websocket.IsEnabled() || !b.IsEnabled() { - return errors.New(exchange.WebsocketNotEnabled) - } - - var dialer websocket.Dialer - var err error - - if b.Websocket.GetProxyAddress() != "" { - var proxy *url.URL - proxy, err = url.Parse(b.Websocket.GetProxyAddress()) - if err != nil { - return err - } - dialer.Proxy = http.ProxyURL(proxy) - } - - b.Conn, _, err = dialer.Dial(b.Websocket.GetWebsocketURL(), http.Header{}) - if err != nil { - return err - } - - err = b.WsUpdateCurrencyPairs() - if err != nil { - return err - } - - go b.WsHandleData() - b.GenerateDefaultSubscriptions() - - return nil -} - -// WsReadData reads data from the websocket connection -func (b *BTCC) WsReadData() (exchange.WebsocketResponse, error) { - mtx.Lock() - _, resp, err := b.Conn.ReadMessage() - mtx.Unlock() - if err != nil { - return exchange.WebsocketResponse{}, err - } - - b.Websocket.TrafficAlert <- struct{}{} - - return exchange.WebsocketResponse{ - Raw: resp, - }, nil -} - -// WsHandleData handles read data -func (b *BTCC) WsHandleData() { - b.Websocket.Wg.Add(1) - - defer func() { - err := b.Conn.Close() - if err != nil { - b.Websocket.DataHandler <- fmt.Errorf("btcc_websocket.go - Unable to close Websocket connection. Error: %s", - err) - } - b.Websocket.Wg.Done() - }() - - for { - select { - case <-b.Websocket.ShutdownC: - return - - default: - resp, err := b.WsReadData() - if err != nil { - b.Websocket.DataHandler <- err - return - } - - var Result WsResponseMain - err = common.JSONDecode(resp.Raw, &Result) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - - switch Result.MsgType { - case msgTypeHeartBeat: - - case msgTypeGetActiveContracts: - log.Debugf("Active Contracts: %s", resp.Raw) - - case msgTypeQuote: - log.Debugf("Quotes: %s", resp.Raw) - - case msgTypeLogin: - log.Debugf("Login: %s", resp.Raw) - - case msgTypeAccountInfo: - log.Debugf("Account info: %s", resp.Raw) - - case msgTypeExecReport: - log.Debugf("Exec Report: %s", resp.Raw) - - case msgTypePlaceOrder: - log.Debugf("Place order: %s", resp.Raw) - - case msgTypeCancelAllOrders: - log.Debugf("Cancel All orders: %s", resp.Raw) - - case msgTypeCancelOrder: - log.Debugf("Cancel order: %s", resp.Raw) - - case msgTypeCancelReplaceOrder: - log.Debugf("Replace order: %s", resp.Raw) - - case msgTypeGetAccountInfo: - log.Debugf("Account info: %s", resp.Raw) - - case msgTypeRetrieveOrder: - log.Debugf("Retrieve order: %s", resp.Raw) - - case msgTypeGetTrades: - var trades WsTrades - - err = common.JSONDecode(resp.Raw, &trades) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - - case "OrderBook": - // NOTE: This seems to be a websocket update not reflected in - // current API docs, this comes in conjunction with the other - // orderbook feeds - var orderbook WsOrderbookSnapshot - - err = common.JSONDecode(resp.Raw, &orderbook) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - - switch orderbook.Type { - case "F": - err = b.WsProcessOrderbookSnapshot(&orderbook) - if err != nil { - b.Websocket.DataHandler <- err - } - - case "I": - err = b.WsProcessOrderbookUpdate(&orderbook) - if err != nil { - b.Websocket.DataHandler <- err - } - } - - case "SubOrderBookResponse": - - case "Ticker": - var ticker WsTicker - - err = common.JSONDecode(resp.Raw, &ticker) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - - tick := exchange.TickerData{} - tick.AssetType = "SPOT" - tick.ClosePrice = ticker.PrevCls - tick.Exchange = b.GetName() - tick.HighPrice = ticker.High - tick.LowPrice = ticker.Low - tick.OpenPrice = ticker.Open - tick.Pair = currency.NewPairFromString(ticker.Symbol) - tick.Quantity = ticker.Volume - timestamp := time.Unix(ticker.Timestamp, 0) - tick.Timestamp = timestamp - - b.Websocket.DataHandler <- tick - - default: - - if common.StringContains(Result.MsgType, "OrderBook") { - var oldOrderbookType WsOrderbookSnapshotOld - err = common.JSONDecode(resp.Raw, &oldOrderbookType) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - - symbol := common.SplitStrings(Result.MsgType, ".") - err = b.WsProcessOldOrderbookSnapshot(oldOrderbookType, symbol[1]) - if err != nil { - b.Websocket.DataHandler <- err - continue - } - continue - } - } - } - } -} - -// WsUpdateCurrencyPairs updates currency pairs from the websocket connection -func (b *BTCC) WsUpdateCurrencyPairs() error { - var currencyResponse WsResponseMain - for { - _, resp, err := b.Conn.ReadMessage() - if err != nil { - return err - } - - b.Websocket.TrafficAlert <- struct{}{} - - err = common.JSONDecode(resp, ¤cyResponse) - if err != nil { - return err - } - - switch currencyResponse.MsgType { - case msgTypeAllTickers: - var tickers WsAllTickerData - err := common.JSONDecode(currencyResponse.Data, &tickers) - if err != nil { - return err - } - - var availableTickers currency.Pairs - for i := range tickers { - availableTickers = append(availableTickers, - currency.NewPairFromString(tickers[i].Symbol)) - } - - err = b.UpdateCurrencies(availableTickers, false, true) - if err != nil { - return fmt.Errorf("%s failed to update available currencies. %s", - b.Name, - err) - } - - case "Heartbeat": - - default: - return fmt.Errorf("btcc_websocket.go error - Updating currency pairs resp incorrect: %s", - string(resp)) - } - } -} - -// WsProcessOrderbookSnapshot processes a new orderbook snapshot -func (b *BTCC) WsProcessOrderbookSnapshot(ob *WsOrderbookSnapshot) error { - var asks, bids []orderbook.Item - for _, data := range ob.List { - var newSize float64 - switch result := data.Size.(type) { - case float64: - newSize = result - case string: - var err error - newSize, err = strconv.ParseFloat(result, 64) - if err != nil { - return err - } - } - - if data.Side == "1" { - asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize}) - continue - } - - bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize}) - } - - var newOrderBook orderbook.Base - - newOrderBook.Asks = asks - newOrderBook.AssetType = "SPOT" - newOrderBook.Bids = bids - newOrderBook.Pair = currency.NewPairFromString(ob.Symbol) - - err := b.Websocket.Orderbook.LoadSnapshot(&newOrderBook, b.GetName(), false) - if err != nil { - return err - } - - b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{ - Exchange: b.GetName(), - Asset: "SPOT", - Pair: currency.NewPairFromString(ob.Symbol), - } - - return nil -} - -// WsProcessOrderbookUpdate processes an orderbook update -func (b *BTCC) WsProcessOrderbookUpdate(ob *WsOrderbookSnapshot) error { - var asks, bids []orderbook.Item - for _, data := range ob.List { - var newSize float64 - switch d := data.Size.(type) { - case float64: - newSize = d - case string: - var err error - newSize, err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - } - - if data.Side == "1" { - if newSize < 0 { - asks = append(asks, orderbook.Item{Price: data.Price, Amount: 0}) - continue - } - asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize}) - continue - } - - if newSize < 0 { - bids = append(bids, orderbook.Item{Price: data.Price, Amount: 0}) - continue - } - - bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize}) - } - - p := currency.NewPairFromString(ob.Symbol) - - err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT") - if err != nil { - return err - } - - b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{ - Exchange: b.GetName(), - Asset: "SPOT", - Pair: currency.NewPairFromString(ob.Symbol), - } - - return nil -} - -// WsProcessOldOrderbookSnapshot processes an old orderbook snapshot -func (b *BTCC) WsProcessOldOrderbookSnapshot(ob WsOrderbookSnapshotOld, symbol string) error { - var asks, bids []orderbook.Item - - askData := ob.Data["Asks"] - bidData := ob.Data["Bids"] - - for _, ask := range askData { - data := ask.([]interface{}) - var price, amount float64 - - switch d := data[0].(type) { - case string: - var err error - price, err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - case float64: - price = d - } - - switch d := data[0].(type) { - case string: - var err error - amount, err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - case float64: - amount = d - } - - asks = append(asks, orderbook.Item{ - Price: price, - Amount: amount, - }) - } - - for _, bid := range bidData { - data := bid.([]interface{}) - var price, amount float64 - - switch d := data[1].(type) { - case string: - var err error - price, err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - case float64: - price = d - } - - switch d := data[1].(type) { - case string: - var err error - amount, err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - case float64: - amount = d - } - - bids = append(bids, orderbook.Item{ - Price: price, - Amount: amount, - }) - } - - p := currency.NewPairFromString(symbol) - - err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT") - if err != nil { - return err - } - - b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{ - Exchange: b.GetName(), - Pair: p, - Asset: "SPOT", - } - - return nil -} - -// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions() -func (b *BTCC) GenerateDefaultSubscriptions() { - subscriptions := []exchange.WebsocketChannelSubscription{} - subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{ - Channel: "SubscribeAllTickers", - }) - - var channels = []string{"SubOrderBook", "GetTrades", "Subscribe"} - enabledCurrencies := b.GetEnabledCurrencies() - for i := range channels { - for j := range enabledCurrencies { - params := make(map[string]interface{}) - if channels[i] == "SubOrderBook" { - params["len"] = "100" - } else if channels[i] == "GetTrades" { - params["count"] = "100" - } - subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{ - Channel: channels[i], - Currency: enabledCurrencies[j], - Params: params, - }) - } - } - b.Websocket.SubscribeToChannels(subscriptions) -} - -// Subscribe sends a websocket message to receive data from the channel -func (b *BTCC) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscription) error { - subscription := WsOutgoing{ - Action: channelToSubscribe.Channel, - Symbol: channelToSubscribe.Currency.String(), - } - if subscription.Action == "SubOrderBook" { - subscription.Len = 100 - } else if subscription.Action == "GetTrades" { - subscription.Count = 100 - } - - return b.wsSend(subscription) -} - -// Unsubscribe sends a websocket message to stop receiving data from the channel -func (b *BTCC) Unsubscribe(channelToSubscribe exchange.WebsocketChannelSubscription) error { - subscription := WsOutgoing{} - switch channelToSubscribe.Channel { - case "SubOrderBook": - subscription.Action = "UnSubOrderBook" - subscription.Symbol = channelToSubscribe.Currency.String() - case "Subscribe": - subscription.Action = "UnSubscribe" - subscription.Symbol = channelToSubscribe.Currency.String() - case "SubscribeAllTickers": - subscription.Action = "UnSubscribeAllTickers" - } - - return b.wsSend(subscription) -} - -// WsSend sends data to the websocket server -func (b *BTCC) wsSend(data interface{}) error { - b.wsRequestMtx.Lock() - defer b.wsRequestMtx.Unlock() - if b.Verbose { - log.Debugf("%v sending message to websocket %v", b.Name, data) - } - return b.Conn.WriteJSON(data) -} diff --git a/exchanges/btcc/btcc_wrapper.go b/exchanges/btcc/btcc_wrapper.go deleted file mode 100644 index 673640d9..00000000 --- a/exchanges/btcc/btcc_wrapper.go +++ /dev/null @@ -1,191 +0,0 @@ -package btcc - -import ( - "sync" - - "github.com/thrasher-/gocryptotrader/common" - "github.com/thrasher-/gocryptotrader/config" - "github.com/thrasher-/gocryptotrader/currency" - exchange "github.com/thrasher-/gocryptotrader/exchanges" - "github.com/thrasher-/gocryptotrader/exchanges/orderbook" - "github.com/thrasher-/gocryptotrader/exchanges/ticker" - log "github.com/thrasher-/gocryptotrader/logger" -) - -// Start starts the BTCC go routine -func (b *BTCC) Start(wg *sync.WaitGroup) { - wg.Add(1) - go func() { - b.Run() - wg.Done() - }() -} - -// Run implements the BTCC wrapper -func (b *BTCC) Run() { - if b.Verbose { - log.Debugf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled())) - log.Debugf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay) - log.Debugf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs) - } - - if common.StringDataContains(b.EnabledPairs.Strings(), "CNY") || - common.StringDataContains(b.AvailablePairs.Strings(), "CNY") || - common.StringDataContains(b.BaseCurrencies.Strings(), "CNY") { - log.Warn("BTCC only supports BTCUSD now, upgrading available, enabled and base currencies to BTCUSD/USD") - pairs := currency.Pairs{currency.Pair{Base: currency.BTC, - Quote: currency.USD}} - cfg := config.GetConfig() - exchCfg, err := cfg.GetExchangeConfig(b.Name) - if err != nil { - log.Errorf("%s failed to get exchange config. %s\n", b.Name, err) - return - } - - exchCfg.BaseCurrencies = currency.Currencies{currency.USD} - exchCfg.AvailablePairs = pairs - exchCfg.EnabledPairs = pairs - b.BaseCurrencies = currency.Currencies{currency.USD} - - err = b.UpdateCurrencies(pairs, false, true) - if err != nil { - log.Errorf("%s failed to update available currencies. %s\n", b.Name, err) - } - - err = b.UpdateCurrencies(pairs, true, true) - if err != nil { - log.Errorf("%s failed to update enabled currencies. %s\n", b.Name, err) - } - - err = cfg.UpdateExchangeConfig(&exchCfg) - if err != nil { - log.Errorf("%s failed to update config. %s\n", b.Name, err) - return - } - } -} - -// UpdateTicker updates and returns the ticker for a currency pair -func (b *BTCC) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) { - return ticker.Price{}, common.ErrFunctionNotSupported -} - -// GetTickerPrice returns the ticker for a currency pair -func (b *BTCC) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) { - return ticker.Price{}, common.ErrFunctionNotSupported -} - -// GetOrderbookEx returns the orderbook for a currency pair -func (b *BTCC) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) { - return orderbook.Base{}, common.ErrFunctionNotSupported -} - -// UpdateOrderbook updates and returns the orderbook for a currency pair -func (b *BTCC) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) { - return orderbook.Base{}, common.ErrFunctionNotSupported -} - -// GetAccountInfo : Retrieves balances for all enabled currencies for -// the Kraken exchange - TODO -func (b *BTCC) GetAccountInfo() (exchange.AccountInfo, error) { - return exchange.AccountInfo{}, common.ErrFunctionNotSupported -} - -// GetFundingHistory returns funding history, deposits and -// withdrawals -func (b *BTCC) GetFundingHistory() ([]exchange.FundHistory, error) { - return nil, common.ErrFunctionNotSupported -} - -// GetExchangeHistory returns historic trade data since exchange opening. -func (b *BTCC) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) { - return nil, common.ErrFunctionNotSupported -} - -// SubmitOrder submits a new order -func (b *BTCC) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) { - return exchange.SubmitOrderResponse{}, common.ErrNotYetImplemented -} - -// ModifyOrder will allow of changing orderbook placement and limit to -// market conversion -func (b *BTCC) ModifyOrder(action *exchange.ModifyOrder) (string, error) { - return "", common.ErrNotYetImplemented -} - -// CancelOrder cancels an order by its corresponding ID number -func (b *BTCC) CancelOrder(order *exchange.OrderCancellation) error { - return common.ErrNotYetImplemented -} - -// CancelAllOrders cancels all orders associated with a currency pair -func (b *BTCC) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) { - return exchange.CancelAllOrdersResponse{}, common.ErrNotYetImplemented -} - -// GetOrderInfo returns information on a current open order -func (b *BTCC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) { - return exchange.OrderDetail{}, common.ErrNotYetImplemented -} - -// GetDepositAddress returns a deposit address for a specified currency -func (b *BTCC) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) { - return "", common.ErrFunctionNotSupported -} - -// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is -// submitted -func (b *BTCC) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.WithdrawRequest) (string, error) { - return "", common.ErrFunctionNotSupported -} - -// WithdrawFiatFunds returns a withdrawal ID when a -// withdrawal is submitted -func (b *BTCC) WithdrawFiatFunds(withdrawRequest *exchange.WithdrawRequest) (string, error) { - return "", common.ErrFunctionNotSupported -} - -// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a -// withdrawal is submitted -func (b *BTCC) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.WithdrawRequest) (string, error) { - return "", common.ErrFunctionNotSupported -} - -// GetWebsocket returns a pointer to the exchange websocket -func (b *BTCC) GetWebsocket() (*exchange.Websocket, error) { - return b.Websocket, nil -} - -// GetFeeByType returns an estimate of fee based on type of transaction -func (b *BTCC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { - if (b.APIKey == "" || b.APISecret == "") && // Todo check connection status - feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { - feeBuilder.FeeType = exchange.OfflineTradeFee - } - return b.GetFee(feeBuilder) -} - -// GetActiveOrders retrieves any orders that are active/open -func (b *BTCC) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) { - return nil, common.ErrNotYetImplemented -} - -// GetOrderHistory retrieves account order information -// Can Limit response to specific order status -func (b *BTCC) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) { - return nil, common.ErrNotYetImplemented -} - -// SubscribeToWebsocketChannels appends to ChannelsToSubscribe -// which lets websocket.manageSubscriptions handle subscribing -func (b *BTCC) SubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error { - b.Websocket.SubscribeToChannels(channels) - return nil -} - -// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe -// which lets websocket.manageSubscriptions handle unsubscribing -func (b *BTCC) UnsubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error { - b.Websocket.UnsubscribeToChannels(channels) - return nil -} diff --git a/exchanges/stats/stats_test.go b/exchanges/stats/stats_test.go index 1b0231e0..448fcddd 100644 --- a/exchanges/stats/stats_test.go +++ b/exchanges/stats/stats_test.go @@ -63,7 +63,7 @@ func TestSwapByPrice(t *testing.T) { Volume: 5, }, { - Exchange: "btcc", + Exchange: "bitfinex", Pair: p, AssetType: "SPOT", Price: 7863, @@ -72,7 +72,7 @@ func TestSwapByPrice(t *testing.T) { } ByPrice.Swap(Items, 0, 1) - if Items[0].Exchange != "btcc" || Items[1].Exchange != "bitstamp" { + if Items[0].Exchange != "bitfinex" || Items[1].Exchange != "bitstamp" { t.Error("Test Failed - stats SwapByPrice did not swap values.") } } @@ -95,7 +95,7 @@ func TestLessByVolume(t *testing.T) { func TestSwapByVolume(t *testing.T) { ByPrice.Swap(Items, 0, 1) - if Items[1].Exchange != "btcc" || Items[0].Exchange != "bitstamp" { + if Items[1].Exchange != "bitfinex" || Items[0].Exchange != "bitstamp" { t.Error("Test Failed - stats SwapByVolume did not swap values.") } } diff --git a/exchanges/ticker/ticker_test.go b/exchanges/ticker/ticker_test.go index 0b969afd..641cec2d 100644 --- a/exchanges/ticker/ticker_test.go +++ b/exchanges/ticker/ticker_test.go @@ -247,6 +247,7 @@ func TestCreateNewTicker(t *testing.T) { func TestProcessTicker(t *testing.T) { // non-appending function to tickers Tickers = []Ticker{} + exchName := "bitstamp" newPair := currency.NewPairFromStrings("BTC", "USD") priceStruct := Price{ Pair: newPair, @@ -259,17 +260,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers PriceATH: 1337, } - err := ProcessTicker("btcc", &Price{}, Spot) + err := ProcessTicker(exchName, &Price{}, Spot) if err == nil { t.Fatal("Test failed. ProcessTicker error cannot be nil") } - err = ProcessTicker("btcc", &priceStruct, Spot) + err = ProcessTicker(exchName, &priceStruct, Spot) if err != nil { t.Fatal("Test failed. ProcessTicker error", err) } - result, err := GetTicker("btcc", newPair, Spot) + result, err := GetTicker(exchName, newPair, Spot) if err != nil { t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker") } @@ -280,17 +281,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers secondPair := currency.NewPairFromStrings("BTC", "AUD") priceStruct.Pair = secondPair - err = ProcessTicker("btcc", &priceStruct, Spot) + err = ProcessTicker(exchName, &priceStruct, Spot) if err != nil { t.Fatal("Test failed. ProcessTicker error", err) } - result, err = GetTicker("btcc", secondPair, Spot) + result, err = GetTicker(exchName, secondPair, Spot) if err != nil { t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker") } - result, err = GetTicker("btcc", newPair, Spot) + result, err = GetTicker(exchName, newPair, Spot) if err != nil { t.Fatal("Test failed. TestProcessTicker failed to return an existing ticker") } diff --git a/testdata/configtest.json b/testdata/configtest.json index 0a749a05..e6640915 100644 --- a/testdata/configtest.json +++ b/testdata/configtest.json @@ -461,46 +461,6 @@ } ] }, - { - "name": "BTCC", - "enabled": true, - "verbose": false, - "websocket": false, - "useSandbox": false, - "restPollingDelay": 10, - "httpTimeout": 15000000000, - "httpUserAgent": "", - "httpDebugging": false, - "authenticatedApiSupport": false, - "apiKey": "Key", - "apiSecret": "Secret", - "apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "proxyAddress": "", - "websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API", - "availablePairs": "BTCUSD", - "enabledPairs": "BTCUSD", - "baseCurrencies": "USD", - "assetTypes": "SPOT", - "supportsAutoPairUpdates": true, - "configCurrencyPairFormat": { - "uppercase": true - }, - "requestCurrencyPairFormat": { - "uppercase": true - }, - "bankAccounts": [ - { - "bankName": "", - "bankAddress": "", - "accountName": "", - "accountNumber": "", - "swiftCode": "", - "iban": "", - "supportedCurrencies": "" - } - ] - }, { "name": "BTSE", "enabled": true, diff --git a/tools/documentation/documentation.go b/tools/documentation/documentation.go index f8a948d5..d484ea13 100644 --- a/tools/documentation/documentation.go +++ b/tools/documentation/documentation.go @@ -55,7 +55,6 @@ const ( bitmex = "..%s..%sexchanges%sbitmex%s" bitstamp = "..%s..%sexchanges%sbitstamp%s" bittrex = "..%s..%sexchanges%sbittrex%s" - btcc = "..%s..%sexchanges%sbtcc%s" btcmarkets = "..%s..%sexchanges%sbtcmarkets%s" coinbasepro = "..%s..%sexchanges%scoinbasepro%s" coinut = "..%s..%sexchanges%scoinut%s" @@ -228,7 +227,6 @@ func addPaths() { codebasePaths["exchanges bitmex"] = fmt.Sprintf(bitmex, path, path, path, path) codebasePaths["exchanges bitstamp"] = fmt.Sprintf(bitstamp, path, path, path, path) codebasePaths["exchanges bittrex"] = fmt.Sprintf(bittrex, path, path, path, path) - codebasePaths["exchanges btcc"] = fmt.Sprintf(btcc, path, path, path, path) codebasePaths["exchanges btcmarkets"] = fmt.Sprintf(btcmarkets, path, path, path, path) codebasePaths["exchanges coinut"] = fmt.Sprintf(coinut, path, path, path, path) codebasePaths["exchanges exmo"] = fmt.Sprintf(exmo, path, path, path, path) diff --git a/tools/documentation/exchanges_templates/btcc.tmpl b/tools/documentation/exchanges_templates/btcc.tmpl deleted file mode 100644 index 095a9fea..00000000 --- a/tools/documentation/exchanges_templates/btcc.tmpl +++ /dev/null @@ -1,106 +0,0 @@ -{{define "exchanges btcc" -}} -{{template "header" .}} -## BTCC Exchange - -### Current Features - -+ REST Support -+ Websocket Support - -### How to enable - -+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example) - -+ Individual package example below: - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### How to do REST public/private calls - -+ If enabled via "configuration".json file the exchange will be added to the -IBotExchange array in the ```go var bot Bot``` and you will only be able to use -the wrapper interface functions for accessing exchange data. View routines.go -for an example of integration usage with GoCryptoTrader. Rudimentary example -below: - -main.go -```go -var b exchange.IBotExchange - -for i := range bot.exchanges { - if bot.exchanges[i].GetName() == "BTCC" { - b = bot.exchanges[i] - } -} - -// Public calls - wrapper functions - -// Fetches current ticker information -tick, err := b.GetTickerPrice() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := b.GetOrderbookEx() -if err != nil { - // Handle error -} - -// Private calls - wrapper functions - make sure your APIKEY and APISECRET are -// set and AuthenticatedAPISupport is set to true - -// Fetches current account information -accountInfo, err := b.GetAccountInfo() -if err != nil { - // Handle error -} -``` - -+ If enabled via individually importing package, rudimentary example below: - -```go -// Public calls - -// Fetches current ticker information -ticker, err := b.GetTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := b.GetOrderBook() -if err != nil { - // Handle error -} - -// Private calls - make sure your APIKEY and APISECRET are set and -// AuthenticatedAPISupport is set to true - -// GetUserInfo returns account info -accountInfo, err := b.GetUserInfo(...) -if err != nil { - // Handle error -} - -// Submits an order and the exchange and returns its tradeID -tradeID, err := b.Trade(...) -if err != nil { - // Handle error -} -``` - -### How to do Websocket public/private calls - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### Please click GoDocs chevron above to view current GoDoc information for this package -{{template "contributions"}} -{{template "donations"}} -{{end}} diff --git a/tools/documentation/root_templates/root_readme.tmpl b/tools/documentation/root_templates/root_readme.tmpl index 8ebb9475..1df36650 100644 --- a/tools/documentation/root_templates/root_readme.tmpl +++ b/tools/documentation/root_templates/root_readme.tmpl @@ -28,7 +28,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader | BitMEX | Yes | Yes | NA | | Bitstamp | Yes | Yes | No | | Bittrex | Yes | No | NA | -| BTCC | Yes | Yes | No | | BTCMarkets | Yes | No | NA | | BTSE | Yes | Yes | NA | | COINUT | Yes | Yes | NA | From d639f6e4a6748d0e03c23673da9fc467f193b058 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 3 Jun 2019 00:48:33 -0700 Subject: [PATCH 5/5] Ignore gocryptotrader binary on macOS/Linux builds Also fix go fmt issues --- .gitignore | 1 + exchanges/huobi/huobi_test.go | 2 +- exchanges/huobihadax/huobihadax_test.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ae9883c7..c3baa137 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ testdata/writefiletest vendor/ # Binaries for programs and plugins +gocryptotrader *.exe *.exe~ *.dll diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index e53fcd3d..2e5ac68d 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -21,7 +21,7 @@ const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false - testSymbol = "btcusdt" + testSymbol = "btcusdt" ) var h HUOBI diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index bd4dad0e..1e3cacb8 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -17,7 +17,7 @@ const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false - testSymbol = "btcusdt" + testSymbol = "btcusdt" ) var h HUOBIHADAX