From ddd19ab6d9a64879966f3a7e9e8f3176b9b8d5af Mon Sep 17 00:00:00 2001 From: Rauno Ots Date: Sun, 13 Dec 2020 23:36:46 +0100 Subject: [PATCH] binance: use currency.Pair for request arguments (#608) * binance: use currency.Pair for request arguments * request calls use type safe arguments * binance API handles the correct conversion now on a lower level * consolidate formatting to a single place * remove unused Pair.ID * add tests for formatting * fix linter issue --- currency/pair.go | 9 ++- currency/pair_test.go | 59 ++++++++++++++ currency/pair_types.go | 1 - exchanges/binance/binance.go | 103 +++++++++++++++++++------ exchanges/binance/binance_test.go | 44 +++++------ exchanges/binance/binance_types.go | 18 ++--- exchanges/binance/binance_websocket.go | 7 +- exchanges/binance/binance_wrapper.go | 81 +++++-------------- exchanges/binance/type_convert.go | 12 +++ 9 files changed, 207 insertions(+), 127 deletions(-) diff --git a/currency/pair.go b/currency/pair.go index 16cfe983..cd800ade 100644 --- a/currency/pair.go +++ b/currency/pair.go @@ -100,14 +100,19 @@ func NewPairFromString(currencyPair string) (Pair, error) { // apply the same format func NewPairFromFormattedPairs(currencyPair string, pairs Pairs, pairFmt PairFormat) (Pair, error) { for x := range pairs { - fPair := pairs[x].Format(pairFmt.Delimiter, pairFmt.Uppercase) - if strings.EqualFold(fPair.String(), currencyPair) { + fPair := pairFmt.Format(pairs[x]) + if strings.EqualFold(fPair, currencyPair) { return pairs[x], nil } } return NewPairFromString(currencyPair) } +// Format formats the given pair as a string +func (f *PairFormat) Format(pair Pair) string { + return pair.Format(f.Delimiter, f.Uppercase).String() +} + // MatchPairsWithNoDelimiter will move along a predictable index on the provided currencyPair // it will then split on that index and verify whether that currencypair exists in the // supplied pairs diff --git a/currency/pair_test.go b/currency/pair_test.go index defd383a..c6feb663 100644 --- a/currency/pair_test.go +++ b/currency/pair_test.go @@ -776,3 +776,62 @@ func TestMatchPairsWithNoDelimiter(t *testing.T) { t.Errorf("unexpected response base: %v quote: %v", p.Base.String(), p.Quote.String()) } } + +func TestPairFormat_Format(t *testing.T) { + type fields struct { + Uppercase bool + Delimiter string + Separator string + Index string + } + tests := []struct { + name string + fields fields + arg Pair + want string + }{ + { + name: "empty", + fields: fields{}, + arg: Pair{}, + want: "", + }, + { + name: "empty format", + fields: fields{}, + arg: Pair{ + Delimiter: "<>", + Base: AAA, + Quote: BTC, + }, + want: "aaabtc", + }, + { + name: "format", + fields: fields{ + Uppercase: true, + Delimiter: "!!!", + }, + arg: Pair{ + Delimiter: "<>", + Base: AAA, + Quote: BTC, + }, + want: "AAA!!!BTC", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + f := &PairFormat{ + Uppercase: tt.fields.Uppercase, + Delimiter: tt.fields.Delimiter, + Separator: tt.fields.Separator, + Index: tt.fields.Index, + } + if got := f.Format(tt.arg); got != tt.want { + t.Errorf("PairFormat.Format() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/currency/pair_types.go b/currency/pair_types.go index 263da25f..d268dee6 100644 --- a/currency/pair_types.go +++ b/currency/pair_types.go @@ -2,7 +2,6 @@ package currency // Pair holds currency pair information type Pair struct { - ID string `json:"id"` Delimiter string `json:"delimiter,omitempty"` Base Code `json:"base,omitempty"` Quote Code `json:"quote,omitempty"` diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index 0ae72bcf..3ba1008b 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -10,7 +10,6 @@ import ( "net/url" "sort" "strconv" - "strings" "time" "github.com/thrasher-corp/gocryptotrader/common" @@ -89,7 +88,11 @@ func (b *Binance) GetOrderBook(obd OrderBookDataRequestParams) (OrderBook, error } params := url.Values{} - params.Set("symbol", strings.ToUpper(obd.Symbol)) + symbol, err := b.formatSymbol(obd.Symbol) + if err != nil { + return orderbook, err + } + params.Set("symbol", symbol) params.Set("limit", fmt.Sprintf("%d", obd.Limit)) var resp OrderBookData @@ -142,7 +145,11 @@ func (b *Binance) GetMostRecentTrades(rtr RecentTradeRequestParams) ([]RecentTra var resp []RecentTrade params := url.Values{} - params.Set("symbol", strings.ToUpper(rtr.Symbol)) + symbol, err := b.formatSymbol(rtr.Symbol) + if err != nil { + return nil, err + } + params.Set("symbol", symbol) params.Set("limit", fmt.Sprintf("%d", rtr.Limit)) path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, recentTrades, params.Encode()) @@ -168,7 +175,11 @@ func (b *Binance) GetHistoricalTrades(symbol string, limit int, fromID int64) ([ // https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list func (b *Binance) GetAggregatedTrades(arg *AggregatedTradeRequestParams) ([]AggregatedTrade, error) { params := url.Values{} - params.Set("symbol", arg.Symbol) + symbol, err := b.formatSymbol(arg.Symbol) + if err != nil { + return nil, err + } + params.Set("symbol", symbol) // if the user request is directly not supported by the exchange, we might be able to fulfill it // by merging results from multiple API requests needBatch := false @@ -291,7 +302,11 @@ func (b *Binance) GetSpotKline(arg *KlinesRequestParams) ([]CandleStick, error) var klineData []CandleStick params := url.Values{} - params.Set("symbol", arg.Symbol) + symbol, err := b.formatSymbol(arg.Symbol) + if err != nil { + return nil, err + } + params.Set("symbol", symbol) params.Set("interval", arg.Interval) if arg.Limit != 0 { params.Set("limit", strconv.Itoa(arg.Limit)) @@ -355,10 +370,14 @@ func (b *Binance) GetSpotKline(arg *KlinesRequestParams) ([]CandleStick, error) // GetAveragePrice returns current average price for a symbol. // // symbol: string of currency pair -func (b *Binance) GetAveragePrice(symbol string) (AveragePrice, error) { +func (b *Binance) GetAveragePrice(symbol currency.Pair) (AveragePrice, error) { resp := AveragePrice{} params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, averagePrice, params.Encode()) @@ -368,10 +387,14 @@ func (b *Binance) GetAveragePrice(symbol string) (AveragePrice, error) { // GetPriceChangeStats returns price change statistics for the last 24 hours // // symbol: string of currency pair -func (b *Binance) GetPriceChangeStats(symbol string) (PriceChangeStats, error) { +func (b *Binance) GetPriceChangeStats(symbol currency.Pair) (PriceChangeStats, error) { resp := PriceChangeStats{} params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, priceChange, params.Encode()) @@ -388,27 +411,35 @@ func (b *Binance) GetTickers() ([]PriceChangeStats, error) { // GetLatestSpotPrice returns latest spot price of symbol // // symbol: string of currency pair -func (b *Binance) GetLatestSpotPrice(symbol string) (SymbolPrice, error) { +func (b *Binance) GetLatestSpotPrice(symbol currency.Pair) (SymbolPrice, error) { resp := SymbolPrice{} params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, symbolPrice, params.Encode()) - return resp, b.SendHTTPRequest(path, symbolPriceLimit(symbol), &resp) + return resp, b.SendHTTPRequest(path, symbolPriceLimit(symbolValue), &resp) } // GetBestPrice returns the latest best price for symbol // // symbol: string of currency pair -func (b *Binance) GetBestPrice(symbol string) (BestPrice, error) { +func (b *Binance) GetBestPrice(symbol currency.Pair) (BestPrice, error) { resp := BestPrice{} params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, bestPrice, params.Encode()) - return resp, b.SendHTTPRequest(path, bestPriceLimit(symbol), &resp) + return resp, b.SendHTTPRequest(path, bestPriceLimit(symbolValue), &resp) } // NewOrder sends a new order to Binance @@ -435,7 +466,11 @@ func (b *Binance) newOrder(api string, o *NewOrderRequest, resp *NewOrderRespons path := b.API.Endpoints.URL + api params := url.Values{} - params.Set("symbol", o.Symbol) + symbol, err := b.formatSymbol(o.Symbol) + if err != nil { + return err + } + params.Set("symbol", symbol) params.Set("side", o.Side) params.Set("type", string(o.TradeType)) if o.QuoteOrderQty > 0 { @@ -469,13 +504,17 @@ func (b *Binance) newOrder(api string, o *NewOrderRequest, resp *NewOrderRespons } // CancelExistingOrder sends a cancel order to Binance -func (b *Binance) CancelExistingOrder(symbol string, orderID int64, origClientOrderID string) (CancelOrderResponse, error) { +func (b *Binance) CancelExistingOrder(symbol currency.Pair, orderID int64, origClientOrderID string) (CancelOrderResponse, error) { var resp CancelOrderResponse path := b.API.Endpoints.URL + cancelOrder + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } params := url.Values{} - params.Set("symbol", symbol) + params.Set("symbol", symbolValue) if orderID != 0 { params.Set("orderId", strconv.FormatInt(orderID, 10)) @@ -491,15 +530,23 @@ func (b *Binance) CancelExistingOrder(symbol string, orderID int64, origClientOr // OpenOrders Current open orders. Get all open orders on a symbol. // Careful when accessing this with no symbol: The number of requests counted against the rate limiter // is significantly higher -func (b *Binance) OpenOrders(symbol string) ([]QueryOrderData, error) { +func (b *Binance) OpenOrders(pair *currency.Pair) ([]QueryOrderData, error) { var resp []QueryOrderData path := b.API.Endpoints.URL + openOrders params := url.Values{} + var symbol string + if pair != nil { + var err error + symbol, err = b.formatSymbol(*pair) + if err != nil { + return resp, err + } + } if symbol != "" { - params.Set("symbol", strings.ToUpper(symbol)) + params.Set("symbol", symbol) } if err := b.SendAuthHTTPRequest(http.MethodGet, path, params, openOrdersLimit(symbol), &resp); err != nil { @@ -512,13 +559,17 @@ func (b *Binance) OpenOrders(symbol string) ([]QueryOrderData, error) { // AllOrders Get all account orders; active, canceled, or filled. // orderId optional param // limit optional param, default 500; max 500 -func (b *Binance) AllOrders(symbol, orderID, limit string) ([]QueryOrderData, error) { +func (b *Binance) AllOrders(symbol currency.Pair, orderID, limit string) ([]QueryOrderData, error) { var resp []QueryOrderData path := b.API.Endpoints.URL + allOrders params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) if orderID != "" { params.Set("orderId", orderID) } @@ -533,13 +584,17 @@ func (b *Binance) AllOrders(symbol, orderID, limit string) ([]QueryOrderData, er } // QueryOrder returns information on a past order -func (b *Binance) QueryOrder(symbol, origClientOrderID string, orderID int64) (QueryOrderData, error) { +func (b *Binance) QueryOrder(symbol currency.Pair, origClientOrderID string, orderID int64) (QueryOrderData, error) { var resp QueryOrderData path := b.API.Endpoints.URL + queryOrder params := url.Values{} - params.Set("symbol", strings.ToUpper(symbol)) + symbolValue, err := b.formatSymbol(symbol) + if err != nil { + return resp, err + } + params.Set("symbol", symbolValue) if origClientOrderID != "" { params.Set("origClientOrderId", origClientOrderID) } diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index 85123c41..991874b2 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -61,9 +61,8 @@ func TestFetchTradablePairs(t *testing.T) { func TestGetOrderBook(t *testing.T) { t.Parallel() - _, err := b.GetOrderBook(OrderBookDataRequestParams{ - Symbol: "BTCUSDT", + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 10, }) @@ -76,7 +75,7 @@ func TestGetMostRecentTrades(t *testing.T) { t.Parallel() _, err := b.GetMostRecentTrades(RecentTradeRequestParams{ - Symbol: "BTCUSDT", + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 15, }) @@ -100,7 +99,7 @@ func TestGetHistoricalTrades(t *testing.T) { func TestGetAggregatedTrades(t *testing.T) { t.Parallel() _, err := b.GetAggregatedTrades(&AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 5, }) if err != nil { @@ -111,7 +110,7 @@ func TestGetAggregatedTrades(t *testing.T) { func TestGetSpotKline(t *testing.T) { t.Parallel() _, err := b.GetSpotKline(&KlinesRequestParams{ - Symbol: "BTCUSDT", + Symbol: currency.NewPair(currency.BTC, currency.USDT), Interval: kline.FiveMin.Short(), Limit: 24, StartTime: time.Unix(1577836800, 0), @@ -125,7 +124,7 @@ func TestGetSpotKline(t *testing.T) { func TestGetAveragePrice(t *testing.T) { t.Parallel() - _, err := b.GetAveragePrice("BTCUSDT") + _, err := b.GetAveragePrice(currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error("Binance GetAveragePrice() error", err) } @@ -134,7 +133,7 @@ func TestGetAveragePrice(t *testing.T) { func TestGetPriceChangeStats(t *testing.T) { t.Parallel() - _, err := b.GetPriceChangeStats("BTCUSDT") + _, err := b.GetPriceChangeStats(currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error("Binance GetPriceChangeStats() error", err) } @@ -152,7 +151,7 @@ func TestGetTickers(t *testing.T) { func TestGetLatestSpotPrice(t *testing.T) { t.Parallel() - _, err := b.GetLatestSpotPrice("BTCUSDT") + _, err := b.GetLatestSpotPrice(currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error("Binance GetLatestSpotPrice() error", err) } @@ -161,7 +160,7 @@ func TestGetLatestSpotPrice(t *testing.T) { func TestGetBestPrice(t *testing.T) { t.Parallel() - _, err := b.GetBestPrice("BTCUSDT") + _, err := b.GetBestPrice(currency.NewPair(currency.BTC, currency.USDT)) if err != nil { t.Error("Binance GetBestPrice() error", err) } @@ -170,7 +169,7 @@ func TestGetBestPrice(t *testing.T) { func TestQueryOrder(t *testing.T) { t.Parallel() - _, err := b.QueryOrder("BTCUSDT", "", 1337) + _, err := b.QueryOrder(currency.NewPair(currency.BTC, currency.USDT), "", 1337) switch { case areTestAPIKeysSet() && err != nil: t.Error("QueryOrder() error", err) @@ -184,7 +183,8 @@ func TestQueryOrder(t *testing.T) { func TestOpenOrders(t *testing.T) { t.Parallel() - _, err := b.OpenOrders("BTCUSDT") + p := currency.NewPair(currency.BTC, currency.USDT) + _, err := b.OpenOrders(&p) switch { case areTestAPIKeysSet() && err != nil: t.Error("OpenOrders() error", err) @@ -198,7 +198,7 @@ func TestOpenOrders(t *testing.T) { func TestAllOrders(t *testing.T) { t.Parallel() - _, err := b.AllOrders("BTCUSDT", "", "") + _, err := b.AllOrders(currency.NewPair(currency.BTC, currency.USDT), "", "") switch { case areTestAPIKeysSet() && err != nil: t.Error("AllOrders() error", err) @@ -366,7 +366,7 @@ func TestNewOrderTest(t *testing.T) { t.Parallel() req := &NewOrderRequest{ - Symbol: "LTCBTC", + Symbol: currency.NewPair(currency.LTC, currency.BTC), Side: order.Buy.String(), TradeType: BinanceRequestParamsOrderLimit, Price: 0.0025, @@ -385,7 +385,7 @@ func TestNewOrderTest(t *testing.T) { } req = &NewOrderRequest{ - Symbol: "LTCBTC", + Symbol: currency.NewPair(currency.LTC, currency.BTC), Side: order.Sell.String(), TradeType: BinanceRequestParamsOrderMarket, Price: 0.0045, @@ -458,7 +458,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { name: "mock batch with timerange", mock: true, args: &AggregatedTradeRequestParams{ - Symbol: currencyPair.String(), + Symbol: currencyPair, StartTime: start, EndTime: start.Add(75 * time.Minute), }, @@ -468,7 +468,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { { name: "batch with timerange", args: &AggregatedTradeRequestParams{ - Symbol: currencyPair.String(), + Symbol: currencyPair, StartTime: start, EndTime: start.Add(75 * time.Minute), }, @@ -479,7 +479,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { name: "mock custom limit with start time set, no end time", mock: true, args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), StartTime: start, Limit: 1001, }, @@ -489,7 +489,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { { name: "custom limit with start time set, no end time", args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), StartTime: time.Date(2020, 11, 18, 12, 0, 0, 0, time.UTC), Limit: 1001, }, @@ -500,7 +500,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) { name: "mock recent trades", mock: true, args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 3, }, numExpected: 3, @@ -541,14 +541,14 @@ func TestGetAggregatedTradesErrors(t *testing.T) { { name: "get recent trades does not support custom limit", args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 1001, }, }, { name: "start time and fromId cannot be both set", args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), StartTime: start, EndTime: start.Add(75 * time.Minute), FromID: 2, @@ -557,7 +557,7 @@ func TestGetAggregatedTradesErrors(t *testing.T) { { name: "can't get most recent 5000 (more than 1000 not allowed)", args: &AggregatedTradeRequestParams{ - Symbol: currency.NewPair(currency.BTC, currency.USDT).String(), + Symbol: currency.NewPair(currency.BTC, currency.USDT), Limit: 5000, }, }, diff --git a/exchanges/binance/binance_types.go b/exchanges/binance/binance_types.go index 5a56d410..8f260c11 100644 --- a/exchanges/binance/binance_types.go +++ b/exchanges/binance/binance_types.go @@ -70,8 +70,8 @@ type ExchangeInfo struct { // OrderBookDataRequestParams represents Klines request data. type OrderBookDataRequestParams struct { - Symbol string `json:"symbol"` // Required field; example LTCBTC,BTCUSDT - Limit int `json:"limit"` // Default 100; max 1000. Valid limits:[5, 10, 20, 50, 100, 500, 1000] + Symbol currency.Pair `json:"symbol"` // Required field; example LTCBTC,BTCUSDT + Limit int `json:"limit"` // Default 100; max 1000. Valid limits:[5, 10, 20, 50, 100, 500, 1000] } // OrderbookItem stores an individual orderbook item @@ -118,8 +118,8 @@ type WebsocketDepthStream struct { // RecentTradeRequestParams represents Klines request data. type RecentTradeRequestParams struct { - Symbol string `json:"symbol"` // Required field. example LTCBTC, BTCUSDT - Limit int `json:"limit"` // Default 500; max 500. + Symbol currency.Pair `json:"symbol"` // Required field. example LTCBTC, BTCUSDT + Limit int `json:"limit"` // Default 500; max 500. } // RecentTrade holds recent trade data @@ -213,7 +213,7 @@ type HistoricalTrade struct { // AggregatedTradeRequestParams holds request params type AggregatedTradeRequestParams struct { - Symbol string // Required field; example LTCBTC, BTCUSDT + Symbol currency.Pair // Required field; example LTCBTC, BTCUSDT // The first trade to retrieve FromID int64 // The API seems to accept (start and end time) or FromID and no other combinations @@ -297,7 +297,7 @@ type BestPrice struct { // NewOrderRequest request type type NewOrderRequest struct { // Symbol (currency pair to trade) - Symbol string + Symbol currency.Pair // Side Buy or Sell Side string // TradeType (market or limit order) @@ -435,9 +435,9 @@ var ( // KlinesRequestParams represents Klines request data. type KlinesRequestParams struct { - Symbol string // Required field; example LTCBTC, BTCUSDT - Interval string // Time interval period - Limit int // Default 500; max 500. + Symbol currency.Pair // Required field; example LTCBTC, BTCUSDT + Interval string // Time interval period + Limit int // Default 500; max 500. StartTime time.Time EndTime time.Time } diff --git a/exchanges/binance/binance_websocket.go b/exchanges/binance/binance_websocket.go index 38e40af8..06132db4 100644 --- a/exchanges/binance/binance_websocket.go +++ b/exchanges/binance/binance_websocket.go @@ -407,13 +407,8 @@ func stringToOrderStatus(status string) (order.Status, error) { // SeedLocalCache seeds depth data func (b *Binance) SeedLocalCache(p currency.Pair) error { - fPair, err := b.FormatExchangeCurrency(p, asset.Spot) - if err != nil { - return err - } - ob, err := b.GetOrderBook(OrderBookDataRequestParams{ - Symbol: fPair.String(), + Symbol: p, Limit: 1000, }) if err != nil { diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 7860a1df..aef6eb8a 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -400,13 +400,8 @@ func (b *Binance) FetchOrderbook(p currency.Pair, assetType asset.Item) (*orderb // UpdateOrderbook updates and returns the orderbook for a currency pair func (b *Binance) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) { - fpair, err := b.FormatExchangeCurrency(p, assetType) - if err != nil { - return nil, err - } - orderbookNew, err := b.GetOrderBook(OrderBookDataRequestParams{ - Symbol: fpair.String(), + Symbol: p, Limit: 1000}) if err != nil { return nil, err @@ -523,14 +518,9 @@ func (b *Binance) GetWithdrawalsHistory(c currency.Code) (resp []exchange.Withdr // GetRecentTrades returns the most recent trades for a currency and asset func (b *Binance) GetRecentTrades(p currency.Pair, assetType asset.Item) ([]trade.Data, error) { - var err error - p, err = b.FormatExchangeCurrency(p, assetType) - if err != nil { - return nil, err - } var resp []trade.Data limit := 1000 - tradeData, err := b.GetMostRecentTrades(RecentTradeRequestParams{p.String(), limit}) + tradeData, err := b.GetMostRecentTrades(RecentTradeRequestParams{p, limit}) if err != nil { return nil, err } @@ -558,12 +548,8 @@ func (b *Binance) GetRecentTrades(p currency.Pair, assetType asset.Item) ([]trad // GetHistoricTrades returns historic trade data within the timeframe provided func (b *Binance) GetHistoricTrades(p currency.Pair, a asset.Item, from, to time.Time) ([]trade.Data, error) { - p, err := b.FormatExchangeCurrency(p, a) - if err != nil { - return nil, err - } req := AggregatedTradeRequestParams{ - Symbol: p.String(), + Symbol: p, StartTime: from, EndTime: to, } @@ -620,13 +606,8 @@ func (b *Binance) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) { return submitOrderResponse, errors.New("unsupported order type") } - fPair, err := b.FormatExchangeCurrency(s.Pair, s.AssetType) - if err != nil { - return submitOrderResponse, err - } - var orderRequest = NewOrderRequest{ - Symbol: fPair.String(), + Symbol: s.Pair, Side: sideType, Price: s.Price, Quantity: s.Amount, @@ -676,12 +657,7 @@ func (b *Binance) CancelOrder(o *order.Cancel) error { return err } - fpair, err := b.FormatExchangeCurrency(o.Pair, o.AssetType) - if err != nil { - return err - } - - _, err = b.CancelExistingOrder(fpair.String(), + _, err = b.CancelExistingOrder(o.Pair, orderIDInt, o.AccountID) return err @@ -697,15 +673,18 @@ func (b *Binance) CancelAllOrders(_ *order.Cancel) (order.CancelAllResponse, err cancelAllOrdersResponse := order.CancelAllResponse{ Status: make(map[string]string), } - openOrders, err := b.OpenOrders("") + openOrders, err := b.OpenOrders(nil) if err != nil { return cancelAllOrdersResponse, err } for i := range openOrders { - _, err = b.CancelExistingOrder(openOrders[i].Symbol, - openOrders[i].OrderID, - "") + pair, _, err := b.GetRequestFormattedPairAndAssetType(openOrders[i].Symbol) + if err != nil { + cancelAllOrdersResponse.Status[strconv.FormatInt(openOrders[i].OrderID, 10)] = err.Error() + continue + } + _, err = b.CancelExistingOrder(pair, openOrders[i].OrderID, "") if err != nil { cancelAllOrdersResponse.Status[strconv.FormatInt(openOrders[i].OrderID, 10)] = err.Error() } @@ -720,17 +699,12 @@ func (b *Binance) GetOrderInfo(orderID string, pair currency.Pair, assetType ass assetType = asset.Spot } - formattedPair, err := b.FormatExchangeCurrency(pair, assetType) - if err != nil { - return - } - orderIDInt64, err := convert.Int64FromString(orderID) if err != nil { return } - resp, err := b.QueryOrder(formattedPair.String(), "", orderIDInt64) + resp, err := b.QueryOrder(pair, "", orderIDInt64) if err != nil { return } @@ -758,7 +732,7 @@ func (b *Binance) GetOrderInfo(orderID string, pair currency.Pair, assetType ass ID: strconv.FormatInt(resp.OrderID, 10), Side: orderSide, Type: orderType, - Pair: formattedPair, + Pair: pair, Cost: resp.CummulativeQuoteQty, AssetType: assetType, CloseTime: resp.UpdateTime, @@ -826,13 +800,7 @@ func (b *Binance) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, var orders []order.Detail for x := range req.Pairs { - fpair, err := b.FormatExchangeCurrency(req.Pairs[x], - asset.Spot) - if err != nil { - return nil, err - } - - resp, err := b.OpenOrders(fpair.String()) + resp, err := b.OpenOrders(&req.Pairs[x]) if err != nil { return nil, err } @@ -879,11 +847,7 @@ func (b *Binance) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail, var orders []order.Detail for x := range req.Pairs { - fpair, err := b.FormatExchangeCurrency(req.Pairs[x], asset.Spot) - if err != nil { - return nil, err - } - resp, err := b.AllOrders(fpair.String(), + resp, err := b.AllOrders(req.Pairs[x], "", "1000") if err != nil { @@ -951,13 +915,9 @@ func (b *Binance) GetHistoricCandles(pair currency.Pair, a asset.Item, start, en return kline.Item{}, errors.New(kline.ErrRequestExceedsExchangeLimits) } - fpair, err := b.FormatExchangeCurrency(pair, a) - if err != nil { - return kline.Item{}, err - } req := KlinesRequestParams{ Interval: b.FormatExchangeKlineInterval(interval), - Symbol: fpair.String(), + Symbol: pair, StartTime: start, EndTime: end, Limit: int(b.Features.Enabled.Kline.ResultLimit), @@ -1003,16 +963,11 @@ func (b *Binance) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, s Interval: interval, } - formattedPair, err := b.FormatExchangeCurrency(pair, a) - if err != nil { - return kline.Item{}, err - } - dates := kline.CalcDateRanges(start, end, interval, b.Features.Enabled.Kline.ResultLimit) for x := range dates { req := KlinesRequestParams{ Interval: b.FormatExchangeKlineInterval(interval), - Symbol: formattedPair.String(), + Symbol: pair, StartTime: dates[x].Start, EndTime: dates[x].End, Limit: int(b.Features.Enabled.Kline.ResultLimit), diff --git a/exchanges/binance/type_convert.go b/exchanges/binance/type_convert.go index 74e58797..c1fa0ddd 100644 --- a/exchanges/binance/type_convert.go +++ b/exchanges/binance/type_convert.go @@ -6,6 +6,8 @@ import ( "time" "github.com/thrasher-corp/gocryptotrader/common/convert" + "github.com/thrasher-corp/gocryptotrader/currency" + "github.com/thrasher-corp/gocryptotrader/exchanges/asset" ) // binanceTime provides an internal conversion helper @@ -344,3 +346,13 @@ func (a *wsListStatus) UnmarshalJSON(data []byte) error { a.Data.TransactionTime = aux.Data.TransactionTime.Time() return nil } + +// formatSymbol formats the given pair to a string suitable for exchange API requests +// currently applicable to Spot and Margin assets +func (b *Binance) formatSymbol(pair currency.Pair) (string, error) { + pairFmt, err := b.GetPairFormat(asset.Spot, true) + if err != nil { + return pair.String(), err + } + return pairFmt.Format(pair), nil +}