Skip to content

Commit

Permalink
binance: use currency.Pair for request arguments (thrasher-corp#608)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Rots authored Dec 13, 2020
1 parent f3da99b commit ddd19ab
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 127 deletions.
9 changes: 7 additions & 2 deletions currency/pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions currency/pair_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}
1 change: 0 additions & 1 deletion currency/pair_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
103 changes: 79 additions & 24 deletions exchanges/binance/binance.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"net/url"
"sort"
"strconv"
"strings"
"time"

"github.com/thrasher-corp/gocryptotrader/common"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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())
Expand All @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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())

Expand All @@ -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())

Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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))
Expand All @@ -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 {
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
Loading

0 comments on commit ddd19ab

Please sign in to comment.