exchanges: Types and unmarshalling methods update (#1899)

* Added TimeInForce type and updated related files

* Linter issue fix and minor coinbasepro type update

* Bitrex consts update

* added unit test and minor changes in bittrex

* Unit tests update

* Fix minor linter issues

* Update TestStringToTimeInForce unit test

* fix conflict with gateio timeInForce

* Update order tests

* Complete updating the order unit tests

* update kucoin and deribit wrapper to match the time in force change

* fix time-in-force related test errors

* linter issue fix

* time in force constants, functions and unit tests update

* shift tif policies to TimeInForce

* Update time-in-force, related functions, and unit tests

* fix linter issue and time-in-force processing

* added a good till crossing tif value

* order type fix and fix related tim-in-force entries

* update time-in-force unmarshaling and unit test

* fix time-in-force error in gateio

* linter issue fix

* update based on review comments

* add unit test and fix missing issues

* minor fix and added benchmark unit test

* change GTT to GTC for limit

* fix linter issue

* added time-in-force value to place order param

* fix minor issues based on review comment and move tif code to separate files

* update on exchanges linked to time-in-force

* resolve missing review comments

* minor linter issues fix

* added time-in-force handler and update timeInForce parametered endpoint

* minor fixes based on review

* nits fix

* update based on review

* linter fix

* rm getTimeInForce func and minor change to time-in-force

* minor change

* update based on review comments

* wrappers and time-in-force calling approach

* update slice data processing

* fix linter issues

* remove unnecessary Unmarshal methods and replace type delatration and added unit tests

* minor change

* minor changes to types

* update gateio string to timeInForce conversion and unit test

* removed unused timeInForceString func from kraken

* removed redundant parentheses in slice unmarshaling

* array to slice conversion and other updates

* reverted slice target to array

* Binanceus unit test NotNil check to Len check

* change NotNil to Len check

* rename unmarshal unit test funcs name

* wrap json strings with []byte
This commit is contained in:
Samuael A.
2025-06-02 06:54:49 +03:00
committed by GitHub
parent 8fa6179f65
commit 0e9adcd1e1
28 changed files with 483 additions and 1095 deletions

View File

@@ -150,11 +150,8 @@ var (
// GetServerTime this endpoint returns the exchange server time.
func (bi *Binanceus) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) {
var response ServerTime
return response.Timestamp,
bi.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
serverTime, spotDefaultRate,
&response)
err := bi.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, serverTime, spotDefaultRate, &response)
return response.Timestamp.Time(), err
}
// GetSystemStatus endpoint to fetch whether the system status is normal or under maintenance.
@@ -312,7 +309,7 @@ func (bi *Binanceus) batchAggregateTrades(ctx context.Context, arg *AggregatedTr
if !endTime.IsZero() && endTime.Unix() != 0 {
// get index for truncating to end time
lastIndex = sort.Search(len(additionalTrades), func(i int) bool {
return endTime.Before(additionalTrades[i].TimeStamp)
return endTime.Before(additionalTrades[i].TimeStamp.Time())
})
}
// don't include the first as the request was inclusive from last ATradeID

View File

@@ -1584,14 +1584,14 @@ func TestWebsocketAggTrade(t *testing.T) {
"stream":"btcusdt@aggTrade",
"data": {
"e": "aggTrade",
"E": 123456789,
"s": "BNBBTC",
"E": 1672515782136,
"s": "BNBBTC",
"a": 12345,
"p": "0.001",
"q": "100",
"f": 100,
"l": 105,
"T": 123456785,
"T": 1672515782136,
"m": true,
"M": true
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
"github.com/thrasher-corp/gocryptotrader/types"
)
var (
@@ -42,10 +43,10 @@ const (
// ExchangeInfo holds the full exchange information type
type ExchangeInfo struct {
Code int64 `json:"code"`
Msg string `json:"msg"`
Timezone string `json:"timezone"`
ServerTime time.Time `json:"serverTime"`
Code int64 `json:"code"`
Msg string `json:"msg"`
Timezone string `json:"timezone"`
ServerTime types.Time `json:"serverTime"`
RateLimits []struct {
RateLimitType string `json:"rateLimitType"`
Interval string `json:"interval"`
@@ -95,12 +96,12 @@ type RecentTradeRequestParams struct {
// RecentTrade holds recent trade data
type RecentTrade struct {
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
Time time.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
Time types.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
}
// HistoricalTradeParams represents historical trades request params.
@@ -112,13 +113,13 @@ type HistoricalTradeParams struct {
// HistoricalTrade holds recent trade data
type HistoricalTrade struct {
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
QuoteQuantity float64 `json:"quoteQty,string"`
Time time.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
QuoteQuantity float64 `json:"quoteQty,string"`
Time types.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
}
// AggregatedTradeRequestParams holds request params
@@ -135,14 +136,14 @@ type AggregatedTradeRequestParams struct {
// AggregatedTrade holds aggregated trade information
type AggregatedTrade struct {
ATradeID int64 `json:"a"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
TimeStamp time.Time `json:"T"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
ATradeID 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"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
}
// toTradeData this method converts the AggregatedTrade data into an instance of trade.Data
@@ -153,7 +154,7 @@ func (a *AggregatedTrade) toTradeData(p currency.Pair, exchange string, aType as
Amount: a.Quantity,
Exchange: exchange,
Price: a.Price,
Timestamp: a.TimeStamp,
Timestamp: a.TimeStamp.Time(),
AssetType: aType,
Side: order.AnySide,
}
@@ -238,25 +239,25 @@ type BestPrice struct {
// PriceChangeStats contains statistics for the last 24 hours trade
type PriceChangeStats 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"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,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 time.Time `json:"openTime"`
CloseTime time.Time `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"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,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"`
}
// Response holds basic binance api response data
@@ -267,17 +268,17 @@ type Response struct {
// Account holds the account data
type Account struct {
MakerCommission int64 `json:"makerCommission"`
TakerCommission int64 `json:"takerCommission"`
BuyerCommission int64 `json:"buyerCommission"`
SellerCommission int64 `json:"sellerCommission"`
CanTrade bool `json:"canTrade"`
CanWithdraw bool `json:"canWithdraw"`
CanDeposit bool `json:"canDeposit"`
UpdateTime time.Time `json:"updateTime"`
AccountType string `json:"accountType"`
Balances []Balance `json:"balances"`
Permissions []string `json:"permissions"`
MakerCommission int64 `json:"makerCommission"`
TakerCommission int64 `json:"takerCommission"`
BuyerCommission int64 `json:"buyerCommission"`
SellerCommission int64 `json:"sellerCommission"`
CanTrade bool `json:"canTrade"`
CanWithdraw bool `json:"canWithdraw"`
CanDeposit bool `json:"canDeposit"`
UpdateTime types.Time `json:"updateTime"`
AccountType string `json:"accountType"`
Balances []Balance `json:"balances"`
Permissions []string `json:"permissions"`
}
// Balance holds query order data
@@ -301,7 +302,7 @@ type TradeStatus struct {
PlannedRecoverTime uint64 `json:"plannedRecoverTime"`
TriggerCondition map[string]uint64 `json:"triggerCondition"`
Indicators map[string]TradingStatusIndicatorItem `json:"indicators"`
UpdateTime time.Time `json:"updateTime"`
UpdateTime types.Time `json:"updateTime"`
}
// TradingStatusIndicatorItem represents Trade Status Indication
@@ -344,21 +345,21 @@ type AssetDistributionHistories struct {
// SubAccount holds a single sub account instance in a Binance US account.
// including the email and related information related to it.
type SubAccount struct {
Email string `json:"email"`
Status string `json:"status"`
Activated bool `json:"activated"`
Mobile string `json:"mobile"`
GAuth bool `json:"gAuth"`
CreateTime time.Time `json:"createTime"`
Email string `json:"email"`
Status string `json:"status"`
Activated bool `json:"activated"`
Mobile string `json:"mobile"`
GAuth bool `json:"gAuth"`
CreateTime types.Time `json:"createTime"`
}
// TransferHistory a single asset transfer history between Sub accounts
type TransferHistory struct {
From string `json:"from"`
To string `json:"to"`
Asset string `json:"asset"`
Qty uint64 `json:"qty,string"`
TimeStamp time.Time `json:"time"`
From string `json:"from"`
To string `json:"to"`
Asset string `json:"asset"`
Qty uint64 `json:"qty,string"`
TimeStamp types.Time `json:"time"`
}
// SubAccountTransferRequestParams contains argument variables holder used to transfer an
@@ -421,14 +422,14 @@ type NewOrderRequest struct {
// NewOrderResponse represents trade order's detailed information.
type NewOrderResponse struct {
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
OrderListID int8 `json:"orderListId"`
ClientOrderID string `json:"clientOrderId"`
TransactionTime time.Time `json:"transactTime"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
OrderListID int8 `json:"orderListId"`
ClientOrderID string `json:"clientOrderId"`
TransactionTime types.Time `json:"transactTime"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
// The cumulative amount of the quote that has been spent (with a BUY order) or received (with a SELL order).
CumulativeQuoteQty float64 `json:"cummulativeQuoteQty,string"`
Status string `json:"status"`
@@ -469,17 +470,17 @@ type CommonOrder struct {
// Order struct represents an ordinary order response.
type Order struct {
CommonOrder
IcebergQty float64 `json:"icebergQty,string"`
Time time.Time `json:"time"`
UpdateTime time.Time `json:"updateTime"`
IsWorking bool `json:"isWorking"`
OrigQuoteOrderQty float64 `json:"origQuoteOrderQty,string"`
IcebergQty float64 `json:"icebergQty,string"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
IsWorking bool `json:"isWorking"`
OrigQuoteOrderQty float64 `json:"origQuoteOrderQty,string"`
}
// OCOOrderReportItem this is used by the OCO order creating response
type OCOOrderReportItem struct {
CommonOrder
TransactionTime time.Time `json:"transactionTime"`
TransactionTime types.Time `json:"transactionTime"`
}
// OrderRequestParams this struct will be used to get a
@@ -514,19 +515,19 @@ type GetTradesParams struct {
// Trade this struct represents a trade response.
type Trade struct {
Symbol string `json:"symbol"`
ID uint64 `json:"id"`
OrderID uint64 `json:"orderId"`
OrderListID int64 `json:"orderListId"`
Price float64 `json:"price"`
Qty float64 `json:"qty"`
QuoteQty float64 `json:"quoteQty"`
Commission float64 `json:"commission"`
CommissionAsset float64 `json:"commissionAsset"`
Time time.Time `json:"time"`
IsBuyer bool `json:"isBuyer"`
IsMaker bool `json:"isMaker"`
IsBestMatch bool `json:"isBestMatch"`
Symbol string `json:"symbol"`
ID uint64 `json:"id"`
OrderID uint64 `json:"orderId"`
OrderListID int64 `json:"orderListId"`
Price float64 `json:"price"`
Qty float64 `json:"qty"`
QuoteQty float64 `json:"quoteQty"`
Commission float64 `json:"commission"`
CommissionAsset float64 `json:"commissionAsset"`
Time types.Time `json:"time"`
IsBuyer bool `json:"isBuyer"`
IsMaker bool `json:"isMaker"`
IsBestMatch bool `json:"isBestMatch"`
}
// OCOOrderInputParams One-cancel-the-other order creation input Parameter
@@ -567,7 +568,7 @@ type OCOOrderResponse struct {
ListStatusType string `json:"listStatusType"`
ListOrderStatus string `json:"listOrderStatus"`
ListClientOrderID string `json:"listClientOrderId"`
TransactionTime time.Time `json:"transactionTime"`
TransactionTime types.Time `json:"transactionTime"`
Symbol string `json:"symbol"`
Orders []OrderShortResponse `json:"orders"`
}
@@ -618,33 +619,33 @@ type RequestQuoteParams struct {
// Quote holds quote information for from-to-coin pair
type Quote struct {
Symbol string `json:"symbol"`
Ratio float64 `json:"ratio,string"`
InverseRatio float64 `json:"inverseRatio,string"`
ValidTimestamp time.Time `json:"validTimestamp"`
ToAmount float64 `json:"toAmount,string"`
FromAmount float64 `json:"fromAmount,string"`
Symbol string `json:"symbol"`
Ratio float64 `json:"ratio,string"`
InverseRatio float64 `json:"inverseRatio,string"`
ValidTimestamp types.Time `json:"validTimestamp"`
ToAmount float64 `json:"toAmount,string"`
FromAmount float64 `json:"fromAmount,string"`
}
// OTCTradeOrderResponse holds OTC(over-the-counter) order identification and status information
type OTCTradeOrderResponse struct {
OrderID uint64 `json:"orderId,string"`
OrderStatus string `json:"orderStatus"`
CreateTime time.Time `json:"createTime"`
OrderID uint64 `json:"orderId,string"`
OrderStatus string `json:"orderStatus"`
CreateTime types.Time `json:"createTime"`
}
// OTCTradeOrder holds OTC(over-the-counter) orders response
type OTCTradeOrder struct {
QuoteID string `json:"quoteId"`
OrderID uint64 `json:"orderId,string"`
OrderStatus string `json:"orderStatus"`
FromCoin string `json:"fromCoin"`
FromAmount float64 `json:"fromAmount"`
ToCoin string `json:"toCoin"`
ToAmount float64 `json:"toAmount"`
Ratio float64 `json:"ratio"`
InverseRatio float64 `json:"inverseRatio"`
CreateTime time.Time `json:"createTime"`
QuoteID string `json:"quoteId"`
OrderID uint64 `json:"orderId,string"`
OrderStatus string `json:"orderStatus"`
FromCoin string `json:"fromCoin"`
FromAmount float64 `json:"fromAmount"`
ToCoin string `json:"toCoin"`
ToAmount float64 `json:"toAmount"`
Ratio float64 `json:"ratio"`
InverseRatio float64 `json:"inverseRatio"`
CreateTime types.Time `json:"createTime"`
}
// OTCTradeOrderRequestParams request param for Over-the-Counter trade order params.
@@ -827,7 +828,7 @@ type update struct {
// WebsocketDepthStream is the difference for the update depth stream
type WebsocketDepthStream struct {
Event string `json:"e"`
Timestamp time.Time `json:"E"`
Timestamp types.Time `json:"E"`
Pair string `json:"s"`
FirstUpdateID int64 `json:"U"`
LastUpdateID int64 `json:"u"`
@@ -874,9 +875,9 @@ type WsAccountPositionData struct {
Available float64 `json:"f,string"`
Locked float64 `json:"l,string"`
} `json:"B"`
EventTime time.Time `json:"E"`
LastUpdated time.Time `json:"u"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
LastUpdated types.Time `json:"u"`
EventType string `json:"e"`
}
// wsBalanceUpdate represents the websocket response of update balance.
@@ -887,11 +888,11 @@ type wsBalanceUpdate struct {
// WsBalanceUpdateData defines websocket account balance data.
type WsBalanceUpdateData struct {
EventTime time.Time `json:"E"`
ClearTime time.Time `json:"T"`
BalanceDelta float64 `json:"d,string"`
Asset string `json:"a"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
ClearTime types.Time `json:"T"`
BalanceDelta float64 `json:"d,string"`
Asset string `json:"a"`
EventType string `json:"e"`
}
type wsOrderUpdate struct {
@@ -901,38 +902,38 @@ type wsOrderUpdate struct {
// WsOrderUpdateData defines websocket account order update data
type WsOrderUpdateData struct {
EventType string `json:"e"`
EventTime time.Time `json:"E"`
Symbol string `json:"s"`
ClientOrderID string `json:"c"`
Side string `json:"S"`
OrderType string `json:"o"`
TimeInForce string `json:"f"`
Quantity float64 `json:"q,string"`
Price float64 `json:"p,string"`
StopPrice float64 `json:"P,string"`
IcebergQuantity float64 `json:"F,string"`
OrderListID int64 `json:"g"`
CancelledClientOrderID string `json:"C"`
CurrentExecutionType string `json:"x"`
OrderStatus string `json:"X"`
RejectionReason string `json:"r"`
OrderID int64 `json:"i"`
LastExecutedQuantity float64 `json:"l,string"`
CumulativeFilledQuantity float64 `json:"z,string"`
LastExecutedPrice float64 `json:"L,string"`
Commission float64 `json:"n,string"`
CommissionAsset string `json:"N"`
TransactionTime time.Time `json:"T"`
TradeID int64 `json:"t"`
Ignored int64 `json:"I"` // Must be ignored explicitly, otherwise it overwrites 'i'.
IsOnOrderBook bool `json:"w"`
IsMaker bool `json:"m"`
Ignored2 bool `json:"M"` // See the comment for "I".
OrderCreationTime time.Time `json:"O"`
CumulativeQuoteTransactedQuantity float64 `json:"Z,string"`
LastQuoteAssetTransactedQuantity float64 `json:"Y,string"`
QuoteOrderQuantity float64 `json:"Q,string"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
Symbol string `json:"s"`
ClientOrderID string `json:"c"`
Side string `json:"S"`
OrderType string `json:"o"`
TimeInForce string `json:"f"`
Quantity float64 `json:"q,string"`
Price float64 `json:"p,string"`
StopPrice float64 `json:"P,string"`
IcebergQuantity float64 `json:"F,string"`
OrderListID int64 `json:"g"`
CancelledClientOrderID string `json:"C"`
CurrentExecutionType string `json:"x"`
OrderStatus string `json:"X"`
RejectionReason string `json:"r"`
OrderID int64 `json:"i"`
LastExecutedQuantity float64 `json:"l,string"`
CumulativeFilledQuantity float64 `json:"z,string"`
LastExecutedPrice float64 `json:"L,string"`
Commission float64 `json:"n,string"`
CommissionAsset string `json:"N"`
TransactionTime types.Time `json:"T"`
TradeID int64 `json:"t"`
Ignored int64 `json:"I"` // Must be ignored explicitly, otherwise it overwrites 'i'.
IsOnOrderBook bool `json:"w"`
IsMaker bool `json:"m"`
Ignored2 bool `json:"M"` // See the comment for "I".
OrderCreationTime types.Time `json:"O"`
CumulativeQuoteTransactedQuantity float64 `json:"Z,string"`
LastQuoteAssetTransactedQuantity float64 `json:"Y,string"`
QuoteOrderQuantity float64 `json:"Q,string"`
}
// WsListStatus holder for websocket account listing status response including the stream information
@@ -943,91 +944,91 @@ type WsListStatus struct {
// WsListStatusData holder for websocket account listing status response.
type WsListStatusData struct {
ListClientOrderID string `json:"C"`
EventTime time.Time `json:"E"`
ListOrderStatus string `json:"L"`
ListClientOrderID string `json:"C"`
EventTime types.Time `json:"E"`
ListOrderStatus string `json:"L"`
Orders []struct {
ClientOrderID string `json:"c"`
OrderID int64 `json:"i"`
Symbol string `json:"s"`
} `json:"O"`
TransactionTime time.Time `json:"T"`
ContingencyType string `json:"c"`
EventType string `json:"e"`
OrderListID int64 `json:"g"`
ListStatusType string `json:"l"`
RejectionReason string `json:"r"`
Symbol string `json:"s"`
TransactionTime types.Time `json:"T"`
ContingencyType string `json:"c"`
EventType string `json:"e"`
OrderListID int64 `json:"g"`
ListStatusType string `json:"l"`
RejectionReason string `json:"r"`
Symbol string `json:"s"`
}
// TradeStream holds the trade stream data
type TradeStream struct {
EventType string `json:"e"`
EventTime time.Time `json:"E"`
Symbol string `json:"s"`
TradeID int64 `json:"t"`
Price string `json:"p"`
Quantity string `json:"q"`
BuyerOrderID int64 `json:"b"`
SellerOrderID int64 `json:"a"`
TimeStamp time.Time `json:"T"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
Symbol string `json:"s"`
TradeID int64 `json:"t"`
Price string `json:"p"`
Quantity string `json:"q"`
BuyerOrderID int64 `json:"b"`
SellerOrderID int64 `json:"a"`
TimeStamp types.Time `json:"T"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
}
// KlineStream holds the kline stream data
type KlineStream struct {
EventType string `json:"e"`
EventTime time.Time `json:"E"`
EventTime types.Time `json:"E"`
Symbol string `json:"s"`
Kline KlineStreamData `json:"k"`
}
// KlineStreamData defines kline streaming data
type KlineStreamData struct {
StartTime time.Time `json:"t"`
CloseTime time.Time `json:"T"`
Symbol string `json:"s"`
Interval string `json:"i"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"L"`
OpenPrice float64 `json:"o,string"`
ClosePrice float64 `json:"c,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
Volume float64 `json:"v,string"`
NumberOfTrades int64 `json:"n"`
KlineClosed bool `json:"x"`
Quote float64 `json:"q,string"`
TakerBuyBaseAssetVolume float64 `json:"V,string"`
TakerBuyQuoteAssetVolume float64 `json:"Q,string"`
StartTime types.Time `json:"t"`
CloseTime types.Time `json:"T"`
Symbol string `json:"s"`
Interval string `json:"i"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"L"`
OpenPrice float64 `json:"o,string"`
ClosePrice float64 `json:"c,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
Volume float64 `json:"v,string"`
NumberOfTrades int64 `json:"n"`
KlineClosed bool `json:"x"`
Quote float64 `json:"q,string"`
TakerBuyBaseAssetVolume float64 `json:"V,string"`
TakerBuyQuoteAssetVolume float64 `json:"Q,string"`
}
// TickerStream holds the ticker stream data
type TickerStream struct {
EventType string `json:"e"`
EventTime time.Time `json:"E"`
Symbol string `json:"s"`
PriceChange float64 `json:"p,string"`
PriceChangePercent float64 `json:"P,string"`
WeightedAvgPrice float64 `json:"w,string"`
ClosePrice float64 `json:"x,string"`
LastPrice float64 `json:"c,string"`
LastPriceQuantity float64 `json:"Q,string"`
BestBidPrice float64 `json:"b,string"`
BestBidQuantity float64 `json:"B,string"`
BestAskPrice float64 `json:"a,string"`
BestAskQuantity float64 `json:"A,string"`
OpenPrice float64 `json:"o,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
TotalTradedVolume float64 `json:"v,string"`
TotalTradedQuoteVolume float64 `json:"q,string"`
OpenTime time.Time `json:"O"`
CloseTime time.Time `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
Symbol string `json:"s"`
PriceChange float64 `json:"p,string"`
PriceChangePercent float64 `json:"P,string"`
WeightedAvgPrice float64 `json:"w,string"`
ClosePrice float64 `json:"x,string"`
LastPrice float64 `json:"c,string"`
LastPriceQuantity float64 `json:"Q,string"`
BestBidPrice float64 `json:"b,string"`
BestBidQuantity float64 `json:"B,string"`
BestAskPrice float64 `json:"a,string"`
BestAskQuantity float64 `json:"A,string"`
OpenPrice float64 `json:"o,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
TotalTradedVolume float64 `json:"v,string"`
TotalTradedQuoteVolume float64 `json:"q,string"`
OpenTime types.Time `json:"O"`
CloseTime types.Time `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
}
// OrderBookTickerStream contains websocket orderbook data
@@ -1043,16 +1044,16 @@ type OrderBookTickerStream struct {
// WebsocketAggregateTradeStream aggregate trade streams push data
type WebsocketAggregateTradeStream struct {
EventType string `json:"e"`
EventTime time.Time `json:"E"`
Symbol string `json:"s"`
AggregateTradeID int64 `json:"a"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
TradeTime time.Time `json:"T"`
IsMaker bool `json:"m"`
EventType string `json:"e"`
EventTime types.Time `json:"E"`
Symbol string `json:"s"`
AggregateTradeID int64 `json:"a"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
TradeTime types.Time `json:"T"`
IsMaker bool `json:"m"`
}
// OCBSOrderRequestParams holds parameters to retrieve OCBS orders.
@@ -1071,22 +1072,22 @@ type OCBSTradeOrdersResponse struct {
// OCBSOrder holds OCBS orders details.
type OCBSOrder struct {
QuoteID string `json:"quoteId"`
OrderID string `json:"orderId"`
OrderStatus string `json:"orderStatus"`
FromCoin string `json:"fromCoin"`
FromAmount float64 `json:"fromAmount"`
ToCoin string `json:"toCoin"`
ToAmount float64 `json:"toAmount"`
FeeCoin string `json:"feeCoin"`
FeeAmount float64 `json:"feeAmount"`
Ratio float64 `json:"ratio"`
CreateTime time.Time `json:"createTime"`
QuoteID string `json:"quoteId"`
OrderID string `json:"orderId"`
OrderStatus string `json:"orderStatus"`
FromCoin string `json:"fromCoin"`
FromAmount float64 `json:"fromAmount"`
ToCoin string `json:"toCoin"`
ToAmount float64 `json:"toAmount"`
FeeCoin string `json:"feeCoin"`
FeeAmount float64 `json:"feeAmount"`
Ratio float64 `json:"ratio"`
CreateTime types.Time `json:"createTime"`
}
// ServerTime holds the exchange server time
type ServerTime struct {
Timestamp time.Time `json:"serverTime"`
Timestamp types.Time `json:"serverTime"`
}
// SubUserToBTCAssets holds the number of BTC assets and the corresponding sub user email.
@@ -1104,13 +1105,13 @@ type SpotUSDMasterAccounts struct {
// SubAccountStatus represents single sub accounts status information.
type SubAccountStatus struct {
Email string `json:"email"`
InsertTime time.Time `json:"insertTime"`
Mobile string `json:"mobile"`
IsUserActive bool `json:"isUserActive"`
IsMarginEnabled bool `json:"isMarginEnabled"`
IsSubUserEnabled bool `json:"isSubUserEnabled"`
IsFutureEnabled bool `json:"isFutureEnabled"`
Email string `json:"email"`
InsertTime types.Time `json:"insertTime"`
Mobile string `json:"mobile"`
IsUserActive bool `json:"isUserActive"`
IsMarginEnabled bool `json:"isMarginEnabled"`
IsSubUserEnabled bool `json:"isSubUserEnabled"`
IsFutureEnabled bool `json:"isFutureEnabled"`
}
// SubAccountDepositAddressRequestParams holds query parameters for Sub-account deposit addresses.
@@ -1130,16 +1131,16 @@ type SubAccountDepositAddress struct {
// SubAccountDepositItem holds the sub-account deposit information
type SubAccountDepositItem struct {
Amount string `json:"amount"`
Coin string `json:"coin"`
Network string `json:"network"`
Status int64 `json:"status"`
Address string `json:"address"`
AddressTag string `json:"addressTag"`
TransactionID string `json:"txId"`
InsertTime time.Time `json:"insertTime"`
TransferType int64 `json:"transferType"`
ConfirmTimes string `json:"confirmTimes"`
Amount string `json:"amount"`
Coin string `json:"coin"`
Network string `json:"network"`
Status int64 `json:"status"`
Address string `json:"address"`
AddressTag string `json:"addressTag"`
TransactionID string `json:"txId"`
InsertTime types.Time `json:"insertTime"`
TransferType int64 `json:"transferType"`
ConfirmTimes string `json:"confirmTimes"`
}
// ReferralRewardHistoryResponse holds reward history response
@@ -1150,10 +1151,10 @@ type ReferralRewardHistoryResponse struct {
// ReferralWithdrawalItem holds reward history item
type ReferralWithdrawalItem struct {
UserID int64 `json:"userId"`
RewardAmount string `json:"rewardAmount"`
ReceiveDateTime time.Time `json:"receiveDateTime"`
RewardType string `json:"rewardType"`
UserID int64 `json:"userId"`
RewardAmount string `json:"rewardAmount"`
ReceiveDateTime types.Time `json:"receiveDateTime"`
RewardType string `json:"rewardType"`
}
// SpotAssetsSnapshotResponse represents spot asset types snapshot information.

View File

@@ -272,8 +272,8 @@ func (bi *Binanceus) wsHandleData(respRaw []byte) error {
Side: orderSide,
Status: orderStatus,
AssetType: assetType,
Date: data.Data.OrderCreationTime,
LastUpdated: data.Data.TransactionTime,
Date: data.Data.OrderCreationTime.Time(),
LastUpdated: data.Data.TransactionTime.Time(),
Pair: pair,
}
return nil
@@ -348,7 +348,7 @@ func (bi *Binanceus) wsHandleData(respRaw []byte) error {
return bi.Websocket.Trade.Update(saveTradeData,
trade.Data{
CurrencyPair: pair,
Timestamp: t.TimeStamp,
Timestamp: t.TimeStamp.Time(),
Price: price,
Amount: amount,
Exchange: bi.Name,
@@ -380,7 +380,7 @@ func (bi *Binanceus) wsHandleData(respRaw []byte) error {
Bid: t.BestBidPrice,
Ask: t.BestAskPrice,
Last: t.LastPrice,
LastUpdated: t.EventTime,
LastUpdated: t.EventTime.Time(),
AssetType: asset.Spot,
Pair: pair,
}
@@ -401,12 +401,12 @@ func (bi *Binanceus) wsHandleData(respRaw []byte) error {
}
bi.Websocket.DataHandler <- websocket.KlineData{
Timestamp: kline.EventTime,
Timestamp: kline.EventTime.Time(),
Pair: pair,
AssetType: asset.Spot,
Exchange: bi.Name,
StartTime: kline.Kline.StartTime,
CloseTime: kline.Kline.CloseTime,
StartTime: kline.Kline.StartTime.Time(),
CloseTime: kline.Kline.CloseTime.Time(),
Interval: kline.Kline.Interval,
OpenPrice: kline.Kline.OpenPrice,
ClosePrice: kline.Kline.ClosePrice,
@@ -705,7 +705,7 @@ func (bi *Binanceus) ProcessUpdate(cp currency.Pair, a asset.Item, ws *Websocket
Asks: updateAsk,
Pair: cp,
UpdateID: ws.LastUpdateID,
UpdateTime: ws.Timestamp,
UpdateTime: ws.Timestamp.Time(),
Asset: a,
})
}

View File

@@ -447,7 +447,7 @@ func (bi *Binanceus) GetRecentTrades(ctx context.Context, p currency.Pair, asset
CurrencyPair: p,
Price: tradeData[i].Price,
Amount: tradeData[i].Quantity,
Timestamp: tradeData[i].Time,
Timestamp: tradeData[i].Time.Time(),
}
}
@@ -664,8 +664,8 @@ func (bi *Binanceus) GetOrderInfo(ctx context.Context, orderID string, pair curr
Status: status,
Price: resp.Price,
ExecutedAmount: resp.ExecutedQty,
Date: resp.Time,
LastUpdated: resp.UpdateTime,
Date: resp.Time.Time(),
LastUpdated: resp.UpdateTime.Time(),
}, nil
}
@@ -763,7 +763,7 @@ func (bi *Binanceus) GetActiveOrders(ctx context.Context, getOrdersRequest *orde
}
orders[x] = order.Detail{
Amount: resp[x].OrigQty,
Date: resp[x].Time,
Date: resp[x].Time.Time(),
Exchange: bi.Name,
OrderID: strconv.FormatUint(resp[x].OrderID, 10),
ClientOrderID: resp[x].ClientOrderID,
@@ -773,7 +773,7 @@ func (bi *Binanceus) GetActiveOrders(ctx context.Context, getOrdersRequest *orde
Status: orderStatus,
Pair: getOrdersRequest.Pairs[0],
AssetType: getOrdersRequest.AssetType,
LastUpdated: resp[x].UpdateTime,
LastUpdated: resp[x].UpdateTime.Time(),
}
}
return getOrdersRequest.Filter(bi.Name, orders), nil

View File

@@ -1,602 +0,0 @@
package binanceus
import (
"time"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/types"
)
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *RecentTrade) UnmarshalJSON(data []byte) error {
type Alias RecentTrade
chil := &struct {
Time int64 `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Time > 0 {
a.Time = time.UnixMilli(chil.Time)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *HistoricalTrade) UnmarshalJSON(data []byte) error {
type Alias HistoricalTrade
chil := &struct {
Time int64 `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Time > 0 {
a.Time = time.UnixMilli(chil.Time)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *AggregatedTrade) UnmarshalJSON(data []byte) error {
type Alias AggregatedTrade
chil := &struct {
TimeStamp int64 `json:"T"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.TimeStamp > 0 {
a.TimeStamp = time.UnixMilli(chil.TimeStamp)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *PriceChangeStats) UnmarshalJSON(data []byte) error {
type Alias PriceChangeStats
chil := &struct {
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.OpenTime > 0 {
a.OpenTime = time.UnixMilli(chil.OpenTime)
}
if chil.CloseTime > 0 {
a.CloseTime = time.UnixMilli(chil.CloseTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *TradeStatus) UnmarshalJSON(data []byte) error {
type Alias TradeStatus
chil := &struct {
UpdateTime int64 `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.UpdateTime > 0 {
a.UpdateTime = time.UnixMilli(chil.UpdateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *SubAccount) UnmarshalJSON(data []byte) error {
type Alias SubAccount
chil := &struct {
CreateTime int64 `json:"createTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.CreateTime > 0 {
a.CreateTime = time.UnixMilli(chil.CreateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *Account) UnmarshalJSON(data []byte) error {
type Alias Account
chil := &struct {
UpdateTime int64 `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.UpdateTime > 0 {
a.UpdateTime = time.UnixMilli(chil.UpdateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
type Alias NewOrderResponse
aux := &struct {
TransactionTime types.Time `json:"transactTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux != nil {
a.TransactionTime = aux.TransactionTime.Time()
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *TransferHistory) UnmarshalJSON(data []byte) error {
type Alias TransferHistory
aux := &struct {
TimeStamp int64 `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
if aux.TimeStamp > 0 {
a.TimeStamp = time.UnixMilli(aux.TimeStamp)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the server Time timestamp
func (a *ExchangeInfo) UnmarshalJSON(data []byte) error {
type Alias ExchangeInfo
chil := &struct {
Servertime int64 `json:"serverTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Servertime > 0 {
a.ServerTime = time.UnixMilli(chil.Servertime)
}
return nil
}
// UnmarshalJSON deserialises the JSON infos, including the order time and update time timestamps
func (a *Order) UnmarshalJSON(data []byte) error {
type Alias Order
chil := &struct {
Time int64 `json:"time"`
UpdateTime int64 `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Time > 0 {
a.Time = time.UnixMilli(chil.Time)
}
if chil.UpdateTime > 0 {
a.UpdateTime = time.UnixMilli(chil.UpdateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *Trade) UnmarshalJSON(data []byte) error {
type Alie Trade
chil := &struct {
Time int64 `json:"time"`
*Alie
}{
Alie: (*Alie)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Time > 0 {
a.Time = time.UnixMilli(chil.Time)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the ( TransactionTime )timestamp
func (a *OCOOrderReportItem) UnmarshalJSON(data []byte) error {
type Alias OCOOrderReportItem
chil := &struct {
*Alias
TransactionTime int64 `json:"transactionTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.TransactionTime > 0 {
a.TransactionTime = time.UnixMilli(chil.TransactionTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (TransactioTime) timestamp
func (a *OCOOrderResponse) UnmarshalJSON(data []byte) error {
type Alias OCOOrderResponse
chil := &struct {
*Alias
TransactionTime int64 `json:"transactionTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.TransactionTime > 0 {
a.TransactionTime = time.UnixMilli(chil.TransactionTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (Create Time) timestamp
func (a *OTCTradeOrderResponse) UnmarshalJSON(data []byte) error {
type Alias OTCTradeOrderResponse
chil := &struct {
CreateTime int64 `json:"createTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.CreateTime > 0 {
a.CreateTime = time.UnixMilli(chil.CreateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (Create Time) timestamp
func (a *OTCTradeOrder) UnmarshalJSON(data []byte) error {
type Alias OTCTradeOrder
chil := &struct {
CreateTime int64 `json:"createTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.CreateTime > 0 {
a.CreateTime = time.UnixMilli(chil.CreateTime)
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (EventTime , and TransactionTime) timestamp
func (a *WsListStatus) UnmarshalJSON(data []byte) error {
type Alias WsListStatus
aux := &struct {
Data struct {
EventTime types.Time `json:"E"`
TransactionTime types.Time `json:"T"`
*WsListStatusData
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data = *aux.Data.WsListStatusData
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.TransactionTime = aux.Data.TransactionTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including (EventTime , OpenTime, and TransactionTime) timestamp
func (a *TickerStream) UnmarshalJSON(data []byte) error {
type Alias TickerStream
aux := &struct {
EventTime types.Time `json:"E"`
OpenTime types.Time `json:"O"`
CloseTime types.Time `json:"C"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.EventTime = aux.EventTime.Time()
a.OpenTime = aux.OpenTime.Time()
a.CloseTime = aux.CloseTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *KlineStream) UnmarshalJSON(data []byte) error {
type Alias KlineStream
aux := &struct {
EventTime types.Time `json:"E"`
Kline struct {
StartTime types.Time `json:"t"`
CloseTime types.Time `json:"T"`
*KlineStreamData
} `json:"k"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Kline = *aux.Kline.KlineStreamData
a.EventTime = aux.EventTime.Time()
a.Kline.StartTime = aux.Kline.StartTime.Time()
a.Kline.CloseTime = aux.Kline.CloseTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (Timestamp and EventTime) timestamp
func (a *TradeStream) UnmarshalJSON(data []byte) error {
type Alias TradeStream
aux := &struct {
TimeStamp types.Time `json:"T"`
EventTime types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.TimeStamp = aux.TimeStamp.Time()
a.EventTime = aux.EventTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (EventTime, OrderCreationTime, and TransactionTime)timestamp
func (a *wsOrderUpdate) UnmarshalJSON(data []byte) error {
type Alias wsOrderUpdate
aux := &struct {
Data struct {
EventTime types.Time `json:"E"`
OrderCreationTime types.Time `json:"O"`
TransactionTime types.Time `json:"T"`
*WsOrderUpdateData
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data = *aux.Data.WsOrderUpdateData
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.OrderCreationTime = aux.Data.OrderCreationTime.Time()
a.Data.TransactionTime = aux.Data.TransactionTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (EventTime and ClearTime) timestamp
func (a *wsBalanceUpdate) UnmarshalJSON(data []byte) error {
type Alias wsBalanceUpdate
aux := &struct {
Data struct {
EventTime types.Time `json:"E"`
ClearTime types.Time `json:"T"`
*WsBalanceUpdateData
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data = *aux.Data.WsBalanceUpdateData
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.ClearTime = aux.Data.ClearTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (EventTime and LastUpdated) timestamp
func (a *wsAccountPosition) UnmarshalJSON(data []byte) error {
type Alias wsAccountPosition
aux := &struct {
Data struct {
EventTime types.Time `json:"E"`
LastUpdated types.Time `json:"u"`
*WsAccountPositionData
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data = *aux.Data.WsAccountPositionData
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.LastUpdated = aux.Data.LastUpdated.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the (Timestamp)timestamp
func (a *WebsocketDepthStream) UnmarshalJSON(data []byte) error {
type Alias WebsocketDepthStream
aux := &struct {
Timestamp types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Timestamp = aux.Timestamp.Time()
return nil
}
// UnmarshalJSON .. .
func (a *WebsocketAggregateTradeStream) UnmarshalJSON(data []byte) error {
type Alias WebsocketAggregateTradeStream
chil := &struct {
*Alias
TradeTime int64 `json:"T"`
EventTime int64 `json:"E"`
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, chil); err != nil {
return err
}
if chil.TradeTime > 0 {
a.TradeTime = time.UnixMilli(chil.TradeTime)
}
if chil.EventTime > 0 {
a.EventTime = time.UnixMilli(chil.EventTime)
}
return nil
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *OCBSOrder) UnmarshalJSON(data []byte) error {
type Alias OCBSOrder
chil := &struct {
*Alias
CreateTime int64 `json:"createTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.CreateTime > 0 {
a.CreateTime = time.UnixMilli(chil.CreateTime)
}
return nil
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *ServerTime) UnmarshalJSON(data []byte) error {
type Alias ServerTime
chil := &struct {
*Alias
Timestamp int64 `json:"serverTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.Timestamp > 0 {
a.Timestamp = time.UnixMilli(chil.Timestamp)
}
return nil
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *SubAccountStatus) UnmarshalJSON(data []byte) error {
type Alias SubAccountStatus
chil := &struct {
*Alias
InsertTime int64 `json:"insertTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.InsertTime > 0 {
a.InsertTime = time.UnixMilli(chil.InsertTime)
}
return nil
}
// UnmarshalJSON deserialises ValidTimestamp timestamp to built in time.Time instance.
func (a *Quote) UnmarshalJSON(data []byte) error {
type Alias Quote
chil := &struct {
*Alias
ValidTimestamp int64 `json:"validTimestamp"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.ValidTimestamp > 0 {
a.ValidTimestamp = time.UnixMilli(chil.ValidTimestamp)
}
return nil
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *SubAccountDepositItem) UnmarshalJSON(data []byte) error {
type Alias SubAccountDepositItem
chil := &struct {
*Alias
InsertTime int64 `json:"insertTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.InsertTime > 0 {
a.InsertTime = time.UnixMilli(chil.InsertTime)
}
return nil
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *ReferralWithdrawalItem) UnmarshalJSON(data []byte) error {
type Alias ReferralWithdrawalItem
chil := &struct {
*Alias
ReceiveDateTime int64 `json:"receiveDateTime"`
}{
Alias: (*Alias)(a),
}
if er := json.Unmarshal(data, chil); er != nil {
return er
}
if chil.ReceiveDateTime > 0 {
a.ReceiveDateTime = time.UnixMilli(chil.ReceiveDateTime)
}
return nil
}

View File

@@ -3497,14 +3497,14 @@ func TestFetchTradablePairs(t *testing.T) {
func TestDeltaUpdateOrderbook(t *testing.T) {
t.Parallel()
data := `{"topic":"orderbook.50.WEMIXUSDT","ts":1697573183768,"type":"snapshot","data":{"s":"WEMIXUSDT","b":[["0.9511","260.703"],["0.9677","0"]],"a":[],"u":3119516,"seq":14126848493},"cts":1728966699481}`
err := b.wsHandleData(asset.Spot, []byte(data))
data := []byte(`{"topic":"orderbook.50.WEMIXUSDT","ts":1697573183768,"type":"snapshot","data":{"s":"WEMIXUSDT","b":[["0.9511","260.703"],["0.9677","0"]],"a":[],"u":3119516,"seq":14126848493},"cts":1728966699481}`)
err := b.wsHandleData(asset.Spot, data)
if err != nil {
t.Fatal(err)
}
update := `{"topic":"orderbook.50.WEMIXUSDT","ts":1697573183768,"type":"delta","data":{"s":"WEMIXUSDT","b":[["0.9511","260.703"],["0.9677","0"]],"a":[],"u":3119516,"seq":14126848493},"cts":1728966699481}`
update := []byte(`{"topic":"orderbook.50.WEMIXUSDT","ts":1697573183768,"type":"delta","data":{"s":"WEMIXUSDT","b":[["0.9511","260.703"],["0.9677","0"]],"a":[],"u":3119516,"seq":14126848493},"cts":1728966699481}`)
var wsResponse WebsocketResponse
err = json.Unmarshal([]byte(update), &wsResponse)
err = json.Unmarshal(update, &wsResponse)
if err != nil {
t.Fatal(err)
}

View File

@@ -233,27 +233,11 @@ func (c *CoinbasePro) GetHistoricRates(ctx context.Context, currencyPair, start,
values.Set("granularity", strconv.FormatInt(granularity, 10))
}
var resp [][6]float64
var resp []History
path := common.EncodeURLValues(
fmt.Sprintf("%s/%s/%s", coinbaseproProducts, currencyPair, coinbaseproHistory),
values)
if err := c.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp); err != nil {
return nil, err
}
history := make([]History, len(resp))
for x := range resp {
history[x] = History{
Time: time.Unix(int64(resp[x][0]), 0),
Low: resp[x][1],
High: resp[x][2],
Open: resp[x][3],
Close: resp[x][4],
Volume: resp[x][5],
}
}
return history, nil
return resp, c.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
}
// GetStats returns a 24 hr stat for the product. Volume is in base currency

View File

@@ -13,6 +13,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
@@ -23,6 +24,7 @@ import (
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
"github.com/thrasher-corp/gocryptotrader/portfolio/banking"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
"github.com/thrasher-corp/gocryptotrader/types"
)
var (
@@ -74,6 +76,30 @@ func TestGetTrades(t *testing.T) {
}
}
func TestHistoryUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[[1746649200,96269.22,96307.18,96275.58,96307.18,1.85952049],[1746649140,96256.39,96297.31,96296,96273.29,3.41045323],[1746649080,96256.01,96365.73,96365.73,96299.99,3.56073877]]`)
var resp []History
err := json.Unmarshal(data, &resp)
require.NoError(t, err)
require.Len(t, resp, 3)
assert.Equal(t, History{
Time: types.Time(time.Unix(1746649200, 0)),
Low: 96269.22,
High: 96307.18,
Open: 96275.58,
Close: 96307.18,
Volume: 1.85952049,
}, resp[0])
}
func TestGetHistoricRates(t *testing.T) {
t.Parallel()
result, err := c.GetHistoricRates(t.Context(), "BTC-USD", "", "", 0)
require.NoError(t, err)
assert.NotNil(t, result)
}
func TestGetHistoricRatesGranularityCheck(t *testing.T) {
end := time.Now()
start := end.Add(-time.Hour * 2)

View File

@@ -4,6 +4,8 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Product holds product information
@@ -49,7 +51,7 @@ type Trade struct {
// History holds historic rate information
type History struct {
Time time.Time
Time types.Time
Low float64
High float64
Open float64
@@ -57,6 +59,11 @@ type History struct {
Volume float64
}
// UnmarshalJSON deserilizes kline data from a JSON array into History fields.
func (h *History) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &[6]any{&h.Time, &h.Low, &h.High, &h.Open, &h.Close, &h.Volume})
}
// Stats holds last 24 hr data for coinbasepro
type Stats struct {
Open float64 `json:"open,string"`

View File

@@ -788,7 +788,7 @@ func (c *CoinbasePro) GetHistoricCandles(ctx context.Context, pair currency.Pair
timeSeries := make([]kline.Candle, len(history))
for x := range history {
timeSeries[x] = kline.Candle{
Time: history[x].Time,
Time: history[x].Time.Time(),
Low: history[x].Low,
High: history[x].High,
Open: history[x].Open,
@@ -820,7 +820,7 @@ func (c *CoinbasePro) GetHistoricCandlesExtended(ctx context.Context, pair curre
for i := range history {
timeSeries = append(timeSeries, kline.Candle{
Time: history[i].Time,
Time: history[i].Time.Time(),
Low: history[i].Low,
High: history[i].High,
Open: history[i].Open,

View File

@@ -289,28 +289,8 @@ func (d *Deribit) GetHistoricalVolatility(ctx context.Context, ccy currency.Code
}
params := url.Values{}
params.Set("currency", ccy.String())
var data [][2]any
err := d.SendHTTPRequest(ctx, exchange.RestFutures, nonMatchingEPL,
common.EncodeURLValues(getHistoricalVolatility, params), &data)
if err != nil {
return nil, err
}
resp := make([]HistoricalVolatilityData, len(data))
for x := range data {
timeData, ok := data[x][0].(float64)
if !ok {
return resp, common.GetTypeAssertError("float64", data[x][0], "time data")
}
val, ok := data[x][1].(float64)
if !ok {
return resp, common.GetTypeAssertError("float64", data[x][1], "volatility value")
}
resp[x] = HistoricalVolatilityData{
Timestamp: timeData,
Value: val,
}
}
return resp, nil
var data []HistoricalVolatilityData
return data, d.SendHTTPRequest(ctx, exchange.RestFutures, nonMatchingEPL, common.EncodeURLValues(getHistoricalVolatility, params), &data)
}
// GetCurrencyIndexPrice retrieves the current index price for the instruments, for the selected currency.

View File

@@ -29,6 +29,7 @@ import (
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Please supply your own keys here to do authenticated endpoint testing
@@ -246,6 +247,8 @@ func TestGetMarkPriceHistory(t *testing.T) {
var resp []MarkPriceHistory
err := json.Unmarshal([]byte(`[[1608142381229,0.5165791606037885],[1608142380231,0.5165737855432504],[1608142379227,0.5165768236356326]]`), &resp)
require.NoError(t, err)
assert.Len(t, resp, 3)
_, err = d.GetMarkPriceHistory(t.Context(), "", time.Now().Add(-5*time.Minute), time.Now())
require.ErrorIs(t, err, errInvalidInstrumentName)
@@ -457,6 +460,19 @@ func TestWSRetrieveFundingRateValue(t *testing.T) {
assert.NotNil(t, result)
}
func TestHistoricalVolatilityDataUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[[1746532800000,33.926694663144644],[1746536400000,33.86888345738641],[1746540000000,33.87689653120242],[1746543600000,33.92229949556179],[1746547200000,33.35430439982866],[1746550800000,33.405720857822644],[1746554400000,33.041661194903895],[1746558000000,33.026907604467596],[1746561600000,33.147012362654635],[1746565200000,32.948314953334105],[1746568800000,32.97264616801311],[1746572400000,32.97051874896058],[1746576000000,33.94405253940284],[1746579600000,34.01745935786804],[1746583200000,34.133772136604854],[1746586800000,33.89032454069847],[1746590400000,34.008502172420556],[1746594000000,34.01444591222428],[1746597600000,34.01154352323321],[1746601200000,33.97800061398224],[1746604800000,33.980501315033024]]`)
var targets []HistoricalVolatilityData
err := json.Unmarshal(data, &targets)
require.NoError(t, err)
require.Len(t, targets, 21)
assert.Equal(t, HistoricalVolatilityData{
Timestamp: types.Time(time.UnixMilli(1746532800000)),
Value: 33.926694663144644,
}, targets[0])
}
func TestGetHistoricalVolatility(t *testing.T) {
t.Parallel()
_, err := d.GetHistoricalVolatility(t.Context(), currency.EMPTYCODE)

View File

@@ -165,8 +165,13 @@ type FundingRateHistory struct {
// HistoricalVolatilityData stores volatility data for requested symbols
type HistoricalVolatilityData struct {
Timestamp float64
Value float64
Timestamp types.Time
Value types.Number
}
// UnmarshalJSON parses volatility data from a JSON array into HistoricalVolatilityData fields.
func (h *HistoricalVolatilityData) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &[2]any{&h.Timestamp, &h.Value})
}
// IndexPrice holds index price for the instruments
@@ -266,14 +271,7 @@ type MarkPriceHistory struct {
// UnmarshalJSON deserialises the JSON info, including the timestamp.
func (a *MarkPriceHistory) UnmarshalJSON(data []byte) error {
var resp [2]float64
err := json.Unmarshal(data, &resp)
if err != nil {
return err
}
a.Timestamp = types.Time(time.UnixMilli(int64(resp[0])))
a.MarkPriceValue = resp[1]
return nil
return json.Unmarshal(data, &[2]any{&a.Timestamp, &a.MarkPriceValue})
}
// Orderbook stores orderbook data

View File

@@ -160,27 +160,8 @@ func (d *Deribit) WSRetrieveHistoricalVolatility(ccy currency.Code) ([]Historica
}{
Currency: ccy,
}
var data [][2]any
err := d.SendWSRequest(nonMatchingEPL, getHistoricalVolatility, input, &data, false)
if err != nil {
return nil, err
}
resp := make([]HistoricalVolatilityData, len(data))
for x := range data {
timeData, ok := data[x][0].(float64)
if !ok {
return resp, common.GetTypeAssertError("float64", data[x][0], "time data")
}
val, ok := data[x][1].(float64)
if !ok {
return resp, common.GetTypeAssertError("float64", data[x][1], "volatility value")
}
resp[x] = HistoricalVolatilityData{
Timestamp: timeData,
Value: val,
}
}
return resp, nil
var data []HistoricalVolatilityData
return data, d.SendWSRequest(nonMatchingEPL, getHistoricalVolatility, input, &data, false)
}
// WSRetrieveCurrencyIndexPrice the current index price for the instruments, for the selected currency through the websocket connection.

View File

@@ -471,55 +471,8 @@ func (g *Gateio) GetCandlesticks(ctx context.Context, currencyPair currency.Pair
if !to.IsZero() {
params.Set("to", strconv.FormatInt(to.Unix(), 10))
}
var candles [][7]string
err = g.SendHTTPRequest(ctx, exchange.RestSpot, publicCandleStickSpotEPL, common.EncodeURLValues(gateioSpotCandlesticks, params), &candles)
if err != nil {
return nil, err
}
if len(candles) == 0 {
return nil, fmt.Errorf("no candlesticks available for instrument %v", currencyPair)
}
candlesticks := make([]Candlestick, len(candles))
for x := range candles {
timestamp, err := strconv.ParseInt(candles[x][0], 10, 64)
if err != nil {
return nil, err
}
quoteTradingVolume, err := strconv.ParseFloat(candles[x][1], 64)
if err != nil {
return nil, err
}
closePrice, err := strconv.ParseFloat(candles[x][2], 64)
if err != nil {
return nil, err
}
highestPrice, err := strconv.ParseFloat(candles[x][3], 64)
if err != nil {
return nil, err
}
lowestPrice, err := strconv.ParseFloat(candles[x][4], 64)
if err != nil {
return nil, err
}
openPrice, err := strconv.ParseFloat(candles[x][5], 64)
if err != nil {
return nil, err
}
baseCurrencyAmount, err := strconv.ParseFloat(candles[x][6], 64)
if err != nil {
return nil, err
}
candlesticks[x] = Candlestick{
Timestamp: time.Unix(timestamp, 0),
QuoteCcyVolume: quoteTradingVolume,
ClosePrice: closePrice,
HighestPrice: highestPrice,
LowestPrice: lowestPrice,
OpenPrice: openPrice,
BaseCcyAmount: baseCurrencyAmount,
}
}
return candlesticks, nil
var candles []Candlestick
return candles, g.SendHTTPRequest(ctx, exchange.RestSpot, publicCandleStickSpotEPL, common.EncodeURLValues(gateioSpotCandlesticks, params), &candles)
}
// GetTradingFeeRatio retrieves user trading fee rates

View File

@@ -191,6 +191,25 @@ func TestGetMarketTrades(t *testing.T) {
}
}
func TestCandlestickUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[["1738108800","229534412.73508700","103734.3","104779.9","101336.6","101343.8","2232.94510000","true"],["1738195200","178316032.62306100","104718.6","106467.1","103286.4","103734.4","1695.00787000","true"],["1738281600","231315376.16747100","102431","106042.7","101555.9","104718.6","2228.03609000","true"]]`)
var targets []Candlestick
err := json.Unmarshal(data, &targets)
require.NoError(t, err)
require.Len(t, targets, 3)
assert.Equal(t, Candlestick{
Timestamp: types.Time(time.Unix(1738108800, 0)),
QuoteCcyVolume: 229534412.73508700,
ClosePrice: 103734.3,
HighestPrice: 104779.9,
LowestPrice: 101336.6,
OpenPrice: 101343.8,
BaseCcyAmount: 2232.94510000,
WindowClosed: true,
}, targets[0])
}
func TestGetCandlesticks(t *testing.T) {
t.Parallel()
if _, err := g.GetCandlesticks(t.Context(), getPair(t, asset.Spot), 0, time.Time{}, time.Time{}, kline.OneDay); err != nil {

View File

@@ -598,13 +598,25 @@ type Trade struct {
// Candlestick represents candlestick data point detail.
type Candlestick struct {
Timestamp time.Time
QuoteCcyVolume float64
ClosePrice float64
HighestPrice float64
LowestPrice float64
OpenPrice float64
BaseCcyAmount float64
Timestamp types.Time
QuoteCcyVolume types.Number
ClosePrice types.Number
HighestPrice types.Number
LowestPrice types.Number
OpenPrice types.Number
BaseCcyAmount types.Number
WindowClosed bool
}
// UnmarshalJSON parses kline data from a JSON array into Candlestick fields.
func (c *Candlestick) UnmarshalJSON(data []byte) error {
var windowClosed string
err := json.Unmarshal(data, &[8]any{&c.Timestamp, &c.QuoteCcyVolume, &c.ClosePrice, &c.HighestPrice, &c.LowestPrice, &c.OpenPrice, &c.BaseCcyAmount, &windowClosed})
if err != nil {
return err
}
c.WindowClosed, err = strconv.ParseBool(windowClosed)
return err
}
// CurrencyChain currency chain detail.

View File

@@ -1691,12 +1691,12 @@ func (g *Gateio) GetHistoricCandles(ctx context.Context, pair currency.Pair, a a
listCandlesticks = make([]kline.Candle, len(candles))
for i := range candles {
listCandlesticks[i] = kline.Candle{
Time: candles[i].Timestamp,
Open: candles[i].OpenPrice,
High: candles[i].HighestPrice,
Low: candles[i].LowestPrice,
Close: candles[i].ClosePrice,
Volume: candles[i].QuoteCcyVolume,
Time: candles[i].Timestamp.Time(),
Open: candles[i].OpenPrice.Float64(),
High: candles[i].HighestPrice.Float64(),
Low: candles[i].LowestPrice.Float64(),
Close: candles[i].ClosePrice.Float64(),
Volume: candles[i].BaseCcyAmount.Float64(),
}
}
case asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.DeliveryFutures:
@@ -1746,12 +1746,12 @@ func (g *Gateio) GetHistoricCandlesExtended(ctx context.Context, pair currency.P
}
for j := range candles {
candlestickItems = append(candlestickItems, kline.Candle{
Time: candles[j].Timestamp,
Open: candles[j].OpenPrice,
High: candles[j].HighestPrice,
Low: candles[j].LowestPrice,
Close: candles[j].ClosePrice,
Volume: candles[j].QuoteCcyVolume,
Time: candles[j].Timestamp.Time(),
Open: candles[j].OpenPrice.Float64(),
High: candles[j].HighestPrice.Float64(),
Low: candles[j].LowestPrice.Float64(),
Close: candles[j].ClosePrice.Float64(),
Volume: candles[j].QuoteCcyVolume.Float64(),
})
}
case asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.DeliveryFutures:

View File

@@ -200,22 +200,8 @@ func (ku *Kucoin) GetKlines(ctx context.Context, symbol, period string, start, e
if !end.IsZero() {
params.Set("endAt", strconv.FormatInt(end.Unix(), 10))
}
var resp [][7]types.Number
err := ku.SendHTTPRequest(ctx, exchange.RestSpot, klinesEPL, common.EncodeURLValues("/v1/market/candles", params), &resp)
if err != nil {
return nil, err
}
klines := make([]Kline, len(resp))
for i := range resp {
klines[i].StartTime = time.Unix(resp[i][0].Int64(), 0)
klines[i].Open = resp[i][1].Float64()
klines[i].Close = resp[i][2].Float64()
klines[i].High = resp[i][3].Float64()
klines[i].Low = resp[i][4].Float64()
klines[i].Volume = resp[i][5].Float64()
klines[i].Amount = resp[i][6].Float64()
}
return klines, nil
var resp []Kline
return resp, ku.SendHTTPRequest(ctx, exchange.RestSpot, klinesEPL, common.EncodeURLValues("/v1/market/candles", params), &resp)
}
// GetCurrenciesV3 the V3 of retrieving list of currencies

View File

@@ -322,23 +322,8 @@ func (ku *Kucoin) GetFuturesKline(ctx context.Context, granularity int64, symbol
if !to.IsZero() {
params.Set("to", strconv.FormatInt(to.UnixMilli(), 10))
}
var resp [][6]float64
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresKlineEPL, common.EncodeURLValues("/v1/kline/query", params), &resp)
if err != nil {
return nil, err
}
kline := make([]FuturesKline, len(resp))
for i := range resp {
kline[i] = FuturesKline{
StartTime: time.UnixMilli(int64(resp[i][0])),
Open: resp[i][1],
High: resp[i][2],
Low: resp[i][3],
Close: resp[i][4],
Volume: resp[i][5],
}
}
return kline, nil
var resp []FuturesKline
return resp, ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresKlineEPL, common.EncodeURLValues("/v1/kline/query", params), &resp)
}
// PostFuturesOrder used to place two types of futures orders: limit and market

View File

@@ -1,8 +1,7 @@
package kucoin
import (
"time"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/types"
)
@@ -147,7 +146,7 @@ type FundingHistoryItem struct {
// FuturesKline stores kline data
type FuturesKline struct {
StartTime time.Time
StartTime types.Time
Open float64
Close float64
High float64
@@ -155,6 +154,11 @@ type FuturesKline struct {
Volume float64
}
// UnmarshalJSON parses kline data from a JSON array into FuturesKline fields.
func (f *FuturesKline) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &[6]any{&f.StartTime, &f.Open, &f.High, &f.Low, &f.Close, &f.Volume})
}
// FutureOrdersResponse represents a future order response list detail
type FutureOrdersResponse struct {
CurrentPage int64 `json:"currentPage"`

View File

@@ -33,6 +33,7 @@ import (
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Please supply your own keys here to do authenticated endpoint testing
@@ -174,6 +175,24 @@ func TestGetTradeHistory(t *testing.T) {
assert.NoError(t, err)
}
func TestKlineUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[["1746645900","96248.3","96060.4","96248.3","95991.1","7.30387554","701787.956631596"],["1746645600","96407.2","96243.5","96420.2","96213.1","6.72799595","648257.95148221"],["1746645300","96382.8","96407.2","96466.1","96227.8","7.31425727","704541.034713515"],["1746645000","96490.5","96382.8","96503","96376.7","5.06147446","488102.261377795"],["1746644700","96424","96490.5","96517.9","96323.4","12.04216802","1160916.511036681"],["1746644400","96593.4","96423.9","96608.6","96403","10.75654084","1037793.471887188"],["1746644100","96200.5","96588.1","96591.6","96200.5","10.12317892","976893.020212471"],["1746643800","96182.2","96191.8","96241.7","95998.6","8.00901063","769988.0586614"],["1746643500","96404.1","96160.1","96477.6","96102.8","10.86244787","1045287.271213675"],["1746643200","96680.1","96395.4","96734.7","96395.3","9.54921963","921978.587594588"],["1746642900","96790.7","96680.1","96851.6","96587.5","11.35501379","1098593.622144195"],["1746642600","96447.7","96760","96868.5","96291.1","16.35392542","1580649.199051741"]]`)
var target []Kline
err := json.Unmarshal(data, &target)
require.NoError(t, err)
require.Len(t, target, 12)
assert.Equal(t, Kline{
StartTime: types.Time(time.Unix(1746645900, 0)),
Open: 96248.3,
Close: 96060.4,
High: 96248.3,
Low: 95991.1,
Volume: 7.30387554,
Amount: 701787.956631596,
}, target[0])
}
func TestGetKlines(t *testing.T) {
t.Parallel()
_, err := ku.GetKlines(t.Context(), "", "1week", time.Time{}, time.Time{})
@@ -184,6 +203,7 @@ func TestGetKlines(t *testing.T) {
result, err := ku.GetKlines(t.Context(), spotTradablePair.String(), "1week", time.Time{}, time.Time{})
assert.NoError(t, err)
assert.NotNil(t, result)
result, err = ku.GetKlines(t.Context(), spotTradablePair.String(), "5min", time.Now().Add(-time.Hour*1), time.Now())
assert.NoError(t, err)
assert.NotNil(t, result)
@@ -1508,6 +1528,23 @@ func TestGetFuturesServiceStatus(t *testing.T) {
assert.NotNil(t, result)
}
func TestFuturesKlineUnmarshalJSON(t *testing.T) {
t.Parallel()
data := []byte(`[1746518400000,1806.48,1806.48,1794.41,1794.41,1560]`)
var target *FuturesKline
err := json.Unmarshal(data, &target)
require.NoError(t, err)
require.NotNil(t, target)
assert.Equal(t, FuturesKline{
StartTime: types.Time(time.UnixMilli(1746518400000)),
Open: 1806.48,
High: 1806.48,
Low: 1794.41,
Close: 1794.41,
Volume: 1560,
}, *target)
}
func TestGetFuturesKline(t *testing.T) {
t.Parallel()
_, err := ku.GetFuturesKline(t.Context(), 0, "XBTUSDTM", time.Time{}, time.Time{})

View File

@@ -179,13 +179,18 @@ type Trade struct {
// Kline stores kline data
type Kline struct {
StartTime time.Time
Open float64
Close float64
High float64
Low float64
Volume float64 // Transaction volume
Amount float64 // Transaction amount
StartTime types.Time
Open types.Number
Close types.Number
High types.Number
Low types.Number
Volume types.Number // Transaction volume
Amount types.Number // Transaction amount
}
// UnmarshalJSON deserilizes kline data from a JSON array into Kline fields.
func (k *Kline) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &[7]any{&k.StartTime, &k.Open, &k.Close, &k.High, &k.Low, &k.Volume, &k.Amount})
}
// CurrencyBase represents currency code response details

View File

@@ -1742,7 +1742,7 @@ func (ku *Kucoin) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
for x := range candles {
timeseries = append(
timeseries, kline.Candle{
Time: candles[x].StartTime,
Time: candles[x].StartTime.Time(),
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
@@ -1763,12 +1763,12 @@ func (ku *Kucoin) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
for x := range candles {
timeseries = append(
timeseries, kline.Candle{
Time: candles[x].StartTime,
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
Close: candles[x].Close,
Volume: candles[x].Volume,
Time: candles[x].StartTime.Time(),
Open: candles[x].Open.Float64(),
High: candles[x].High.Float64(),
Low: candles[x].Low.Float64(),
Close: candles[x].Close.Float64(),
Volume: candles[x].Volume.Float64(),
})
}
default:
@@ -1796,7 +1796,7 @@ func (ku *Kucoin) GetHistoricCandlesExtended(ctx context.Context, pair currency.
for y := range candles {
timeSeries = append(
timeSeries, kline.Candle{
Time: candles[y].StartTime,
Time: candles[y].StartTime.Time(),
Open: candles[y].Open,
High: candles[y].High,
Low: candles[y].Low,
@@ -1821,12 +1821,12 @@ func (ku *Kucoin) GetHistoricCandlesExtended(ctx context.Context, pair currency.
for x := range candles {
timeSeries = append(
timeSeries, kline.Candle{
Time: candles[x].StartTime,
Open: candles[x].Open,
High: candles[x].High,
Low: candles[x].Low,
Close: candles[x].Close,
Volume: candles[x].Volume,
Time: candles[x].StartTime.Time(),
Open: candles[x].Open.Float64(),
High: candles[x].High.Float64(),
Low: candles[x].Low.Float64(),
Close: candles[x].Close.Float64(),
Volume: candles[x].Volume.Float64(),
})
}
}

View File

@@ -5553,9 +5553,9 @@ func TestGetOptionsTickBands(t *testing.T) {
func TestExtractIndexCandlestick(t *testing.T) {
t.Parallel()
data := `[ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "1" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "1" ]]`
data := []byte(`[ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "1" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "1" ]]`)
var resp []CandlestickHistoryItem
err := json.Unmarshal([]byte(data), &resp)
err := json.Unmarshal(data, &resp)
require.NoError(t, err)
require.Len(t, resp, 2)
require.Equal(t, 3.743, resp[0].HighestPrice.Float64())

View File

@@ -690,8 +690,7 @@ type ExpiryOpenInterestAndVolume struct {
// UnmarshalJSON deserializes slice of data into ExpiryOpenInterestAndVolume structure
func (e *ExpiryOpenInterestAndVolume) UnmarshalJSON(data []byte) error {
var expiryTimeString string
target := [6]any{&e.Timestamp, &expiryTimeString, &e.CallOpenInterest, &e.PutOpenInterest, &e.CallVolume, &e.PutVolume}
err := json.Unmarshal(data, &target)
err := json.Unmarshal(data, &[6]any{&e.Timestamp, &expiryTimeString, &e.CallOpenInterest, &e.PutOpenInterest, &e.CallVolume, &e.PutVolume})
if err != nil {
return err
}

View File

@@ -127,19 +127,19 @@ func TestUnmarshalJSON(t *testing.T) {
GoodTillCancel | PostOnly | ImmediateOrCancel, GoodTillCancel | PostOnly, GoodTillCancel, UnknownTIF, PostOnly | ImmediateOrCancel,
GoodTillCancel, GoodTillCancel, PostOnly, PostOnly, ImmediateOrCancel, GoodTillDay, GoodTillDay, GoodTillTime, FillOrKill, FillOrKill,
}
data := `{"tifs": ["GTC,POSTONLY,IOC", "GTC,POSTONLY", "GTC", "", "POSTONLY,IOC", "GoodTilCancel", "GoodTILLCANCEL", "POST_ONLY", "POC","IOC", "GTD", "gtd","gtt", "fok", "fillOrKill"]}`
data := []byte(`{"tifs": ["GTC,POSTONLY,IOC", "GTC,POSTONLY", "GTC", "", "POSTONLY,IOC", "GoodTilCancel", "GoodTILLCANCEL", "POST_ONLY", "POC","IOC", "GTD", "gtd","gtt", "fok", "fillOrKill"]}`)
target := &struct {
TIFs []TimeInForce `json:"tifs"`
}{}
err := json.Unmarshal([]byte(data), &target)
err := json.Unmarshal(data, &target)
require.NoError(t, err)
require.Equal(t, targets, target.TIFs)
data = `{"tifs": ["abcd,POSTONLY,IOC", "GTC,POSTONLY", "GTC", "", "POSTONLY,IOC", "GoodTilCancel", "GoodTILLCANCEL", "POST_ONLY", "POC","IOC", "GTD", "gtd","gtt", "fok", "fillOrKill"]}`
data = []byte(`{"tifs": ["abcd,POSTONLY,IOC", "GTC,POSTONLY", "GTC", "", "POSTONLY,IOC", "GoodTilCancel", "GoodTILLCANCEL", "POST_ONLY", "POC","IOC", "GTD", "gtd","gtt", "fok", "fillOrKill"]}`)
target = &struct {
TIFs []TimeInForce `json:"tifs"`
}{}
err = json.Unmarshal([]byte(data), &target)
err = json.Unmarshal(data, &target)
require.ErrorIs(t, err, ErrInvalidTimeInForce)
}