diff --git a/exchanges/binanceus/binanceus.go b/exchanges/binanceus/binanceus.go index 91939219..087a12e4 100644 --- a/exchanges/binanceus/binanceus.go +++ b/exchanges/binanceus/binanceus.go @@ -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 diff --git a/exchanges/binanceus/binanceus_test.go b/exchanges/binanceus/binanceus_test.go index 96dfd9fd..ebad1dba 100644 --- a/exchanges/binanceus/binanceus_test.go +++ b/exchanges/binanceus/binanceus_test.go @@ -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 } diff --git a/exchanges/binanceus/binanceus_types.go b/exchanges/binanceus/binanceus_types.go index 905cafb5..f6544eff 100644 --- a/exchanges/binanceus/binanceus_types.go +++ b/exchanges/binanceus/binanceus_types.go @@ -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. diff --git a/exchanges/binanceus/binanceus_websocket.go b/exchanges/binanceus/binanceus_websocket.go index ecfea815..1480d67f 100644 --- a/exchanges/binanceus/binanceus_websocket.go +++ b/exchanges/binanceus/binanceus_websocket.go @@ -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, }) } diff --git a/exchanges/binanceus/binanceus_wrapper.go b/exchanges/binanceus/binanceus_wrapper.go index 4a7c9a78..b9959262 100644 --- a/exchanges/binanceus/binanceus_wrapper.go +++ b/exchanges/binanceus/binanceus_wrapper.go @@ -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 diff --git a/exchanges/binanceus/type_convert.go b/exchanges/binanceus/type_convert.go deleted file mode 100644 index aaa45c0f..00000000 --- a/exchanges/binanceus/type_convert.go +++ /dev/null @@ -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 -} diff --git a/exchanges/bybit/bybit_test.go b/exchanges/bybit/bybit_test.go index d1f4adc3..e7324bb3 100644 --- a/exchanges/bybit/bybit_test.go +++ b/exchanges/bybit/bybit_test.go @@ -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) } diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index c2a4af00..658788ad 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -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 diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 2249cb0c..b3f56af9 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -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) diff --git a/exchanges/coinbasepro/coinbasepro_types.go b/exchanges/coinbasepro/coinbasepro_types.go index 4274b0bc..c9cb48aa 100644 --- a/exchanges/coinbasepro/coinbasepro_types.go +++ b/exchanges/coinbasepro/coinbasepro_types.go @@ -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"` diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index cdda50b3..68d37e96 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -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, diff --git a/exchanges/deribit/deribit.go b/exchanges/deribit/deribit.go index 1a91175f..28ab4576 100644 --- a/exchanges/deribit/deribit.go +++ b/exchanges/deribit/deribit.go @@ -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. diff --git a/exchanges/deribit/deribit_test.go b/exchanges/deribit/deribit_test.go index 7473194d..fb41a438 100644 --- a/exchanges/deribit/deribit_test.go +++ b/exchanges/deribit/deribit_test.go @@ -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) diff --git a/exchanges/deribit/deribit_types.go b/exchanges/deribit/deribit_types.go index ed5359ef..cdcfd713 100644 --- a/exchanges/deribit/deribit_types.go +++ b/exchanges/deribit/deribit_types.go @@ -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 diff --git a/exchanges/deribit/deribit_ws_endpoints.go b/exchanges/deribit/deribit_ws_endpoints.go index 3133c458..c491efb7 100644 --- a/exchanges/deribit/deribit_ws_endpoints.go +++ b/exchanges/deribit/deribit_ws_endpoints.go @@ -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. diff --git a/exchanges/gateio/gateio.go b/exchanges/gateio/gateio.go index 0abd37e1..bacaa176 100644 --- a/exchanges/gateio/gateio.go +++ b/exchanges/gateio/gateio.go @@ -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 diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index c691dd5a..fedf394c 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -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 { diff --git a/exchanges/gateio/gateio_types.go b/exchanges/gateio/gateio_types.go index a1399aac..46057fbf 100644 --- a/exchanges/gateio/gateio_types.go +++ b/exchanges/gateio/gateio_types.go @@ -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. diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index 8cab6c05..b286e480 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -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: diff --git a/exchanges/kucoin/kucoin.go b/exchanges/kucoin/kucoin.go index e7b33505..1d6212fe 100644 --- a/exchanges/kucoin/kucoin.go +++ b/exchanges/kucoin/kucoin.go @@ -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 diff --git a/exchanges/kucoin/kucoin_futures.go b/exchanges/kucoin/kucoin_futures.go index 62c8dc9d..974e45e8 100644 --- a/exchanges/kucoin/kucoin_futures.go +++ b/exchanges/kucoin/kucoin_futures.go @@ -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 diff --git a/exchanges/kucoin/kucoin_futures_types.go b/exchanges/kucoin/kucoin_futures_types.go index 43ab2a84..e2f60774 100644 --- a/exchanges/kucoin/kucoin_futures_types.go +++ b/exchanges/kucoin/kucoin_futures_types.go @@ -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"` diff --git a/exchanges/kucoin/kucoin_test.go b/exchanges/kucoin/kucoin_test.go index 38560e31..891680e4 100644 --- a/exchanges/kucoin/kucoin_test.go +++ b/exchanges/kucoin/kucoin_test.go @@ -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{}) diff --git a/exchanges/kucoin/kucoin_types.go b/exchanges/kucoin/kucoin_types.go index f55dbe8a..20de283b 100644 --- a/exchanges/kucoin/kucoin_types.go +++ b/exchanges/kucoin/kucoin_types.go @@ -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 diff --git a/exchanges/kucoin/kucoin_wrapper.go b/exchanges/kucoin/kucoin_wrapper.go index 68726cdc..13118c50 100644 --- a/exchanges/kucoin/kucoin_wrapper.go +++ b/exchanges/kucoin/kucoin_wrapper.go @@ -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(), }) } } diff --git a/exchanges/okx/okx_test.go b/exchanges/okx/okx_test.go index 1301a2ce..5aeee376 100644 --- a/exchanges/okx/okx_test.go +++ b/exchanges/okx/okx_test.go @@ -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()) diff --git a/exchanges/okx/okx_types.go b/exchanges/okx/okx_types.go index 13d6c638..6f91fb05 100644 --- a/exchanges/okx/okx_types.go +++ b/exchanges/okx/okx_types.go @@ -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 } diff --git a/exchanges/order/timeinforce_test.go b/exchanges/order/timeinforce_test.go index 0022a699..155bab6c 100644 --- a/exchanges/order/timeinforce_test.go +++ b/exchanges/order/timeinforce_test.go @@ -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) }