mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-30 23:16:52 +00:00
codebase: Cleanup various things (#1935)
* codebase: Rid base64/hex to string common funcs * codebase: Rid local scope variable usage and other improvements * codebase: Refactor currency pair usage across multiple exchanges - Updated HitBTC tests to use the new currency pair format. - Modified Kraken futures types to use currency.Pair instead of string for Symbol. - Adjusted Kraken wrapper methods to handle currency pairs correctly. - Refined OKX tests and types to utilize currency.Pair for instrument IDs. - Enhanced Poloniex tests to consistently use predefined currency pairs. - Streamlined order and orderbook tests to replace string pairs with currency.NewBTCUSD(). - Improved Yobit tests to utilize a standardized currency pair format. - Updated validator wrapper to use currency pairs directly instead of string conversions. * codebase: Use types.Number where possible * refactor: update PayoutFee type to types.Number for consistency * Refactor: Remove crypto functions to use standard library and other minor changes - Removed custom crypto functions for SHA256, SHA512, and MD5 from the common/crypto package. - Replaced usages of removed functions with standard library implementations in various files including: - cmd/websocket_client/main.go - engine/apiserver.go - exchanges/kraken/kraken.go - exchanges/lbank/lbank.go - exchanges/okx/okx_business_websocket.go - exchanges/kucoin/kucoin_websocket.go - gctscript/vm/vm.go - Updated tests to reflect changes in the crypto functions. - Renamed several functions for clarity, particularly in the context of order book updates across multiple exchanges. * refactor: replace assert with require for consistency in test assertions * refactor: Improve Binance futures candlestick test, standardise orderbook update function names and improve test parallelism * refactor: Replace require.Len with require.Equal for better output in TestGetFuturesKlineData
This commit is contained in:
@@ -2,6 +2,7 @@ package binance
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -129,54 +130,28 @@ func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestPara
|
||||
}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("limit", strconv.Itoa(obd.Limit))
|
||||
var resp OrderBookData
|
||||
if err := b.SendHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
orderBookDepth+"?"+params.Encode(),
|
||||
orderbookLimit(obd.Limit), &resp); err != nil {
|
||||
|
||||
var resp *OrderBookData
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, common.EncodeURLValues(orderBookDepth, params), orderbookLimit(obd.Limit), &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderbook := OrderBook{
|
||||
ob := &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 nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderbook.Bids[x] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: amount,
|
||||
}
|
||||
ob.Bids[x].Price = resp.Bids[x][0].Float64()
|
||||
ob.Bids[x].Quantity = resp.Bids[x][1].Float64()
|
||||
}
|
||||
|
||||
for x := range resp.Asks {
|
||||
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderbook.Asks[x] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: amount,
|
||||
}
|
||||
ob.Asks[x].Price = resp.Asks[x][0].Float64()
|
||||
ob.Asks[x].Quantity = resp.Asks[x][1].Float64()
|
||||
}
|
||||
|
||||
return &orderbook, nil
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// GetMostRecentTrades returns recent trade activity
|
||||
@@ -861,21 +836,14 @@ func (b *Binance) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, m
|
||||
|
||||
interim := json.RawMessage{}
|
||||
err = b.SendPayload(ctx, f, func() (*request.Item, error) {
|
||||
fullPath := endpointPath + path
|
||||
params.Set("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||||
signature := params.Encode()
|
||||
var hmacSigned []byte
|
||||
hmacSigned, err = crypto.GetHMAC(crypto.HashSHA256,
|
||||
[]byte(signature),
|
||||
[]byte(creds.Secret))
|
||||
hmacSigned, err := crypto.GetHMAC(crypto.HashSHA256, []byte(params.Encode()), []byte(creds.Secret))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hmacSignedStr := crypto.HexEncodeToString(hmacSigned)
|
||||
headers := make(map[string]string)
|
||||
headers["X-MBX-APIKEY"] = creds.Key
|
||||
fullPath = common.EncodeURLValues(fullPath, params)
|
||||
fullPath += "&signature=" + hmacSignedStr
|
||||
fullPath := common.EncodeURLValues(endpointPath+path, params) + "&signature=" + hex.EncodeToString(hmacSigned)
|
||||
return &request.Item{
|
||||
Method: method,
|
||||
Path: fullPath,
|
||||
|
||||
@@ -105,46 +105,27 @@ func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair,
|
||||
rateBudget = cFuturesOrderbook500Rate
|
||||
}
|
||||
|
||||
var data OrderbookData
|
||||
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesOrderbook+params.Encode(), rateBudget, &data)
|
||||
if err != nil {
|
||||
var data *OrderbookData
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesOrderbook+params.Encode(), rateBudget, &data); err != nil {
|
||||
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 nil, err
|
||||
}
|
||||
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Asks[x] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
}
|
||||
ob := &OrderBook{
|
||||
Bids: make([]OrderbookItem, len(data.Bids)),
|
||||
Asks: make([]OrderbookItem, len(data.Asks)),
|
||||
}
|
||||
|
||||
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 nil, err
|
||||
}
|
||||
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Bids[y] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
}
|
||||
for x := range data.Bids {
|
||||
ob.Bids[x].Price = data.Bids[x][0].Float64()
|
||||
ob.Bids[x].Quantity = data.Bids[x][1].Float64()
|
||||
}
|
||||
return &resp, nil
|
||||
|
||||
for x := range data.Asks {
|
||||
ob.Asks[x].Price = data.Asks[x][0].Float64()
|
||||
ob.Asks[x].Quantity = data.Asks[x][1].Float64()
|
||||
}
|
||||
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// GetFuturesPublicTrades gets recent public trades for CoinMarginedFutures,
|
||||
@@ -268,99 +249,11 @@ func (b *Binance) GetFuturesKlineData(ctx context.Context, symbol currency.Pair,
|
||||
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
|
||||
}
|
||||
|
||||
var data [][10]any
|
||||
var resp []FuturesCandleStick
|
||||
rateBudget := getKlineRateBudget(limit)
|
||||
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesKlineData+params.Encode(), rateBudget, &data)
|
||||
if err != nil {
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesKlineData+params.Encode(), rateBudget, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 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 nil, errors.New("type assertion failed for open")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Open = floatData
|
||||
strData, ok = data[x][2].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for high")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.High = floatData
|
||||
strData, ok = data[x][3].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for low")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Low = floatData
|
||||
strData, ok = data[x][4].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Close = floatData
|
||||
strData, ok = data[x][5].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Volume = floatData
|
||||
floatData, ok = data[x][6].(float64)
|
||||
if !ok {
|
||||
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 nil, errors.New("type assertion failed for base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.BaseAssetVolume = floatData
|
||||
floatData, ok = data[x][8].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy volume")
|
||||
}
|
||||
tempData.TakerBuyVolume = floatData
|
||||
strData, ok = data[x][9].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.TakerBuyBaseAssetVolume = floatData
|
||||
resp[x] = tempData
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -388,98 +281,11 @@ func (b *Binance) GetContinuousKlineData(ctx context.Context, pair, contractType
|
||||
}
|
||||
|
||||
rateBudget := getKlineRateBudget(limit)
|
||||
var data [][10]any
|
||||
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesContinuousKline+params.Encode(), rateBudget, &data)
|
||||
if err != nil {
|
||||
var resp []FuturesCandleStick
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesContinuousKline+params.Encode(), rateBudget, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 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 nil, errors.New("type assertion failed for open")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Open = floatData
|
||||
strData, ok = data[x][2].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for high")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.High = floatData
|
||||
strData, ok = data[x][3].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for low")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Low = floatData
|
||||
strData, ok = data[x][4].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Close = floatData
|
||||
strData, ok = data[x][5].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Volume = floatData
|
||||
floatData, ok = data[x][6].(float64)
|
||||
if !ok {
|
||||
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 nil, errors.New("type assertion failed for base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.BaseAssetVolume = floatData
|
||||
floatData, ok = data[x][8].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy volume")
|
||||
}
|
||||
tempData.TakerBuyVolume = floatData
|
||||
strData, ok = data[x][9].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.TakerBuyBaseAssetVolume = floatData
|
||||
resp[x] = tempData
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -503,99 +309,12 @@ func (b *Binance) GetIndexPriceKlines(ctx context.Context, pair, interval string
|
||||
}
|
||||
|
||||
rateBudget := getKlineRateBudget(limit)
|
||||
var data [][10]any
|
||||
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesIndexKline+params.Encode(), rateBudget, &data)
|
||||
var candles []FuturesCandleStick
|
||||
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesIndexKline+params.Encode(), rateBudget, &candles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 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 nil, errors.New("type assertion failed for open")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Open = floatData
|
||||
strData, ok = data[x][2].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for high")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.High = floatData
|
||||
strData, ok = data[x][3].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for low")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Low = floatData
|
||||
strData, ok = data[x][4].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Close = floatData
|
||||
strData, ok = data[x][5].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Volume = floatData
|
||||
floatData, ok = data[x][6].(float64)
|
||||
if !ok {
|
||||
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 nil, errors.New("type assertion failed for base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.BaseAssetVolume = floatData
|
||||
floatData, ok = data[x][8].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy volume")
|
||||
}
|
||||
tempData.TakerBuyVolume = floatData
|
||||
strData, ok = data[x][9].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.TakerBuyBaseAssetVolume = floatData
|
||||
resp[x] = tempData
|
||||
}
|
||||
return resp, nil
|
||||
return candles, nil
|
||||
}
|
||||
|
||||
// GetMarkPriceKline gets mark price kline data
|
||||
@@ -621,100 +340,14 @@ func (b *Binance) GetMarkPriceKline(ctx context.Context, symbol currency.Pair, i
|
||||
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
|
||||
}
|
||||
|
||||
var data [][10]any
|
||||
var candles []FuturesCandleStick
|
||||
rateBudget := getKlineRateBudget(limit)
|
||||
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesMarkPriceKline+params.Encode(), rateBudget, &data)
|
||||
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesMarkPriceKline+params.Encode(), rateBudget, &candles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 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 nil, errors.New("type assertion failed for open")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Open = floatData
|
||||
strData, ok = data[x][2].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for high")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.High = floatData
|
||||
strData, ok = data[x][3].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for low")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Low = floatData
|
||||
strData, ok = data[x][4].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Close = floatData
|
||||
strData, ok = data[x][5].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Volume = floatData
|
||||
floatData, ok = data[x][6].(float64)
|
||||
if !ok {
|
||||
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 nil, errors.New("type assertion failed for base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.BaseAssetVolume = floatData
|
||||
floatData, ok = data[x][8].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy volume")
|
||||
}
|
||||
tempData.TakerBuyVolume = floatData
|
||||
strData, ok = data[x][9].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.TakerBuyBaseAssetVolume = floatData
|
||||
resp[x] = tempData
|
||||
}
|
||||
return resp, nil
|
||||
return candles, nil
|
||||
}
|
||||
|
||||
func getKlineRateBudget(limit uint64) request.EndpointLimit {
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
|
||||
mockws "github.com/thrasher-corp/gocryptotrader/internal/testing/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
// Please supply your own keys here for due diligence testing
|
||||
@@ -661,16 +662,32 @@ func TestGetIndexAndMarkPrice(t *testing.T) {
|
||||
|
||||
func TestGetFuturesKlineData(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := b.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "1M", 5, time.Time{}, time.Time{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
r, err := b.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("BTCUSD", "PERP", "_"), "1M", 5, time.Time{}, time.Time{})
|
||||
require.NoError(t, err, "GetFuturesKlineData must not error")
|
||||
if mockTests {
|
||||
require.Equal(t, 5, len(r), "GetFuturesKlineData must return 5 items in mock test")
|
||||
exp := FuturesCandleStick{
|
||||
OpenTime: types.Time(time.UnixMilli(1596240000000)),
|
||||
Open: 11785,
|
||||
High: 12513.6,
|
||||
Low: 11114.1,
|
||||
Close: 11663.5,
|
||||
Volume: 12155433,
|
||||
CloseTime: types.Time(time.UnixMilli(1598918399999)),
|
||||
BaseAssetVolume: 104142.54608485,
|
||||
NumberOfTrades: 359100,
|
||||
TakerBuyVolume: 6013546,
|
||||
TakerBuyBaseAssetVolume: 51511.95826419,
|
||||
}
|
||||
assert.Equal(t, exp, r[0])
|
||||
} else {
|
||||
assert.NotEmpty(t, r, "GetFuturesKlineData should return data")
|
||||
}
|
||||
|
||||
start, end := getTime()
|
||||
_, err = b.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("LTCUSD", "PERP", "_"), "5m", 5, start, end)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
r, err = b.GetFuturesKlineData(t.Context(), currency.NewPairWithDelimiter("LTCUSD", "PERP", "_"), "5m", 5, start, end)
|
||||
require.NoError(t, err, "GetFuturesKlineData must not error")
|
||||
assert.NotEmpty(t, r, "GetFuturesKlineData should return data")
|
||||
}
|
||||
|
||||
func TestGetContinuousKlineData(t *testing.T) {
|
||||
@@ -2318,43 +2335,32 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinance_FormatExchangeKlineInterval(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
func TestFormatExchangeKlineInterval(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, tc := range []struct {
|
||||
interval kline.Interval
|
||||
output string
|
||||
}{
|
||||
{
|
||||
"OneMin",
|
||||
kline.OneMin,
|
||||
"1m",
|
||||
},
|
||||
{
|
||||
"OneDay",
|
||||
kline.OneDay,
|
||||
"1d",
|
||||
},
|
||||
{
|
||||
"OneWeek",
|
||||
kline.OneWeek,
|
||||
"1w",
|
||||
},
|
||||
{
|
||||
"OneMonth",
|
||||
kline.OneMonth,
|
||||
"1M",
|
||||
},
|
||||
}
|
||||
|
||||
for x := range testCases {
|
||||
test := testCases[x]
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ret := b.FormatExchangeKlineInterval(test.interval)
|
||||
|
||||
if ret != test.output {
|
||||
t.Fatalf("unexpected result return expected: %v received: %v", test.output, ret)
|
||||
}
|
||||
} {
|
||||
t.Run(tc.interval.String(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, tc.output, b.FormatExchangeKlineInterval(tc.interval))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2444,7 +2450,7 @@ func TestFormatChannelLevels(t *testing.T) {
|
||||
|
||||
var websocketDepthUpdate = []byte(`{"E":1608001030784,"U":7145637266,"a":[["19455.19000000","0.59490200"],["19455.37000000","0.00000000"],["19456.11000000","0.00000000"],["19456.16000000","0.00000000"],["19458.67000000","0.06400000"],["19460.73000000","0.05139800"],["19461.43000000","0.00000000"],["19464.59000000","0.00000000"],["19466.03000000","0.45000000"],["19466.36000000","0.00000000"],["19508.67000000","0.00000000"],["19572.96000000","0.00217200"],["24386.00000000","0.00256600"]],"b":[["19455.18000000","2.94649200"],["19453.15000000","0.01233600"],["19451.18000000","0.00000000"],["19446.85000000","0.11427900"],["19446.74000000","0.00000000"],["19446.73000000","0.00000000"],["19444.45000000","0.14937800"],["19426.75000000","0.00000000"],["19416.36000000","0.36052100"]],"e":"depthUpdate","s":"BTCUSDT","u":7145637297}`)
|
||||
|
||||
func TestProcessUpdate(t *testing.T) {
|
||||
func TestProcessOrderbookUpdate(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := new(Binance) //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
|
||||
require.NoError(t, testexch.Setup(b), "Test instance Setup must not error")
|
||||
|
||||
@@ -136,11 +136,11 @@ type OrderbookItem struct {
|
||||
|
||||
// OrderBookData is resp data from orderbook endpoint
|
||||
type OrderBookData struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
LastUpdateID int64 `json:"lastUpdateId"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Asks [][2]string `json:"asks"`
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
LastUpdateID int64 `json:"lastUpdateId"`
|
||||
Bids [][2]types.Number `json:"bids"`
|
||||
Asks [][2]types.Number `json:"asks"`
|
||||
}
|
||||
|
||||
// OrderBook actual structured data that can be used for orderbook
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
@@ -113,49 +112,27 @@ func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, l
|
||||
rateBudget = uFuturesOrderbook500Rate
|
||||
}
|
||||
|
||||
var data OrderbookData
|
||||
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesOrderbook+params.Encode(), rateBudget, &data)
|
||||
if err != nil {
|
||||
var data *OrderbookData
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesOrderbook+params.Encode(), rateBudget, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := OrderBook{
|
||||
ob := &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 nil, err
|
||||
}
|
||||
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Asks[x] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
}
|
||||
ob.Asks[x].Price = data.Asks[x][0].Float64()
|
||||
ob.Asks[x].Quantity = data.Asks[x][1].Float64()
|
||||
}
|
||||
for y := range data.Bids {
|
||||
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Bids[y] = OrderbookItem{
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
}
|
||||
for x := range data.Bids {
|
||||
ob.Bids[x].Price = data.Bids[x][0].Float64()
|
||||
ob.Bids[x].Quantity = data.Bids[x][1].Float64()
|
||||
}
|
||||
return &resp, nil
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// URecentTrades gets recent trades for usdt margined futures
|
||||
@@ -253,105 +230,11 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
|
||||
rateBudget = uFuturesKlineMaxRate
|
||||
}
|
||||
|
||||
var data [][10]any
|
||||
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesKlineData+params.Encode(), rateBudget, &data)
|
||||
if err != nil {
|
||||
var resp []FuturesCandleStick
|
||||
if err := b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesKlineData+params.Encode(), rateBudget, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 nil, errors.New("type assertion failed for opentime")
|
||||
}
|
||||
tempData.OpenTime, err = convert.TimeFromUnixTimestampFloat(floatData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
strData, ok = data[x][1].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for open")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Open = floatData
|
||||
strData, ok = data[x][2].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for high")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.High = floatData
|
||||
strData, ok = data[x][3].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for low")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Low = floatData
|
||||
strData, ok = data[x][4].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Close = floatData
|
||||
strData, ok = data[x][5].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.Volume = floatData
|
||||
floatData, ok = data[x][6].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for close time")
|
||||
}
|
||||
tempData.CloseTime, err = convert.TimeFromUnixTimestampFloat(floatData)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
strData, ok = data[x][7].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.BaseAssetVolume = floatData
|
||||
floatData, ok = data[x][8].(float64)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy volume")
|
||||
}
|
||||
tempData.TakerBuyVolume = floatData
|
||||
strData, ok = data[x][9].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("type assertion failed for taker buy base asset volume")
|
||||
}
|
||||
floatData, err = strconv.ParseFloat(strData, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempData.TakerBuyBaseAssetVolume = floatData
|
||||
resp[x] = tempData
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -613,8 +613,8 @@ func (b *Binance) manageSubs(op string, subs subscription.List) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ProcessUpdate processes the websocket orderbook update
|
||||
func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error {
|
||||
// ProcessOrderbookUpdate processes the websocket orderbook update
|
||||
func (b *Binance) ProcessOrderbookUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error {
|
||||
updateBid := make([]orderbook.Tranche, len(ws.UpdateBids))
|
||||
for i := range ws.UpdateBids {
|
||||
updateBid[i] = orderbook.Tranche{
|
||||
@@ -666,7 +666,7 @@ func (b *Binance) applyBufferUpdate(pair currency.Pair) error {
|
||||
}
|
||||
|
||||
if recent != nil {
|
||||
err = b.obm.checkAndProcessUpdate(b.ProcessUpdate, pair, recent)
|
||||
err = b.obm.checkAndProcessOrderbookUpdate(b.ProcessOrderbookUpdate, pair, recent)
|
||||
if err != nil {
|
||||
log.Errorf(
|
||||
log.WebsocketMgr,
|
||||
@@ -919,7 +919,7 @@ func (o *orderbookManager) fetchBookViaREST(pair currency.Pair) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *orderbookManager) checkAndProcessUpdate(processor func(currency.Pair, asset.Item, *WebsocketDepthStream) error, pair currency.Pair, recent *orderbook.Base) error {
|
||||
func (o *orderbookManager) checkAndProcessOrderbookUpdate(processor func(currency.Pair, asset.Item, *WebsocketDepthStream) error, pair currency.Pair, recent *orderbook.Base) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
state, ok := o.state[pair.Base][pair.Quote][asset.Spot]
|
||||
|
||||
@@ -1674,12 +1674,12 @@ func (b *Binance) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
}
|
||||
for i := range candles {
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: candles[i].OpenTime,
|
||||
Open: candles[i].Open,
|
||||
High: candles[i].High,
|
||||
Low: candles[i].Low,
|
||||
Close: candles[i].Close,
|
||||
Volume: candles[i].Volume,
|
||||
Time: candles[i].OpenTime.Time(),
|
||||
Open: candles[i].Open.Float64(),
|
||||
High: candles[i].High.Float64(),
|
||||
Low: candles[i].Low.Float64(),
|
||||
Close: candles[i].Close.Float64(),
|
||||
Volume: candles[i].Volume.Float64(),
|
||||
})
|
||||
}
|
||||
case asset.CoinMarginedFutures:
|
||||
@@ -1695,12 +1695,12 @@ func (b *Binance) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
|
||||
}
|
||||
for i := range candles {
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: candles[i].OpenTime,
|
||||
Open: candles[i].Open,
|
||||
High: candles[i].High,
|
||||
Low: candles[i].Low,
|
||||
Close: candles[i].Close,
|
||||
Volume: candles[i].Volume,
|
||||
Time: candles[i].OpenTime.Time(),
|
||||
Open: candles[i].Open.Float64(),
|
||||
High: candles[i].High.Float64(),
|
||||
Low: candles[i].Low.Float64(),
|
||||
Close: candles[i].Close.Float64(),
|
||||
Volume: candles[i].Volume.Float64(),
|
||||
})
|
||||
}
|
||||
default:
|
||||
@@ -1755,12 +1755,12 @@ func (b *Binance) GetHistoricCandlesExtended(ctx context.Context, pair currency.
|
||||
}
|
||||
for i := range candles {
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: candles[i].OpenTime,
|
||||
Open: candles[i].Open,
|
||||
High: candles[i].High,
|
||||
Low: candles[i].Low,
|
||||
Close: candles[i].Close,
|
||||
Volume: candles[i].Volume,
|
||||
Time: candles[i].OpenTime.Time(),
|
||||
Open: candles[i].Open.Float64(),
|
||||
High: candles[i].High.Float64(),
|
||||
Low: candles[i].Low.Float64(),
|
||||
Close: candles[i].Close.Float64(),
|
||||
Volume: candles[i].Volume.Float64(),
|
||||
})
|
||||
}
|
||||
case asset.CoinMarginedFutures:
|
||||
@@ -1776,12 +1776,12 @@ func (b *Binance) GetHistoricCandlesExtended(ctx context.Context, pair currency.
|
||||
}
|
||||
for i := range candles {
|
||||
timeSeries = append(timeSeries, kline.Candle{
|
||||
Time: candles[i].OpenTime,
|
||||
Open: candles[i].Open,
|
||||
High: candles[i].High,
|
||||
Low: candles[i].Low,
|
||||
Close: candles[i].Close,
|
||||
Volume: candles[i].Volume,
|
||||
Time: candles[i].OpenTime.Time(),
|
||||
Open: candles[i].Open.Float64(),
|
||||
High: candles[i].High.Float64(),
|
||||
Low: candles[i].Low.Float64(),
|
||||
Close: candles[i].Close.Float64(),
|
||||
Volume: candles[i].Volume.Float64(),
|
||||
})
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package binance
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
@@ -63,17 +62,22 @@ type SymbolOrderBookTicker struct {
|
||||
|
||||
// FuturesCandleStick holds kline data
|
||||
type FuturesCandleStick struct {
|
||||
OpenTime time.Time
|
||||
Open float64
|
||||
High float64
|
||||
Low float64
|
||||
Close float64
|
||||
Volume float64
|
||||
CloseTime time.Time
|
||||
BaseAssetVolume float64
|
||||
OpenTime types.Time
|
||||
Open types.Number
|
||||
High types.Number
|
||||
Low types.Number
|
||||
Close types.Number
|
||||
Volume types.Number
|
||||
CloseTime types.Time
|
||||
BaseAssetVolume types.Number
|
||||
NumberOfTrades int64
|
||||
TakerBuyVolume float64
|
||||
TakerBuyBaseAssetVolume float64
|
||||
TakerBuyVolume types.Number
|
||||
TakerBuyBaseAssetVolume types.Number
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals FuturesCandleStick data from JSON
|
||||
func (f *FuturesCandleStick) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &[11]any{&f.OpenTime, &f.Open, &f.High, &f.Low, &f.Close, &f.Volume, &f.CloseTime, &f.BaseAssetVolume, &f.NumberOfTrades, &f.TakerBuyVolume, &f.TakerBuyBaseAssetVolume})
|
||||
}
|
||||
|
||||
// AllLiquidationOrders gets all liquidation orders
|
||||
|
||||
@@ -42,10 +42,10 @@ var (
|
||||
|
||||
// OrderbookData stores ob data for umargined and cmargined futures
|
||||
type OrderbookData struct {
|
||||
LastUpdateID int64 `json:"lastUpdateID"`
|
||||
Timestamp int64 `json:"T"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Asks [][2]string `json:"asks"`
|
||||
LastUpdateID int64 `json:"lastUpdateID"`
|
||||
Timestamp int64 `json:"T"`
|
||||
Bids [][2]types.Number `json:"bids"`
|
||||
Asks [][2]types.Number `json:"asks"`
|
||||
}
|
||||
|
||||
// UPublicTradesData stores trade data
|
||||
|
||||
Reference in New Issue
Block a user