Binance: convert timestamps to time.Time (#601)

* add custom Unmarshal function for JSON types
* pass KlinesRequestParams as pointer, because now the object is bigger
This commit is contained in:
Rauno Ots
2020-11-30 01:17:27 +01:00
committed by GitHub
parent 46747c13f4
commit b7d99f741d
6 changed files with 573 additions and 235 deletions

View File

@@ -184,10 +184,10 @@ func (b *Binance) GetAggregatedTrades(arg *AggregatedTradeRequestParams) ([]Aggr
params.Set("fromId", strconv.FormatInt(arg.FromID, 10))
}
if !arg.StartTime.IsZero() {
params.Set("startTime", strconv.FormatInt(convert.UnixMillis(arg.StartTime), 10))
params.Set("startTime", timeString(arg.StartTime))
}
if !arg.EndTime.IsZero() {
params.Set("endTime", strconv.FormatInt(convert.UnixMillis(arg.EndTime), 10))
params.Set("endTime", timeString(arg.EndTime))
}
// startTime and endTime are set and time between startTime and endTime is more than 1 hour
@@ -231,8 +231,8 @@ func (b *Binance) batchAggregateTrades(arg *AggregatedTradeRequestParams, params
// All requests returned empty
return nil, nil
}
params.Set("startTime", strconv.FormatInt(convert.UnixMillis(start), 10))
params.Set("endTime", strconv.FormatInt(convert.UnixMillis(start.Add(time.Hour)), 10))
params.Set("startTime", timeString(start))
params.Set("endTime", timeString(start.Add(time.Hour)))
path := b.API.Endpoints.URL + aggregatedTrades + "?" + params.Encode()
err := b.SendHTTPRequest(path, limitDefault, &resp)
if err != nil {
@@ -260,7 +260,7 @@ func (b *Binance) batchAggregateTrades(arg *AggregatedTradeRequestParams, params
if !arg.EndTime.IsZero() {
// get index for truncating to end time
lastIndex = sort.Search(len(additionalTrades), func(i int) bool {
return convert.UnixMillis(arg.EndTime) < additionalTrades[i].TimeStamp
return arg.EndTime.Before(additionalTrades[i].TimeStamp)
})
}
// don't include the first as the request was inclusive from last ATradeID
@@ -286,7 +286,7 @@ func (b *Binance) batchAggregateTrades(arg *AggregatedTradeRequestParams, params
// interval: the interval time for the data
// startTime: startTime filter for kline data
// endTime: endTime filter for the kline data
func (b *Binance) GetSpotKline(arg KlinesRequestParams) ([]CandleStick, error) {
func (b *Binance) GetSpotKline(arg *KlinesRequestParams) ([]CandleStick, error) {
var resp interface{}
var klineData []CandleStick
@@ -296,11 +296,11 @@ func (b *Binance) GetSpotKline(arg KlinesRequestParams) ([]CandleStick, error) {
if arg.Limit != 0 {
params.Set("limit", strconv.Itoa(arg.Limit))
}
if arg.StartTime != 0 {
params.Set("startTime", strconv.FormatInt(arg.StartTime, 10))
if !arg.StartTime.IsZero() {
params.Set("startTime", timeString(arg.StartTime))
}
if arg.EndTime != 0 {
params.Set("endTime", strconv.FormatInt(arg.EndTime, 10))
if !arg.EndTime.IsZero() {
params.Set("endTime", timeString(arg.EndTime))
}
path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, candleStick, params.Encode())

View File

@@ -38,10 +38,16 @@ func setFeeBuilder() *exchange.FeeBuilder {
func TestGetExchangeInfo(t *testing.T) {
t.Parallel()
_, err := b.GetExchangeInfo()
info, err := b.GetExchangeInfo()
if err != nil {
t.Error(err)
}
if mockTests {
serverTime := time.Date(2020, 4, 15, 23, 44, 38, int(861*time.Millisecond), time.UTC)
if !info.Servertime.Equal(serverTime) {
t.Errorf("Expected %v, got %v", serverTime, info.Servertime)
}
}
}
func TestFetchTradablePairs(t *testing.T) {
@@ -104,12 +110,12 @@ func TestGetAggregatedTrades(t *testing.T) {
func TestGetSpotKline(t *testing.T) {
t.Parallel()
_, err := b.GetSpotKline(KlinesRequestParams{
_, err := b.GetSpotKline(&KlinesRequestParams{
Symbol: "BTCUSDT",
Interval: kline.FiveMin.Short(),
Limit: 24,
StartTime: time.Unix(1577836800, 0).Unix() * 1000,
EndTime: time.Unix(1580515200, 0).Unix() * 1000,
StartTime: time.Unix(1577836800, 0),
EndTime: time.Unix(1580515200, 0),
})
if err != nil {
t.Error("Binance GetSpotKline() error", err)
@@ -514,8 +520,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) {
if len(result) != tt.numExpected {
t.Errorf("GetAggregatedTradesBatched() expected %v entries, got %v", tt.numExpected, len(result))
}
lastTrade := result[len(result)-1]
lastTradeTime := time.Unix(0, lastTrade.TimeStamp*int64(time.Millisecond))
lastTradeTime := result[len(result)-1].TimeStamp
if !lastTradeTime.Equal(tt.lastExpected) {
t.Errorf("last trade expected %v, got %v", tt.lastExpected, lastTradeTime)
}

View File

@@ -14,10 +14,10 @@ type Response struct {
// ExchangeInfo holds the full exchange information type
type ExchangeInfo struct {
Code int `json:"code"`
Msg string `json:"msg"`
Timezone string `json:"timezone"`
Servertime int64 `json:"serverTime"`
Code int `json:"code"`
Msg string `json:"msg"`
Timezone string `json:"timezone"`
Servertime time.Time `json:"serverTime"`
RateLimits []struct {
RateLimitType string `json:"rateLimitType"`
Interval string `json:"interval"`
@@ -97,7 +97,7 @@ type DepthUpdateParams []struct {
// WebsocketDepthStream is the difference for the update depth stream
type WebsocketDepthStream struct {
Event string `json:"e"`
Timestamp int64 `json:"E"`
Timestamp time.Time `json:"E"`
Pair string `json:"s"`
FirstUpdateID int64 `json:"U"`
LastUpdateID int64 `json:"u"`
@@ -113,91 +113,91 @@ 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 int64 `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 time.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
}
// TradeStream holds the trade stream data
type TradeStream struct {
EventType string `json:"e"`
EventTime int64 `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 int64 `json:"T"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
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"`
}
// KlineStream holds the kline stream data
type KlineStream struct {
EventType string `json:"e"`
EventTime int64 `json:"E"`
Symbol string `json:"s"`
EventType string `json:"e"`
EventTime time.Time `json:"E"`
Symbol string `json:"s"`
Kline struct {
StartTime int64 `json:"t"`
CloseTime int64 `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 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"`
} `json:"k"`
}
// TickerStream holds the ticker stream data
type TickerStream struct {
EventType string `json:"e"`
EventTime int64 `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 int64 `json:"O"`
CloseTime int64 `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
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"`
}
// HistoricalTrade holds recent trade data
type HistoricalTrade struct {
Code int `json:"code"`
Msg string `json:"msg"`
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Quantity float64 `json:"qty,string"`
Time int64 `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
IsBestMatch bool `json:"isBestMatch"`
Code int `json:"code"`
Msg string `json:"msg"`
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"`
}
// AggregatedTradeRequestParams holds request params
@@ -214,14 +214,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 int64 `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 time.Time `json:"T"`
Maker bool `json:"m"`
BestMatchPrice bool `json:"M"`
}
// CandleStick holds kline data
@@ -247,25 +247,25 @@ type AveragePrice 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 int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"firstId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
Symbol string `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
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"`
}
// SymbolPrice holds basic symbol price
@@ -307,15 +307,15 @@ type NewOrderRequest struct {
// NewOrderResponse is the return structured response from the exchange
type NewOrderResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
ClientOrderID string `json:"clientOrderId"`
TransactionTime int64 `json:"transactTime"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
Code int `json:"code"`
Msg string `json:"msg"`
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
ClientOrderID string `json:"clientOrderId"`
TransactionTime time.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"`
@@ -340,26 +340,26 @@ type CancelOrderResponse struct {
// QueryOrderData holds query order data
type QueryOrderData struct {
Code int `json:"code"`
Msg string `json:"msg"`
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
Type string `json:"type"`
Side string `json:"side"`
StopPrice float64 `json:"stopPrice,string"`
IcebergQty float64 `json:"icebergQty,string"`
Time float64 `json:"time"`
IsWorking bool `json:"isWorking"`
CummulativeQuoteQty float64 `json:"cummulativeQuoteQty,string"`
OrderListID int64 `json:"orderListId"`
OrigQuoteOrderQty float64 `json:"origQuoteOrderQty,string"`
UpdateTime int64 `json:"updateTime"`
Code int `json:"code"`
Msg string `json:"msg"`
Symbol string `json:"symbol"`
OrderID int64 `json:"orderId"`
ClientOrderID string `json:"clientOrderId"`
Price float64 `json:"price,string"`
OrigQty float64 `json:"origQty,string"`
ExecutedQty float64 `json:"executedQty,string"`
Status string `json:"status"`
TimeInForce string `json:"timeInForce"`
Type string `json:"type"`
Side string `json:"side"`
StopPrice float64 `json:"stopPrice,string"`
IcebergQty float64 `json:"icebergQty,string"`
Time time.Time `json:"time"`
IsWorking bool `json:"isWorking"`
CummulativeQuoteQty float64 `json:"cummulativeQuoteQty,string"`
OrderListID int64 `json:"orderListId"`
OrigQuoteOrderQty float64 `json:"origQuoteOrderQty,string"`
UpdateTime time.Time `json:"updateTime"`
}
// Balance holds query order data
@@ -378,7 +378,7 @@ type Account struct {
CanTrade bool `json:"canTrade"`
CanWithdraw bool `json:"canWithdraw"`
CanDeposit bool `json:"canDeposit"`
UpdateTime int64 `json:"updateTime"`
UpdateTime time.Time `json:"updateTime"`
Balances []Balance `json:"balances"`
}
@@ -427,8 +427,8 @@ type KlinesRequestParams struct {
Symbol string // Required field; example LTCBTC, BTCUSDT
Interval string // Time interval period
Limit int // Default 500; max 500.
StartTime int64
EndTime int64
StartTime time.Time
EndTime time.Time
}
// WithdrawalFees the large list of predefined withdrawal fees
@@ -616,16 +616,16 @@ type UserAccountStream struct {
type wsAccountInfo struct {
Stream string `json:"stream"`
Data struct {
CanDeposit bool `json:"D"`
CanTrade bool `json:"T"`
CanWithdraw bool `json:"W"`
EventTime int64 `json:"E"`
LastUpdated int64 `json:"u"`
BuyerCommission float64 `json:"b"`
MakerCommission float64 `json:"m"`
SellerCommission float64 `json:"s"`
TakerCommission float64 `json:"t"`
EventType string `json:"e"`
CanDeposit bool `json:"D"`
CanTrade bool `json:"T"`
CanWithdraw bool `json:"W"`
EventTime time.Time `json:"E"`
LastUpdated time.Time `json:"u"`
BuyerCommission float64 `json:"b"`
MakerCommission float64 `json:"m"`
SellerCommission float64 `json:"s"`
TakerCommission float64 `json:"t"`
EventType string `json:"e"`
Currencies []struct {
Asset string `json:"a"`
Available float64 `json:"f,string"`
@@ -642,77 +642,77 @@ type wsAccountPosition struct {
Available float64 `json:"f,string"`
Locked float64 `json:"l,string"`
} `json:"B"`
EventTime int64 `json:"E"`
LastUpdated int64 `json:"u"`
EventType string `json:"e"`
EventTime time.Time `json:"E"`
LastUpdated time.Time `json:"u"`
EventType string `json:"e"`
} `json:"data"`
}
type wsBalanceUpdate struct {
Stream string `json:"stream"`
Data struct {
EventTime int64 `json:"E"`
ClearTime int64 `json:"T"`
BalanceDelta float64 `json:"d,string"`
Asset string `json:"a"`
EventType string `json:"e"`
EventTime time.Time `json:"E"`
ClearTime time.Time `json:"T"`
BalanceDelta float64 `json:"d,string"`
Asset string `json:"a"`
EventType string `json:"e"`
} `json:"data"`
}
type wsOrderUpdate struct {
Stream string `json:"stream"`
Data struct {
ClientOrderID string `json:"C"`
EventTime int64 `json:"E"`
IcebergQuantity float64 `json:"F,string"`
LastExecutedPrice float64 `json:"L,string"`
CommissionAsset float64 `json:"N"`
OrderCreationTime int64 `json:"O"`
StopPrice float64 `json:"P,string"`
QuoteOrderQuantity float64 `json:"Q,string"`
Side string `json:"S"`
TransactionTime int64 `json:"T"`
OrderStatus string `json:"X"`
LastQuoteAssetTransactedQuantity float64 `json:"Y,string"`
CumulativeQuoteTransactedQuantity float64 `json:"Z,string"`
CancelledClientOrderID string `json:"c"`
EventType string `json:"e"`
TimeInForce string `json:"f"`
OrderListID int64 `json:"g"`
OrderID int64 `json:"i"`
LastExecutedQuantity float64 `json:"l,string"`
IsMaker bool `json:"m"`
Commission float64 `json:"n,string"`
OrderType string `json:"o"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
RejectionReason string `json:"r"`
Symbol string `json:"s"`
TradeID int64 `json:"t"`
IsOnOrderBook bool `json:"w"`
CurrentExecutionType string `json:"x"`
CumulativeFilledQuantity float64 `json:"z,string"`
ClientOrderID string `json:"C"`
EventTime time.Time `json:"E"`
IcebergQuantity float64 `json:"F,string"`
LastExecutedPrice float64 `json:"L,string"`
CommissionAsset float64 `json:"N"`
OrderCreationTime time.Time `json:"O"`
StopPrice float64 `json:"P,string"`
QuoteOrderQuantity float64 `json:"Q,string"`
Side string `json:"S"`
TransactionTime time.Time `json:"T"`
OrderStatus string `json:"X"`
LastQuoteAssetTransactedQuantity float64 `json:"Y,string"`
CumulativeQuoteTransactedQuantity float64 `json:"Z,string"`
CancelledClientOrderID string `json:"c"`
EventType string `json:"e"`
TimeInForce string `json:"f"`
OrderListID int64 `json:"g"`
OrderID int64 `json:"i"`
LastExecutedQuantity float64 `json:"l,string"`
IsMaker bool `json:"m"`
Commission float64 `json:"n,string"`
OrderType string `json:"o"`
Price float64 `json:"p,string"`
Quantity float64 `json:"q,string"`
RejectionReason string `json:"r"`
Symbol string `json:"s"`
TradeID int64 `json:"t"`
IsOnOrderBook bool `json:"w"`
CurrentExecutionType string `json:"x"`
CumulativeFilledQuantity float64 `json:"z,string"`
} `json:"data"`
}
type wsListStatus struct {
Stream string `json:"stream"`
Data struct {
ListClientOrderID string `json:"C"`
EventTime int64 `json:"E"`
ListOrderStatus string `json:"L"`
ListClientOrderID string `json:"C"`
EventTime time.Time `json:"E"`
ListOrderStatus string `json:"L"`
Orders []struct {
ClientOrderID string `json:"c"`
OrderID int64 `json:"i"`
Symbol string `json:"s"`
} `json:"O"`
TransactionTime int64 `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 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"`
} `json:"data"`
}

View File

@@ -229,7 +229,7 @@ func (b *Binance) wsHandleData(respRaw []byte) error {
Side: oSide,
Status: oStatus,
AssetType: a,
Date: time.Unix(0, data.Data.OrderCreationTime*int64(time.Millisecond)),
Date: data.Data.OrderCreationTime,
Pair: p,
}
case "listStatus":
@@ -297,7 +297,7 @@ func (b *Binance) wsHandleData(respRaw []byte) error {
return b.AddTradesToBuffer(trade.Data{
CurrencyPair: pair,
Timestamp: time.Unix(0, t.TimeStamp*int64(time.Millisecond)),
Timestamp: t.TimeStamp,
Price: price,
Amount: amount,
Exchange: b.Name,
@@ -329,7 +329,7 @@ func (b *Binance) wsHandleData(respRaw []byte) error {
Bid: t.BestBidPrice,
Ask: t.BestAskPrice,
Last: t.LastPrice,
LastUpdated: time.Unix(0, t.EventTime*int64(time.Millisecond)),
LastUpdated: t.EventTime,
AssetType: asset.Spot,
Pair: pair,
}
@@ -349,12 +349,12 @@ func (b *Binance) wsHandleData(respRaw []byte) error {
}
b.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, kline.EventTime*int64(time.Millisecond)),
Timestamp: kline.EventTime,
Pair: pair,
AssetType: asset.Spot,
Exchange: b.Name,
StartTime: time.Unix(0, kline.Kline.StartTime*int64(time.Millisecond)),
CloseTime: time.Unix(0, kline.Kline.CloseTime*int64(time.Millisecond)),
StartTime: kline.Kline.StartTime,
CloseTime: kline.Kline.CloseTime,
Interval: kline.Kline.Interval,
OpenPrice: kline.Kline.OpenPrice,
ClosePrice: kline.Kline.ClosePrice,

View File

@@ -519,7 +519,7 @@ func (b *Binance) GetRecentTrades(p currency.Pair, assetType asset.Item) ([]trad
AssetType: assetType,
Price: tradeData[i].Price,
Amount: tradeData[i].Quantity,
Timestamp: time.Unix(0, tradeData[i].Time*int64(time.Millisecond)),
Timestamp: tradeData[i].Time,
})
}
if b.IsSaveTradeDataEnabled() {
@@ -564,7 +564,7 @@ func (a *AggregatedTrade) toTradeData(p currency.Pair, exchange string, aType as
Amount: a.Quantity,
Exchange: exchange,
Price: a.Price,
Timestamp: time.Unix(0, a.TimeStamp*int64(time.Millisecond)),
Timestamp: a.TimeStamp,
AssetType: aType,
Side: order.AnySide,
}
@@ -718,11 +718,6 @@ func (b *Binance) GetOrderInfo(orderID string, pair currency.Pair, assetType ass
return
}
orderCloseDate, err := convert.TimeFromUnixTimestampFloat(float64(resp.UpdateTime))
if err != nil {
return
}
status, err := order.StringToOrderStatus(resp.Status)
if err != nil {
return
@@ -743,7 +738,7 @@ func (b *Binance) GetOrderInfo(orderID string, pair currency.Pair, assetType ass
Pair: formattedPair,
Cost: resp.CummulativeQuoteQty,
AssetType: assetType,
CloseTime: orderCloseDate,
CloseTime: resp.UpdateTime,
Status: status,
Price: resp.Price,
ExecutedAmount: resp.ExecutedQty,
@@ -822,10 +817,6 @@ func (b *Binance) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail,
for i := range resp {
orderSide := order.Side(strings.ToUpper(resp[i].Side))
orderType := order.Type(strings.ToUpper(resp[i].Type))
orderDate, err := convert.TimeFromUnixTimestampFloat(resp[i].Time)
if err != nil {
return nil, err
}
pair, err := currency.NewPairFromString(resp[i].Symbol)
if err != nil {
@@ -834,7 +825,7 @@ func (b *Binance) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail,
orders = append(orders, order.Detail{
Amount: resp[i].OrigQty,
Date: orderDate,
Date: resp[i].Time,
Exchange: b.Name,
ID: strconv.FormatInt(resp[i].OrderID, 10),
Side: orderSide,
@@ -879,10 +870,6 @@ func (b *Binance) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
for i := range resp {
orderSide := order.Side(strings.ToUpper(resp[i].Side))
orderType := order.Type(strings.ToUpper(resp[i].Type))
orderDate, err := convert.TimeFromUnixTimestampFloat(resp[i].Time)
if err != nil {
return nil, err
}
// New orders are covered in GetOpenOrders
if resp[i].Status == "NEW" {
continue
@@ -895,7 +882,7 @@ func (b *Binance) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
orders = append(orders, order.Detail{
Amount: resp[i].OrigQty,
Date: orderDate,
Date: resp[i].Time,
Exchange: b.Name,
ID: strconv.FormatInt(resp[i].OrderID, 10),
Side: orderSide,
@@ -948,8 +935,8 @@ func (b *Binance) GetHistoricCandles(pair currency.Pair, a asset.Item, start, en
req := KlinesRequestParams{
Interval: b.FormatExchangeKlineInterval(interval),
Symbol: fpair.String(),
StartTime: start.Unix() * 1000,
EndTime: end.Unix() * 1000,
StartTime: start,
EndTime: end,
Limit: int(b.Features.Enabled.Kline.ResultLimit),
}
@@ -960,7 +947,7 @@ func (b *Binance) GetHistoricCandles(pair currency.Pair, a asset.Item, start, en
Interval: interval,
}
candles, err := b.GetSpotKline(req)
candles, err := b.GetSpotKline(&req)
if err != nil {
return kline.Item{}, err
}
@@ -1003,12 +990,12 @@ func (b *Binance) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, s
req := KlinesRequestParams{
Interval: b.FormatExchangeKlineInterval(interval),
Symbol: formattedPair.String(),
StartTime: dates[x].Start.UTC().Unix() * 1000,
EndTime: dates[x].End.UTC().Unix() * 1000,
StartTime: dates[x].Start,
EndTime: dates[x].End,
Limit: int(b.Features.Enabled.Kline.ResultLimit),
}
candles, err := b.GetSpotKline(req)
candles, err := b.GetSpotKline(&req)
if err != nil {
return kline.Item{}, err
}

View File

@@ -0,0 +1,346 @@
package binance
import (
"encoding/json"
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
)
// binanceTime provides an internal conversion helper
type binanceTime time.Time
func (t *binanceTime) UnmarshalJSON(data []byte) error {
var timestamp int64
if err := json.Unmarshal(data, &timestamp); err != nil {
return err
}
*t = binanceTime(time.Unix(0, timestamp*int64(time.Millisecond)))
return nil
}
// Time returns a time.Time object
func (t binanceTime) Time() time.Time {
return time.Time(t)
}
// timeString gets the time as Binance timestamp
func timeString(t time.Time) string {
return strconv.FormatInt(convert.UnixMillis(t), 10)
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *ExchangeInfo) UnmarshalJSON(data []byte) error {
type Alias ExchangeInfo
aux := &struct {
Servertime binanceTime `json:"serverTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Servertime = aux.Servertime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *AggregatedTrade) UnmarshalJSON(data []byte) error {
type Alias AggregatedTrade
aux := &struct {
TimeStamp binanceTime `json:"T"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.TimeStamp = aux.TimeStamp.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
type Alias NewOrderResponse
aux := &struct {
TransactionTime binanceTime `json:"transactTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
// there can be an empty response, then `a` is set to nil
if aux != nil {
a.TransactionTime = aux.TransactionTime.Time()
} else {
a = nil
}
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *TradeStream) UnmarshalJSON(data []byte) error {
type Alias TradeStream
aux := &struct {
TimeStamp binanceTime `json:"T"`
EventTime binanceTime `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 timestamp
func (a *KlineStream) UnmarshalJSON(data []byte) error {
type Alias KlineStream
aux := &struct {
EventTime binanceTime `json:"E"`
Kline struct {
StartTime binanceTime `json:"t"`
CloseTime binanceTime `json:"T"`
} `json:"k"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
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
func (a *TickerStream) UnmarshalJSON(data []byte) error {
type Alias TickerStream
aux := &struct {
EventTime binanceTime `json:"E"`
OpenTime binanceTime `json:"O"`
CloseTime binanceTime `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 *PriceChangeStats) UnmarshalJSON(data []byte) error {
type Alias PriceChangeStats
aux := &struct {
OpenTime binanceTime `json:"openTime"`
CloseTime binanceTime `json:"closeTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.OpenTime = aux.OpenTime.Time()
a.CloseTime = aux.CloseTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *RecentTrade) UnmarshalJSON(data []byte) error {
type Alias RecentTrade
aux := &struct {
Time binanceTime `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Time = aux.Time.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *HistoricalTrade) UnmarshalJSON(data []byte) error {
type Alias HistoricalTrade
aux := &struct {
Time binanceTime `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Time = aux.Time.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *QueryOrderData) UnmarshalJSON(data []byte) error {
type Alias QueryOrderData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Time = aux.Time.Time()
a.UpdateTime = aux.UpdateTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *Account) UnmarshalJSON(data []byte) error {
type Alias Account
aux := &struct {
UpdateTime binanceTime `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.UpdateTime = aux.UpdateTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *WebsocketDepthStream) UnmarshalJSON(data []byte) error {
type Alias WebsocketDepthStream
aux := &struct {
Timestamp binanceTime `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Timestamp = aux.Timestamp.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *wsAccountInfo) UnmarshalJSON(data []byte) error {
type Alias wsAccountInfo
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
LastUpdated binanceTime `json:"u"`
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.LastUpdated = aux.Data.LastUpdated.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *wsAccountPosition) UnmarshalJSON(data []byte) error {
type Alias wsAccountPosition
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
LastUpdated binanceTime `json:"u"`
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.LastUpdated = aux.Data.LastUpdated.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *wsBalanceUpdate) UnmarshalJSON(data []byte) error {
type Alias wsBalanceUpdate
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
ClearTime binanceTime `json:"T"`
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.ClearTime = aux.Data.ClearTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (a *wsOrderUpdate) UnmarshalJSON(data []byte) error {
type Alias wsOrderUpdate
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
OrderCreationTime binanceTime `json:"O"`
TransactionTime binanceTime `json:"T"`
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
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 timestamp
func (a *wsListStatus) UnmarshalJSON(data []byte) error {
type Alias wsListStatus
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
TransactionTime binanceTime `json:"T"`
} `json:"data"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
a.Data.EventTime = aux.Data.EventTime.Time()
a.Data.TransactionTime = aux.Data.TransactionTime.Time()
return nil
}