mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
pkg/exchange: add time to SliceOrderBook
This commit is contained in:
parent
6f4f1ad558
commit
50bfd8ee0e
|
@ -71,9 +71,10 @@ var orderbookCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
if bid, ask, ok := orderBook.BestBidAndAsk(); ok {
|
if bid, ask, ok := orderBook.BestBidAndAsk(); ok {
|
||||||
log.Infof("ASK | %f x %f / %f x %f | BID",
|
log.Infof("ASK | %f x %f / %f x %f | BID | %s",
|
||||||
ask.Volume.Float64(), ask.Price.Float64(),
|
ask.Volume.Float64(), ask.Price.Float64(),
|
||||||
bid.Price.Float64(), bid.Volume.Float64())
|
bid.Price.Float64(), bid.Volume.Float64(),
|
||||||
|
book.Time.String())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -84,9 +85,10 @@ var orderbookCmd = &cobra.Command{
|
||||||
orderBook.Update(book)
|
orderBook.Update(book)
|
||||||
|
|
||||||
if bid, ask, ok := orderBook.BestBidAndAsk(); ok {
|
if bid, ask, ok := orderBook.BestBidAndAsk(); ok {
|
||||||
log.Infof("ASK | %f x %f / %f x %f | BID",
|
log.Infof("ASK | %f x %f / %f x %f | BID | %s",
|
||||||
ask.Volume.Float64(), ask.Price.Float64(),
|
ask.Volume.Float64(), ask.Price.Float64(),
|
||||||
bid.Price.Float64(), bid.Volume.Float64())
|
bid.Price.Float64(), bid.Volume.Float64(),
|
||||||
|
book.Time.String())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1346,6 +1346,8 @@ func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (snapshot type
|
||||||
|
|
||||||
func convertDepth(snapshot types.SliceOrderBook, symbol string, finalUpdateID int64, response *binance.DepthResponse) (types.SliceOrderBook, int64, error) {
|
func convertDepth(snapshot types.SliceOrderBook, symbol string, finalUpdateID int64, response *binance.DepthResponse) (types.SliceOrderBook, int64, error) {
|
||||||
snapshot.Symbol = symbol
|
snapshot.Symbol = symbol
|
||||||
|
// empty time since the API does not provide time information.
|
||||||
|
snapshot.Time = time.Time{}
|
||||||
finalUpdateID = response.LastUpdateID
|
finalUpdateID = response.LastUpdateID
|
||||||
for _, entry := range response.Bids {
|
for _, entry := range response.Bids {
|
||||||
// entry.Price, Quantity: entry.Quantity
|
// entry.Price, Quantity: entry.Quantity
|
||||||
|
|
|
@ -461,6 +461,7 @@ func (e *DepthEvent) String() (o string) {
|
||||||
|
|
||||||
func (e *DepthEvent) OrderBook() (book types.SliceOrderBook, err error) {
|
func (e *DepthEvent) OrderBook() (book types.SliceOrderBook, err error) {
|
||||||
book.Symbol = e.Symbol
|
book.Symbol = e.Symbol
|
||||||
|
book.Time = types.NewMillisecondTimestampFromInt(e.EventBase.Time).Time()
|
||||||
|
|
||||||
// already in descending order
|
// already in descending order
|
||||||
book.Bids = e.Bids
|
book.Bids = e.Bids
|
||||||
|
|
|
@ -88,6 +88,7 @@ func NewStream(ex *Exchange, client *binance.Client, futuresClient *futures.Clie
|
||||||
if ok {
|
if ok {
|
||||||
err := f.AddUpdate(types.SliceOrderBook{
|
err := f.AddUpdate(types.SliceOrderBook{
|
||||||
Symbol: e.Symbol,
|
Symbol: e.Symbol,
|
||||||
|
Time: types.NewMillisecondTimestampFromInt(e.EventBase.Time).Time(),
|
||||||
Bids: e.Bids,
|
Bids: e.Bids,
|
||||||
Asks: e.Asks,
|
Asks: e.Asks,
|
||||||
}, e.FirstUpdateID, e.FinalUpdateID)
|
}, e.FirstUpdateID, e.FinalUpdateID)
|
||||||
|
|
|
@ -131,6 +131,7 @@ func (s *Stream) parseWebSocketEvent(in []byte) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
book.Type = e.WebSocketTopicEvent.Type
|
book.Type = e.WebSocketTopicEvent.Type
|
||||||
|
book.ServerTime = e.WebSocketTopicEvent.Ts.Time()
|
||||||
return &book, nil
|
return &book, nil
|
||||||
|
|
||||||
case TopicTypeKLine:
|
case TopicTypeKLine:
|
||||||
|
|
|
@ -35,6 +35,7 @@ func getTestClientOrSkip(t *testing.T) *Stream {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStream(t *testing.T) {
|
func TestStream(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
s := getTestClientOrSkip(t)
|
s := getTestClientOrSkip(t)
|
||||||
|
|
||||||
t.Run("Auth test", func(t *testing.T) {
|
t.Run("Auth test", func(t *testing.T) {
|
||||||
|
@ -182,6 +183,7 @@ func TestStream_parseWebSocketEvent(t *testing.T) {
|
||||||
UpdateId: fixedpoint.NewFromFloat(1854104),
|
UpdateId: fixedpoint.NewFromFloat(1854104),
|
||||||
SequenceId: fixedpoint.NewFromFloat(10559247733),
|
SequenceId: fixedpoint.NewFromFloat(10559247733),
|
||||||
Type: DataTypeDelta,
|
Type: DataTypeDelta,
|
||||||
|
ServerTime: types.NewMillisecondTimestampFromInt(1691130685111).Time(),
|
||||||
}, *book)
|
}, *book)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/exchange/bybit/bybitapi"
|
"github.com/c9s/bbgo/pkg/exchange/bybit/bybitapi"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
@ -117,14 +118,18 @@ type BookEvent struct {
|
||||||
SequenceId fixedpoint.Value `json:"seq"`
|
SequenceId fixedpoint.Value `json:"seq"`
|
||||||
|
|
||||||
// internal use
|
// internal use
|
||||||
// Type can be one of snapshot or delta. Copied from WebSocketTopicEvent.Type
|
// Copied from WebSocketTopicEvent.Type, WebSocketTopicEvent.Ts
|
||||||
|
// Type can be one of snapshot or delta.
|
||||||
Type DataType
|
Type DataType
|
||||||
|
// ServerTime using the websocket timestamp as server time. Since the event not provide server time information.
|
||||||
|
ServerTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BookEvent) OrderBook() (snapshot types.SliceOrderBook) {
|
func (e *BookEvent) OrderBook() (snapshot types.SliceOrderBook) {
|
||||||
snapshot.Symbol = e.Symbol
|
snapshot.Symbol = e.Symbol
|
||||||
snapshot.Bids = e.Bids
|
snapshot.Bids = e.Bids
|
||||||
snapshot.Asks = e.Asks
|
snapshot.Asks = e.Asks
|
||||||
|
snapshot.Time = e.ServerTime
|
||||||
return snapshot
|
return snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -438,6 +438,7 @@ func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (types.SliceOr
|
||||||
|
|
||||||
return types.SliceOrderBook{
|
return types.SliceOrderBook{
|
||||||
Symbol: toGlobalSymbol(symbol),
|
Symbol: toGlobalSymbol(symbol),
|
||||||
|
Time: orderBook.Time.Time(),
|
||||||
Bids: orderBook.Bids,
|
Bids: orderBook.Bids,
|
||||||
Asks: orderBook.Asks,
|
Asks: orderBook.Asks,
|
||||||
}, sequence, nil
|
}, sequence, nil
|
||||||
|
|
|
@ -73,6 +73,7 @@ func (s *Stream) handleOrderBookL2Event(e *WebSocketOrderBookL2Event) {
|
||||||
if ok {
|
if ok {
|
||||||
f.AddUpdate(types.SliceOrderBook{
|
f.AddUpdate(types.SliceOrderBook{
|
||||||
Symbol: toGlobalSymbol(e.Symbol),
|
Symbol: toGlobalSymbol(e.Symbol),
|
||||||
|
Time: e.Time.Time(),
|
||||||
Bids: e.Changes.Bids,
|
Bids: e.Changes.Bids,
|
||||||
Asks: e.Changes.Asks,
|
Asks: e.Changes.Asks,
|
||||||
}, e.SequenceStart, e.SequenceEnd)
|
}, e.SequenceStart, e.SequenceEnd)
|
||||||
|
|
|
@ -80,6 +80,7 @@ type WebSocketOrderBookL2Event struct {
|
||||||
Asks types.PriceVolumeSlice `json:"asks"`
|
Asks types.PriceVolumeSlice `json:"asks"`
|
||||||
Bids types.PriceVolumeSlice `json:"bids"`
|
Bids types.PriceVolumeSlice `json:"bids"`
|
||||||
} `json:"changes"`
|
} `json:"changes"`
|
||||||
|
Time types.MillisecondTimestamp `json:"time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebSocketCandleEvent struct {
|
type WebSocketCandleEvent struct {
|
||||||
|
|
|
@ -81,25 +81,25 @@ type KLineEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
"c": "kline",
|
"c": "kline",
|
||||||
"M": "btcusdt",
|
"M": "btcusdt",
|
||||||
"e": "update",
|
"e": "update",
|
||||||
"T": 1602999650179,
|
"T": 1602999650179,
|
||||||
"k": {
|
"k": {
|
||||||
"ST": 1602999900000,
|
"ST": 1602999900000,
|
||||||
"ET": 1602999900000,
|
"ET": 1602999900000,
|
||||||
"M": "btcusdt",
|
"M": "btcusdt",
|
||||||
"R": "5m",
|
"R": "5m",
|
||||||
"O": "11417.21",
|
"O": "11417.21",
|
||||||
"H": "11417.21",
|
"H": "11417.21",
|
||||||
"L": "11417.21",
|
"L": "11417.21",
|
||||||
"C": "11417.21",
|
"C": "11417.21",
|
||||||
"v": "0",
|
"v": "0",
|
||||||
"ti": 0,
|
"ti": 0,
|
||||||
"x": false
|
"x": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
type KLinePayload struct {
|
type KLinePayload struct {
|
||||||
StartTime int64 `json:"ST"`
|
StartTime int64 `json:"ST"`
|
||||||
|
@ -175,6 +175,7 @@ func (e *BookEvent) Time() time.Time {
|
||||||
|
|
||||||
func (e *BookEvent) OrderBook() (snapshot types.SliceOrderBook, err error) {
|
func (e *BookEvent) OrderBook() (snapshot types.SliceOrderBook, err error) {
|
||||||
snapshot.Symbol = strings.ToUpper(e.Market)
|
snapshot.Symbol = strings.ToUpper(e.Market)
|
||||||
|
snapshot.Time = e.Time()
|
||||||
|
|
||||||
for _, bid := range e.Bids {
|
for _, bid := range e.Bids {
|
||||||
pv, err := bid.PriceVolumePair()
|
pv, err := bid.PriceVolumePair()
|
||||||
|
|
|
@ -188,6 +188,7 @@ func (s *Stream) handleBookEvent(e max.BookEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
newBook.Symbol = toGlobalSymbol(e.Market)
|
newBook.Symbol = toGlobalSymbol(e.Market)
|
||||||
|
newBook.Time = e.Time()
|
||||||
|
|
||||||
switch e.Event {
|
switch e.Event {
|
||||||
case "snapshot":
|
case "snapshot":
|
||||||
|
|
|
@ -81,6 +81,7 @@ func (data *BookEvent) BookTicker() types.BookTicker {
|
||||||
func (data *BookEvent) Book() types.SliceOrderBook {
|
func (data *BookEvent) Book() types.SliceOrderBook {
|
||||||
book := types.SliceOrderBook{
|
book := types.SliceOrderBook{
|
||||||
Symbol: data.Symbol,
|
Symbol: data.Symbol,
|
||||||
|
Time: types.NewMillisecondTimestampFromInt(data.MillisecondTimestamp).Time(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bid := range data.Bids {
|
for _, bid := range data.Bids {
|
||||||
|
|
|
@ -12,11 +12,14 @@ import (
|
||||||
|
|
||||||
// SliceOrderBook is a general order book structure which could be used
|
// SliceOrderBook is a general order book structure which could be used
|
||||||
// for RESTful responses and websocket stream parsing
|
// for RESTful responses and websocket stream parsing
|
||||||
|
//
|
||||||
//go:generate callbackgen -type SliceOrderBook
|
//go:generate callbackgen -type SliceOrderBook
|
||||||
type SliceOrderBook struct {
|
type SliceOrderBook struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
Bids PriceVolumeSlice
|
Bids PriceVolumeSlice
|
||||||
Asks PriceVolumeSlice
|
Asks PriceVolumeSlice
|
||||||
|
// Time represents the server time. If empty, it indicates that the server does not provide this information.
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
lastUpdateTime time.Time
|
lastUpdateTime time.Time
|
||||||
|
|
||||||
|
@ -162,6 +165,8 @@ func (b *SliceOrderBook) String() string {
|
||||||
sb.WriteString("BOOK ")
|
sb.WriteString("BOOK ")
|
||||||
sb.WriteString(b.Symbol)
|
sb.WriteString(b.Symbol)
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
|
sb.WriteString(b.Time.Format(time.RFC1123))
|
||||||
|
sb.WriteString("\n")
|
||||||
|
|
||||||
if len(b.Asks) > 0 {
|
if len(b.Asks) > 0 {
|
||||||
sb.WriteString("ASKS:\n")
|
sb.WriteString("ASKS:\n")
|
||||||
|
@ -187,6 +192,7 @@ func (b *SliceOrderBook) String() string {
|
||||||
func (b *SliceOrderBook) CopyDepth(limit int) OrderBook {
|
func (b *SliceOrderBook) CopyDepth(limit int) OrderBook {
|
||||||
var book SliceOrderBook
|
var book SliceOrderBook
|
||||||
book.Symbol = b.Symbol
|
book.Symbol = b.Symbol
|
||||||
|
book.Time = b.Time
|
||||||
book.Bids = b.Bids.CopyDepth(limit)
|
book.Bids = b.Bids.CopyDepth(limit)
|
||||||
book.Asks = b.Asks.CopyDepth(limit)
|
book.Asks = b.Asks.CopyDepth(limit)
|
||||||
return &book
|
return &book
|
||||||
|
@ -195,6 +201,7 @@ func (b *SliceOrderBook) CopyDepth(limit int) OrderBook {
|
||||||
func (b *SliceOrderBook) Copy() OrderBook {
|
func (b *SliceOrderBook) Copy() OrderBook {
|
||||||
var book SliceOrderBook
|
var book SliceOrderBook
|
||||||
book.Symbol = b.Symbol
|
book.Symbol = b.Symbol
|
||||||
|
book.Time = b.Time
|
||||||
book.Bids = b.Bids.Copy()
|
book.Bids = b.Bids.Copy()
|
||||||
book.Asks = b.Asks.Copy()
|
book.Asks = b.Asks.Copy()
|
||||||
return &book
|
return &book
|
||||||
|
|
Loading…
Reference in New Issue
Block a user