mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
binance: fix depth snapshot buffering
This commit is contained in:
parent
d3f06bc9d7
commit
686dcef2c5
|
@ -48,16 +48,8 @@ var rootCmd = &cobra.Command{
|
||||||
stream.SetPublicOnly()
|
stream.SetPublicOnly()
|
||||||
stream.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{})
|
stream.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{})
|
||||||
|
|
||||||
stream.OnBookSnapshot(func(book types.SliceOrderBook) {
|
streamBook := types.NewStreamBook(symbol)
|
||||||
// log.Infof("book snapshot: %+v", book)
|
streamBook.BindStream(stream)
|
||||||
})
|
|
||||||
|
|
||||||
stream.OnBookUpdate(func(book types.SliceOrderBook) {
|
|
||||||
// log.Infof("book update: %+v", book)
|
|
||||||
})
|
|
||||||
|
|
||||||
streambook := types.NewStreamBook(symbol)
|
|
||||||
streambook.BindStream(stream)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -66,8 +58,8 @@ var rootCmd = &cobra.Command{
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
|
|
||||||
case <-streambook.C:
|
case <-streamBook.C:
|
||||||
book := streambook.Copy()
|
book := streamBook.Copy()
|
||||||
|
|
||||||
if valid, err := book.IsValid(); !valid {
|
if valid, err := book.IsValid(); !valid {
|
||||||
log.Errorf("order book is invalid, error: %v", err)
|
log.Errorf("order book is invalid, error: %v", err)
|
||||||
|
|
|
@ -160,6 +160,18 @@ func (f *DepthFrame) PushEvent(e DepthEvent) {
|
||||||
|
|
||||||
// drop old events
|
// drop old events
|
||||||
if e.FinalUpdateID <= snapshot.FinalUpdateID {
|
if e.FinalUpdateID <= snapshot.FinalUpdateID {
|
||||||
|
log.Infof("DROP %s depth update event, updateID %d ~ %d (len %d)",
|
||||||
|
f.Symbol,
|
||||||
|
e.FirstUpdateID, e.FinalUpdateID, e.FinalUpdateID-e.FirstUpdateID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.FirstUpdateID > snapshot.FinalUpdateID+1 {
|
||||||
|
log.Infof("MISSING %s depth update event, resetting, updateID %d ~ %d (len %d)",
|
||||||
|
f.Symbol,
|
||||||
|
e.FirstUpdateID, e.FinalUpdateID, e.FinalUpdateID-e.FirstUpdateID)
|
||||||
|
|
||||||
|
f.reset()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +193,7 @@ func (f *DepthFrame) fetch(ctx context.Context) (*DepthEvent, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
event := DepthEvent{
|
event := DepthEvent{
|
||||||
|
Symbol: f.Symbol,
|
||||||
FirstUpdateID: 0,
|
FirstUpdateID: 0,
|
||||||
FinalUpdateID: response.LastUpdateID,
|
FinalUpdateID: response.LastUpdateID,
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,17 +319,40 @@ type DepthEvent struct {
|
||||||
Asks []DepthEntry
|
Asks []DepthEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *DepthEvent) String() (o string) {
|
||||||
|
o += fmt.Sprintf("Depth %s bid/ask = ", e.Symbol)
|
||||||
|
|
||||||
|
if len(e.Bids) == 0 {
|
||||||
|
o += "empty"
|
||||||
|
} else {
|
||||||
|
o += e.Bids[0].PriceLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
o += "/"
|
||||||
|
|
||||||
|
if len(e.Asks) == 0 {
|
||||||
|
o += "empty"
|
||||||
|
} else {
|
||||||
|
o += e.Asks[0].PriceLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
o += fmt.Sprintf(" %d ~ %d", e.FirstUpdateID, e.FinalUpdateID)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
for _, entry := range e.Bids {
|
for _, entry := range e.Bids {
|
||||||
quantity, err := fixedpoint.NewFromString(entry.Quantity)
|
quantity, err := fixedpoint.NewFromString(entry.Quantity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("depth quantity parse error: %s", entry.Quantity)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
price, err := fixedpoint.NewFromString(entry.PriceLevel)
|
price, err := fixedpoint.NewFromString(entry.PriceLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("depth price parse error: %s", entry.PriceLevel)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,11 +367,13 @@ func (e *DepthEvent) OrderBook() (book types.SliceOrderBook, err error) {
|
||||||
for _, entry := range e.Asks {
|
for _, entry := range e.Asks {
|
||||||
quantity, err := fixedpoint.NewFromString(entry.Quantity)
|
quantity, err := fixedpoint.NewFromString(entry.Quantity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("depth quantity parse error: %s", entry.Quantity)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
price, err := fixedpoint.NewFromString(entry.PriceLevel)
|
price, err := fixedpoint.NewFromString(entry.PriceLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("depth price parse error: %s", entry.PriceLevel)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +385,7 @@ func (e *DepthEvent) OrderBook() (book types.SliceOrderBook, err error) {
|
||||||
book.Asks = book.Asks.Upsert(pv, false)
|
book.Asks = book.Asks.Upsert(pv, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return book, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDepthEntry(val *fastjson.Value) (*DepthEntry, error) {
|
func parseDepthEntry(val *fastjson.Value) (*DepthEntry, error) {
|
||||||
|
|
|
@ -88,27 +88,29 @@ func NewStream(client *binance.Client) *Stream {
|
||||||
|
|
||||||
stream.depthFrames[e.Symbol] = f
|
stream.depthFrames[e.Symbol] = f
|
||||||
|
|
||||||
f.OnReady(func(e DepthEvent, bufEvents []DepthEvent) {
|
f.OnReady(func(snapshotDepth DepthEvent, bufEvents []DepthEvent) {
|
||||||
snapshot, err := e.OrderBook()
|
log.Infof("depth snapshot: %s", snapshotDepth.String())
|
||||||
|
|
||||||
|
snapshot, err := snapshotDepth.OrderBook()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("book snapshot convert error")
|
log.WithError(err).Error("book snapshot convert error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if valid, err := snapshot.IsValid(); !valid {
|
if valid, err := snapshot.IsValid(); !valid {
|
||||||
log.Warnf("depth snapshot is invalid, event: %+v, error: %v", e, err)
|
log.Errorf("depth snapshot is invalid, event: %+v, error: %v", snapshotDepth, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.EmitBookSnapshot(snapshot)
|
stream.EmitBookSnapshot(snapshot)
|
||||||
|
|
||||||
for _, e := range bufEvents {
|
for _, e := range bufEvents {
|
||||||
book, err := e.OrderBook()
|
bookUpdate, err := e.OrderBook()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("book convert error")
|
log.WithError(err).Error("book convert error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.EmitBookUpdate(book)
|
stream.EmitBookUpdate(bookUpdate)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -185,7 +187,7 @@ func NewStream(client *binance.Client) *Stream {
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.OnDisconnect(func() {
|
stream.OnDisconnect(func() {
|
||||||
log.Infof("resetting depth snapshot...")
|
log.Infof("resetting depth snapshots...")
|
||||||
for _, f := range stream.depthFrames {
|
for _, f := range stream.depthFrames {
|
||||||
f.reset()
|
f.reset()
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,27 @@ func NewMutexOrderBook(symbol string) *MutexOrderBook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) IsValid() (ok bool, err error) {
|
||||||
|
b.Lock()
|
||||||
|
ok, err = b.OrderBook.IsValid()
|
||||||
|
b.Unlock()
|
||||||
|
return ok, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) BestBid() (pv PriceVolume, ok bool) {
|
||||||
|
b.Lock()
|
||||||
|
pv, ok = b.OrderBook.BestBid()
|
||||||
|
b.Unlock()
|
||||||
|
return pv, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) BestAsk() (pv PriceVolume, ok bool) {
|
||||||
|
b.Lock()
|
||||||
|
pv, ok = b.OrderBook.BestAsk()
|
||||||
|
b.Unlock()
|
||||||
|
return pv, ok
|
||||||
|
}
|
||||||
|
|
||||||
func (b *MutexOrderBook) Load(book SliceOrderBook) {
|
func (b *MutexOrderBook) Load(book SliceOrderBook) {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
b.OrderBook.Load(book)
|
b.OrderBook.Load(book)
|
||||||
|
@ -66,14 +87,16 @@ func (b *MutexOrderBook) Reset() {
|
||||||
|
|
||||||
func (b *MutexOrderBook) CopyDepth(depth int) OrderBook {
|
func (b *MutexOrderBook) CopyDepth(depth int) OrderBook {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
defer b.Unlock()
|
book := b.OrderBook.CopyDepth(depth)
|
||||||
return b.OrderBook.CopyDepth(depth)
|
b.Unlock()
|
||||||
|
return book
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MutexOrderBook) Copy() OrderBook {
|
func (b *MutexOrderBook) Copy() OrderBook {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
defer b.Unlock()
|
book := b.OrderBook.Copy()
|
||||||
return b.OrderBook.Copy()
|
b.Unlock()
|
||||||
|
return book
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MutexOrderBook) Update(update SliceOrderBook) {
|
func (b *MutexOrderBook) Update(update SliceOrderBook) {
|
||||||
|
|
|
@ -93,10 +93,10 @@ func (b *SliceOrderBook) PriceVolumesBySide(side SideType) PriceVolumeSlice {
|
||||||
switch side {
|
switch side {
|
||||||
|
|
||||||
case SideTypeBuy:
|
case SideTypeBuy:
|
||||||
return b.Bids
|
return b.Bids.Copy()
|
||||||
|
|
||||||
case SideTypeSell:
|
case SideTypeSell:
|
||||||
return b.Asks
|
return b.Asks.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -122,11 +122,6 @@ func (b *SliceOrderBook) updateBids(pvs PriceVolumeSlice) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SliceOrderBook) load(book SliceOrderBook) {
|
|
||||||
b.Reset()
|
|
||||||
b.update(book)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *SliceOrderBook) update(book SliceOrderBook) {
|
func (b *SliceOrderBook) update(book SliceOrderBook) {
|
||||||
b.updateBids(book.Bids)
|
b.updateBids(book.Bids)
|
||||||
b.updateAsks(book.Asks)
|
b.updateAsks(book.Asks)
|
||||||
|
@ -138,7 +133,8 @@ func (b *SliceOrderBook) Reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SliceOrderBook) Load(book SliceOrderBook) {
|
func (b *SliceOrderBook) Load(book SliceOrderBook) {
|
||||||
b.load(book)
|
b.Reset()
|
||||||
|
b.update(book)
|
||||||
b.EmitLoad(b)
|
b.EmitLoad(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user