exchanges: Refactor time handling and other minor improvements (#1948)

* exchanges: Refactor time handling and other minor improvements

- Updated Kraken wrapper to utilise new time handling methods.
- Simplified Kucoin types by removing unnecessary structures and using direct JSON unmarshalling.
- Improved websocket handling in Kucoin to directly parse candlestick data.
- Modified Lbank types to use the new time representation.
- Adjusted Poloniex wrapper and types to utilise the new time handling.
- Updated Yobit types and wrapper to reflect changes in time representation.
- Introduced DateTime type for better handling of specific time formats.
- Added tests for DateTime unmarshalling to ensure correctness.
- Rid UTC().Unix and UTC().UnixMilli as it's not needed
- Correct Huobi timestamp usage for some endpoints.
- Rid RFC3339 time parsing since Go does that automatically.

* exchanges: Refactor JSON unmarshalling for various types and improve test coverage

* linter: Update error message in TestGetKlines

* refactor: Simplify JSON unmarshalling in MovementHistory and improve test assertions in GetKlines

* refactor: Improve JSON unmarshalling for channel name and clarify comment in wsProcessOpenOrders

* refactor: Update time handling in Huobi types to use types.Time for createdAt fields and relax GetLiquidationOrders test

* refactor: Move wsTicker, wsSpread, wsTrades, and wsCandle types to kraken_types.go for better organistion

* refactor: Add validation for underlying parameter in GetExpirationTime and update tests
This commit is contained in:
Adrian Gallagher
2025-07-01 09:11:55 +10:00
committed by GitHub
parent 48a66c9faa
commit 3cc9a2b9e0
92 changed files with 2488 additions and 3276 deletions

View File

@@ -14,7 +14,6 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
@@ -373,69 +372,8 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
if !arg.EndTime.IsZero() {
params.Set("endTime", strconv.FormatInt(arg.EndTime.UnixMilli(), 10))
}
path := candleStick + "?" + params.Encode()
var resp any
err = b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
path,
spotDefaultRate,
&resp)
if err != nil {
return nil, err
}
responseData, ok := resp.([]any)
if !ok {
return nil, common.GetTypeAssertError("[]any", resp)
}
klineData := make([]CandleStick, len(responseData))
for x := range responseData {
individualData, ok := responseData[x].([]any)
if !ok {
return nil, common.GetTypeAssertError("[]any", responseData[x])
}
if len(individualData) != 12 {
return nil, errors.New("unexpected kline data length")
}
var candle CandleStick
if candle.OpenTime, err = convert.TimeFromUnixTimestampFloat(individualData[0]); err != nil {
return nil, err
}
if candle.Open, err = convert.FloatFromString(individualData[1]); err != nil {
return nil, err
}
if candle.High, err = convert.FloatFromString(individualData[2]); err != nil {
return nil, err
}
if candle.Low, err = convert.FloatFromString(individualData[3]); err != nil {
return nil, err
}
if candle.Close, err = convert.FloatFromString(individualData[4]); err != nil {
return nil, err
}
if candle.Volume, err = convert.FloatFromString(individualData[5]); err != nil {
return nil, err
}
if candle.CloseTime, err = convert.TimeFromUnixTimestampFloat(individualData[6]); err != nil {
return nil, err
}
if candle.QuoteAssetVolume, err = convert.FloatFromString(individualData[7]); err != nil {
return nil, err
}
if candle.TradeCount, ok = individualData[8].(float64); !ok {
return nil, common.GetTypeAssertError("float64", individualData[8])
}
if candle.TakerBuyAssetVolume, err = convert.FloatFromString(individualData[9]); err != nil {
return nil, err
}
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
return nil, err
}
klineData[x] = candle
}
return klineData, nil
var resp []CandleStick
return resp, b.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, common.EncodeURLValues(candleStick, params), spotDefaultRate, &resp)
}
// GetAveragePrice returns current average price for a symbol.
@@ -1013,11 +951,11 @@ func (b *Binance) DepositHistory(ctx context.Context, c currency.Code, status st
}
if !startTime.IsZero() {
params.Set("startTime", strconv.FormatInt(startTime.UTC().UnixMilli(), 10))
params.Set("startTime", strconv.FormatInt(startTime.UnixMilli(), 10))
}
if !endTime.IsZero() {
params.Set("endTime", strconv.FormatInt(endTime.UTC().UnixMilli(), 10))
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
}
if offset != 0 {
@@ -1065,11 +1003,11 @@ func (b *Binance) WithdrawHistory(ctx context.Context, c currency.Code, status s
}
if !startTime.IsZero() {
params.Set("startTime", strconv.FormatInt(startTime.UTC().UnixMilli(), 10))
params.Set("startTime", strconv.FormatInt(startTime.UnixMilli(), 10))
}
if !endTime.IsZero() {
params.Set("endTime", strconv.FormatInt(endTime.UTC().UnixMilli(), 10))
params.Set("endTime", strconv.FormatInt(endTime.UnixMilli(), 10))
}
if offset != 0 {

View File

@@ -1165,16 +1165,32 @@ func TestGetAggregatedTrades(t *testing.T) {
func TestGetSpotKline(t *testing.T) {
t.Parallel()
start, end := getTime()
_, err := b.GetSpotKline(t.Context(),
&KlinesRequestParams{
Symbol: currency.NewBTCUSDT(),
Interval: kline.FiveMin.Short(),
Limit: 24,
StartTime: start,
EndTime: end,
})
if err != nil {
t.Error("Binance GetSpotKline() error", err)
r, err := b.GetSpotKline(t.Context(), &KlinesRequestParams{
Symbol: currency.NewBTCUSDT(),
Interval: kline.FiveMin.Short(),
Limit: 24,
StartTime: start,
EndTime: end,
})
require.NoError(t, err, "GetSpotKline must not error")
if mockTests {
require.Equal(t, 24, len(r), "GetSpotKline must return 24 items in mock test")
exp := CandleStick{
OpenTime: types.Time(time.UnixMilli(1577836800000)),
Open: 7195.24,
High: 7196.25,
Low: 7178.64,
Close: 7179.78,
Volume: 95.509133,
CloseTime: types.Time(time.UnixMilli(1577837099999)),
QuoteAssetVolume: 686317.13625177,
TradeCount: 1127,
TakerBuyAssetVolume: 32.773245,
TakerBuyQuoteAssetVolume: 235537.29504531,
}
assert.Equal(t, exp, r[0])
} else {
assert.NotEmpty(t, r, "GetSpotKline should return data")
}
}
@@ -1484,14 +1500,9 @@ func TestGetAggregatedTradesBatched(t *testing.T) {
if err != nil {
t.Fatal(err)
}
start, err := time.Parse(time.RFC3339, "2020-01-02T15:04:05Z")
if err != nil {
t.Fatal(err)
}
expectTime, err := time.Parse(time.RFC3339Nano, "2020-01-02T16:19:04.831Z")
if err != nil {
t.Fatal(err)
}
start := time.Date(2020, 1, 2, 15, 4, 5, 0, time.UTC)
expectTime := time.Date(2020, 1, 2, 16, 19, 4, 831_000_000, time.UTC)
tests := []struct {
name string
// mock test or live test
@@ -1576,10 +1587,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) {
func TestGetAggregatedTradesErrors(t *testing.T) {
t.Parallel()
start, err := time.Parse(time.RFC3339, "2020-01-02T15:04:05Z")
if err != nil {
t.Fatal(err)
}
start := time.Date(2020, 1, 2, 15, 4, 5, 0, time.UTC)
tests := []struct {
name string
args *AggregatedTradeRequestParams

View File

@@ -6,6 +6,7 @@ import (
"github.com/shopspring/decimal"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/types"
)
@@ -306,17 +307,34 @@ type IndexMarkPrice struct {
// CandleStick holds kline data
type CandleStick struct {
OpenTime time.Time
Open float64
High float64
Low float64
Close float64
Volume float64
CloseTime time.Time
QuoteAssetVolume float64
TradeCount float64
TakerBuyAssetVolume float64
TakerBuyQuoteAssetVolume float64
OpenTime types.Time
Open types.Number
High types.Number
Low types.Number
Close types.Number
Volume types.Number
CloseTime types.Time
QuoteAssetVolume types.Number
TradeCount int64
TakerBuyAssetVolume types.Number
TakerBuyQuoteAssetVolume types.Number
}
// UnmarshalJSON unmarshals JSON data into a CandleStick struct
func (c *CandleStick) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &[11]any{
&c.OpenTime,
&c.Open,
&c.High,
&c.Low,
&c.Close,
&c.Volume,
&c.CloseTime,
&c.QuoteAssetVolume,
&c.TradeCount,
&c.TakerBuyAssetVolume,
&c.TakerBuyQuoteAssetVolume,
})
}
// AveragePrice holds current average symbol price
@@ -692,16 +710,16 @@ var WithdrawalFees = map[currency.Code]float64{
// DepositHistory stores deposit history info
type DepositHistory struct {
Amount float64 `json:"amount,string"`
Coin string `json:"coin"`
Network string `json:"network"`
Status uint8 `json:"status"`
Address string `json:"address"`
AddressTag string `json:"adressTag"`
TransactionID string `json:"txId"`
InsertTime float64 `json:"insertTime"`
TransferType uint8 `json:"transferType"`
ConfirmTimes string `json:"confirmTimes"`
Amount float64 `json:"amount,string"`
Coin string `json:"coin"`
Network string `json:"network"`
Status uint8 `json:"status"`
Address string `json:"address"`
AddressTag string `json:"adressTag"`
TransactionID string `json:"txId"`
InsertTime types.Time `json:"insertTime"`
TransferType uint8 `json:"transferType"`
ConfirmTimes string `json:"confirmTimes"`
}
// WithdrawResponse contains status of withdrawal request

View File

@@ -16,6 +16,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/types"
)
const (
@@ -70,13 +71,13 @@ const (
// UServerTime gets the server time
func (b *Binance) UServerTime(ctx context.Context) (time.Time, error) {
var data struct {
ServerTime int64 `json:"serverTime"`
ServerTime types.Time `json:"serverTime"`
}
err := b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesServerTime, uFuturesDefaultRate, &data)
if err != nil {
return time.Time{}, err
}
return time.UnixMilli(data.ServerTime), nil
return data.ServerTime.Time(), nil
}
// UExchangeInfo stores usdt margined futures data

View File

@@ -1653,12 +1653,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.USDTMarginedFutures:
@@ -1734,12 +1734,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.USDTMarginedFutures:
@@ -1933,7 +1933,7 @@ func (b *Binance) GetServerTime(ctx context.Context, ai asset.Item) (time.Time,
if err != nil {
return time.Time{}, err
}
return time.UnixMilli(info.ServerTime), nil
return info.ServerTime.Time(), nil
}
return time.Time{}, fmt.Errorf("%s %w", ai, asset.ErrNotSupported)
}
@@ -2128,14 +2128,14 @@ func (b *Binance) GetHistoricalFundingRates(ctx context.Context, r *fundingrate.
}
for j := range frh {
pairRate.FundingRates = append(pairRate.FundingRates, fundingrate.Rate{
Time: time.UnixMilli(frh[j].FundingTime),
Time: frh[j].FundingTime.Time(),
Rate: decimal.NewFromFloat(frh[j].FundingRate),
})
}
if len(frh) < requestLimit {
break
}
sd = time.UnixMilli(frh[len(frh)-1].FundingTime)
sd = frh[len(frh)-1].FundingTime.Time()
}
var mp []UMarkPrice
mp, err = b.UGetMarkPrice(ctx, fPair)
@@ -2155,8 +2155,7 @@ func (b *Binance) GetHistoricalFundingRates(ctx context.Context, r *fundingrate.
}
for j := range income {
for x := range pairRate.FundingRates {
tt := time.UnixMilli(income[j].Time)
tt = tt.Truncate(time.Duration(fundingRateFrequency) * time.Hour)
tt := income[j].Time.Time().Truncate(time.Duration(fundingRateFrequency) * time.Hour)
if !tt.Equal(pairRate.FundingRates[x].Time) {
continue
}
@@ -2194,14 +2193,14 @@ func (b *Binance) GetHistoricalFundingRates(ctx context.Context, r *fundingrate.
}
for j := range frh {
pairRate.FundingRates = append(pairRate.FundingRates, fundingrate.Rate{
Time: time.UnixMilli(frh[j].FundingTime),
Time: frh[j].FundingTime.Time(),
Rate: decimal.NewFromFloat(frh[j].FundingRate),
})
}
if len(frh) < requestLimit {
break
}
sd = time.UnixMilli(frh[len(frh)-1].FundingTime)
sd = frh[len(frh)-1].FundingTime.Time()
}
var mp []IndexMarkPrice
mp, err = b.GetIndexAndMarkPrice(ctx, fPair.String(), "")
@@ -2221,8 +2220,7 @@ func (b *Binance) GetHistoricalFundingRates(ctx context.Context, r *fundingrate.
}
for j := range income {
for x := range pairRate.FundingRates {
tt := time.UnixMilli(income[j].Timestamp)
tt = tt.Truncate(8 * time.Hour)
tt := income[j].Timestamp.Time().Truncate(8 * time.Hour)
if !tt.Equal(pairRate.FundingRates[x].Time) {
continue
}

View File

@@ -39,25 +39,25 @@ type MarkPriceData struct {
Symbol string `json:"symbol"`
MarkPrice float64 `json:"markPrice"`
LastFundingRate float64 `json:"lastFundingRate"`
NextFundingTime int64 `json:"nextFundingTime"`
NextFundingTime types.Time `json:"nextFundingTime"`
Time types.Time `json:"time"`
}
// SymbolPriceTicker stores ticker price stats
type SymbolPriceTicker struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Time types.Time `json:"time"`
}
// SymbolOrderBookTicker stores orderbook ticker data
type SymbolOrderBookTicker struct {
Symbol string `json:"symbol"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
BidQty float64 `json:"bidQty,string"`
AskQty float64 `json:"askQty,string"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
BidQty float64 `json:"bidQty,string"`
AskQty float64 `json:"askQty,string"`
Time types.Time `json:"time"`
}
// FuturesCandleStick holds kline data
@@ -82,83 +82,83 @@ func (f *FuturesCandleStick) UnmarshalJSON(data []byte) error {
// AllLiquidationOrders gets all liquidation orders
type AllLiquidationOrders struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
AveragePrice float64 `json:"averagePrice,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
Side string `json:"side"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
AveragePrice float64 `json:"averagePrice,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
Side string `json:"side"`
Time types.Time `json:"time"`
}
// OpenInterestData stores open interest data
type OpenInterestData struct {
Symbol string `json:"symbol"`
Pair string `json:"pair"`
OpenInterest float64 `json:"openInterest,string"`
ContractType string `json:"contractType"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
OpenInterest float64 `json:"openInterest,string"`
ContractType string `json:"contractType"`
Time types.Time `json:"time"`
}
// OpenInterestStats stores stats for open interest data
type OpenInterestStats struct {
Pair string `json:"pair"`
ContractType string `json:"contractType"`
SumOpenInterest float64 `json:"sumOpenInterest,string"`
SumOpenInterestValue float64 `json:"sumOpenInterestValue,string"`
Timestamp int64 `json:"timestamp"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
SumOpenInterest float64 `json:"sumOpenInterest,string"`
SumOpenInterestValue float64 `json:"sumOpenInterestValue,string"`
Timestamp types.Time `json:"timestamp"`
}
// TopTraderAccountRatio stores account ratio data for top traders
type TopTraderAccountRatio struct {
Pair string `json:"pair"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongAccount float64 `json:"longAccount,string"`
ShortAccount float64 `json:"shortAccount,string"`
Timestamp int64 `json:"timestamp"`
Pair string `json:"pair"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongAccount float64 `json:"longAccount,string"`
ShortAccount float64 `json:"shortAccount,string"`
Timestamp types.Time `json:"timestamp"`
}
// TopTraderPositionRatio stores position ratio for top trader accounts
type TopTraderPositionRatio struct {
Pair string `json:"pair"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongPosition float64 `json:"longPosition,string"`
ShortPosition float64 `json:"shortPosition,string"`
Timestamp int64 `json:"timestamp"`
Pair string `json:"pair"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongPosition float64 `json:"longPosition,string"`
ShortPosition float64 `json:"shortPosition,string"`
Timestamp types.Time `json:"timestamp"`
}
// GlobalLongShortRatio stores ratio data of all longs vs shorts
type GlobalLongShortRatio struct {
Symbol string `json:"symbol"`
LongShortRatio float64 `json:"longShortRatio"`
LongAccount float64 `json:"longAccount"`
ShortAccount float64 `json:"shortAccount"`
Timestamp string `json:"timestamp"`
Symbol string `json:"symbol"`
LongShortRatio float64 `json:"longShortRatio"`
LongAccount float64 `json:"longAccount"`
ShortAccount float64 `json:"shortAccount"`
Timestamp types.Time `json:"timestamp"`
}
// TakerBuySellVolume stores taker buy sell volume
type TakerBuySellVolume struct {
Pair string `json:"pair"`
ContractType string `json:"contractType"`
TakerBuyVolume float64 `json:"takerBuyVol,string"`
BuySellRatio float64 `json:"takerSellVol,string"`
BuyVol float64 `json:"takerBuyVolValue,string"`
SellVol float64 `json:"takerSellVolValue,string"`
Timestamp int64 `json:"timestamp"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
TakerBuyVolume float64 `json:"takerBuyVol,string"`
BuySellRatio float64 `json:"takerSellVol,string"`
BuyVol float64 `json:"takerBuyVolValue,string"`
SellVol float64 `json:"takerSellVolValue,string"`
Timestamp types.Time `json:"timestamp"`
}
// FuturesBasisData gets futures basis data
type FuturesBasisData struct {
Pair string `json:"pair"`
ContractType string `json:"contractType"`
FuturesPrice float64 `json:"futuresPrice,string"`
IndexPrice float64 `json:"indexPrice,string"`
Basis float64 `json:"basis,string"`
BasisRate float64 `json:"basisRate,string"`
Timestamp int64 `json:"timestamp"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
FuturesPrice float64 `json:"futuresPrice,string"`
IndexPrice float64 `json:"indexPrice,string"`
Basis float64 `json:"basis,string"`
BasisRate float64 `json:"basisRate,string"`
Timestamp types.Time `json:"timestamp"`
}
// PlaceBatchOrderData stores batch order data for placing
@@ -182,32 +182,32 @@ type PlaceBatchOrderData struct {
// BatchCancelOrderData stores batch cancel order data
type BatchCancelOrderData struct {
ClientOrderID string `json:"clientOrderID"`
CumQty float64 `json:"cumQty,string"`
CumBase float64 `json:"cumBase,string"`
ExecuteQty float64 `json:"executeQty,string"`
OrderID int64 `json:"orderID,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
Price float64 `json:"price,string"`
ReduceOnly bool `json:"reduceOnly"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Status string `json:"status"`
StopPrice int64 `json:"stopPrice"`
ClosePosition bool `json:"closePosition"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
TimeInForce string `json:"TimeInForce"`
OrderType string `json:"type"`
OrigType string `json:"origType"`
ActivatePrice float64 `json:"activatePrice,string"`
PriceRate float64 `json:"priceRate,string"`
UpdateTime int64 `json:"updateTime"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect"`
Code int64 `json:"code"`
Msg string `json:"msg"`
ClientOrderID string `json:"clientOrderID"`
CumQty float64 `json:"cumQty,string"`
CumBase float64 `json:"cumBase,string"`
ExecuteQty float64 `json:"executeQty,string"`
OrderID int64 `json:"orderID,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
Price float64 `json:"price,string"`
ReduceOnly bool `json:"reduceOnly"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Status string `json:"status"`
StopPrice int64 `json:"stopPrice"`
ClosePosition bool `json:"closePosition"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
TimeInForce string `json:"TimeInForce"`
OrderType string `json:"type"`
OrigType string `json:"origType"`
ActivatePrice float64 `json:"activatePrice,string"`
PriceRate float64 `json:"priceRate,string"`
UpdateTime types.Time `json:"updateTime"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect"`
Code int64 `json:"code"`
Msg string `json:"msg"`
}
// FuturesNewOrderRequest stores all the data needed to submit a
@@ -233,30 +233,30 @@ type FuturesNewOrderRequest struct {
// FuturesOrderPlaceData stores futures order data
type FuturesOrderPlaceData struct {
ClientOrderID string `json:"clientOrderId"`
CumQty float64 `json:"cumQty,string"`
CumBase float64 `json:"cumBase,string"`
ExecuteQty float64 `json:"executedQty,string"`
OrderID int64 `json:"orderId"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
Price float64 `json:"price,string"`
ReduceOnly bool `json:"reduceOnly"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Status string `json:"status"`
StopPrice float64 `json:"stopPrice,string"`
ClosePosition bool `json:"closePosition"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
TimeInForce string `json:"TimeInForce"`
OrderType string `json:"type"`
OrigType string `json:"origType"`
ActivatePrice float64 `json:"activatePrice,string"`
PriceRate float64 `json:"priceRate,string"`
UpdateTime int64 `json:"updateTime"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect"`
ClientOrderID string `json:"clientOrderId"`
CumQty float64 `json:"cumQty,string"`
CumBase float64 `json:"cumBase,string"`
ExecuteQty float64 `json:"executedQty,string"`
OrderID int64 `json:"orderId"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
Price float64 `json:"price,string"`
ReduceOnly bool `json:"reduceOnly"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Status string `json:"status"`
StopPrice float64 `json:"stopPrice,string"`
ClosePosition bool `json:"closePosition"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
TimeInForce string `json:"TimeInForce"`
OrderType string `json:"type"`
OrigType string `json:"origType"`
ActivatePrice float64 `json:"activatePrice,string"`
PriceRate float64 `json:"priceRate,string"`
UpdateTime types.Time `json:"updateTime"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect"`
}
// FuturesOrderGetData stores futures order data for get requests
@@ -354,14 +354,14 @@ type MarginInfoData struct {
// FuturesAccountBalanceData stores account balance data for futures
type FuturesAccountBalanceData struct {
AccountAlias string `json:"accountAlias"`
Asset string `json:"asset"`
Balance float64 `json:"balance,string"`
WithdrawAvailable float64 `json:"withdrawAvailable,string"`
CrossWalletBalance float64 `json:"crossWalletBalance,string"`
CrossUnPNL float64 `json:"crossUnPNL,string"`
AvailableBalance float64 `json:"availableBalance,string"`
UpdateTime int64 `json:"updateTime"`
AccountAlias string `json:"accountAlias"`
Asset string `json:"asset"`
Balance float64 `json:"balance,string"`
WithdrawAvailable float64 `json:"withdrawAvailable,string"`
CrossWalletBalance float64 `json:"crossWalletBalance,string"`
CrossUnPNL float64 `json:"crossUnPNL,string"`
AvailableBalance float64 `json:"availableBalance,string"`
UpdateTime types.Time `json:"updateTime"`
}
// FuturesAccountInformationPosition holds account position data
@@ -440,12 +440,12 @@ type ModifyIsolatedMarginData struct {
// GetPositionMarginChangeHistoryData gets margin change history for positions
type GetPositionMarginChangeHistoryData struct {
Amount float64 `json:"amount"`
Asset string `json:"asset"`
Symbol string `json:"symbol"`
Timestamp int64 `json:"time"`
MarginChangeType int64 `json:"type"`
PositionSide string `json:"positionSide"`
Amount float64 `json:"amount"`
Asset string `json:"asset"`
Symbol string `json:"symbol"`
Timestamp types.Time `json:"time"`
MarginChangeType int64 `json:"type"`
PositionSide string `json:"positionSide"`
}
// FuturesPositionInformation stores futures position info
@@ -469,32 +469,32 @@ type FuturesPositionInformation struct {
// FuturesAccountTradeList stores account trade list data
type FuturesAccountTradeList struct {
Symbol string `json:"symbol"`
ID int64 `json:"id"`
OrderID int64 `json:"orderID"`
Pair string `json:"pair"`
Side string `json:"side"`
Price string `json:"price"`
Qty float64 `json:"qty"`
RealizedPNL float64 `json:"realizedPNL"`
MarginAsset string `json:"marginAsset"`
BaseQty float64 `json:"baseQty"`
Commission float64 `json:"commission"`
CommissionAsset string `json:"commissionAsset"`
Timestamp int64 `json:"timestamp"`
PositionSide string `json:"positionSide"`
Buyer bool `json:"buyer"`
Maker bool `json:"maker"`
Symbol string `json:"symbol"`
ID int64 `json:"id"`
OrderID int64 `json:"orderID"`
Pair string `json:"pair"`
Side string `json:"side"`
Price string `json:"price"`
Qty float64 `json:"qty"`
RealizedPNL float64 `json:"realizedPNL"`
MarginAsset string `json:"marginAsset"`
BaseQty float64 `json:"baseQty"`
Commission float64 `json:"commission"`
CommissionAsset string `json:"commissionAsset"`
Timestamp types.Time `json:"timestamp"`
PositionSide string `json:"positionSide"`
Buyer bool `json:"buyer"`
Maker bool `json:"maker"`
}
// FuturesIncomeHistoryData stores futures income history data
type FuturesIncomeHistoryData struct {
Symbol string `json:"symbol"`
IncomeType string `json:"incomeType"`
Income float64 `json:"income,string"`
Asset string `json:"asset"`
Info string `json:"info"`
Timestamp int64 `json:"time"`
Symbol string `json:"symbol"`
IncomeType string `json:"incomeType"`
Income float64 `json:"income,string"`
Asset string `json:"asset"`
Info string `json:"info"`
Timestamp types.Time `json:"time"`
}
// NotionalBracketData stores notional bracket data
@@ -511,27 +511,27 @@ type NotionalBracketData struct {
// ForcedOrdersData stores forced orders data
type ForcedOrdersData struct {
OrderID int64 `json:"orderId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
CumQuote float64 `json:"cumQuote,string"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"orderType"`
ReduceOnly bool `json:"reduceOnly"`
ClosePosition bool `json:"closePosition"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
StopPrice float64 `json:"stopPrice,string"`
WorkingType string `json:"workingType"`
PriceProtect float64 `json:"priceProtect,string"`
OrigType string `json:"origType"`
Time int64 `json:"time"`
UpdateTime int64 `json:"updateTime"`
OrderID int64 `json:"orderId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
CumQuote float64 `json:"cumQuote,string"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"orderType"`
ReduceOnly bool `json:"reduceOnly"`
ClosePosition bool `json:"closePosition"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
StopPrice float64 `json:"stopPrice,string"`
WorkingType string `json:"workingType"`
PriceProtect float64 `json:"priceProtect,string"`
OrigType string `json:"origType"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
}
// ADLEstimateData stores data for ADL estimates
@@ -546,18 +546,18 @@ type ADLEstimateData struct {
// InterestHistoryData gets interest history data
type InterestHistoryData struct {
Asset string `json:"asset"`
Interest float64 `json:"interest"`
LendingType string `json:"lendingType"`
ProductName string `json:"productName"`
Time string `json:"time"`
Asset string `json:"asset"`
Interest float64 `json:"interest"`
LendingType string `json:"lendingType"`
ProductName string `json:"productName"`
Time types.Time `json:"time"`
}
// FundingRateData stores funding rates data
type FundingRateData struct {
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate,string"`
FundingTime int64 `json:"fundingTime"`
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate,string"`
FundingTime types.Time `json:"fundingTime"`
}
// SymbolsData stores perp futures' symbols
@@ -578,7 +578,7 @@ type UFuturesExchangeInfo struct {
Limit int64 `json:"limit"`
RateLimitType string `json:"rateLimitType"`
} `json:"rateLimits"`
ServerTime int64 `json:"serverTime"`
ServerTime types.Time `json:"serverTime"`
Symbols []UFuturesSymbolInfo `json:"symbols"`
Timezone string `json:"timezone"`
}
@@ -634,7 +634,7 @@ type CExchangeInfo struct {
Limit int64 `json:"limit"`
RateLimitType string `json:"rateLimitType"`
} `json:"rateLimits"`
ServerTime int64 `json:"serverTime"`
ServerTime types.Time `json:"serverTime"`
Symbols []struct {
Filters []struct {
FilterType string `json:"filterType"`

View File

@@ -2,8 +2,12 @@ package binance
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/types"
)
func TestFuturesNewOrderRequest_Unmarshal(t *testing.T) {
@@ -37,34 +41,32 @@ func TestFuturesNewOrderRequest_Unmarshal(t *testing.T) {
`
var x FuturesOrderPlaceData
if err := json.Unmarshal([]byte(inp), &x); err != nil {
t.Error(err)
}
if x.OrderID != 18662274680 ||
x.Symbol != "ETHUSD_PERP" ||
x.Pair != "ETHUSD" ||
x.Status != "NEW" ||
x.ClientOrderID != "customID" ||
x.Price != 4096 ||
x.AvgPrice != 2 ||
x.OrigQty != 8 ||
x.ExecuteQty != 4 ||
x.CumQty != 32 ||
x.CumBase != 16 ||
x.TimeInForce != "GTC" ||
x.OrderType != cfuturesLimit ||
!x.ReduceOnly ||
!x.ClosePosition ||
x.StopPrice != 2048 ||
x.WorkingType != "CONTRACT_PRICE" ||
!x.PriceProtect ||
x.OrigType != cfuturesMarket ||
x.UpdateTime != 1635931801320 ||
x.ActivatePrice != 64 ||
x.PriceRate != 32 {
// If any of these values isn't set as expected, mark test as failed.
t.Errorf("unmarshaling failed: %v", x)
require.NoError(t, json.Unmarshal([]byte(inp), &x))
exp := FuturesOrderPlaceData{
OrderID: 18662274680,
Symbol: "ETHUSD_PERP",
Pair: "ETHUSD",
Status: "NEW",
ClientOrderID: "customID",
Price: 4096.0,
AvgPrice: 2.0,
OrigQty: 8.0,
ExecuteQty: 4.0,
CumQty: 32.0,
CumBase: 16.0,
TimeInForce: "GTC",
OrderType: cfuturesLimit,
ReduceOnly: true,
ClosePosition: true,
StopPrice: 2048.0,
Side: "BUY",
PositionSide: "BOTH",
WorkingType: "CONTRACT_PRICE",
PriceProtect: true,
OrigType: cfuturesMarket,
UpdateTime: types.Time(time.UnixMilli(1635931801320)),
ActivatePrice: 64.0,
PriceRate: 32.0,
}
assert.Equal(t, exp, x)
}

View File

@@ -43,7 +43,7 @@ var (
// OrderbookData stores ob data for umargined and cmargined futures
type OrderbookData struct {
LastUpdateID int64 `json:"lastUpdateID"`
Timestamp int64 `json:"T"`
Timestamp types.Time `json:"T"`
Bids [][2]types.Number `json:"bids"`
Asks [][2]types.Number `json:"asks"`
}
@@ -60,13 +60,13 @@ type UPublicTradesData struct {
// UCompressedTradeData stores compressed trade data
type UCompressedTradeData struct {
AggregateTradeID int64 `json:"a"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
Timestamp int64 `json:"t"`
IsBuyerMaker bool `json:"m"`
AggregateTradeID int64 `json:"a"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
Timestamp types.Time `json:"t"`
IsBuyerMaker bool `json:"m"`
}
// UMarkPrice stores mark price data
@@ -91,99 +91,99 @@ type FundingRateInfoResponse struct {
// FundingRateHistory stores funding rate history
type FundingRateHistory struct {
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate,string"`
FundingTime int64 `json:"fundingTime"`
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate,string"`
FundingTime types.Time `json:"fundingTime"`
}
// U24HrPriceChangeStats stores price change stats data
type U24HrPriceChangeStats struct {
Symbol string `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"firstId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
Symbol string `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime types.Time `json:"openTime"`
CloseTime types.Time `json:"closeTime"`
FirstID int64 `json:"firstId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
}
// USymbolPriceTicker stores symbol price ticker data
type USymbolPriceTicker struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
Time types.Time `json:"time"`
}
// USymbolOrderbookTicker stores symbol orderbook ticker data
type USymbolOrderbookTicker struct {
Symbol string `json:"symbol"`
BidPrice float64 `json:"bidPrice,string"`
BidQty float64 `json:"bidQty,string"`
AskPrice float64 `json:"askPrice,string"`
AskQty float64 `json:"askQty,string"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
BidPrice float64 `json:"bidPrice,string"`
BidQty float64 `json:"bidQty,string"`
AskPrice float64 `json:"askPrice,string"`
AskQty float64 `json:"askQty,string"`
Time types.Time `json:"time"`
}
// ULiquidationOrdersData stores liquidation orders data
type ULiquidationOrdersData struct {
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
AveragePrice float64 `json:"averagePrice,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
Side string `json:"side"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
AveragePrice float64 `json:"averagePrice,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
Side string `json:"side"`
Time types.Time `json:"time"`
}
// UOpenInterestData stores open interest data
type UOpenInterestData struct {
OpenInterest float64 `json:"openInterest,string"`
Symbol string `json:"symbol"`
Time int64 `json:"time"`
OpenInterest float64 `json:"openInterest,string"`
Symbol string `json:"symbol"`
Time types.Time `json:"time"`
}
// UOpenInterestStats stores open interest stats data
type UOpenInterestStats struct {
Symbol string `json:"symbol"`
SumOpenInterest float64 `json:"sumOpenInterest,string"`
SumOpenInterestValue float64 `json:"sumOpenInterestValue,string"`
Timestamp int64 `json:"timestamp"`
Symbol string `json:"symbol"`
SumOpenInterest float64 `json:"sumOpenInterest,string"`
SumOpenInterestValue float64 `json:"sumOpenInterestValue,string"`
Timestamp types.Time `json:"timestamp"`
}
// ULongShortRatio stores top trader accounts' or positions' or global long/short ratio data
type ULongShortRatio struct {
Symbol string `json:"symbol"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongAccount float64 `json:"longAccount,string"`
ShortAccount float64 `json:"shortAccount,string"`
Timestamp int64 `json:"timestamp"`
Symbol string `json:"symbol"`
LongShortRatio float64 `json:"longShortRatio,string"`
LongAccount float64 `json:"longAccount,string"`
ShortAccount float64 `json:"shortAccount,string"`
Timestamp types.Time `json:"timestamp"`
}
// UTakerVolumeData stores volume data on buy/sell side from takers
type UTakerVolumeData struct {
BuySellRatio float64 `json:"buySellRatio,string"`
BuyVol float64 `json:"buyVol,string"`
SellVol float64 `json:"sellVol,string"`
Timestamp int64 `json:"timestamp"`
BuySellRatio float64 `json:"buySellRatio,string"`
BuyVol float64 `json:"buyVol,string"`
SellVol float64 `json:"sellVol,string"`
Timestamp types.Time `json:"timestamp"`
}
// UCompositeIndexInfoData stores composite index data for usdt margined futures
type UCompositeIndexInfoData struct {
Symbol string `json:"symbol"`
Time int64 `json:"time"`
Symbol string `json:"symbol"`
Time types.Time `json:"time"`
BaseAssetList []struct {
BaseAsset string `json:"baseAsset"`
WeightInQuantity float64 `json:"weightInQuantity,string"`
@@ -263,7 +263,7 @@ type UAccountInformationV2Data struct {
CanTrade bool `json:"canTrade"`
CanDeposit bool `json:"canDeposit"`
CanWithdraw bool `json:"canWithdraw"`
UpdateTime int64 `json:"updateTime"`
UpdateTime types.Time `json:"updateTime"`
MultiAssetsMargin bool `json:"multiAssetsMargin"`
TotalInitialMargin float64 `json:"totalInitialMargin,string"`
TotalMaintenanceMargin float64 `json:"totalMaintMargin,string"`
@@ -331,12 +331,12 @@ type UModifyIsolatedPosMargin struct {
// UPositionMarginChangeHistoryData gets position margin change history data
type UPositionMarginChangeHistoryData struct {
Amount float64 `json:"amount,string"`
Asset string `json:"asset"`
Symbol string `json:"symbol"`
Time int64 `json:"time"`
MarginType int64 `json:"type"`
PositionSide string `json:"positionSide"`
Amount float64 `json:"amount,string"`
Asset string `json:"asset"`
Symbol string `json:"symbol"`
Time types.Time `json:"time"`
MarginType int64 `json:"type"`
PositionSide string `json:"positionSide"`
}
// UPositionInformationV2 stores positions data
@@ -360,32 +360,32 @@ type UPositionInformationV2 struct {
// UAccountTradeHistory stores trade data for the users account
type UAccountTradeHistory struct {
Buyer bool `json:"buyer"`
Commission float64 `json:"commission,string"`
CommissionAsset string `json:"commissionAsset"`
ID int64 `json:"id"`
Maker bool `json:"maker"`
OrderID int64 `json:"orderId"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty"`
RealizedPNL float64 `json:"realizedPnl,string"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Symbol string `json:"symbol"`
Time int64 `json:"time"`
Buyer bool `json:"buyer"`
Commission float64 `json:"commission,string"`
CommissionAsset string `json:"commissionAsset"`
ID int64 `json:"id"`
Maker bool `json:"maker"`
OrderID int64 `json:"orderId"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty"`
RealizedPNL float64 `json:"realizedPnl,string"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
Symbol string `json:"symbol"`
Time types.Time `json:"time"`
}
// UAccountIncomeHistory stores income history data
type UAccountIncomeHistory struct {
Symbol string `json:"symbol"`
IncomeType string `json:"incomeType"`
Income float64 `json:"income,string"`
Asset string `json:"asset"`
Info string `json:"info"`
Time int64 `json:"time"`
TranID int64 `json:"tranId"`
TradeID string `json:"tradeId"`
Symbol string `json:"symbol"`
IncomeType string `json:"incomeType"`
Income float64 `json:"income,string"`
Asset string `json:"asset"`
Info string `json:"info"`
Time types.Time `json:"time"`
TranID int64 `json:"tranId"`
TradeID string `json:"tradeId"`
}
// UNotionalLeverageAndBrakcetsData stores notional and leverage brackets data for the account
@@ -413,27 +413,27 @@ type UPositionADLEstimationData struct {
// UForceOrdersData stores liquidation orders data for the account
type UForceOrdersData struct {
OrderID int64 `json:"orderId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
CumQuote float64 `json:"cumQuote,string"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
ReduceOnly bool `json:"reduceOnly"`
ClosePosition bool `json:"closePosition"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
StopPrice float64 `json:"stopPrice,string"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect,string"`
OrigType string `json:"origType"`
Time int64 `json:"time"`
UpdateTime int64 `json:"updateTime"`
OrderID int64 `json:"orderId"`
Symbol string `json:"symbol"`
Status string `json:"status"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
CumQuote float64 `json:"cumQuote,string"`
TimeInForce string `json:"timeInForce"`
OrderType string `json:"type"`
ReduceOnly bool `json:"reduceOnly"`
ClosePosition bool `json:"closePosition"`
Side string `json:"side"`
PositionSide string `json:"positionSide"`
StopPrice float64 `json:"stopPrice,string"`
WorkingType string `json:"workingType"`
PriceProtect bool `json:"priceProtect,string"`
OrigType string `json:"origType"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
}
// UFuturesNewOrderRequest stores order data for placing