mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
Bugfix/improvement: Orderbook/ticker update processing (#364)
* Greatly increases efficiency of web socket orderbook processing by minimising multiple map lookups. Changes buffer to use pointers. Ensures orderbook benchmarks are on equal footing and set correctly. Removes data race by not setting waitgroup adds inside go routine causing wait and add to happen simultaneously. Updates ticker and orderbook service to use a pointer var instead of map lookups when setting data. * Removes misguided comment * Removes waitgroups and goroutines for updating bids and asks for non-id orderbook updates via websocket. Updates benchmarks to be consistent
This commit is contained in:
@@ -95,11 +95,12 @@ func (s *Service) Update(b *Base) error {
|
||||
}
|
||||
|
||||
default:
|
||||
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.Bids = b.Bids
|
||||
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.Asks = b.Asks
|
||||
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.LastUpdated = b.LastUpdated
|
||||
ids = s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].Assoc
|
||||
ids = append(ids, s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].Main)
|
||||
book := s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType]
|
||||
book.b.Bids = b.Bids
|
||||
book.b.Asks = b.Asks
|
||||
book.b.LastUpdated = b.LastUpdated
|
||||
ids = book.Assoc
|
||||
ids = append(ids, book.Main)
|
||||
}
|
||||
s.Unlock()
|
||||
return s.mux.Publish(ids, b)
|
||||
|
||||
@@ -147,19 +147,20 @@ func (s *Service) Update(p *Price) error {
|
||||
}
|
||||
|
||||
default:
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Last = p.Last
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].High = p.High
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Low = p.Low
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Bid = p.Bid
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Ask = p.Ask
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Volume = p.Volume
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].QuoteVolume = p.QuoteVolume
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].PriceATH = p.PriceATH
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Open = p.Open
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Close = p.Close
|
||||
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].LastUpdated = p.LastUpdated
|
||||
ids = s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Assoc
|
||||
ids = append(ids, s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Main)
|
||||
ticker := s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType]
|
||||
ticker.Last = p.Last
|
||||
ticker.High = p.High
|
||||
ticker.Low = p.Low
|
||||
ticker.Bid = p.Bid
|
||||
ticker.Ask = p.Ask
|
||||
ticker.Volume = p.Volume
|
||||
ticker.QuoteVolume = p.QuoteVolume
|
||||
ticker.PriceATH = p.PriceATH
|
||||
ticker.Open = p.Open
|
||||
ticker.Close = p.Close
|
||||
ticker.LastUpdated = p.LastUpdated
|
||||
ids = ticker.Assoc
|
||||
ids = append(ids, ticker.Main)
|
||||
}
|
||||
s.Unlock()
|
||||
return s.mux.Publish(ids, p)
|
||||
|
||||
@@ -92,6 +92,7 @@ func (w *Websocket) Connect() error {
|
||||
go w.connectionMonitor()
|
||||
}
|
||||
if w.SupportsFunctionality(WebsocketSubscribeSupported) || w.SupportsFunctionality(WebsocketUnsubscribeSupported) {
|
||||
w.Wg.Add(1)
|
||||
go w.manageSubscriptions()
|
||||
}
|
||||
|
||||
@@ -498,7 +499,6 @@ func (w *Websocket) manageSubscriptions() {
|
||||
w.DataHandler <- fmt.Errorf("%v does not support channel subscriptions, exiting ManageSubscriptions()", w.exchangeName)
|
||||
return
|
||||
}
|
||||
w.Wg.Add(1)
|
||||
defer func() {
|
||||
if w.verbose {
|
||||
log.Debugf(log.WebsocketMgr, "%v ManageSubscriptions exiting", w.exchangeName)
|
||||
|
||||
@@ -352,12 +352,13 @@ func TestManageSubscriptionsStartStop(t *testing.T) {
|
||||
ShutdownC: make(chan struct{}),
|
||||
Functionality: WebsocketSubscribeSupported | WebsocketUnsubscribeSupported,
|
||||
}
|
||||
w.Wg.Add(1)
|
||||
go w.manageSubscriptions()
|
||||
close(w.ShutdownC)
|
||||
w.Wg.Wait()
|
||||
}
|
||||
|
||||
// TestManageSubscriptionsStartStop logic test
|
||||
// TestManageSubscriptions logic test
|
||||
func TestManageSubscriptions(t *testing.T) {
|
||||
w := Websocket{
|
||||
ShutdownC: make(chan struct{}),
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
@@ -33,21 +32,22 @@ func (w *WebsocketOrderbookLocal) Update(orderbookUpdate *WebsocketOrderbookUpda
|
||||
}
|
||||
w.m.Lock()
|
||||
defer w.m.Unlock()
|
||||
if _, ok := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]; !ok {
|
||||
obLookup, ok := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]
|
||||
if !ok {
|
||||
return fmt.Errorf("ob.Base could not be found for Exchange %s CurrencyPair: %s AssetType: %s",
|
||||
w.exchangeName,
|
||||
orderbookUpdate.CurrencyPair.String(),
|
||||
orderbookUpdate.AssetType)
|
||||
}
|
||||
if w.bufferEnabled {
|
||||
overBufferLimit := w.processBufferUpdate(orderbookUpdate)
|
||||
overBufferLimit := w.processBufferUpdate(obLookup, orderbookUpdate)
|
||||
if !overBufferLimit {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
w.processObUpdate(orderbookUpdate)
|
||||
w.processObUpdate(obLookup, orderbookUpdate)
|
||||
}
|
||||
err := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Process()
|
||||
err := obLookup.Process()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -58,144 +58,142 @@ func (w *WebsocketOrderbookLocal) Update(orderbookUpdate *WebsocketOrderbookUpda
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WebsocketOrderbookLocal) processBufferUpdate(orderbookUpdate *WebsocketOrderbookUpdate) bool {
|
||||
func (w *WebsocketOrderbookLocal) processBufferUpdate(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) bool {
|
||||
if w.buffer == nil {
|
||||
w.buffer = make(map[currency.Pair]map[asset.Item][]WebsocketOrderbookUpdate)
|
||||
w.buffer = make(map[currency.Pair]map[asset.Item][]*WebsocketOrderbookUpdate)
|
||||
}
|
||||
if w.buffer[orderbookUpdate.CurrencyPair] == nil {
|
||||
w.buffer[orderbookUpdate.CurrencyPair] = make(map[asset.Item][]WebsocketOrderbookUpdate)
|
||||
w.buffer[orderbookUpdate.CurrencyPair] = make(map[asset.Item][]*WebsocketOrderbookUpdate)
|
||||
}
|
||||
if len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]) <= w.obBufferLimit {
|
||||
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = append(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], *orderbookUpdate)
|
||||
if len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]) < w.obBufferLimit {
|
||||
bufferLookup := w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]
|
||||
if len(bufferLookup) <= w.obBufferLimit {
|
||||
bufferLookup = append(bufferLookup, orderbookUpdate)
|
||||
if len(bufferLookup) < w.obBufferLimit {
|
||||
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = bufferLookup
|
||||
return false
|
||||
}
|
||||
}
|
||||
if w.sortBuffer {
|
||||
// sort by last updated to ensure each update is in order
|
||||
if w.sortBufferByUpdateIDs {
|
||||
sort.Slice(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], func(i, j int) bool {
|
||||
return w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i].UpdateID < w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][j].UpdateID
|
||||
sort.Slice(bufferLookup, func(i, j int) bool {
|
||||
return bufferLookup[i].UpdateID < bufferLookup[j].UpdateID
|
||||
})
|
||||
} else {
|
||||
sort.Slice(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], func(i, j int) bool {
|
||||
return w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i].UpdateTime.Before(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][j].UpdateTime)
|
||||
sort.Slice(bufferLookup, func(i, j int) bool {
|
||||
return bufferLookup[i].UpdateTime.Before(bufferLookup[j].UpdateTime)
|
||||
})
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]); i++ {
|
||||
w.processObUpdate(&w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i])
|
||||
for i := 0; i < len(bufferLookup); i++ {
|
||||
w.processObUpdate(o, bufferLookup[i])
|
||||
}
|
||||
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = bufferLookup
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WebsocketOrderbookLocal) processObUpdate(orderbookUpdate *WebsocketOrderbookUpdate) {
|
||||
func (w *WebsocketOrderbookLocal) processObUpdate(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) {
|
||||
if w.updateEntriesByID {
|
||||
w.updateByIDAndAction(orderbookUpdate)
|
||||
w.updateByIDAndAction(o, orderbookUpdate)
|
||||
} else {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go w.updateAsksByPrice(orderbookUpdate, &wg)
|
||||
go w.updateBidsByPrice(orderbookUpdate, &wg)
|
||||
wg.Wait()
|
||||
w.updateAsksByPrice(o, orderbookUpdate)
|
||||
w.updateBidsByPrice(o, orderbookUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsocketOrderbookLocal) updateAsksByPrice(base *WebsocketOrderbookUpdate, wg *sync.WaitGroup) {
|
||||
func (w *WebsocketOrderbookLocal) updateAsksByPrice(o *orderbook.Base, base *WebsocketOrderbookUpdate) {
|
||||
for j := 0; j < len(base.Asks); j++ {
|
||||
found := false
|
||||
for k := 0; k < len(w.ob[base.CurrencyPair][base.AssetType].Asks); k++ {
|
||||
if w.ob[base.CurrencyPair][base.AssetType].Asks[k].Price == base.Asks[j].Price {
|
||||
for k := 0; k < len(o.Asks); k++ {
|
||||
if o.Asks[k].Price == base.Asks[j].Price {
|
||||
found = true
|
||||
if base.Asks[j].Amount == 0 {
|
||||
w.ob[base.CurrencyPair][base.AssetType].Asks = append(w.ob[base.CurrencyPair][base.AssetType].Asks[:k],
|
||||
w.ob[base.CurrencyPair][base.AssetType].Asks[k+1:]...)
|
||||
o.Asks = append(o.Asks[:k],
|
||||
o.Asks[k+1:]...)
|
||||
break
|
||||
}
|
||||
w.ob[base.CurrencyPair][base.AssetType].Asks[k].Amount = base.Asks[j].Amount
|
||||
o.Asks[k].Amount = base.Asks[j].Amount
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
w.ob[base.CurrencyPair][base.AssetType].Asks = append(w.ob[base.CurrencyPair][base.AssetType].Asks, base.Asks[j])
|
||||
o.Asks = append(o.Asks, base.Asks[j])
|
||||
}
|
||||
}
|
||||
sort.Slice(w.ob[base.CurrencyPair][base.AssetType].Asks, func(i, j int) bool {
|
||||
return w.ob[base.CurrencyPair][base.AssetType].Asks[i].Price < w.ob[base.CurrencyPair][base.AssetType].Asks[j].Price
|
||||
sort.Slice(o.Asks, func(i, j int) bool {
|
||||
return o.Asks[i].Price < o.Asks[j].Price
|
||||
})
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func (w *WebsocketOrderbookLocal) updateBidsByPrice(base *WebsocketOrderbookUpdate, wg *sync.WaitGroup) {
|
||||
func (w *WebsocketOrderbookLocal) updateBidsByPrice(o *orderbook.Base, base *WebsocketOrderbookUpdate) {
|
||||
for j := 0; j < len(base.Bids); j++ {
|
||||
found := false
|
||||
for k := 0; k < len(w.ob[base.CurrencyPair][base.AssetType].Bids); k++ {
|
||||
if w.ob[base.CurrencyPair][base.AssetType].Bids[k].Price == base.Bids[j].Price {
|
||||
for k := 0; k < len(o.Bids); k++ {
|
||||
if o.Bids[k].Price == base.Bids[j].Price {
|
||||
found = true
|
||||
if base.Bids[j].Amount == 0 {
|
||||
w.ob[base.CurrencyPair][base.AssetType].Bids = append(w.ob[base.CurrencyPair][base.AssetType].Bids[:k],
|
||||
w.ob[base.CurrencyPair][base.AssetType].Bids[k+1:]...)
|
||||
o.Bids = append(o.Bids[:k],
|
||||
o.Bids[k+1:]...)
|
||||
break
|
||||
}
|
||||
w.ob[base.CurrencyPair][base.AssetType].Bids[k].Amount = base.Bids[j].Amount
|
||||
o.Bids[k].Amount = base.Bids[j].Amount
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
w.ob[base.CurrencyPair][base.AssetType].Bids = append(w.ob[base.CurrencyPair][base.AssetType].Bids, base.Bids[j])
|
||||
o.Bids = append(o.Bids, base.Bids[j])
|
||||
}
|
||||
}
|
||||
sort.Slice(w.ob[base.CurrencyPair][base.AssetType].Bids, func(i, j int) bool {
|
||||
return w.ob[base.CurrencyPair][base.AssetType].Bids[i].Price > w.ob[base.CurrencyPair][base.AssetType].Bids[j].Price
|
||||
sort.Slice(o.Bids, func(i, j int) bool {
|
||||
return o.Bids[i].Price > o.Bids[j].Price
|
||||
})
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
// updateByIDAndAction will receive an action to execute against the orderbook
|
||||
// it will then match by IDs instead of price to perform the action
|
||||
func (w *WebsocketOrderbookLocal) updateByIDAndAction(orderbookUpdate *WebsocketOrderbookUpdate) {
|
||||
func (w *WebsocketOrderbookLocal) updateByIDAndAction(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) {
|
||||
switch orderbookUpdate.Action {
|
||||
case "update":
|
||||
for _, target := range orderbookUpdate.Bids {
|
||||
for i := range w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids {
|
||||
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].ID == target.ID {
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].Amount = target.Amount
|
||||
for i := range o.Bids {
|
||||
if o.Bids[i].ID == target.ID {
|
||||
o.Bids[i].Amount = target.Amount
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, target := range orderbookUpdate.Asks {
|
||||
for i := range w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks {
|
||||
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].ID == target.ID {
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].Amount = target.Amount
|
||||
for i := range o.Asks {
|
||||
if o.Asks[i].ID == target.ID {
|
||||
o.Asks[i].Amount = target.Amount
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case "delete":
|
||||
for _, target := range orderbookUpdate.Bids {
|
||||
for i := 0; i < len(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids); i++ {
|
||||
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].ID == target.ID {
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[:i],
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i+1:]...)
|
||||
for i := 0; i < len(o.Bids); i++ {
|
||||
if o.Bids[i].ID == target.ID {
|
||||
o.Bids = append(o.Bids[:i],
|
||||
o.Bids[i+1:]...)
|
||||
i--
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, target := range orderbookUpdate.Asks {
|
||||
for i := 0; i < len(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks); i++ {
|
||||
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].ID == target.ID {
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[:i],
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i+1:]...)
|
||||
for i := 0; i < len(o.Asks); i++ {
|
||||
if o.Asks[i].ID == target.ID {
|
||||
o.Asks = append(o.Asks[:i],
|
||||
o.Asks[i+1:]...)
|
||||
i--
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case "insert":
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids, orderbookUpdate.Bids...)
|
||||
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks, orderbookUpdate.Asks...)
|
||||
o.Bids = append(o.Bids, orderbookUpdate.Bids...)
|
||||
o.Asks = append(o.Asks, orderbookUpdate.Asks...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,10 +225,11 @@ func (w *WebsocketOrderbookLocal) LoadSnapshot(newOrderbook *orderbook.Base) err
|
||||
if w.ob[newOrderbook.Pair] == nil {
|
||||
w.ob[newOrderbook.Pair] = make(map[asset.Item]*orderbook.Base)
|
||||
}
|
||||
if w.ob[newOrderbook.Pair][newOrderbook.AssetType] != nil &&
|
||||
(len(w.ob[newOrderbook.Pair][newOrderbook.AssetType].Asks) > 0 ||
|
||||
len(w.ob[newOrderbook.Pair][newOrderbook.AssetType].Bids) > 0) {
|
||||
w.ob[newOrderbook.Pair][newOrderbook.AssetType] = newOrderbook
|
||||
fullObLookup := w.ob[newOrderbook.Pair][newOrderbook.AssetType]
|
||||
if fullObLookup != nil &&
|
||||
(len(fullObLookup.Asks) > 0 ||
|
||||
len(fullObLookup.Bids) > 0) {
|
||||
fullObLookup = newOrderbook
|
||||
return newOrderbook.Process()
|
||||
}
|
||||
w.ob[newOrderbook.Pair][newOrderbook.AssetType] = newOrderbook
|
||||
|
||||
@@ -43,6 +43,61 @@ func createSnapshot() (obl *WebsocketOrderbookLocal, curr currency.Pair, asks, b
|
||||
return
|
||||
}
|
||||
|
||||
func bidAskGenerator() []orderbook.Item {
|
||||
var response []orderbook.Item
|
||||
randIterator := 100
|
||||
for i := 0; i < randIterator; i++ {
|
||||
price := float64(rand.Intn(1000))
|
||||
if price == 0 {
|
||||
price = 1
|
||||
}
|
||||
response = append(response, orderbook.Item{
|
||||
Amount: float64(rand.Intn(1)),
|
||||
Price: price,
|
||||
ID: int64(i),
|
||||
})
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func BenchmarkUpdateBidsByPrice(b *testing.B) {
|
||||
ob, curr, _, _, err := createSnapshot()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bidAsks := bidAskGenerator()
|
||||
update := &WebsocketOrderbookUpdate{
|
||||
Bids: bidAsks,
|
||||
Asks: bidAsks,
|
||||
CurrencyPair: curr,
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
ob.updateBidsByPrice(ob.ob[curr][asset.Spot], update)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUpdateAsksByPrice(b *testing.B) {
|
||||
ob, curr, _, _, err := createSnapshot()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bidAsks := bidAskGenerator()
|
||||
update := &WebsocketOrderbookUpdate{
|
||||
Bids: bidAsks,
|
||||
Asks: bidAsks,
|
||||
CurrencyPair: curr,
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
ob.updateAsksByPrice(ob.ob[curr][asset.Spot], update)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkBufferPerformance demonstrates buffer more performant than multi
|
||||
// process calls
|
||||
func BenchmarkBufferPerformance(b *testing.B) {
|
||||
@@ -50,6 +105,42 @@ func BenchmarkBufferPerformance(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
obl.bufferEnabled = true
|
||||
cp := currency.NewPairFromString("BTCUSD")
|
||||
// This is to ensure we do not send in zero orderbook info to our main book
|
||||
// in orderbook.go, orderbooks should not be zero even after an update.
|
||||
dummyItem := orderbook.Item{
|
||||
Amount: 1333337,
|
||||
Price: 1337.1337,
|
||||
ID: 1337,
|
||||
}
|
||||
obl.ob[cp][asset.Spot].Bids = append(obl.ob[cp][asset.Spot].Bids, dummyItem)
|
||||
update := &WebsocketOrderbookUpdate{
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
CurrencyPair: curr,
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randomIndex := rand.Intn(4)
|
||||
update.Asks = itemArray[randomIndex]
|
||||
update.Bids = itemArray[randomIndex]
|
||||
err = obl.Update(update)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkBufferSortingPerformance benchmark
|
||||
func BenchmarkBufferSortingPerformance(b *testing.B) {
|
||||
obl, curr, asks, bids, err := createSnapshot()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
obl.bufferEnabled = true
|
||||
obl.sortBuffer = true
|
||||
cp := currency.NewPairFromString("BTCUSD")
|
||||
// This is to ensure we do not send in zero orderbook info to our main book
|
||||
@@ -67,8 +158,9 @@ func BenchmarkBufferPerformance(b *testing.B) {
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randomIndex := rand.Intn(5)
|
||||
randomIndex := rand.Intn(4)
|
||||
update.Asks = itemArray[randomIndex]
|
||||
update.Bids = itemArray[randomIndex]
|
||||
err = obl.Update(update)
|
||||
@@ -79,14 +171,23 @@ func BenchmarkBufferPerformance(b *testing.B) {
|
||||
}
|
||||
|
||||
// BenchmarkBufferSortingPerformance benchmark
|
||||
func BenchmarkBufferSortingPerformance(b *testing.B) {
|
||||
func BenchmarkBufferSortingByIDPerformance(b *testing.B) {
|
||||
obl, curr, asks, bids, err := createSnapshot()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
obl.sortBuffer = true
|
||||
obl.bufferEnabled = true
|
||||
obl.obBufferLimit = 5
|
||||
obl.sortBuffer = true
|
||||
obl.sortBufferByUpdateIDs = true
|
||||
cp := currency.NewPairFromString("BTCUSD")
|
||||
// This is to ensure we do not send in zero orderbook info to our main book
|
||||
// in orderbook.go, orderbooks should not be zero even after an update.
|
||||
dummyItem := orderbook.Item{
|
||||
Amount: 1333337,
|
||||
Price: 1337.1337,
|
||||
ID: 1337,
|
||||
}
|
||||
obl.ob[cp][asset.Spot].Bids = append(obl.ob[cp][asset.Spot].Bids, dummyItem)
|
||||
update := &WebsocketOrderbookUpdate{
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
@@ -94,8 +195,9 @@ func BenchmarkBufferSortingPerformance(b *testing.B) {
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randomIndex := rand.Intn(5)
|
||||
randomIndex := rand.Intn(4)
|
||||
update.Asks = itemArray[randomIndex]
|
||||
update.Bids = itemArray[randomIndex]
|
||||
err = obl.Update(update)
|
||||
@@ -128,8 +230,9 @@ func BenchmarkNoBufferPerformance(b *testing.B) {
|
||||
UpdateTime: time.Now(),
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randomIndex := rand.Intn(5)
|
||||
randomIndex := rand.Intn(4)
|
||||
update.Asks = itemArray[randomIndex]
|
||||
update.Bids = itemArray[randomIndex]
|
||||
err = obl.Update(update)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// appending and deleting changes and updates the main store in wsorderbook.go
|
||||
type WebsocketOrderbookLocal struct {
|
||||
ob map[currency.Pair]map[asset.Item]*orderbook.Base
|
||||
buffer map[currency.Pair]map[asset.Item][]WebsocketOrderbookUpdate
|
||||
buffer map[currency.Pair]map[asset.Item][]*WebsocketOrderbookUpdate
|
||||
obBufferLimit int
|
||||
bufferEnabled bool
|
||||
sortBuffer bool
|
||||
|
||||
Reference in New Issue
Block a user