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:
Adrian Gallagher
2025-06-12 14:12:36 +10:00
committed by GitHub
parent ce134a0a1d
commit d5ba674fc4
115 changed files with 1327 additions and 3112 deletions

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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")

View File

@@ -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

View File

@@ -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
}

View File

@@ -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]

View File

@@ -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:

View File

@@ -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

View File

@@ -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