CI: Fix golangci-lint linter issues, add prealloc linter and bump version depends for Go 1.18 (#915)

* Bump CI versions

* Specifically set go version as 1.17.x bumps it to 1.18

* Another

* Adjust AppVeyor

* Part 1 of linter issues

* Part 2

* Fix various linters and improvements

* Part 3

* Finishing touches

* Tests and EqualFold

* Fix nitterinos plus bonus requester jobs bump for exchanges with large number of tests

* Fix nitterinos and bump golangci-lint timeout for AppVeyor

* Address nits, ensure all books are returned on err due to syncer regression

* Fix the wiggins

* Fix duplication

* Fix nitterinos
This commit is contained in:
Adrian Gallagher
2022-04-20 13:45:15 +10:00
committed by GitHub
parent c48e5ea90a
commit 9a4eb9de84
216 changed files with 3493 additions and 2424 deletions

View File

@@ -119,16 +119,15 @@ func (b *Binance) GetExchangeInfo(ctx context.Context) (ExchangeInfo, error) {
// OrderBookDataRequestParams contains the following members
// symbol: string of currency pair
// limit: returned limit amount
func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestParams) (OrderBook, error) {
var orderbook OrderBook
func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestParams) (*OrderBook, error) {
if err := b.CheckLimit(obd.Limit); err != nil {
return orderbook, err
return nil, err
}
params := url.Values{}
symbol, err := b.FormatSymbol(obd.Symbol, asset.Spot)
if err != nil {
return orderbook, err
return nil, err
}
params.Set("symbol", symbol)
params.Set("limit", fmt.Sprintf("%d", obd.Limit))
@@ -138,52 +137,54 @@ func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestPara
exchange.RestSpotSupplementary,
orderBookDepth+"?"+params.Encode(),
orderbookLimit(obd.Limit), &resp); err != nil {
return orderbook, err
return nil, err
}
orderbook := OrderBook{
Bids: make([]OrderbookItem, len(resp.Bids)),
Asks: make([]OrderbookItem, len(resp.Asks)),
LastUpdateID: resp.LastUpdateID,
}
for x := range resp.Bids {
price, err := strconv.ParseFloat(resp.Bids[x][0], 64)
if err != nil {
return orderbook, err
return nil, err
}
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
if err != nil {
return orderbook, err
return nil, err
}
orderbook.Bids = append(orderbook.Bids, OrderbookItem{
orderbook.Bids[x] = OrderbookItem{
Price: price,
Quantity: amount,
})
}
}
for x := range resp.Asks {
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
if err != nil {
return orderbook, err
return nil, err
}
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
if err != nil {
return orderbook, err
return nil, err
}
orderbook.Asks = append(orderbook.Asks, OrderbookItem{
orderbook.Asks[x] = OrderbookItem{
Price: price,
Quantity: amount,
})
}
}
orderbook.LastUpdateID = resp.LastUpdateID
return orderbook, nil
return &orderbook, nil
}
// GetMostRecentTrades returns recent trade activity
// limit: Up to 500 results returned
func (b *Binance) GetMostRecentTrades(ctx context.Context, rtr RecentTradeRequestParams) ([]RecentTrade, error) {
var resp []RecentTrade
params := url.Values{}
symbol, err := b.FormatSymbol(rtr.Symbol, asset.Spot)
if err != nil {
@@ -194,6 +195,7 @@ func (b *Binance) GetMostRecentTrades(ctx context.Context, rtr RecentTradeReques
path := recentTrades + "?" + params.Encode()
var resp []RecentTrade
return resp, b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
}
@@ -356,14 +358,12 @@ func (b *Binance) batchAggregateTrades(ctx context.Context, arg *AggregatedTrade
// startTime: startTime filter for kline data
// endTime: endTime filter for the kline data
func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([]CandleStick, error) {
var resp interface{}
var klineData []CandleStick
params := url.Values{}
symbol, err := b.FormatSymbol(arg.Symbol, asset.Spot)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("symbol", symbol)
params.Set("interval", arg.Interval)
if arg.Limit != 0 {
@@ -377,6 +377,7 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
}
path := candleStick + "?" + params.Encode()
var resp interface{}
err = b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
@@ -390,6 +391,8 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
if !ok {
return nil, errors.New("unable to type assert responseData")
}
klineData := make([]CandleStick, len(responseData))
for x := range responseData {
individualData, ok := responseData[x].([]interface{})
if !ok {
@@ -432,7 +435,7 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
return nil, err
}
klineData = append(klineData, candle)
klineData[x] = candle
}
return klineData, nil
}

View File

@@ -82,10 +82,18 @@ func (b *Binance) FuturesExchangeInfo(ctx context.Context) (CExchangeInfo, error
}
// GetFuturesOrderbook gets orderbook data for CoinMarginedFutures,
func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (OrderBook, error) {
var resp OrderBook
var data OrderbookData
func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (*OrderBook, error) {
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1000 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
rateBudget := cFuturesDefaultRate
switch {
case limit == 5, limit == 10, limit == 20, limit == 50:
@@ -97,48 +105,47 @@ func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair,
case limit == 1000:
rateBudget = cFuturesOrderbook1000Rate
}
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1000 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
var data OrderbookData
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesOrderbook+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var resp OrderBook
var price, quantity float64
resp.Asks = make([]OrderbookItem, len(data.Asks))
for x := range data.Asks {
price, err = strconv.ParseFloat(data.Asks[x][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Asks = append(resp.Asks, OrderbookItem{
resp.Asks[x] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
resp.Bids = make([]OrderbookItem, len(data.Bids))
for y := range data.Bids {
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Bids = append(resp.Bids, OrderbookItem{
resp.Bids[y] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
return resp, nil
return &resp, nil
}
// GetFuturesPublicTrades gets recent public trades for CoinMarginedFutures,
@@ -232,13 +239,11 @@ func (b *Binance) GetIndexAndMarkPrice(ctx context.Context, symbol, pair string)
// GetFuturesKlineData gets futures kline data for CoinMarginedFutures,
func (b *Binance) GetFuturesKlineData(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
if !symbol.IsEmpty() {
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params.Set("symbol", symbolValue)
}
@@ -246,453 +251,462 @@ func (b *Binance) GetFuturesKlineData(ctx context.Context, symbol currency.Pair,
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
var data [][10]interface{}
rateBudget := getKlineRateBudget(limit)
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesKlineData+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetContinuousKlineData gets continuous kline data
func (b *Binance) GetContinuousKlineData(ctx context.Context, pair, contractType, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
params.Set("pair", pair)
if !common.StringDataCompare(validContractType, contractType) {
return resp, errors.New("invalid contractType")
return nil, errors.New("invalid contractType")
}
params.Set("contractType", contractType)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
rateBudget := getKlineRateBudget(limit)
var data [][10]interface{}
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesContinuousKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetIndexPriceKlines gets continuous kline data
func (b *Binance) GetIndexPriceKlines(ctx context.Context, pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
params.Set("pair", pair)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
rateBudget := getKlineRateBudget(limit)
var data [][10]interface{}
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesIndexKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetMarkPriceKline gets mark price kline data
func (b *Binance) GetMarkPriceKline(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
var data [][10]interface{}
rateBudget := getKlineRateBudget(limit)
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesMarkPriceKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
@@ -1466,12 +1480,12 @@ func (b *Binance) FuturesPositionsADLEstimate(ctx context.Context, symbol curren
// FetchCoinMarginExchangeLimits fetches coin margined order execution limits
func (b *Binance) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
var limits []order.MinMaxLevel
coinFutures, err := b.FuturesExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(coinFutures.Symbols))
for x := range coinFutures.Symbols {
symbol := strings.Split(coinFutures.Symbols[x].Symbol, currency.UnderscoreDelimiter)
var cp currency.Pair

View File

@@ -36,6 +36,7 @@ func TestMain(m *testing.M) {
log.Fatal("Binance setup error", err)
}
b.setupOrderbookManager()
request.MaxRequestJobs = 100
b.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
log.Printf(sharedtestvalues.LiveTesting, b.Name)
os.Exit(m.Run())

View File

@@ -12,6 +12,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
)
@@ -57,6 +58,7 @@ func TestMain(m *testing.M) {
log.Fatal(err)
}
}
request.MaxRequestJobs = 100
log.Printf(sharedtestvalues.MockTesting, b.Name)
os.Exit(m.Run())
}

View File

@@ -84,22 +84,22 @@ func (b *Binance) UExchangeInfo(ctx context.Context) (UFuturesExchangeInfo, erro
}
// UFuturesOrderbook gets orderbook data for usdt margined futures
func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (OrderBook, error) {
var resp OrderBook
var data OrderbookData
params := url.Values{}
func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (*OrderBook, error) {
symbolValue, err := b.FormatSymbol(symbol, asset.USDTMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
strLimit := strconv.FormatInt(limit, 10)
if strLimit != "" {
if !common.StringDataCompare(uValidOBLimits, strLimit) {
return resp, fmt.Errorf("invalid limit: %v", limit)
return nil, fmt.Errorf("invalid limit: %v", limit)
}
params.Set("limit", strLimit)
}
rateBudget := uFuturesDefaultRate
switch {
case limit == 5, limit == 10, limit == 20, limit == 50:
@@ -111,42 +111,50 @@ func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, l
case limit == 1000:
rateBudget = uFuturesOrderbook1000Rate
}
var data OrderbookData
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesOrderbook+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
resp.Symbol = symbolValue
resp.LastUpdateID = data.LastUpdateID
resp := OrderBook{
Symbol: symbolValue,
LastUpdateID: data.LastUpdateID,
Bids: make([]OrderbookItem, len(data.Bids)),
Asks: make([]OrderbookItem, len(data.Asks)),
}
var price, quantity float64
for x := range data.Asks {
price, err = strconv.ParseFloat(data.Asks[x][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Asks = append(resp.Asks, OrderbookItem{
resp.Asks[x] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
for y := range data.Bids {
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Bids = append(resp.Bids, OrderbookItem{
resp.Bids[y] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
return resp, nil
return &resp, nil
}
// URecentTrades gets recent trades for usdt margined futures
@@ -212,16 +220,14 @@ func (b *Binance) UCompressedTrades(ctx context.Context, symbol currency.Pair, f
// UKlineData gets kline data for usdt margined futures
func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
symbolValue, err := b.FormatSymbol(symbol, asset.USDTMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params.Set("symbol", symbolValue)
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval")
return nil, errors.New("invalid interval")
}
params.Set("interval", interval)
if limit > 0 && limit <= 1500 {
@@ -229,7 +235,7 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
}
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("startTime", timeString(startTime))
params.Set("endTime", timeString(endTime))
@@ -245,71 +251,76 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
case limit > 1000:
rateBudget = uFuturesKlineMaxRate
}
var data [][10]interface{}
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesKlineData+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var tempData FuturesCandleStick
var floatData float64
var strData string
var ok bool
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var tempData FuturesCandleStick
var floatData float64
var strData string
var ok bool
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for opentime")
return nil, errors.New("type assertion failed for opentime")
}
tempData.OpenTime, err = convert.TimeFromUnixTimestampFloat(floatData)
if err != nil {
return resp, err
return nil, err
}
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime, err = convert.TimeFromUnixTimestampFloat(floatData)
if err != nil {
@@ -317,28 +328,28 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
}
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed base asset volume")
return nil, errors.New("type assertion failed base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
@@ -1139,12 +1150,12 @@ func (b *Binance) GetFundingRates(ctx context.Context, symbol currency.Pair, lim
// FetchUSDTMarginExchangeLimits fetches USDT margined order execution limits
func (b *Binance) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
var limits []order.MinMaxLevel
usdtFutures, err := b.UExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(usdtFutures.Symbols))
for x := range usdtFutures.Symbols {
var cp currency.Pair
cp, err = currency.NewPairFromStrings(usdtFutures.Symbols[x].BaseAsset,

View File

@@ -482,31 +482,32 @@ func (b *Binance) SeedLocalCache(ctx context.Context, p currency.Pair) error {
if err != nil {
return err
}
return b.SeedLocalCacheWithBook(p, &ob)
return b.SeedLocalCacheWithBook(p, ob)
}
// SeedLocalCacheWithBook seeds the local orderbook cache
func (b *Binance) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *OrderBook) error {
var newOrderBook orderbook.Base
newOrderBook := orderbook.Base{
Pair: p,
Asset: asset.Spot,
Exchange: b.Name,
LastUpdateID: orderbookNew.LastUpdateID,
VerifyOrderbook: b.CanVerifyOrderbook,
Bids: make(orderbook.Items, len(orderbookNew.Bids)),
Asks: make(orderbook.Items, len(orderbookNew.Asks)),
}
for i := range orderbookNew.Bids {
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
newOrderBook.Bids[i] = orderbook.Item{
Amount: orderbookNew.Bids[i].Quantity,
Price: orderbookNew.Bids[i].Price,
})
}
}
for i := range orderbookNew.Asks {
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
newOrderBook.Asks[i] = orderbook.Item{
Amount: orderbookNew.Asks[i].Quantity,
Price: orderbookNew.Asks[i].Price,
})
}
}
newOrderBook.Pair = p
newOrderBook.Asset = asset.Spot
newOrderBook.Exchange = b.Name
newOrderBook.LastUpdateID = orderbookNew.LastUpdateID
newOrderBook.VerifyOrderbook = b.CanVerifyOrderbook
return b.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
}
@@ -626,7 +627,7 @@ func (b *Binance) Unsubscribe(channelsToUnsubscribe []stream.ChannelSubscription
// ProcessUpdate processes the websocket orderbook update
func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error {
var updateBid []orderbook.Item
updateBid := make([]orderbook.Item, len(ws.UpdateBids))
for i := range ws.UpdateBids {
price, ok := ws.UpdateBids[i][0].(string)
if !ok {
@@ -644,10 +645,10 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep
if err != nil {
return err
}
updateBid = append(updateBid, orderbook.Item{Price: p, Amount: a})
updateBid[i] = orderbook.Item{Price: p, Amount: a}
}
var updateAsk []orderbook.Item
updateAsk := make([]orderbook.Item, len(ws.UpdateAsks))
for i := range ws.UpdateAsks {
price, ok := ws.UpdateAsks[i][0].(string)
if !ok {
@@ -665,7 +666,7 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep
if err != nil {
return err
}
updateAsk = append(updateAsk, orderbook.Item{Price: p, Amount: a})
updateAsk[i] = orderbook.Item{Price: p, Amount: a}
}
return b.Websocket.Orderbook.Update(&buffer.Update{

View File

@@ -657,7 +657,7 @@ func (b *Binance) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp
Asset: assetType,
VerifyOrderbook: b.CanVerifyOrderbook,
}
var orderbookNew OrderBook
var orderbookNew *OrderBook
var err error
switch assetType {
case asset.Spot, asset.Margin:
@@ -673,17 +673,20 @@ func (b *Binance) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp
if err != nil {
return book, err
}
book.Bids = make(orderbook.Items, len(orderbookNew.Bids))
for x := range orderbookNew.Bids {
book.Bids = append(book.Bids, orderbook.Item{
book.Bids[x] = orderbook.Item{
Amount: orderbookNew.Bids[x].Quantity,
Price: orderbookNew.Bids[x].Price,
})
}
}
book.Asks = make(orderbook.Items, len(orderbookNew.Asks))
for x := range orderbookNew.Asks {
book.Asks = append(book.Asks, orderbook.Item{
book.Asks[x] = orderbook.Item{
Amount: orderbookNew.Asks[x].Quantity,
Price: orderbookNew.Asks[x].Price,
})
}
}
err = book.Process()
@@ -834,15 +837,16 @@ func (b *Binance) GetWithdrawalsHistory(ctx context.Context, c currency.Code) (r
// GetRecentTrades returns the most recent trades for a currency and asset
func (b *Binance) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
var resp []trade.Data
limit := 1000
const limit = 1000
tradeData, err := b.GetMostRecentTrades(ctx,
RecentTradeRequestParams{p, limit})
if err != nil {
return nil, err
}
resp := make([]trade.Data, len(tradeData))
for i := range tradeData {
resp = append(resp, trade.Data{
resp[i] = trade.Data{
TID: strconv.FormatInt(tradeData[i].ID, 10),
Exchange: b.Name,
CurrencyPair: p,
@@ -850,7 +854,7 @@ func (b *Binance) GetRecentTrades(ctx context.Context, p currency.Pair, assetTyp
Price: tradeData[i].Price,
Amount: tradeData[i].Quantity,
Timestamp: tradeData[i].Time,
})
}
}
if b.IsSaveTradeDataEnabled() {
err := trade.AddTradesToBuffer(b.Name, resp...)
@@ -874,11 +878,11 @@ func (b *Binance) GetHistoricTrades(ctx context.Context, p currency.Pair, a asse
if err != nil {
return nil, err
}
var result []trade.Data
result := make([]trade.Data, len(trades))
exName := b.GetName()
for i := range trades {
t := trades[i].toTradeData(p, exName, a)
result = append(result, *t)
result[i] = *t
}
return result, nil
}