From 8b9d6e4d6c93ce0553fc68580c51a5e7bec4c0f9 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 09:28:25 +1100 Subject: [PATCH 01/13] initial purge and benchmarks proof before rn overhaul --- exchanges/orderbook/depth.go | 39 +- exchanges/orderbook/depth_test.go | 12 +- exchanges/orderbook/linked_list.go | 604 ++++++--------------- exchanges/orderbook/linked_list_test.go | 670 +++++++----------------- exchanges/orderbook/node.go | 126 ----- exchanges/orderbook/node_test.go | 101 ---- exchanges/orderbook/orderbook_test.go | 3 - exchanges/orderbook/unsafe.go | 168 ------ exchanges/orderbook/unsafe_test.go | 279 ---------- 9 files changed, 388 insertions(+), 1614 deletions(-) delete mode 100644 exchanges/orderbook/node.go delete mode 100644 exchanges/orderbook/node_test.go delete mode 100644 exchanges/orderbook/unsafe.go delete mode 100644 exchanges/orderbook/unsafe_test.go diff --git a/exchanges/orderbook/depth.go b/exchanges/orderbook/depth.go index cde8842cf17..38e8855e378 100644 --- a/exchanges/orderbook/depth.go +++ b/exchanges/orderbook/depth.go @@ -37,8 +37,8 @@ type Depth struct { asks bids - // unexported stack of nodes - stack *stack + // // unexported stack of nodes + // stack *stack alert.Notice @@ -56,9 +56,9 @@ type Depth struct { // NewDepth returns a new depth item func NewDepth(id uuid.UUID) *Depth { return &Depth{ - stack: newStack(), - _ID: id, - mux: service.Mux, + // stack: newStack(), + _ID: id, + mux: service.Mux, } } @@ -107,8 +107,8 @@ func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated d.lastUpdateID = lastUpdateID d.lastUpdated = lastUpdated d.restSnapshot = updateByREST - d.bids.load(bids, d.stack, lastUpdated) - d.asks.load(asks, d.stack, lastUpdated) + d.bids.load(bids) + d.asks.load(asks) d.validationError = nil d.Alert() return nil @@ -119,9 +119,8 @@ func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated func (d *Depth) invalidate(withReason error) error { d.lastUpdateID = 0 d.lastUpdated = time.Time{} - tn := time.Now() - d.bids.load(nil, d.stack, tn) - d.asks.load(nil, d.stack, tn) + d.bids.load(nil) + d.asks.load(nil) d.validationError = fmt.Errorf("%s %s %s Reason: [%w]", d.exchange, d.pair, @@ -160,10 +159,10 @@ func (d *Depth) UpdateBidAskByPrice(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - d.bids.updateInsertByPrice(update.Bids, d.stack, d.options.maxDepth, update.UpdateTime) + d.bids.updateInsertByPrice(update.Bids, d.options.maxDepth) } if len(update.Asks) != 0 { - d.asks.updateInsertByPrice(update.Asks, d.stack, d.options.maxDepth, update.UpdateTime) + d.asks.updateInsertByPrice(update.Asks, d.options.maxDepth) } d.updateAndAlert(update) return nil @@ -210,13 +209,13 @@ func (d *Depth) DeleteBidAskByID(update *Update, bypassErr bool) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.deleteByID(update.Bids, d.stack, bypassErr, update.UpdateTime) + err := d.bids.deleteByID(update.Bids, bypassErr) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.deleteByID(update.Asks, d.stack, bypassErr, update.UpdateTime) + err := d.asks.deleteByID(update.Asks, bypassErr) if err != nil { return d.invalidate(err) } @@ -237,13 +236,13 @@ func (d *Depth) InsertBidAskByID(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.insertUpdates(update.Bids, d.stack) + err := d.bids.insertUpdates(update.Bids) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.insertUpdates(update.Asks, d.stack) + err := d.asks.insertUpdates(update.Asks) if err != nil { return d.invalidate(err) } @@ -264,13 +263,13 @@ func (d *Depth) UpdateInsertByID(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.updateInsertByID(update.Bids, d.stack) + err := d.bids.updateInsertByID(update.Bids) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.updateInsertByID(update.Asks, d.stack) + err := d.asks.updateInsertByID(update.Asks) if err != nil { return d.invalidate(err) } @@ -340,7 +339,7 @@ func (d *Depth) GetAskLength() (int, error) { if d.validationError != nil { return 0, d.validationError } - return d.asks.length, nil + return len(d.asks.linkedList), nil } // GetBidLength returns length of bids @@ -350,7 +349,7 @@ func (d *Depth) GetBidLength() (int, error) { if d.validationError != nil { return 0, d.validationError } - return d.bids.length, nil + return len(d.bids.linkedList), nil } // TotalBidAmounts returns the total amount of bids and the total orderbook diff --git a/exchanges/orderbook/depth_test.go b/exchanges/orderbook/depth_test.go index 93ec560b802..06410f2917f 100644 --- a/exchanges/orderbook/depth_test.go +++ b/exchanges/orderbook/depth_test.go @@ -35,7 +35,7 @@ func TestGetLength(t *testing.T) { assert.NoError(t, err, "GetAskLength should not error") assert.Zero(t, askLen, "ask length should be zero") - d.asks.load([]Item{{Price: 1337}}, d.stack, time.Now()) + d.asks.load([]Item{{Price: 1337}}) askLen, err = d.GetAskLength() assert.NoError(t, err, "GetAskLength should not error") @@ -55,7 +55,7 @@ func TestGetLength(t *testing.T) { assert.NoError(t, err, "GetBidLength should not error") assert.Zero(t, bidLen, "bid length should be zero") - d.bids.load([]Item{{Price: 1337}}, d.stack, time.Now()) + d.bids.load([]Item{{Price: 1337}}) bidLen, err = d.GetBidLength() assert.NoError(t, err, "GetBidLength should not error") @@ -65,8 +65,8 @@ func TestGetLength(t *testing.T) { func TestRetrieve(t *testing.T) { t.Parallel() d := NewDepth(id) - d.asks.load([]Item{{Price: 1337}}, d.stack, time.Now()) - d.bids.load([]Item{{Price: 1337}}, d.stack, time.Now()) + d.asks.load([]Item{{Price: 1337}}) + d.bids.load([]Item{{Price: 1337}}) d.options = options{ exchange: "THE BIG ONE!!!!!!", pair: currency.NewPair(currency.THETA, currency.USD), @@ -125,8 +125,8 @@ func TestTotalAmounts(t *testing.T) { assert.Zero(t, liquidity, "total ask liquidity should be zero") assert.Zero(t, value, "total ask value should be zero") - d.asks.load([]Item{{Price: 1337, Amount: 1}}, d.stack, time.Now()) - d.bids.load([]Item{{Price: 1337, Amount: 10}}, d.stack, time.Now()) + d.asks.load([]Item{{Price: 1337, Amount: 1}}) + d.bids.load([]Item{{Price: 1337, Amount: 10}}) liquidity, value, err = d.TotalBidAmounts() assert.NoError(t, err, "TotalBidAmounts should not error") diff --git a/exchanges/orderbook/linked_list.go b/exchanges/orderbook/linked_list.go index 0b64f309e37..7f74268c0cd 100644 --- a/exchanges/orderbook/linked_list.go +++ b/exchanges/orderbook/linked_list.go @@ -3,7 +3,6 @@ package orderbook import ( "errors" "fmt" - "time" "github.com/thrasher-corp/gocryptotrader/common/math" ) @@ -25,14 +24,10 @@ var ( errInvalidCost = errors.New("invalid cost amount") errInvalidAmount = errors.New("invalid amount") errInvalidHeadPrice = errors.New("invalid head price") + errNoLiquidity = errors.New("no liquidity") ) -// linkedList defines a linked list for a depth level, reutilisation of nodes -// to and from a stack. -type linkedList struct { - length int - head *Node -} +type linkedList []Item // comparison defines expected functionality to compare between two reference // price levels @@ -41,69 +36,41 @@ type comparison func(float64, float64) bool // load iterates across new items and refreshes linked list. It creates a linked // list exactly the same as the item slice that is supplied, if items is of nil // value it will flush entire list. -func (ll *linkedList) load(items Items, stack *stack, tn time.Time) { - // Tip sets up a pointer to a struct field variable pointer. This is used - // so when a node is popped from the stack we can reference that current - // nodes' struct 'next' field and set on next iteration without utilising - // assignment for example `prev.Next = *node`. - var tip = &ll.head - // Prev denotes a place holder to node and all of its next references need - // to be pushed back onto stack. - var prev *Node - for i := range items { - if *tip == nil { - // Extend node chain - *tip = stack.Pop() - // Set current node prev to last node - (*tip).Prev = prev - ll.length++ - } - // Set item value - (*tip).Value = items[i] - // Set previous to current node - prev = *tip - // Set tip to next node - tip = &(*tip).Next - } - - // Push has references to dangling nodes that need to be removed and pushed - // back onto stack for reuse - var push *Node - // Cleave unused reference chain from main chain - if prev == nil { - // The entire chain will need to be pushed back on to stack - push = *tip - ll.head = nil - } else { - push = prev.Next - prev.Next = nil +func (ll *linkedList) load(items Items) { + if len(items) == 0 { + *ll = (*ll)[:0] // Flush + return } - - // Push unused pointers back on stack - for push != nil { - pending := push.Next - stack.Push(push, tn) - ll.length-- - push = pending + if len(items) <= len(*ll) { + copy(*ll, items) // Reuse + *ll = (*ll)[:len(items)] // Flush excess + return + } + if len(items) > cap(*ll) { + *ll = make([]Item, len(items)) // Extend + copy(*ll, items) // Copy + return } + *ll = (*ll)[:0] // Flush + *ll = append(*ll, items...) // Append } // updateByID amends price by corresponding ID and returns an error if not found -func (ll *linkedList) updateByID(updts []Item) error { +func (ll linkedList) updateByID(updts []Item) error { updates: for x := range updts { - for tip := ll.head; tip != nil; tip = tip.Next { - if updts[x].ID != tip.Value.ID { // Filter IDs that don't match + for y := range ll { + if updts[x].ID != ll[y].ID { // Filter IDs that don't match continue } if updts[x].Price > 0 { // Only apply changes when zero values are not present, Bitmex // for example sends 0 price values. - tip.Value.Price = updts[x].Price - tip.Value.StrPrice = updts[x].StrPrice + ll[y].Price = updts[x].Price + ll[y].StrPrice = updts[x].StrPrice } - tip.Value.Amount = updts[x].Amount - tip.Value.StrAmount = updts[x].StrAmount + ll[y].Amount = updts[x].Amount + ll[y].StrAmount = updts[x].StrAmount continue updates } return fmt.Errorf("update error: %w ID: %d not found", @@ -114,14 +81,15 @@ updates: } // deleteByID deletes reference by ID -func (ll *linkedList) deleteByID(updts Items, stack *stack, bypassErr bool, tn time.Time) error { +func (ll *linkedList) deleteByID(updts Items, bypassErr bool) error { updates: for x := range updts { - for tip := &ll.head; *tip != nil; tip = &(*tip).Next { - if updts[x].ID != (*tip).Value.ID { + for y := range *ll { + if updts[x].ID != (*ll)[y].ID { continue } - stack.Push(deleteAtTip(ll, tip), tn) + + *ll = append((*ll)[:y], (*ll)[y+1:]...) continue updates } if !bypassErr { @@ -133,102 +101,60 @@ updates: return nil } -// cleanup reduces the max size of the depth length if exceeded. Is used after -// updates have been applied instead of adhoc, reason being its easier to prune -// at the end. (can't inline) -func (ll *linkedList) cleanup(maxChainLength int, stack *stack, tn time.Time) { - // Reduces the max length of total linked list chain, occurs after updates - // have been implemented as updates can push length out of bounds, if - // cleaved after that update, new update might not applied correctly. - n := ll.head - for i := 0; i < maxChainLength; i++ { - if n.Next == nil { - return - } - n = n.Next - } - - // cleave reference to current node - if n.Prev != nil { - n.Prev.Next = nil - } else { - ll.head = nil - } - - var pruned int - for n != nil { - pruned++ - pending := n.Next - stack.Push(n, tn) - n = pending - } - ll.length -= pruned -} - // amount returns total depth liquidity and value -func (ll *linkedList) amount() (liquidity, value float64) { - for tip := ll.head; tip != nil; tip = tip.Next { - liquidity += tip.Value.Amount - value += tip.Value.Amount * tip.Value.Price +func (ll linkedList) amount() (liquidity, value float64) { + for x := range ll { + liquidity += ll[x].Amount + value += ll[x].Amount * ll[x].Price } return } // retrieve returns a full slice of contents from the linked list -func (ll *linkedList) retrieve(count int) Items { - if count == 0 || ll.length < count { - count = ll.length +func (ll linkedList) retrieve(count int) Items { + if count == 0 || len(ll) < count { + count = len(ll) } - depth := make(Items, count) - for i, tip := 0, ll.head; i < count && tip != nil; i, tip = i+1, tip.Next { - depth[i] = tip.Value - } - return depth + return Items(ll[:count]) } // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *linkedList) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, compare func(float64, float64) bool, tn time.Time) { +func (ll *linkedList) updateInsertByPrice(updts Items, maxChainLength int, compare func(float64, float64) bool) { +updateroo: for x := range updts { - for tip := &ll.head; ; tip = &(*tip).Next { - if *tip == nil { - insertHeadSpecific(ll, &updts[x], stack) - break - } - if (*tip).Value.Price == updts[x].Price { // Match check - if updts[x].Amount <= 0 { // Capture delete update - stack.Push(deleteAtTip(ll, tip), tn) - } else { // Amend current amount value - (*tip).Value.Amount = updts[x].Amount - (*tip).Value.StrAmount = updts[x].StrAmount + for y := range *ll { + switch { + case (*ll)[y].Price == updts[x].Price: + if updts[x].Amount <= 0 { + // Delete + if y+1 == len(*ll) { + *ll = (*ll)[:y] + } else { + *ll = append((*ll)[:y], (*ll)[y+1:]...) + } + } else { + // Update + (*ll)[y].Amount = updts[x].Amount + (*ll)[y].StrAmount = updts[x].StrAmount } - break // Continue updates - } - - if compare((*tip).Value.Price, updts[x].Price) { // Insert - // This check below filters zero values and provides an - // optimisation for when select exchanges send a delete update - // to a non-existent price level (OTC/Hidden order) so we can - // break instantly and reduce the traversal of the entire chain. + continue updateroo + case compare((*ll)[y].Price, updts[x].Price): if updts[x].Amount > 0 { - insertAtTip(ll, tip, &updts[x], stack) + *ll = append(*ll, Item{}) // Extend + copy((*ll)[y+1:], (*ll)[y:]) // Copy elements from index y onwards one position to the right + (*ll)[y] = updts[x] // Insert updts[x] at index y } - break // Continue updates - } - - if (*tip).Next == nil { // Tip is at tail - // This check below is just a catch all in the event the above - // zero value check fails - if updts[x].Amount > 0 { - insertAtTail(ll, tip, &updts[x], stack) - } - break + continue updateroo } } + if updts[x].Amount > 0 { + *ll = append(*ll, updts[x]) + } } // Reduces length of total linked list chain to a maxChainLength value - if maxChainLength != 0 && ll.length > maxChainLength { - ll.cleanup(maxChainLength, stack, tn) + if maxChainLength != 0 && len(*ll) > maxChainLength { + *ll = (*ll)[:maxChainLength] } } @@ -239,155 +165,102 @@ func (ll *linkedList) updateInsertByPrice(updts Items, stack *stack, maxChainLen // 3) Update price exceeds traversal node price before ID found, save node // address for either; node ID matches then re-address node or end of depth pop // a node from the stack (worst case) -func (ll *linkedList) updateInsertByID(updts Items, stack *stack, compare comparison) error { +func (ll *linkedList) updateInsertByID(updts Items, compare comparison) error { updates: for x := range updts { if updts[x].Amount <= 0 { return errAmountCannotBeLessOrEqualToZero } - // bookmark allows for saving of a position of a node in the event that - // an update price exceeds the current node price. We can then match an - // ID and re-assign that ID's node to that positioning without popping - // from the stack and then pushing to the stack later for cleanup. - // If the ID is not found we can pop from stack then insert into that - // price level - var bookmark *Node - for tip := ll.head; tip != nil; tip = tip.Next { - if tip.Value.ID == updts[x].ID { - if tip.Value.Price != updts[x].Price { // Price level change - if tip.Next == nil { + var popped bool + for y := 0; y < len(*ll); y++ { + if (*ll)[y].ID == updts[x].ID { + if (*ll)[y].Price != updts[x].Price { // Price level change + if y+1 == len(*ll) { // end of depth // no movement needed just a re-adjustment - tip.Value.Price = updts[x].Price - tip.Value.StrPrice = updts[x].StrPrice - tip.Value.Amount = updts[x].Amount - tip.Value.StrAmount = updts[x].StrAmount + (*ll)[y] = updts[x] continue updates } - // bookmark tip to move this node to correct price level - bookmark = tip + copy((*ll)[y:], (*ll)[y+1:]) // remove him: cya m8 + *ll = (*ll)[:len(*ll)-1] // keep underlying array + y-- // adjust index + popped = true continue // continue through node depth } // no price change, amend amount and continue update - tip.Value.Amount = updts[x].Amount - tip.Value.StrAmount = updts[x].StrAmount + (*ll)[y].Amount = updts[x].Amount + (*ll)[y].StrAmount = updts[x].StrAmount continue updates // continue to next update } - if compare(tip.Value.Price, updts[x].Price) { - if bookmark != nil { // shift bookmarked node to current tip - bookmark.Value = updts[x] - move(&ll.head, bookmark, tip) + if compare((*ll)[y].Price, updts[x].Price) { + *ll = append(*ll, Item{}) // Extend + copy((*ll)[y+1:], (*ll)[y:]) // Copy elements from index y onwards one position to the right + (*ll)[y] = updts[x] // Insert updts[x] at index y + + if popped { // already found ID and popped continue updates } // search for ID - for n := tip.Next; n != nil; n = n.Next { - if n.Value.ID == updts[x].ID { - n.Value = updts[x] - // inserting before the tip - move(&ll.head, n, tip) - continue updates - } - } - // ID not matched in depth so add correct level for insert - if tip.Next == nil { - n := stack.Pop() - n.Value = updts[x] - ll.length++ - if tip.Prev == nil { - tip.Prev = n - n.Next = tip - ll.head = n - continue updates + for z := y + 1; z < len(*ll); z++ { + if (*ll)[z].ID == updts[x].ID { + copy((*ll)[z:], (*ll)[z+1:]) // remove him: cya m8 + *ll = (*ll)[:len(*ll)-1] // keep underlying array + break } - tip.Prev.Next = n - n.Prev = tip.Prev - tip.Prev = n - n.Next = tip - continue updates - } - bookmark = tip - break - } - - if tip.Next == nil { - if shiftBookmark(tip, &bookmark, &ll.head, &updts[x]) { - continue updates } + continue updates } } - n := stack.Pop() - n.Value = updts[x] - insertNodeAtBookmark(ll, bookmark, n) // Won't inline with stack + *ll = append(*ll, updts[x]) } return nil } // insertUpdates inserts new updates for bids or asks based on price level -func (ll *linkedList) insertUpdates(updts Items, stack *stack, comp comparison) error { +func (ll *linkedList) insertUpdates(updts Items, comp comparison) error { +updaterino: for x := range updts { - var prev *Node - for tip := &ll.head; ; tip = &(*tip).Next { - if *tip == nil { // Head - n := stack.Pop() - n.Value = updts[x] - n.Prev = prev - ll.length++ - *tip = n - break // Continue updates - } - - if (*tip).Value.Price == updts[x].Price { // Price already found - return fmt.Errorf("%w for price %f", - errCollisionDetected, - updts[x].Price) - } - - if comp((*tip).Value.Price, updts[x].Price) { // Alignment - n := stack.Pop() - n.Value = updts[x] - n.Prev = prev - ll.length++ - // Reference current with new node - (*tip).Prev = n - // Push tip to the right - n.Next = *tip - // This is the same as prev.Next = n - *tip = n - break // Continue updates - } + if len(*ll) == 0 { // TODO: Offset this and outline + *ll = append(*ll, updts[x]) + continue + } - if (*tip).Next == nil { // Tail - insertAtTail(ll, tip, &updts[x], stack) - break // Continue updates + for y := range *ll { + switch { + case (*ll)[y].Price == updts[x].Price: // Price already found + return fmt.Errorf("%w for price %f", errCollisionDetected, updts[x].Price) + case comp((*ll)[y].Price, updts[x].Price): // price at correct spot + *ll = append((*ll)[:y], append([]Item{updts[x]}, (*ll)[y:]...)...) + continue updaterino } - prev = *tip } + *ll = append(*ll, updts[x]) } return nil } // getHeadPriceNoLock gets best/head price -func (ll *linkedList) getHeadPriceNoLock() (float64, error) { - if ll.head == nil { +func (ll linkedList) getHeadPriceNoLock() (float64, error) { + if len(ll) == 0 { return 0, errNoLiquidity } - return ll.head.Value.Price, nil + return ll[0].Price, nil } // getHeadVolumeNoLock gets best/head volume -func (ll *linkedList) getHeadVolumeNoLock() (float64, error) { - if ll.head == nil { +func (ll linkedList) getHeadVolumeNoLock() (float64, error) { + if len(ll) == 0 { return 0, errNoLiquidity } - return ll.head.Value.Amount, nil + return ll[0].Amount, nil } // getMovementByQuotation traverses through orderbook liquidity using quotation // currency as a limiter and returns orderbook movement details. Swap boolean // allows the swap of sold and purchased to reduce code so it doesn't need to be // specific to bid or ask. -func (ll *linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) (*Movement, error) { +func (ll linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) (*Movement, error) { if quote <= 0 { return nil, errQuoteAmountInvalid } @@ -402,29 +275,30 @@ func (ll *linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) } m := Movement{StartPrice: refPrice} - for tip := ll.head; tip != nil; tip = tip.Next { - trancheValue := tip.Value.Amount * tip.Value.Price + for x := range ll { + trancheValue := ll[x].Amount * ll[x].Price leftover := quote - trancheValue if leftover < 0 { m.Purchased += quote - m.Sold += quote / trancheValue * tip.Value.Amount + m.Sold += quote / trancheValue * ll[x].Amount // This tranche is not consumed so the book shifts to this price. - m.EndPrice = tip.Value.Price + m.EndPrice = ll[x].Price quote = 0 break } // Full tranche consumed - m.Purchased += tip.Value.Price * tip.Value.Amount - m.Sold += tip.Value.Amount + m.Purchased += ll[x].Price * ll[x].Amount + m.Sold += ll[x].Amount quote = leftover if leftover == 0 { // Price no longer exists on the book so use next full price tranche // to calculate book impact. If available. - if tip.Next != nil { - m.EndPrice = tip.Next.Value.Price + if x+1 < len(ll) { + m.EndPrice = ll[x+1].Price } else { m.FullBookSideConsumed = true } + break } } return m.finalizeFields(m.Purchased, m.Sold, head, quote, swap) @@ -434,7 +308,7 @@ func (ll *linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) // as a limiter and returns orderbook movement details. Swap boolean allows the // swap of sold and purchased to reduce code so it doesn't need to be specific // to bid or ask. -func (ll *linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Movement, error) { +func (ll linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Movement, error) { if base <= 0 { return nil, errBaseAmountInvalid } @@ -449,28 +323,29 @@ func (ll *linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Mov } m := Movement{StartPrice: refPrice} - for tip := ll.head; tip != nil; tip = tip.Next { - leftover := base - tip.Value.Amount + for x := range ll { + leftover := base - ll[x].Amount if leftover < 0 { - m.Purchased += tip.Value.Price * base + m.Purchased += ll[x].Price * base m.Sold += base // This tranche is not consumed so the book shifts to this price. - m.EndPrice = tip.Value.Price + m.EndPrice = ll[x].Price base = 0 break } // Full tranche consumed - m.Purchased += tip.Value.Price * tip.Value.Amount - m.Sold += tip.Value.Amount + m.Purchased += ll[x].Price * ll[x].Amount + m.Sold += ll[x].Amount base = leftover if leftover == 0 { // Price no longer exists on the book so use next full price tranche // to calculate book impact. - if tip.Next != nil { - m.EndPrice = tip.Next.Value.Price + if x+1 < len(ll) { + m.EndPrice = ll[x+1].Price } else { m.FullBookSideConsumed = true } + break } } return m.finalizeFields(m.Purchased, m.Sold, head, base, swap) @@ -489,18 +364,18 @@ func bidCompare(left, right float64) bool { // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *bids) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, tn time.Time) { - ll.linkedList.updateInsertByPrice(updts, stack, maxChainLength, bidCompare, tn) +func (ll *bids) updateInsertByPrice(updts Items, maxChainLength int) { + ll.linkedList.updateInsertByPrice(updts, maxChainLength, bidCompare) } // updateInsertByID updates or inserts if not found -func (ll *bids) updateInsertByID(updts Items, stack *stack) error { - return ll.linkedList.updateInsertByID(updts, stack, bidCompare) +func (ll *bids) updateInsertByID(updts Items) error { + return ll.linkedList.updateInsertByID(updts, bidCompare) } // insertUpdates inserts new updates for bids based on price level -func (ll *bids) insertUpdates(updts Items, stack *stack) error { - return ll.linkedList.insertUpdates(updts, stack, bidCompare) +func (ll *bids) insertUpdates(updts Items) error { + return ll.linkedList.insertUpdates(updts, bidCompare) } // hitBidsByNominalSlippage hits the bids by the required nominal slippage @@ -519,16 +394,16 @@ func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if ll.head == nil { + if len(ll.linkedList) == 0 { return nil, errNoLiquidity } nominal := &Movement{StartPrice: refPrice, EndPrice: refPrice} var cumulativeValue, cumulativeAmounts float64 - for tip := ll.head; tip != nil; tip = tip.Next { - totalTrancheValue := tip.Value.Price * tip.Value.Amount + for x := range ll.linkedList { + totalTrancheValue := ll.linkedList[x].Price * ll.linkedList[x].Amount currentFullValue := totalTrancheValue + cumulativeValue - currentTotalAmounts := cumulativeAmounts + tip.Value.Amount + currentTotalAmounts := cumulativeAmounts + ll.linkedList[x].Amount nominal.AverageOrderCost = currentFullValue / currentTotalAmounts percent := math.CalculatePercentageGainOrLoss(nominal.AverageOrderCost, refPrice) @@ -545,24 +420,24 @@ func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, } comparative := targetCost * cumulativeAmounts comparativeDiff := comparative - cumulativeValue - trancheTargetPriceDiff := tip.Value.Price - targetCost + trancheTargetPriceDiff := ll.linkedList[x].Price - targetCost trancheAmountExpectation := comparativeDiff / trancheTargetPriceDiff nominal.NominalPercentage = slippage nominal.Sold = cumulativeAmounts + trancheAmountExpectation - nominal.Purchased += trancheAmountExpectation * tip.Value.Price + nominal.Purchased += trancheAmountExpectation * ll.linkedList[x].Price nominal.AverageOrderCost = nominal.Purchased / nominal.Sold - nominal.EndPrice = tip.Value.Price + nominal.EndPrice = ll.linkedList[x].Price return nominal, nil } - nominal.EndPrice = tip.Value.Price + nominal.EndPrice = ll.linkedList[x].Price cumulativeValue = currentFullValue nominal.NominalPercentage = percent - nominal.Sold += tip.Value.Amount + nominal.Sold += ll.linkedList[x].Amount nominal.Purchased += totalTrancheValue cumulativeAmounts = currentTotalAmounts if slippage == percent { - nominal.FullBookSideConsumed = tip.Next == nil + nominal.FullBookSideConsumed = x+1 >= len(ll.linkedList) return nominal, nil } } @@ -586,25 +461,25 @@ func (ll *bids) hitBidsByImpactSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if ll.head == nil { + if len(ll.linkedList) == 0 { return nil, errNoLiquidity } impact := &Movement{StartPrice: refPrice, EndPrice: refPrice} - for tip := ll.head; tip != nil; tip = tip.Next { - percent := math.CalculatePercentageGainOrLoss(tip.Value.Price, refPrice) + for x := range ll.linkedList { + percent := math.CalculatePercentageGainOrLoss(ll.linkedList[x].Price, refPrice) if percent != 0 { percent *= -1 } - impact.EndPrice = tip.Value.Price + impact.EndPrice = ll.linkedList[x].Price impact.ImpactPercentage = percent if slippage <= percent { // Don't include this tranche amount as this consumes the tranche // book price, thus obtaining a higher percentage impact. return impact, nil } - impact.Sold += tip.Value.Amount - impact.Purchased += tip.Value.Amount * tip.Value.Price + impact.Sold += ll.linkedList[x].Amount + impact.Purchased += ll.linkedList[x].Amount * ll.linkedList[x].Price impact.AverageOrderCost = impact.Purchased / impact.Sold } impact.FullBookSideConsumed = true @@ -625,18 +500,18 @@ func askCompare(left, right float64) bool { // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *asks) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, tn time.Time) { - ll.linkedList.updateInsertByPrice(updts, stack, maxChainLength, askCompare, tn) +func (ll *asks) updateInsertByPrice(updts Items, maxChainLength int) { + ll.linkedList.updateInsertByPrice(updts, maxChainLength, askCompare) } // updateInsertByID updates or inserts if not found -func (ll *asks) updateInsertByID(updts Items, stack *stack) error { - return ll.linkedList.updateInsertByID(updts, stack, askCompare) +func (ll *asks) updateInsertByID(updts Items) error { + return ll.linkedList.updateInsertByID(updts, askCompare) } // insertUpdates inserts new updates for asks based on price level -func (ll *asks) insertUpdates(updts Items, stack *stack) error { - return ll.linkedList.insertUpdates(updts, stack, askCompare) +func (ll *asks) insertUpdates(updts Items) error { + return ll.linkedList.insertUpdates(updts, askCompare) } // liftAsksByNominalSlippage lifts the asks by the required nominal slippage @@ -651,16 +526,16 @@ func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement return nil, errInvalidReferencePrice } - if ll.head == nil { + if len(ll.linkedList) == 0 { return nil, errNoLiquidity } nominal := &Movement{StartPrice: refPrice, EndPrice: refPrice} var cumulativeAmounts float64 - for tip := ll.head; tip != nil; tip = tip.Next { - totalTrancheValue := tip.Value.Price * tip.Value.Amount + for x := range ll.linkedList { + totalTrancheValue := ll.linkedList[x].Price * ll.linkedList[x].Amount currentValue := totalTrancheValue + nominal.Sold - currentAmounts := cumulativeAmounts + tip.Value.Amount + currentAmounts := cumulativeAmounts + ll.linkedList[x].Amount nominal.AverageOrderCost = currentValue / currentAmounts percent := math.CalculatePercentageGainOrLoss(nominal.AverageOrderCost, refPrice) @@ -675,19 +550,19 @@ func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement comparative := targetCost * cumulativeAmounts comparativeDiff := comparative - nominal.Sold - trancheTargetPriceDiff := tip.Value.Price - targetCost + trancheTargetPriceDiff := ll.linkedList[x].Price - targetCost trancheAmountExpectation := comparativeDiff / trancheTargetPriceDiff nominal.NominalPercentage = slippage - nominal.Sold += trancheAmountExpectation * tip.Value.Price + nominal.Sold += trancheAmountExpectation * ll.linkedList[x].Price nominal.Purchased += trancheAmountExpectation nominal.AverageOrderCost = nominal.Sold / nominal.Purchased - nominal.EndPrice = tip.Value.Price + nominal.EndPrice = ll.linkedList[x].Price return nominal, nil } - nominal.EndPrice = tip.Value.Price + nominal.EndPrice = ll.linkedList[x].Price nominal.Sold = currentValue - nominal.Purchased += tip.Value.Amount + nominal.Purchased += ll.linkedList[x].Amount nominal.NominalPercentage = percent if slippage == percent { return nominal, nil @@ -710,22 +585,22 @@ func (ll *asks) liftAsksByImpactSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if ll.head == nil { + if len(ll.linkedList) == 0 { return nil, errNoLiquidity } impact := &Movement{StartPrice: refPrice, EndPrice: refPrice} - for tip := ll.head; tip != nil; tip = tip.Next { - percent := math.CalculatePercentageGainOrLoss(tip.Value.Price, refPrice) + for x := range ll.linkedList { + percent := math.CalculatePercentageGainOrLoss(ll.linkedList[x].Price, refPrice) impact.ImpactPercentage = percent - impact.EndPrice = tip.Value.Price + impact.EndPrice = ll.linkedList[x].Price if slippage <= percent { // Don't include this tranche amount as this consumes the tranche // book price, thus obtaining a higher percentage impact. return impact, nil } - impact.Sold += tip.Value.Amount * tip.Value.Price - impact.Purchased += tip.Value.Amount + impact.Sold += ll.linkedList[x].Amount * ll.linkedList[x].Price + impact.Purchased += ll.linkedList[x].Amount impact.AverageOrderCost = impact.Sold / impact.Purchased } impact.FullBookSideConsumed = true @@ -733,139 +608,6 @@ func (ll *asks) liftAsksByImpactSlippage(slippage, refPrice float64) (*Movement, return impact, nil } -// move moves a node from a point in a node chain to another node position, -// this left justified towards head as element zero is the top of the depth -// side. (can inline) -func move(head **Node, from, to *Node) { - if from.Next != nil { // From is at tail - from.Next.Prev = from.Prev - } - if from.Prev == nil { // From is at head - (*head).Next.Prev = nil - *head = (*head).Next - } else { - from.Prev.Next = from.Next - } - // insert from node next to 'to' node - if to.Prev == nil { // Destination is at head position - *head = from - } else { - to.Prev.Next = from - } - from.Prev = to.Prev - to.Prev = from - from.Next = to -} - -// deleteAtTip removes a node from tip target returns old node (can inline) -func deleteAtTip(ll *linkedList, tip **Node) *Node { - // Old is a placeholder for current tips node value to push - // back on to the stack. - old := *tip - switch { - case old.Prev == nil: // At head position - // shift current tip head to the right - *tip = old.Next - // Remove reference to node from chain - if old.Next != nil { // This is when liquidity hits zero - old.Next.Prev = nil - } - case old.Next == nil: // At tail position - // Remove reference to node from chain - old.Prev.Next = nil - default: - // Reference prior node in chain to next node in chain - // bypassing current node - old.Prev.Next = old.Next - old.Next.Prev = old.Prev - } - ll.length-- - return old -} - -// insertAtTip inserts at a tip target (can inline) -func insertAtTip(ll *linkedList, tip **Node, updt *Item, stack *stack) { - n := stack.Pop() - n.Value = *updt - n.Next = *tip - n.Prev = (*tip).Prev - if (*tip).Prev == nil { // Tip is at head - // Replace head which will push everything to the right - // when this node will reference new node below - *tip = n - } else { - // Reference new node to previous node - (*tip).Prev.Next = n - } - // Reference next node to new node - n.Next.Prev = n - ll.length++ -} - -// insertAtTail inserts at tail end of node chain (can inline) -func insertAtTail(ll *linkedList, tip **Node, updt *Item, stack *stack) { - n := stack.Pop() - n.Value = *updt - // Reference tip to new node - (*tip).Next = n - // Reference new node with current tip - n.Prev = *tip - ll.length++ -} - -// insertHeadSpecific inserts at head specifically there might be an instance -// where the liquidity on an exchange does fall to zero through a streaming -// endpoint then it comes back online. (can inline) -func insertHeadSpecific(ll *linkedList, updt *Item, stack *stack) { - n := stack.Pop() - n.Value = *updt - ll.head = n - ll.length++ -} - -// insertNodeAtBookmark inserts a new node at a bookmarked node position -// returns if a node needs to replace head (can inline) -func insertNodeAtBookmark(ll *linkedList, bookmark, n *Node) { - switch { - case bookmark == nil: // Zero liquidity and we are rebuilding from scratch - ll.head = n - case bookmark.Prev == nil: - n.Prev = bookmark.Prev - bookmark.Prev = n - n.Next = bookmark - ll.head = n - case bookmark.Next == nil: - n.Prev = bookmark - bookmark.Next = n - default: - bookmark.Prev.Next = n - n.Prev = bookmark.Prev - bookmark.Prev = n - n.Next = bookmark - } - ll.length++ -} - -// shiftBookmark moves a bookmarked node to the tip's next position or if nil, -// sets tip as bookmark (can inline) -func shiftBookmark(tip *Node, bookmark, head **Node, updt *Item) bool { - if *bookmark == nil { // End of the chain and no bookmark set - *bookmark = tip // Set tip to bookmark so we can set a new node there - return false - } - (*bookmark).Value = *updt - (*bookmark).Next.Prev = (*bookmark).Prev - if (*bookmark).Prev == nil { // Bookmark is at head - *head = (*bookmark).Next - } else { - (*bookmark).Prev.Next = (*bookmark).Next - } - tip.Next = *bookmark - (*bookmark).Prev = tip - (*bookmark).Next = nil - return true -} - // finalizeFields sets average order costing, percentages, slippage cost and // preserves existing fields. func (m *Movement) finalizeFields(cost, amount, headPrice, leftover float64, swap bool) (*Movement, error) { diff --git a/exchanges/orderbook/linked_list_test.go b/exchanges/orderbook/linked_list_test.go index 6f09e340d79..6c3481194ec 100644 --- a/exchanges/orderbook/linked_list_test.go +++ b/exchanges/orderbook/linked_list_test.go @@ -56,9 +56,9 @@ var bid = Items{ } // Display displays depth content for tests -func (ll *linkedList) display() { - for tip := ll.head; tip != nil; tip = tip.Next { - fmt.Printf("NODE: %+v %p \n", tip, tip) +func (ll linkedList) display() { + for x := range ll { + fmt.Printf("NODE: %+v %p \n", ll[x], &ll[x]) } fmt.Println() } @@ -67,7 +67,6 @@ func TestLoad(t *testing.T) { list := asks{} Check(t, list, 0, 0, 0) - stack := newStack() list.load(Items{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, @@ -75,11 +74,7 @@ func TestLoad(t *testing.T) { {Price: 7, Amount: 1}, {Price: 9, Amount: 1}, {Price: 11, Amount: 1}, - }, stack, time.Now()) - - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } + }) Check(t, list, 6, 36, 6) @@ -87,11 +82,7 @@ func TestLoad(t *testing.T) { {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, - }, stack, time.Now()) - - if stack.getCount() != 3 { - t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount()) - } + }) Check(t, list, 3, 9, 3) @@ -100,37 +91,26 @@ func TestLoad(t *testing.T) { {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, {Price: 7, Amount: 1}, - }, stack, time.Now()) - - if stack.getCount() != 2 { - t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount()) - } + }) Check(t, list, 4, 16, 4) // purge entire list - list.load(nil, stack, time.Now()) - - if stack.getCount() != 6 { - t.Fatalf("incorrect stack count expected: %v received: %v", 6, stack.getCount()) - } - + list.load(nil) Check(t, list, 0, 0, 0) } -// 22222386 57.3 ns/op 0 B/op 0 allocs/op (old) -// 27906781 42.4 ns/op 0 B/op 0 allocs/op (new) +// 27906781 42.4 ns/op 0 B/op 0 allocs/op (old) +// 84119028 13.87 ns/op 0 B/op 0 allocs/op (new) func BenchmarkLoad(b *testing.B) { ll := linkedList{} - s := newStack() for i := 0; i < b.N; i++ { - ll.load(ask, s, time.Now()) + ll.load(ask) } } func TestUpdateInsertByPrice(t *testing.T) { a := asks{} - stack := newStack() asksSnapshot := Items{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, @@ -139,89 +119,53 @@ func TestUpdateInsertByPrice(t *testing.T) { {Price: 9, Amount: 1}, {Price: 11, Amount: 1}, } - a.load(asksSnapshot, stack, time.Now()) + a.load(asksSnapshot) // Update one instance with matching price - a.updateInsertByPrice(Items{ - {Price: 1, Amount: 2}, - }, stack, 0, time.Now()) + a.updateInsertByPrice(Items{{Price: 1, Amount: 2}}, 0) Check(t, a, 7, 37, 6) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert at head a.updateInsertByPrice(Items{ {Price: 0.5, Amount: 2}, - }, stack, 0, time.Now()) + }, 0) Check(t, a, 9, 38, 7) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert at tail a.updateInsertByPrice(Items{ {Price: 12, Amount: 2}, - }, stack, 0, time.Now()) + }, 0) Check(t, a, 11, 62, 8) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert between price and up to and beyond max allowable depth level a.updateInsertByPrice(Items{ {Price: 11.5, Amount: 2}, {Price: 10.5, Amount: 2}, {Price: 13, Amount: 2}, - }, stack, 10, time.Now()) + }, 10) Check(t, a, 15, 106, 10) - if stack.getCount() != 1 { - t.Fatalf("incorrect stack count expected: %v received: %v", 1, stack.getCount()) - } - // delete at tail - a.updateInsertByPrice(Items{ - {Price: 12, Amount: 0}, - }, stack, 0, time.Now()) + a.updateInsertByPrice(Items{{Price: 12, Amount: 0}}, 0) Check(t, a, 13, 82, 9) - if stack.getCount() != 2 { - t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount()) - } - // delete at mid - a.updateInsertByPrice(Items{ - {Price: 7, Amount: 0}, - }, stack, 0, time.Now()) + a.updateInsertByPrice(Items{{Price: 7, Amount: 0}}, 0) Check(t, a, 12, 75, 8) - if stack.getCount() != 3 { - t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount()) - } - // delete at head - a.updateInsertByPrice(Items{ - {Price: 0.5, Amount: 0}, - }, stack, 0, time.Now()) + a.updateInsertByPrice(Items{{Price: 0.5, Amount: 0}}, 0) Check(t, a, 10, 74, 7) - if stack.getCount() != 4 { - t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount()) - } - // purge if liquidity plunges to zero - a.load(nil, stack, time.Now()) + a.load(nil) // rebuild everything again a.updateInsertByPrice(Items{ @@ -231,14 +175,10 @@ func TestUpdateInsertByPrice(t *testing.T) { {Price: 7, Amount: 1}, {Price: 9, Amount: 1}, {Price: 11, Amount: 1}, - }, stack, 0, time.Now()) + }, 0) Check(t, a, 6, 36, 6) - if stack.getCount() != 5 { - t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount()) - } - b := bids{} bidsSnapshot := Items{ {Price: 11, Amount: 1}, @@ -248,89 +188,49 @@ func TestUpdateInsertByPrice(t *testing.T) { {Price: 3, Amount: 1}, {Price: 1, Amount: 1}, } - b.load(bidsSnapshot, stack, time.Now()) + b.load(bidsSnapshot) // Update one instance with matching price - b.updateInsertByPrice(Items{ - {Price: 11, Amount: 2}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 11, Amount: 2}}, 0) Check(t, b, 7, 47, 6) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert at head - b.updateInsertByPrice(Items{ - {Price: 12, Amount: 2}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 12, Amount: 2}}, 0) Check(t, b, 9, 71, 7) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert at tail - b.updateInsertByPrice(Items{ - {Price: 0.5, Amount: 2}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 0.5, Amount: 2}}, 0) Check(t, b, 11, 72, 8) - if stack.getCount() != 0 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert between price and up to and beyond max allowable depth level b.updateInsertByPrice(Items{ {Price: 11.5, Amount: 2}, {Price: 10.5, Amount: 2}, {Price: 13, Amount: 2}, - }, stack, 10, time.Now()) + }, 10) Check(t, b, 15, 141, 10) - if stack.getCount() != 1 { - t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount()) - } - // Insert between price and up to and beyond max allowable depth level - b.updateInsertByPrice(Items{ - {Price: 1, Amount: 0}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 1, Amount: 0}}, 0) Check(t, b, 14, 140, 9) - if stack.getCount() != 2 { - t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount()) - } - // delete at mid - b.updateInsertByPrice(Items{ - {Price: 10.5, Amount: 0}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 10.5, Amount: 0}}, 0) Check(t, b, 12, 119, 8) - if stack.getCount() != 3 { - t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount()) - } - // delete at head - b.updateInsertByPrice(Items{ - {Price: 13, Amount: 0}, - }, stack, 0, time.Now()) + b.updateInsertByPrice(Items{{Price: 13, Amount: 0}}, 0) Check(t, b, 10, 93, 7) - if stack.getCount() != 4 { - t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount()) - } - // purge if liquidity plunges to zero - b.load(nil, stack, time.Now()) + b.load(nil) // rebuild everything again b.updateInsertByPrice(Items{ @@ -340,47 +240,16 @@ func TestUpdateInsertByPrice(t *testing.T) { {Price: 7, Amount: 1}, {Price: 9, Amount: 1}, {Price: 11, Amount: 1}, - }, stack, 0, time.Now()) + }, 0) Check(t, b, 6, 36, 6) - - if stack.getCount() != 5 { - t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount()) - } } -func TestCleanup(t *testing.T) { - a := asks{} - stack := newStack() - asksSnapshot := Items{ - {Price: 1, Amount: 1}, - {Price: 3, Amount: 1}, - {Price: 5, Amount: 1}, - {Price: 7, Amount: 1}, - {Price: 9, Amount: 1}, - {Price: 11, Amount: 1}, - } - a.load(asksSnapshot, stack, time.Now()) - - a.cleanup(6, stack, time.Now()) - Check(t, a, 6, 36, 6) - a.cleanup(5, stack, time.Now()) - Check(t, a, 5, 25, 5) - a.cleanup(1, stack, time.Now()) - Check(t, a, 1, 1, 1) - a.cleanup(10, stack, time.Now()) - Check(t, a, 1, 1, 1) - a.cleanup(0, stack, time.Now()) // will purge, underlying checks are done elseware to prevent this - Check(t, a, 0, 0, 0) -} - -// 46154023 24.0 ns/op 0 B/op 0 allocs/op (old) -// 134830672 9.83 ns/op 0 B/op 0 allocs/op (new) +// 134830672 9.83 ns/op 0 B/op 0 allocs/op (old) +// 206689897 5.761 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) { a := asks{} - stack := newStack() - - a.load(ask, stack, time.Now()) + a.load(ask) updates := Items{ { @@ -394,16 +263,16 @@ func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) { } for i := 0; i < b.N; i++ { - a.updateInsertByPrice(updates, stack, 0, time.Now()) + a.updateInsertByPrice(updates, 0) } } -// 49763002 24.9 ns/op 0 B/op 0 allocs/op +// 49763002 24.9 ns/op 0 B/op 0 allocs/op (old) +// 25662849 45.32 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) { a := asks{} - stack := newStack() - a.load(ask, stack, time.Now()) + a.load(ask) updates := Items{ { @@ -417,13 +286,12 @@ func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) { } for i := 0; i < b.N; i++ { - a.updateInsertByPrice(updates, stack, 0, time.Now()) + a.updateInsertByPrice(updates, 0) } } func TestUpdateByID(t *testing.T) { a := asks{} - s := newStack() asksSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -432,7 +300,7 @@ func TestUpdateByID(t *testing.T) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) err := a.updateByID(Items{ {Price: 1, Amount: 1, ID: 1}, @@ -475,10 +343,10 @@ func TestUpdateByID(t *testing.T) { } } -// 46043871 25.9 ns/op 0 B/op 0 allocs/op +// 46043871 25.9 ns/op 0 B/op 0 allocs/op (old) +// 63445401 18.51 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateByID(b *testing.B) { asks := linkedList{} - s := newStack() asksSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -487,17 +355,10 @@ func BenchmarkUpdateByID(b *testing.B) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - asks.load(asksSnapshot, s, time.Now()) + asks.load(asksSnapshot) for i := 0; i < b.N; i++ { - err := asks.updateByID(Items{ - {Price: 1, Amount: 1, ID: 1}, - {Price: 3, Amount: 1, ID: 3}, - {Price: 5, Amount: 1, ID: 5}, - {Price: 7, Amount: 1, ID: 7}, - {Price: 9, Amount: 1, ID: 9}, - {Price: 11, Amount: 1, ID: 11}, - }) + err := asks.updateByID(asksSnapshot) if err != nil { b.Fatal(err) } @@ -506,7 +367,6 @@ func BenchmarkUpdateByID(b *testing.B) { func TestDeleteByID(t *testing.T) { a := asks{} - s := newStack() asksSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -515,12 +375,10 @@ func TestDeleteByID(t *testing.T) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Delete at head - err := a.deleteByID(Items{ - {Price: 1, Amount: 1, ID: 1}, - }, s, false, time.Now()) + err := a.deleteByID(Items{{Price: 1, Amount: 1, ID: 1}}, false) if err != nil { t.Fatal(err) } @@ -528,9 +386,7 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 5, 35, 5) // Delete at tail - err = a.deleteByID(Items{ - {Price: 1, Amount: 1, ID: 11}, - }, s, false, time.Now()) + err = a.deleteByID(Items{{Price: 1, Amount: 1, ID: 11}}, false) if err != nil { t.Fatal(err) } @@ -538,9 +394,7 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 4, 24, 4) // Delete in middle - err = a.deleteByID(Items{ - {Price: 1, Amount: 1, ID: 5}, - }, s, false, time.Now()) + err = a.deleteByID(Items{{Price: 1, Amount: 1, ID: 5}}, false) if err != nil { t.Fatal(err) } @@ -548,25 +402,42 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 3, 19, 3) // Intentional error - err = a.deleteByID(Items{ - {Price: 11, Amount: 1, ID: 1337}, - }, s, false, time.Now()) + err = a.deleteByID(Items{{Price: 11, Amount: 1, ID: 1337}}, false) if !errors.Is(err, errIDCannotBeMatched) { t.Fatalf("expecting %s but received %v", errIDCannotBeMatched, err) } // Error bypass - err = a.deleteByID(Items{ - {Price: 11, Amount: 1, ID: 1337}, - }, s, true, time.Now()) + err = a.deleteByID(Items{{Price: 11, Amount: 1, ID: 1337}}, true) if err != nil { t.Fatal(err) } } +// 20476837 53.17 ns/op 0 B/op 0 allocs/op +func BenchmarkDeleteByID(b *testing.B) { + asks := linkedList{} + asksSnapshot := Items{ + {Price: 1, Amount: 1, ID: 1}, + {Price: 3, Amount: 1, ID: 3}, + {Price: 5, Amount: 1, ID: 5}, + {Price: 7, Amount: 1, ID: 7}, + {Price: 9, Amount: 1, ID: 9}, + {Price: 11, Amount: 1, ID: 11}, + } + asks.load(asksSnapshot) + + for i := 0; i < b.N; i++ { + err := asks.deleteByID(asksSnapshot, false) + if err != nil { + b.Fatal(err) + } + asks.load(asksSnapshot) // reset + } +} + func TestUpdateInsertByIDAsk(t *testing.T) { a := asks{} - s := newStack() asksSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -575,12 +446,10 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Update one instance with matching ID - err := a.updateInsertByID(Items{ - {Price: 1, Amount: 2, ID: 1}, - }, s) + err := a.updateInsertByID(Items{{Price: 1, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -588,7 +457,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 7, 37, 6) // Reset - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Update all instances with matching ID in order err = a.updateInsertByID(Items{ @@ -598,7 +467,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -613,7 +482,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 5, Amount: 2, ID: 5}, {Price: 3, Amount: 2, ID: 3}, {Price: 1, Amount: 2, ID: 1}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -628,7 +497,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 9, Amount: 2, ID: 9}, {Price: 1, Amount: 2, ID: 1}, {Price: 5, Amount: 2, ID: 5}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -643,7 +512,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -658,7 +527,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -666,7 +535,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 63, 6) // Reset - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Update all instances move one after ID err = a.updateInsertByID(Items{ @@ -676,7 +545,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -684,7 +553,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 78, 6) // Reset - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Update all instances move one after ID to tail err = a.updateInsertByID(Items{ @@ -694,7 +563,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -710,7 +579,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, {Price: 10, Amount: 2, ID: 10}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -718,7 +587,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 106, 7) // Reset - a.load(asksSnapshot, s, time.Now()) + a.load(asksSnapshot) // Update all instances pop at head err = a.updateInsertByID(Items{ @@ -729,7 +598,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -737,9 +606,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 87, 7) // bookmark head and move to mid - err = a.updateInsertByID(Items{ - {Price: 7.5, Amount: 2, ID: 0}, - }, s) + err = a.updateInsertByID(Items{{Price: 7.5, Amount: 2, ID: 0}}) if err != nil { t.Fatal(err) } @@ -747,9 +614,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 101, 7) // bookmark head and move to tail - err = a.updateInsertByID(Items{ - {Price: 12.5, Amount: 2, ID: 1}, - }, s) + err = a.updateInsertByID(Items{{Price: 12.5, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -757,9 +622,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 124, 7) // move tail location to head - err = a.updateInsertByID(Items{ - {Price: 2.5, Amount: 2, ID: 1}, - }, s) + err = a.updateInsertByID(Items{{Price: 2.5, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -767,9 +630,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 104, 7) // move tail location to mid - err = a.updateInsertByID(Items{ - {Price: 8, Amount: 2, ID: 5}, - }, s) + err = a.updateInsertByID(Items{{Price: 8, Amount: 2, ID: 5}}) if err != nil { t.Fatal(err) } @@ -777,9 +638,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 96, 7) // insert at tail dont match - err = a.updateInsertByID(Items{ - {Price: 30, Amount: 2, ID: 1234}, - }, s) + err = a.updateInsertByID(Items{{Price: 30, Amount: 2, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -787,9 +646,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 16, 156, 8) // insert between last and 2nd last - err = a.updateInsertByID(Items{ - {Price: 12, Amount: 2, ID: 12345}, - }, s) + err = a.updateInsertByID(Items{{Price: 12, Amount: 2, ID: 12345}}) if err != nil { t.Fatal(err) } @@ -797,9 +654,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 18, 180, 9) // readjust at end - err = a.updateInsertByID(Items{ - {Price: 29, Amount: 3, ID: 1234}, - }, s) + err = a.updateInsertByID(Items{{Price: 29, Amount: 3, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -807,9 +662,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 19, 207, 9) // readjust further and decrease price past tail - err = a.updateInsertByID(Items{ - {Price: 31, Amount: 3, ID: 1234}, - }, s) + err = a.updateInsertByID(Items{{Price: 31, Amount: 3, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -817,7 +670,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 19, 213, 9) // purge - a.load(nil, s, time.Now()) + a.load(nil) // insert with no liquidity and jumbled err = a.updateInsertByID(Items{ @@ -828,7 +681,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { {Price: 12, Amount: 2, ID: 5}, {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -836,9 +689,29 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 87, 7) } +// 21614455 81.74 ns/op 0 B/op 0 allocs/op +func BenchmarkUpdateInsertByID_asks(b *testing.B) { + asks := linkedList{} + asksSnapshot := Items{ + {Price: 1, Amount: 1, ID: 1}, + {Price: 3, Amount: 1, ID: 3}, + {Price: 5, Amount: 1, ID: 5}, + {Price: 7, Amount: 1, ID: 7}, + {Price: 9, Amount: 1, ID: 9}, + {Price: 11, Amount: 1, ID: 11}, + } + asks.load(asksSnapshot) + + for i := 0; i < b.N; i++ { + err := asks.updateInsertByID(asksSnapshot, askCompare) + if err != nil { + b.Fatal(err) + } + } +} + func TestUpdateInsertByIDBids(t *testing.T) { b := bids{} - s := newStack() bidsSnapshot := Items{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, @@ -847,12 +720,10 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 3, Amount: 1, ID: 3}, {Price: 1, Amount: 1, ID: 1}, } - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) // Update one instance with matching ID - err := b.updateInsertByID(Items{ - {Price: 1, Amount: 2, ID: 1}, - }, s) + err := b.updateInsertByID(Items{{Price: 1, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -860,7 +731,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 7, 37, 6) // Reset - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) // Update all instances with matching ID in order err = b.updateInsertByID(Items{ @@ -870,7 +741,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -885,7 +756,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 5, Amount: 2, ID: 5}, {Price: 3, Amount: 2, ID: 3}, {Price: 1, Amount: 2, ID: 1}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -900,7 +771,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 9, Amount: 2, ID: 9}, {Price: 1, Amount: 2, ID: 1}, {Price: 5, Amount: 2, ID: 5}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -915,7 +786,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -930,7 +801,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -938,7 +809,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 63, 6) // Reset - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) // Update all instances move one after ID err = b.updateInsertByID(Items{ @@ -948,7 +819,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -956,7 +827,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 78, 6) // Reset - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) // Update all instances move one after ID to tail err = b.updateInsertByID(Items{ @@ -966,7 +837,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -982,7 +853,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, {Price: 10, Amount: 2, ID: 10}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -990,7 +861,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 106, 7) // Reset - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) // Update all instances pop at tail err = b.updateInsertByID(Items{ @@ -1001,7 +872,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -1009,9 +880,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 87, 7) // bookmark head and move to mid - err = b.updateInsertByID(Items{ - {Price: 9.5, Amount: 2, ID: 5}, - }, s) + err = b.updateInsertByID(Items{{Price: 9.5, Amount: 2, ID: 5}}) if err != nil { t.Fatal(err) } @@ -1019,9 +888,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 82, 7) // bookmark head and move to tail - err = b.updateInsertByID(Items{ - {Price: 0.25, Amount: 2, ID: 11}, - }, s) + err = b.updateInsertByID(Items{{Price: 0.25, Amount: 2, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1029,9 +896,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 60.5, 7) // move tail location to head - err = b.updateInsertByID(Items{ - {Price: 10, Amount: 2, ID: 11}, - }, s) + err = b.updateInsertByID(Items{{Price: 10, Amount: 2, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1039,9 +904,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 80, 7) // move tail location to mid - err = b.updateInsertByID(Items{ - {Price: 7.5, Amount: 2, ID: 0}, - }, s) + err = b.updateInsertByID(Items{{Price: 7.5, Amount: 2, ID: 0}}) if err != nil { t.Fatal(err) } @@ -1049,9 +912,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 94, 7) // insert at head dont match - err = b.updateInsertByID(Items{ - {Price: 30, Amount: 2, ID: 1234}, - }, s) + err = b.updateInsertByID(Items{{Price: 30, Amount: 2, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -1059,34 +920,28 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 16, 154, 8) // insert between last and 2nd last - err = b.updateInsertByID(Items{ - {Price: 1.5, Amount: 2, ID: 12345}, - }, s) + err = b.updateInsertByID(Items{{Price: 1.5, Amount: 2, ID: 12345}}) if err != nil { t.Fatal(err) } Check(t, b, 18, 157, 9) // readjust at end - err = b.updateInsertByID(Items{ - {Price: 1, Amount: 3, ID: 1}, - }, s) + err = b.updateInsertByID(Items{{Price: 1, Amount: 3, ID: 1}}) if err != nil { t.Fatal(err) } Check(t, b, 19, 158, 9) // readjust further and decrease price past tail - err = b.updateInsertByID(Items{ - {Price: .9, Amount: 3, ID: 1}, - }, s) + err = b.updateInsertByID(Items{{Price: .9, Amount: 3, ID: 1}}) if err != nil { t.Fatal(err) } Check(t, b, 19, 157.7, 9) // purge - b.load(nil, s, time.Now()) + b.load(nil) // insert with no liquidity and jumbled err = b.updateInsertByID(Items{ @@ -1097,7 +952,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { {Price: 7, Amount: 2, ID: 7}, {Price: 9, Amount: 2, ID: 9}, {Price: 11, Amount: 2, ID: 11}, - }, s) + }) if err != nil { t.Fatal(err) } @@ -1105,9 +960,30 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 87, 7) } +// 20328886 59.94 ns/op 0 B/op 0 allocs/op +func BenchmarkUpdateInsertByID_bids(b *testing.B) { + bids := linkedList{} + bidsSnapshot := Items{ + {Price: 0.5, Amount: 2, ID: 0}, + {Price: 1, Amount: 2, ID: 1}, + {Price: 3, Amount: 2, ID: 3}, + {Price: 12, Amount: 2, ID: 5}, + {Price: 7, Amount: 2, ID: 7}, + {Price: 9, Amount: 2, ID: 9}, + {Price: 11, Amount: 2, ID: 11}, + } + bids.load(bidsSnapshot) + + for i := 0; i < b.N; i++ { + err := bids.updateInsertByID(bidsSnapshot, bidCompare) + if err != nil { + b.Fatal(err) + } + } +} + func TestInsertUpdatesBid(t *testing.T) { b := bids{} - s := newStack() bidsSnapshot := Items{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, @@ -1116,7 +992,7 @@ func TestInsertUpdatesBid(t *testing.T) { {Price: 3, Amount: 1, ID: 3}, {Price: 1, Amount: 1, ID: 1}, } - b.load(bidsSnapshot, s, time.Now()) + b.load(bidsSnapshot) err := b.insertUpdates(Items{ {Price: 11, Amount: 1, ID: 11}, @@ -1125,7 +1001,7 @@ func TestInsertUpdatesBid(t *testing.T) { {Price: 5, Amount: 1, ID: 5}, {Price: 3, Amount: 1, ID: 3}, {Price: 1, Amount: 1, ID: 1}, - }, s) + }) if !errors.Is(err, errCollisionDetected) { t.Fatalf("expected error %s but received %v", errCollisionDetected, err) } @@ -1133,9 +1009,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 6, 36, 6) // Insert at head - err = b.insertUpdates(Items{ - {Price: 12, Amount: 1, ID: 11}, - }, s) + err = b.insertUpdates(Items{{Price: 12, Amount: 1, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1143,9 +1017,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 7, 48, 7) // Insert at tail - err = b.insertUpdates(Items{ - {Price: 0.5, Amount: 1, ID: 12}, - }, s) + err = b.insertUpdates(Items{{Price: 0.5, Amount: 1, ID: 12}}) if err != nil { t.Fatal(err) } @@ -1153,9 +1025,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 8, 48.5, 8) // Insert at mid - err = b.insertUpdates(Items{ - {Price: 5.5, Amount: 1, ID: 13}, - }, s) + err = b.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1163,12 +1033,10 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 9, 54, 9) // purge - b.load(nil, s, time.Now()) + b.load(nil) // Add one at head - err = b.insertUpdates(Items{ - {Price: 5.5, Amount: 1, ID: 13}, - }, s) + err = b.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1178,7 +1046,6 @@ func TestInsertUpdatesBid(t *testing.T) { func TestInsertUpdatesAsk(t *testing.T) { a := asks{} - s := newStack() askSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -1187,7 +1054,7 @@ func TestInsertUpdatesAsk(t *testing.T) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - a.load(askSnapshot, s, time.Now()) + a.load(askSnapshot) err := a.insertUpdates(Items{ {Price: 11, Amount: 1, ID: 11}, @@ -1196,7 +1063,7 @@ func TestInsertUpdatesAsk(t *testing.T) { {Price: 5, Amount: 1, ID: 5}, {Price: 3, Amount: 1, ID: 3}, {Price: 1, Amount: 1, ID: 1}, - }, s) + }) if !errors.Is(err, errCollisionDetected) { t.Fatalf("expected error %s but received %v", errCollisionDetected, err) } @@ -1204,9 +1071,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 6, 36, 6) // Insert at tail - err = a.insertUpdates(Items{ - {Price: 12, Amount: 1, ID: 11}, - }, s) + err = a.insertUpdates(Items{{Price: 12, Amount: 1, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1214,9 +1079,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 7, 48, 7) // Insert at head - err = a.insertUpdates(Items{ - {Price: 0.5, Amount: 1, ID: 12}, - }, s) + err = a.insertUpdates(Items{{Price: 0.5, Amount: 1, ID: 12}}) if err != nil { t.Fatal(err) } @@ -1224,9 +1087,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 8, 48.5, 8) // Insert at mid - err = a.insertUpdates(Items{ - {Price: 5.5, Amount: 1, ID: 13}, - }, s) + err = a.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1234,12 +1095,10 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 9, 54, 9) // purge - a.load(nil, s, time.Now()) + a.load(nil) // Add one at head - err = a.insertUpdates(Items{ - {Price: 5.5, Amount: 1, ID: 13}, - }, s) + err = a.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1248,7 +1107,7 @@ func TestInsertUpdatesAsk(t *testing.T) { } // check checks depth values after an update has taken place -func Check(t *testing.T, depth interface{}, liquidity, value float64, nodeCount int) { +func Check(t *testing.T, depth interface{}, liquidity, value float64, expectedLen int) { t.Helper() b, isBid := depth.(bids) a, isAsk := depth.(asks) @@ -1264,7 +1123,6 @@ func Check(t *testing.T, depth interface{}, liquidity, value float64, nodeCount } liquidityTotal, valueTotal := ll.amount() - if liquidityTotal != liquidity { ll.display() t.Fatalf("mismatched liquidity expecting %v but received %v", @@ -1279,74 +1137,36 @@ func Check(t *testing.T, depth interface{}, liquidity, value float64, nodeCount valueTotal) } - if ll.length != nodeCount { + if len(ll) != expectedLen { ll.display() - t.Fatalf("mismatched node count expecting %v but received %v", - nodeCount, - ll.length) + t.Fatalf("mismatched expected length count expecting %v but received %v", + expectedLen, + len(ll)) } - if ll.head == nil { + if len(ll) == 0 { return } - var tail *Node var price float64 - for tip := ll.head; ; tip = tip.Next { + for x := range ll { switch { case price == 0: - price = tip.Value.Price - case isBid && price < tip.Value.Price: + price = ll[x].Price + case isBid && price < ll[x].Price: ll.display() t.Fatal("Bid pricing out of order should be descending") - case isAsk && price > tip.Value.Price: + case isAsk && price > ll[x].Price: ll.display() t.Fatal("Ask pricing out of order should be ascending") default: - price = tip.Value.Price + price = ll[x].Price } - - if tip.Next == nil { - tail = tip - break - } - } - - var liqReversed, valReversed float64 - var nodeReversed int - for tip := tail; tip != nil; tip = tip.Prev { - liqReversed += tip.Value.Amount - valReversed += tip.Value.Amount * tip.Value.Price - nodeReversed++ - } - - if liquidity-liqReversed != 0 { - ll.display() - fmt.Println(liquidity, liqReversed) - t.Fatalf("mismatched liquidity when reversing direction expecting %v but received %v", - 0, - liquidity-liqReversed) - } - - if nodeCount-nodeReversed != 0 { - ll.display() - t.Fatalf("mismatched node count when reversing direction expecting %v but received %v", - 0, - nodeCount-nodeReversed) - } - - if value-valReversed != 0 { - ll.display() - fmt.Println(valReversed, value) - t.Fatalf("mismatched total book value when reversing direction expecting %v but received %v", - 0, - value-valReversed) } } func TestAmount(t *testing.T) { a := asks{} - s := newStack() askSnapshot := Items{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, @@ -1355,7 +1175,7 @@ func TestAmount(t *testing.T) { {Price: 9, Amount: 1, ID: 9}, {Price: 11, Amount: 1, ID: 11}, } - a.load(askSnapshot, s, time.Now()) + a.load(askSnapshot) liquidity, value := a.amount() if liquidity != 6 { @@ -1367,116 +1187,6 @@ func TestAmount(t *testing.T) { } } -func TestShiftBookmark(t *testing.T) { - bookmarkedNode := &Node{ - Value: Item{ - ID: 1337, - Amount: 1, - Price: 2, - }, - Next: nil, - Prev: nil, - shelved: time.Time{}, - } - - originalBookmarkPrev := &Node{ - Value: Item{ - ID: 1336, - }, - Next: bookmarkedNode, - Prev: nil, // At head - shelved: time.Time{}, - } - originalBookmarkNext := &Node{ - Value: Item{ - ID: 1338, - }, - Next: nil, // This can be left nil in actuality this will be - // populated - Prev: bookmarkedNode, - shelved: time.Time{}, - } - - // associate previous and next nodes to bookmarked node - bookmarkedNode.Prev = originalBookmarkPrev - bookmarkedNode.Next = originalBookmarkNext - - tip := &Node{ - Value: Item{ - ID: 69420, - }, - Next: nil, // In this case tip will be at tail - Prev: nil, - shelved: time.Time{}, - } - - tipprev := &Node{ - Value: Item{ - ID: 69419, - }, - Next: tip, - Prev: nil, // This can be left nil in actuality this will be - // populated - shelved: time.Time{}, - } - - // associate tips prev field with the correct prev node - tip.Prev = tipprev - - if !shiftBookmark(tip, &bookmarkedNode, nil, &Item{Amount: 1336, ID: 1337, Price: 9999}) { - t.Fatal("There should be liquidity so we don't need to set tip to bookmark") - } - - if bookmarkedNode.Value.Price != 9999 || - bookmarkedNode.Value.Amount != 1336 || - bookmarkedNode.Value.ID != 1337 { - t.Fatal("bookmarked details are not set correctly with shift") - } - - if bookmarkedNode.Prev != tip { - t.Fatal("bookmarked prev memory address does not point to tip") - } - - if bookmarkedNode.Next != nil { - t.Fatal("bookmarked next is at tail and should be nil") - } - - if bookmarkedNode.Next != nil { - t.Fatal("bookmarked next is at tail and should be nil") - } - - if originalBookmarkPrev.Next != originalBookmarkNext { - t.Fatal("original bookmarked prev node should be associated with original bookmarked next node") - } - - if originalBookmarkNext.Prev != originalBookmarkPrev { - t.Fatal("original bookmarked next node should be associated with original bookmarked prev node") - } - - var nilBookmark *Node - - if shiftBookmark(tip, &nilBookmark, nil, &Item{Amount: 1336, ID: 1337, Price: 9999}) { - t.Fatal("there should not be a bookmarked node") - } - - if tip != nilBookmark { - t.Fatal("nilBookmark not reassigned") - } - - head := bookmarkedNode - bookmarkedNode.Prev = nil - bookmarkedNode.Next = originalBookmarkNext - tip.Next = nil - - if !shiftBookmark(tip, &bookmarkedNode, &head, &Item{Amount: 1336, ID: 1337, Price: 9999}) { - t.Fatal("There should be liquidity so we don't need to set tip to bookmark") - } - - if head != originalBookmarkNext { - t.Fatal("unexpected pointer variable") - } -} - func TestGetMovementByBaseAmount(t *testing.T) { t.Parallel() cases := []struct { diff --git a/exchanges/orderbook/node.go b/exchanges/orderbook/node.go deleted file mode 100644 index 5e428d5df5d..00000000000 --- a/exchanges/orderbook/node.go +++ /dev/null @@ -1,126 +0,0 @@ -package orderbook - -import ( - "sync/atomic" - "time" -) - -const ( - neutral uint32 = iota - active -) - -var ( - defaultInterval = time.Minute - defaultAllowance = time.Second * 30 -) - -// Node defines a linked list node for an orderbook item -type Node struct { - Value Item - Next *Node - Prev *Node - // Denotes time pushed to stack, this will influence cleanup routine when - // there is a pause or minimal actions during period - shelved time.Time -} - -// stack defines a FILO list of reusable nodes -type stack struct { - nodes []*Node - sema uint32 - count int32 -} - -// newStack returns a ptr to a new stack instance, also starts the cleaning -// service -func newStack() *stack { - s := &stack{} - go s.cleaner() - return s -} - -// Push pushes a node pointer into the stack to be reused the time is passed in -// to allow for inlining which sets the time at which the node is theoretically -// pushed to a stack. -func (s *stack) Push(n *Node, tn time.Time) { - if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) { - // Stack is in use, for now we can dereference pointer - return - } - // Adds a time when its placed back on to stack. - n.shelved = tn - n.Next = nil - n.Prev = nil - n.Value = Item{} - - // Allows for resize when overflow TODO: rethink this - s.nodes = append(s.nodes[:s.count], n) - s.count++ - atomic.StoreUint32(&s.sema, neutral) -} - -// Pop returns the last pointer off the stack and reduces the count and if empty -// will produce a lovely fresh node -func (s *stack) Pop() *Node { - if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) { - // Stack is in use, for now we can allocate a new node pointer - return &Node{} - } - - if s.count == 0 { - // Create an empty node when no nodes are in slice or when cleaning - // service is running - atomic.StoreUint32(&s.sema, neutral) - return &Node{} - } - s.count-- - n := s.nodes[s.count] - atomic.StoreUint32(&s.sema, neutral) - return n -} - -// cleaner (POC) runs to the defaultTimer to clean excess nodes (nodes not being -// utilised) TODO: Couple time parameters to check for a reduction in activity. -// Add in counter per second function (?) so if there is a lot of activity don't -// inhibit stack performance. -func (s *stack) cleaner() { - tt := time.NewTimer(defaultInterval) -sleeperino: - for range tt.C { - if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) { - // Stack is in use, reset timer to zero to recheck for neutral state. - tt.Reset(0) - continue - } - // As the old nodes are going to be left justified on this slice we - // should just be able to shift the nodes that are still within time - // allowance all the way to the left. Not going to resize capacity - // because if it can get this big, it might as well stay this big. - // TODO: Test and rethink if sizing is an issue - for x := int32(0); x < s.count; x++ { - if time.Since(s.nodes[x].shelved) > defaultAllowance { - // Old node found continue - continue - } - // First good node found, everything to the left of this on the - // slice can be reassigned - var counter int32 - for y := int32(0); y+x < s.count; y++ { // Go through good nodes - // Reassign - s.nodes[y] = s.nodes[y+x] - // Add to the changed counter to remove from main - // counter - counter++ - } - s.count -= counter - atomic.StoreUint32(&s.sema, neutral) - tt.Reset(defaultInterval) - continue sleeperino - } - // Nodes are old, flush entirety. - s.count = 0 - atomic.StoreUint32(&s.sema, neutral) - tt.Reset(defaultInterval) - } -} diff --git a/exchanges/orderbook/node_test.go b/exchanges/orderbook/node_test.go deleted file mode 100644 index 6c31145f9c9..00000000000 --- a/exchanges/orderbook/node_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package orderbook - -import ( - "fmt" - "sync/atomic" - "testing" - "time" -) - -func TestPushPop(t *testing.T) { - s := newStack() - var nSlice [100]*Node - for i := 0; i < 100; i++ { - nSlice[i] = s.Pop() - } - - if s.getCount() != 0 { - t.Fatalf("incorrect stack count expected %v but received %v", 0, s.getCount()) - } - - for i := 0; i < 100; i++ { - s.Push(nSlice[i], time.Now()) - } - - if s.getCount() != 100 { - t.Fatalf("incorrect stack count expected %v but received %v", 100, s.getCount()) - } -} - -func TestCleaner(t *testing.T) { - s := newStack() - var nSlice [100]*Node - for i := 0; i < 100; i++ { - nSlice[i] = s.Pop() - } - - tn := time.Now() - for i := 0; i < 50; i++ { - s.Push(nSlice[i], tn) - } - // Makes all the 50 pushed nodes invalid - time.Sleep(time.Millisecond * 260) - tn = time.Now() - for i := 50; i < 100; i++ { - s.Push(nSlice[i], tn) - } - time.Sleep(time.Millisecond * 50) - if s.getCount() != 50 { - t.Fatalf("incorrect stack count expected %v but received %v", 50, s.getCount()) - } - time.Sleep(time.Millisecond * 350) - if s.getCount() != 0 { - t.Fatalf("incorrect stack count expected %v but received %v", 0, s.getCount()) - } -} - -// Display nodes for testing purposes -func (s *stack) Display() { - for i := int32(0); i < s.getCount(); i++ { - fmt.Printf("NODE IN STACK: %+v %p \n", s.nodes[i], s.nodes[i]) - } - fmt.Println("TOTAL COUNT:", s.getCount()) -} - -// 158 9,521,717 ns/op 9600104 B/op 100001 allocs/op -func BenchmarkWithoutStack(b *testing.B) { - var n *Node - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - for j := 0; j < 100000; j++ { - n = new(Node) - n.Value.Price = 1337 - } - } -} - -// 316 3,485,211 ns/op 1 B/op 0 allocs/op -func BenchmarkWithStack(b *testing.B) { - var n *Node - stack := newStack() - b.ReportAllocs() - b.ResetTimer() - tn := time.Now() - for i := 0; i < b.N; i++ { - for j := 0; j < 100000; j++ { - n = stack.Pop() - n.Value.Price = 1337 - stack.Push(n, tn) - } - } -} - -// getCount is a test helper function to derive the count that does not race. -func (s *stack) getCount() int32 { - if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) { - return -1 - } - defer atomic.StoreUint32(&s.sema, neutral) - return s.count -} diff --git a/exchanges/orderbook/orderbook_test.go b/exchanges/orderbook/orderbook_test.go index 5c8b0debb78..00cdadb474c 100644 --- a/exchanges/orderbook/orderbook_test.go +++ b/exchanges/orderbook/orderbook_test.go @@ -16,9 +16,6 @@ import ( ) func TestMain(m *testing.M) { - // Sets up lower values for test environment - defaultInterval = time.Millisecond * 250 - defaultAllowance = time.Millisecond * 100 err := dispatch.Start(dispatch.DefaultMaxWorkers, dispatch.DefaultJobsLimit*10) if err != nil { log.Fatal(err) diff --git a/exchanges/orderbook/unsafe.go b/exchanges/orderbook/unsafe.go deleted file mode 100644 index 0b0a4c3ac1a..00000000000 --- a/exchanges/orderbook/unsafe.go +++ /dev/null @@ -1,168 +0,0 @@ -package orderbook - -import ( - "errors" - "fmt" - "sync" - "time" - - "github.com/thrasher-corp/gocryptotrader/exchanges/alert" -) - -var errNoLiquidity = errors.New("no liquidity") - -// Unsafe is an exported linked list reference to the current bid/ask heads and -// a reference to the underlying depth mutex. This allows for the exposure of -// the internal list to an external strategy or subsystem. The bid and ask -// fields point to the actual head fields contained on both linked list structs, -// so that this struct can be reusable and not needed to be called on each -// inspection. -type Unsafe struct { - BidHead **Node - AskHead **Node - m *sync.Mutex - - // UpdatedViaREST defines if sync manager is updating this book via the REST - // protocol then this book is not considered live and cannot be trusted. - UpdatedViaREST *bool - LastUpdated *time.Time - *alert.Notice -} - -// Lock locks down the underlying linked list which inhibits all pending updates -// for strategy inspection. -func (src *Unsafe) Lock() { - src.m.Lock() -} - -// Unlock unlocks the underlying linked list after inspection by a strategy to -// resume normal operations -func (src *Unsafe) Unlock() { - src.m.Unlock() -} - -// LockWith locks both books for the context of cross orderbook inspection. -// WARNING: When inspecting diametrically opposed books a higher order mutex -// MUST be used or a dead lock will occur. -func (src *Unsafe) LockWith(dst sync.Locker) { - src.m.Lock() - dst.Lock() -} - -// UnlockWith unlocks both books for the context of cross orderbook inspection -func (src *Unsafe) UnlockWith(dst sync.Locker) { - dst.Unlock() // Unlock in reverse order - src.m.Unlock() -} - -// GetUnsafe returns an unsafe orderbook with pointers to the linked list heads. -func (d *Depth) GetUnsafe() *Unsafe { - return &Unsafe{ - BidHead: &d.bids.linkedList.head, - AskHead: &d.asks.linkedList.head, - m: &d.m, - Notice: &d.Notice, - UpdatedViaREST: &d.options.restSnapshot, - LastUpdated: &d.options.lastUpdated, - } -} - -// CheckBidLiquidity determines if the liquidity is sufficient for usage -func (src *Unsafe) CheckBidLiquidity() error { - _, err := src.GetBidLiquidity() - return err -} - -// CheckAskLiquidity determines if the liquidity is sufficient for usage -func (src *Unsafe) CheckAskLiquidity() error { - _, err := src.GetAskLiquidity() - return err -} - -// GetBestBid returns the top bid price -func (src *Unsafe) GetBestBid() (float64, error) { - bid, err := src.GetBidLiquidity() - if err != nil { - return 0, fmt.Errorf("get orderbook best bid price %w", err) - } - return bid.Value.Price, nil -} - -// GetBestAsk returns the top ask price -func (src *Unsafe) GetBestAsk() (float64, error) { - ask, err := src.GetAskLiquidity() - if err != nil { - return 0, fmt.Errorf("get orderbook best ask price %w", err) - } - return ask.Value.Price, nil -} - -// GetBidLiquidity gets the head node for the bid liquidity -func (src *Unsafe) GetBidLiquidity() (*Node, error) { - n := *src.BidHead - if n == nil { - return nil, fmt.Errorf("bid %w", errNoLiquidity) - } - return n, nil -} - -// GetAskLiquidity gets the head node for the ask liquidity -func (src *Unsafe) GetAskLiquidity() (*Node, error) { - n := *src.AskHead - if n == nil { - return nil, fmt.Errorf("ask %w", errNoLiquidity) - } - return n, nil -} - -// GetLiquidity checks and returns nodes to the top bids and asks -func (src *Unsafe) GetLiquidity() (ask, bid *Node, err error) { - bid, err = src.GetBidLiquidity() - if err != nil { - return nil, nil, err - } - ask, err = src.GetAskLiquidity() - if err != nil { - return nil, nil, err - } - return ask, bid, nil -} - -// GetMidPrice returns the average between the top bid and top ask. -func (src *Unsafe) GetMidPrice() (float64, error) { - ask, bid, err := src.GetLiquidity() - if err != nil { - return 0, fmt.Errorf("get orderbook mid price %w", err) - } - return (bid.Value.Price + ask.Value.Price) / 2, nil -} - -// GetSpread returns the spread between the top bid and top asks. -func (src *Unsafe) GetSpread() (float64, error) { - ask, bid, err := src.GetLiquidity() - if err != nil { - return 0, fmt.Errorf("get orderbook price spread %w", err) - } - return ask.Value.Price - bid.Value.Price, nil -} - -// GetImbalance returns difference between the top bid and top ask amounts -// divided by its sum. -func (src *Unsafe) GetImbalance() (float64, error) { - ask, bid, err := src.GetLiquidity() - if err != nil { - return 0, fmt.Errorf("get orderbook imbalance %w", err) - } - top := bid.Value.Amount - ask.Value.Amount - bottom := bid.Value.Amount + ask.Value.Amount - if bottom == 0 { - return 0, errNoLiquidity - } - return top / bottom, nil -} - -// IsStreaming returns if the orderbook is updated by a streaming protocol and -// is most likely more up to date than that of a REST protocol update. -func (src *Unsafe) IsStreaming() bool { - return !*src.UpdatedViaREST -} diff --git a/exchanges/orderbook/unsafe_test.go b/exchanges/orderbook/unsafe_test.go deleted file mode 100644 index e14f4d21ebb..00000000000 --- a/exchanges/orderbook/unsafe_test.go +++ /dev/null @@ -1,279 +0,0 @@ -package orderbook - -import ( - "errors" - "testing" - "time" - - "github.com/gofrs/uuid" -) - -var unsafeID, _ = uuid.NewV4() - -type externalBook struct{} - -func (e *externalBook) Lock() {} -func (e *externalBook) Unlock() {} - -func TestUnsafe(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - ob := d.GetUnsafe() - if ob.AskHead == nil || ob.BidHead == nil || ob.m == nil { - t.Fatal("these items should not be nil") - } - - ob2 := &externalBook{} - ob.Lock() - ob.Unlock() //nolint:staticcheck, gocritic // Not needed in test - ob.LockWith(ob2) - ob.UnlockWith(ob2) -} - -func TestGetLiquidity(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - _, _, err := unsafe.GetLiquidity() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err = d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - _, _, err = unsafe.GetLiquidity() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err = d.LoadSnapshot([]Item{{Price: 2}}, []Item{{Price: 2}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - aN, bN, err := unsafe.GetLiquidity() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if aN == nil { - t.Fatal("unexpected value") - } - - if bN == nil { - t.Fatal("unexpected value") - } -} - -func TestCheckBidLiquidity(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - err := unsafe.CheckBidLiquidity() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err = d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - err = unsafe.CheckBidLiquidity() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } -} - -func TestCheckAskLiquidity(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - err := unsafe.CheckAskLiquidity() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err = d.LoadSnapshot(nil, []Item{{Price: 2}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - err = unsafe.CheckAskLiquidity() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } -} - -func TestGetBestBid(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - if _, err := unsafe.GetBestBid(); !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err := d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - bestBid, err := unsafe.GetBestBid() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if bestBid != 2 { - t.Fatal("unexpected value") - } -} - -func TestGetBestAsk(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - if _, err := unsafe.GetBestAsk(); !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err := d.LoadSnapshot(nil, []Item{{Price: 2}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - bestAsk, err := unsafe.GetBestAsk() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if bestAsk != 2 { - t.Fatal("unexpected value") - } -} - -func TestGetMidPrice(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - if _, err := unsafe.GetMidPrice(); !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err := d.LoadSnapshot([]Item{{Price: 1}}, []Item{{Price: 2}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - mid, err := unsafe.GetMidPrice() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if mid != 1.5 { - t.Fatal("unexpected value") - } -} - -func TestGetSpread(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - if _, err := unsafe.GetSpread(); !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - err := d.LoadSnapshot([]Item{{Price: 1}}, []Item{{Price: 2}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - spread, err := unsafe.GetSpread() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if spread != 1 { - t.Fatal("unexpected value") - } -} - -func TestGetImbalance(t *testing.T) { - t.Parallel() - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - _, err := unsafe.GetImbalance() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - // unlikely event zero amounts - err = d.LoadSnapshot([]Item{{Price: 1, Amount: 0}}, []Item{{Price: 2, Amount: 0}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - _, err = unsafe.GetImbalance() - if !errors.Is(err, errNoLiquidity) { - t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) - } - - // balance skewed to asks - err = d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1000}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - imbalance, err := unsafe.GetImbalance() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if imbalance != -0.998001998001998 { - t.Fatal("unexpected value") - } - - // balance skewed to bids - err = d.LoadSnapshot([]Item{{Price: 1, Amount: 1000}}, []Item{{Price: 2, Amount: 1}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - imbalance, err = unsafe.GetImbalance() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if imbalance != 0.998001998001998 { - t.Fatal("unexpected value") - } - - // in balance - err = d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - imbalance, err = unsafe.GetImbalance() - if !errors.Is(err, nil) { - t.Fatalf("received: '%v' but expected: '%v'", err, nil) - } - - if imbalance != 0 { - t.Fatal("unexpected value") - } -} - -func TestIsStreaming(t *testing.T) { - d := NewDepth(unsafeID) - unsafe := d.GetUnsafe() - if !unsafe.IsStreaming() { - t.Fatalf("received: '%v' but expected: '%v'", unsafe.IsStreaming(), true) - } - - err := d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Now(), true) - if err != nil { - t.Fatal(err) - } - if unsafe.IsStreaming() { - t.Fatalf("received: '%v' but expected: '%v'", unsafe.IsStreaming(), false) - } - - err = d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Now(), false) - if err != nil { - t.Fatal(err) - } - if !unsafe.IsStreaming() { - t.Fatalf("received: '%v' but expected: '%v'", unsafe.IsStreaming(), true) - } -} From da5446e313b3c5c873343d55c62229c461c3e95b Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 10:50:53 +1100 Subject: [PATCH 02/13] rn LinkedList -> Tranche(s) and purge references --- .../orderbook/{linked_list.go => Tranches.go} | 334 +++++++------- exchanges/orderbook/calculator.go | 20 +- exchanges/orderbook/calculator_test.go | 12 +- exchanges/orderbook/depth.go | 147 +++--- exchanges/orderbook/depth_test.go | 86 ++-- exchanges/orderbook/orderbook.go | 26 +- exchanges/orderbook/orderbook_test.go | 153 +++---- exchanges/orderbook/orderbook_types.go | 21 +- .../{linked_list_test.go => tranches_test.go} | 418 +++++++++--------- 9 files changed, 590 insertions(+), 627 deletions(-) rename exchanges/orderbook/{linked_list.go => Tranches.go} (63%) rename exchanges/orderbook/{linked_list_test.go => tranches_test.go} (79%) diff --git a/exchanges/orderbook/linked_list.go b/exchanges/orderbook/Tranches.go similarity index 63% rename from exchanges/orderbook/linked_list.go rename to exchanges/orderbook/Tranches.go index 7f74268c0cd..017b426168a 100644 --- a/exchanges/orderbook/linked_list.go +++ b/exchanges/orderbook/Tranches.go @@ -12,7 +12,7 @@ import ( const FullLiquidityExhaustedPercentage = -100 var ( - errIDCannotBeMatched = errors.New("cannot match ID on linked list") + errIDCannotBeMatched = errors.New("cannot match ID") errCollisionDetected = errors.New("cannot insert update, collision detected") errAmountCannotBeLessOrEqualToZero = errors.New("amount cannot be less than or equal to zero") errInvalidNominalSlippage = errors.New("invalid slippage amount, its value must be greater than or equal to zero") @@ -27,50 +27,50 @@ var ( errNoLiquidity = errors.New("no liquidity") ) -type linkedList []Item +// Tranches defines a slice of orderbook Tranche +type Tranches []Tranche // comparison defines expected functionality to compare between two reference // price levels type comparison func(float64, float64) bool -// load iterates across new items and refreshes linked list. It creates a linked -// list exactly the same as the item slice that is supplied, if items is of nil -// value it will flush entire list. -func (ll *linkedList) load(items Items) { - if len(items) == 0 { - *ll = (*ll)[:0] // Flush +// load iterates across new tranches and refreshes stored slice with this +// incoming snapshot. +func (ts *Tranches) load(incoming Tranches) { + if len(incoming) == 0 { + *ts = (*ts)[:0] // Flush return } - if len(items) <= len(*ll) { - copy(*ll, items) // Reuse - *ll = (*ll)[:len(items)] // Flush excess + if len(incoming) <= len(*ts) { + copy(*ts, incoming) // Reuse + *ts = (*ts)[:len(incoming)] // Flush excess return } - if len(items) > cap(*ll) { - *ll = make([]Item, len(items)) // Extend - copy(*ll, items) // Copy + if len(incoming) > cap(*ts) { + *ts = make([]Tranche, len(incoming)) // Extend + copy(*ts, incoming) // Copy return } - *ll = (*ll)[:0] // Flush - *ll = append(*ll, items...) // Append + *ts = (*ts)[:0] // Flush + *ts = append(*ts, incoming...) // Append } // updateByID amends price by corresponding ID and returns an error if not found -func (ll linkedList) updateByID(updts []Item) error { +func (ts Tranches) updateByID(updts []Tranche) error { updates: for x := range updts { - for y := range ll { - if updts[x].ID != ll[y].ID { // Filter IDs that don't match + for y := range ts { + if updts[x].ID != ts[y].ID { // Filter IDs that don't match continue } if updts[x].Price > 0 { // Only apply changes when zero values are not present, Bitmex // for example sends 0 price values. - ll[y].Price = updts[x].Price - ll[y].StrPrice = updts[x].StrPrice + ts[y].Price = updts[x].Price + ts[y].StrPrice = updts[x].StrPrice } - ll[y].Amount = updts[x].Amount - ll[y].StrAmount = updts[x].StrAmount + ts[y].Amount = updts[x].Amount + ts[y].StrAmount = updts[x].StrAmount continue updates } return fmt.Errorf("update error: %w ID: %d not found", @@ -81,15 +81,15 @@ updates: } // deleteByID deletes reference by ID -func (ll *linkedList) deleteByID(updts Items, bypassErr bool) error { +func (ts *Tranches) deleteByID(updts Tranches, bypassErr bool) error { updates: for x := range updts { - for y := range *ll { - if updts[x].ID != (*ll)[y].ID { + for y := range *ts { + if updts[x].ID != (*ts)[y].ID { continue } - *ll = append((*ll)[:y], (*ll)[y+1:]...) + *ts = append((*ts)[:y], (*ts)[y+1:]...) continue updates } if !bypassErr { @@ -102,165 +102,167 @@ updates: } // amount returns total depth liquidity and value -func (ll linkedList) amount() (liquidity, value float64) { - for x := range ll { - liquidity += ll[x].Amount - value += ll[x].Amount * ll[x].Price +func (ts Tranches) amount() (liquidity, value float64) { + for x := range ts { + liquidity += ts[x].Amount + value += ts[x].Amount * ts[x].Price } return } -// retrieve returns a full slice of contents from the linked list -func (ll linkedList) retrieve(count int) Items { - if count == 0 || len(ll) < count { - count = len(ll) - } - return Items(ll[:count]) +// retrieve returns a a slice of contents from the stored Tranches up to the +// count length. If count is zero or greater than the length of the stored +// Tranches, the entire slice is returned. +func (ll Tranches) retrieve(count int) Tranches { + if count == 0 || len(ll) <= count { + // In this situation we have to allocate a new slice to prevent the + // caller from modifying the underlying array. + bucket := make(Tranches, len(ll)) + copy(bucket, ll) + return bucket + } + // This will auto allocate a slice because it is a reduction of the + // underlying array. + return ll[:count] } // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *linkedList) updateInsertByPrice(updts Items, maxChainLength int, compare func(float64, float64) bool) { +func (ts *Tranches) updateInsertByPrice(updts Tranches, maxChainLength int, compare func(float64, float64) bool) { updateroo: for x := range updts { - for y := range *ll { + for y := range *ts { switch { - case (*ll)[y].Price == updts[x].Price: + case (*ts)[y].Price == updts[x].Price: if updts[x].Amount <= 0 { // Delete - if y+1 == len(*ll) { - *ll = (*ll)[:y] + if y+1 == len(*ts) { + *ts = (*ts)[:y] } else { - *ll = append((*ll)[:y], (*ll)[y+1:]...) + *ts = append((*ts)[:y], (*ts)[y+1:]...) } } else { // Update - (*ll)[y].Amount = updts[x].Amount - (*ll)[y].StrAmount = updts[x].StrAmount + (*ts)[y].Amount = updts[x].Amount + (*ts)[y].StrAmount = updts[x].StrAmount } continue updateroo - case compare((*ll)[y].Price, updts[x].Price): + case compare((*ts)[y].Price, updts[x].Price): if updts[x].Amount > 0 { - *ll = append(*ll, Item{}) // Extend - copy((*ll)[y+1:], (*ll)[y:]) // Copy elements from index y onwards one position to the right - (*ll)[y] = updts[x] // Insert updts[x] at index y + *ts = append(*ts, Tranche{}) // Extend + copy((*ts)[y+1:], (*ts)[y:]) // Copy elements from index y onwards one position to the right + (*ts)[y] = updts[x] // Insert updts[x] at index y } continue updateroo } } if updts[x].Amount > 0 { - *ll = append(*ll, updts[x]) + *ts = append(*ts, updts[x]) } } - // Reduces length of total linked list chain to a maxChainLength value - if maxChainLength != 0 && len(*ll) > maxChainLength { - *ll = (*ll)[:maxChainLength] + // Reduces length of total stored slice length to a maxChainLength value + if maxChainLength != 0 && len(*ts) > maxChainLength { + *ts = (*ts)[:maxChainLength] } } // updateInsertByID updates or inserts if not found for a bid or ask depth -// 1) node ID found amount amended (best case) -// 2) node ID found amount and price amended and node moved to correct position -// (medium case) -// 3) Update price exceeds traversal node price before ID found, save node -// address for either; node ID matches then re-address node or end of depth pop -// a node from the stack (worst case) -func (ll *linkedList) updateInsertByID(updts Items, compare comparison) error { +func (ts *Tranches) updateInsertByID(updts Tranches, compare comparison) error { updates: for x := range updts { if updts[x].Amount <= 0 { return errAmountCannotBeLessOrEqualToZero } var popped bool - for y := 0; y < len(*ll); y++ { - if (*ll)[y].ID == updts[x].ID { - if (*ll)[y].Price != updts[x].Price { // Price level change - if y+1 == len(*ll) { // end of depth + for y := 0; y < len(*ts); y++ { + if (*ts)[y].ID == updts[x].ID { + if (*ts)[y].Price != updts[x].Price { // Price level change + if y+1 == len(*ts) { // end of depth // no movement needed just a re-adjustment - (*ll)[y] = updts[x] + (*ts)[y] = updts[x] continue updates } - copy((*ll)[y:], (*ll)[y+1:]) // remove him: cya m8 - *ll = (*ll)[:len(*ll)-1] // keep underlying array + copy((*ts)[y:], (*ts)[y+1:]) // RM tranche and shift left + *ts = (*ts)[:len(*ts)-1] // Unlink residual element from end of slice y-- // adjust index popped = true continue // continue through node depth } // no price change, amend amount and continue update - (*ll)[y].Amount = updts[x].Amount - (*ll)[y].StrAmount = updts[x].StrAmount + (*ts)[y].Amount = updts[x].Amount + (*ts)[y].StrAmount = updts[x].StrAmount continue updates // continue to next update } - if compare((*ll)[y].Price, updts[x].Price) { - *ll = append(*ll, Item{}) // Extend - copy((*ll)[y+1:], (*ll)[y:]) // Copy elements from index y onwards one position to the right - (*ll)[y] = updts[x] // Insert updts[x] at index y + if compare((*ts)[y].Price, updts[x].Price) { + *ts = append(*ts, Tranche{}) // Extend + copy((*ts)[y+1:], (*ts)[y:]) // Copy elements from index y onwards one position to the right + (*ts)[y] = updts[x] // Insert updts[x] at index y if popped { // already found ID and popped continue updates } // search for ID - for z := y + 1; z < len(*ll); z++ { - if (*ll)[z].ID == updts[x].ID { - copy((*ll)[z:], (*ll)[z+1:]) // remove him: cya m8 - *ll = (*ll)[:len(*ll)-1] // keep underlying array + for z := y + 1; z < len(*ts); z++ { + if (*ts)[z].ID == updts[x].ID { + copy((*ts)[z:], (*ts)[z+1:]) // RM tranche and shift left + *ts = (*ts)[:len(*ts)-1] // Unlink residual element from end of slice break } } continue updates } } - *ll = append(*ll, updts[x]) + *ts = append(*ts, updts[x]) } return nil } // insertUpdates inserts new updates for bids or asks based on price level -func (ll *linkedList) insertUpdates(updts Items, comp comparison) error { +func (ts *Tranches) insertUpdates(updts Tranches, comp comparison) error { updaterino: for x := range updts { - if len(*ll) == 0 { // TODO: Offset this and outline - *ll = append(*ll, updts[x]) + if len(*ts) == 0 { + *ts = append(*ts, updts[x]) continue } - for y := range *ll { + for y := range *ts { switch { - case (*ll)[y].Price == updts[x].Price: // Price already found + case (*ts)[y].Price == updts[x].Price: // Price already found return fmt.Errorf("%w for price %f", errCollisionDetected, updts[x].Price) - case comp((*ll)[y].Price, updts[x].Price): // price at correct spot - *ll = append((*ll)[:y], append([]Item{updts[x]}, (*ll)[y:]...)...) + case comp((*ts)[y].Price, updts[x].Price): // price at correct spot + *ts = append((*ts)[:y], append([]Tranche{updts[x]}, (*ts)[y:]...)...) continue updaterino } } - *ll = append(*ll, updts[x]) + *ts = append(*ts, updts[x]) } return nil } // getHeadPriceNoLock gets best/head price -func (ll linkedList) getHeadPriceNoLock() (float64, error) { - if len(ll) == 0 { +func (ts Tranches) getHeadPriceNoLock() (float64, error) { + if len(ts) == 0 { return 0, errNoLiquidity } - return ll[0].Price, nil + return ts[0].Price, nil } // getHeadVolumeNoLock gets best/head volume -func (ll linkedList) getHeadVolumeNoLock() (float64, error) { - if len(ll) == 0 { +func (ts Tranches) getHeadVolumeNoLock() (float64, error) { + if len(ts) == 0 { return 0, errNoLiquidity } - return ll[0].Amount, nil + return ts[0].Amount, nil } // getMovementByQuotation traverses through orderbook liquidity using quotation // currency as a limiter and returns orderbook movement details. Swap boolean // allows the swap of sold and purchased to reduce code so it doesn't need to be // specific to bid or ask. -func (ll linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) (*Movement, error) { +func (ts Tranches) getMovementByQuotation(quote, refPrice float64, swap bool) (*Movement, error) { if quote <= 0 { return nil, errQuoteAmountInvalid } @@ -269,32 +271,32 @@ func (ll linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) return nil, errInvalidReferencePrice } - head, err := ll.getHeadPriceNoLock() + head, err := ts.getHeadPriceNoLock() if err != nil { return nil, err } m := Movement{StartPrice: refPrice} - for x := range ll { - trancheValue := ll[x].Amount * ll[x].Price + for x := range ts { + trancheValue := ts[x].Amount * ts[x].Price leftover := quote - trancheValue if leftover < 0 { m.Purchased += quote - m.Sold += quote / trancheValue * ll[x].Amount + m.Sold += quote / trancheValue * ts[x].Amount // This tranche is not consumed so the book shifts to this price. - m.EndPrice = ll[x].Price + m.EndPrice = ts[x].Price quote = 0 break } // Full tranche consumed - m.Purchased += ll[x].Price * ll[x].Amount - m.Sold += ll[x].Amount + m.Purchased += ts[x].Price * ts[x].Amount + m.Sold += ts[x].Amount quote = leftover if leftover == 0 { // Price no longer exists on the book so use next full price tranche // to calculate book impact. If available. - if x+1 < len(ll) { - m.EndPrice = ll[x+1].Price + if x+1 < len(ts) { + m.EndPrice = ts[x+1].Price } else { m.FullBookSideConsumed = true } @@ -308,7 +310,7 @@ func (ll linkedList) getMovementByQuotation(quote, refPrice float64, swap bool) // as a limiter and returns orderbook movement details. Swap boolean allows the // swap of sold and purchased to reduce code so it doesn't need to be specific // to bid or ask. -func (ll linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Movement, error) { +func (ts Tranches) getMovementByBase(base, refPrice float64, swap bool) (*Movement, error) { if base <= 0 { return nil, errBaseAmountInvalid } @@ -317,31 +319,31 @@ func (ll linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Move return nil, errInvalidReferencePrice } - head, err := ll.getHeadPriceNoLock() + head, err := ts.getHeadPriceNoLock() if err != nil { return nil, err } m := Movement{StartPrice: refPrice} - for x := range ll { - leftover := base - ll[x].Amount + for x := range ts { + leftover := base - ts[x].Amount if leftover < 0 { - m.Purchased += ll[x].Price * base + m.Purchased += ts[x].Price * base m.Sold += base // This tranche is not consumed so the book shifts to this price. - m.EndPrice = ll[x].Price + m.EndPrice = ts[x].Price base = 0 break } // Full tranche consumed - m.Purchased += ll[x].Price * ll[x].Amount - m.Sold += ll[x].Amount + m.Purchased += ts[x].Price * ts[x].Amount + m.Sold += ts[x].Amount base = leftover if leftover == 0 { // Price no longer exists on the book so use next full price tranche // to calculate book impact. - if x+1 < len(ll) { - m.EndPrice = ll[x+1].Price + if x+1 < len(ts) { + m.EndPrice = ts[x+1].Price } else { m.FullBookSideConsumed = true } @@ -351,11 +353,8 @@ func (ll linkedList) getMovementByBase(base, refPrice float64, swap bool) (*Move return m.finalizeFields(m.Purchased, m.Sold, head, base, swap) } -// bids embed a linked list to attach methods for bid depth specific -// functionality -type bids struct { - linkedList -} +// bidTranches bid depth specific functionality +type bidTranches struct{ Tranches } // bidCompare ensures price is in correct descending alignment (can inline) func bidCompare(left, right float64) bool { @@ -364,24 +363,24 @@ func bidCompare(left, right float64) bool { // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *bids) updateInsertByPrice(updts Items, maxChainLength int) { - ll.linkedList.updateInsertByPrice(updts, maxChainLength, bidCompare) +func (bids *bidTranches) updateInsertByPrice(updts Tranches, maxChainLength int) { + bids.Tranches.updateInsertByPrice(updts, maxChainLength, bidCompare) } // updateInsertByID updates or inserts if not found -func (ll *bids) updateInsertByID(updts Items) error { - return ll.linkedList.updateInsertByID(updts, bidCompare) +func (bids *bidTranches) updateInsertByID(updts Tranches) error { + return bids.Tranches.updateInsertByID(updts, bidCompare) } // insertUpdates inserts new updates for bids based on price level -func (ll *bids) insertUpdates(updts Items) error { - return ll.linkedList.insertUpdates(updts, bidCompare) +func (bids *bidTranches) insertUpdates(updts Tranches) error { + return bids.Tranches.insertUpdates(updts, bidCompare) } // hitBidsByNominalSlippage hits the bids by the required nominal slippage // percentage, calculated from the reference price and returns orderbook // movement details. -func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, error) { +func (bids *bidTranches) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, error) { if slippage < 0 { return nil, errInvalidNominalSlippage } @@ -394,16 +393,16 @@ func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if len(ll.linkedList) == 0 { + if len(bids.Tranches) == 0 { return nil, errNoLiquidity } nominal := &Movement{StartPrice: refPrice, EndPrice: refPrice} var cumulativeValue, cumulativeAmounts float64 - for x := range ll.linkedList { - totalTrancheValue := ll.linkedList[x].Price * ll.linkedList[x].Amount + for x := range bids.Tranches { + totalTrancheValue := bids.Tranches[x].Price * bids.Tranches[x].Amount currentFullValue := totalTrancheValue + cumulativeValue - currentTotalAmounts := cumulativeAmounts + ll.linkedList[x].Amount + currentTotalAmounts := cumulativeAmounts + bids.Tranches[x].Amount nominal.AverageOrderCost = currentFullValue / currentTotalAmounts percent := math.CalculatePercentageGainOrLoss(nominal.AverageOrderCost, refPrice) @@ -420,24 +419,24 @@ func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, } comparative := targetCost * cumulativeAmounts comparativeDiff := comparative - cumulativeValue - trancheTargetPriceDiff := ll.linkedList[x].Price - targetCost + trancheTargetPriceDiff := bids.Tranches[x].Price - targetCost trancheAmountExpectation := comparativeDiff / trancheTargetPriceDiff nominal.NominalPercentage = slippage nominal.Sold = cumulativeAmounts + trancheAmountExpectation - nominal.Purchased += trancheAmountExpectation * ll.linkedList[x].Price + nominal.Purchased += trancheAmountExpectation * bids.Tranches[x].Price nominal.AverageOrderCost = nominal.Purchased / nominal.Sold - nominal.EndPrice = ll.linkedList[x].Price + nominal.EndPrice = bids.Tranches[x].Price return nominal, nil } - nominal.EndPrice = ll.linkedList[x].Price + nominal.EndPrice = bids.Tranches[x].Price cumulativeValue = currentFullValue nominal.NominalPercentage = percent - nominal.Sold += ll.linkedList[x].Amount + nominal.Sold += bids.Tranches[x].Amount nominal.Purchased += totalTrancheValue cumulativeAmounts = currentTotalAmounts if slippage == percent { - nominal.FullBookSideConsumed = x+1 >= len(ll.linkedList) + nominal.FullBookSideConsumed = x+1 >= len(bids.Tranches) return nominal, nil } } @@ -448,7 +447,7 @@ func (ll *bids) hitBidsByNominalSlippage(slippage, refPrice float64) (*Movement, // hitBidsByImpactSlippage hits the bids by the required impact slippage // percentage, calculated from the reference price and returns orderbook // movement details. -func (ll *bids) hitBidsByImpactSlippage(slippage, refPrice float64) (*Movement, error) { +func (bids *bidTranches) hitBidsByImpactSlippage(slippage, refPrice float64) (*Movement, error) { if slippage <= 0 { return nil, errInvalidImpactSlippage } @@ -461,25 +460,25 @@ func (ll *bids) hitBidsByImpactSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if len(ll.linkedList) == 0 { + if len(bids.Tranches) == 0 { return nil, errNoLiquidity } impact := &Movement{StartPrice: refPrice, EndPrice: refPrice} - for x := range ll.linkedList { - percent := math.CalculatePercentageGainOrLoss(ll.linkedList[x].Price, refPrice) + for x := range bids.Tranches { + percent := math.CalculatePercentageGainOrLoss(bids.Tranches[x].Price, refPrice) if percent != 0 { percent *= -1 } - impact.EndPrice = ll.linkedList[x].Price + impact.EndPrice = bids.Tranches[x].Price impact.ImpactPercentage = percent if slippage <= percent { // Don't include this tranche amount as this consumes the tranche // book price, thus obtaining a higher percentage impact. return impact, nil } - impact.Sold += ll.linkedList[x].Amount - impact.Purchased += ll.linkedList[x].Amount * ll.linkedList[x].Price + impact.Sold += bids.Tranches[x].Amount + impact.Purchased += bids.Tranches[x].Amount * bids.Tranches[x].Price impact.AverageOrderCost = impact.Purchased / impact.Sold } impact.FullBookSideConsumed = true @@ -487,11 +486,8 @@ func (ll *bids) hitBidsByImpactSlippage(slippage, refPrice float64) (*Movement, return impact, nil } -// asks embed a linked list to attach methods for ask depth specific -// functionality -type asks struct { - linkedList -} +// askTranches ask depth specific functionality +type askTranches struct{ Tranches } // askCompare ensures price is in correct ascending alignment (can inline) func askCompare(left, right float64) bool { @@ -500,24 +496,24 @@ func askCompare(left, right float64) bool { // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates -func (ll *asks) updateInsertByPrice(updts Items, maxChainLength int) { - ll.linkedList.updateInsertByPrice(updts, maxChainLength, askCompare) +func (ask *askTranches) updateInsertByPrice(updts Tranches, maxChainLength int) { + ask.Tranches.updateInsertByPrice(updts, maxChainLength, askCompare) } // updateInsertByID updates or inserts if not found -func (ll *asks) updateInsertByID(updts Items) error { - return ll.linkedList.updateInsertByID(updts, askCompare) +func (ask *askTranches) updateInsertByID(updts Tranches) error { + return ask.Tranches.updateInsertByID(updts, askCompare) } // insertUpdates inserts new updates for asks based on price level -func (ll *asks) insertUpdates(updts Items) error { - return ll.linkedList.insertUpdates(updts, askCompare) +func (ask *askTranches) insertUpdates(updts Tranches) error { + return ask.Tranches.insertUpdates(updts, askCompare) } // liftAsksByNominalSlippage lifts the asks by the required nominal slippage // percentage, calculated from the reference price and returns orderbook // movement details. -func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement, error) { +func (ask *askTranches) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement, error) { if slippage < 0 { return nil, errInvalidNominalSlippage } @@ -526,16 +522,16 @@ func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement return nil, errInvalidReferencePrice } - if len(ll.linkedList) == 0 { + if len(ask.Tranches) == 0 { return nil, errNoLiquidity } nominal := &Movement{StartPrice: refPrice, EndPrice: refPrice} var cumulativeAmounts float64 - for x := range ll.linkedList { - totalTrancheValue := ll.linkedList[x].Price * ll.linkedList[x].Amount + for x := range ask.Tranches { + totalTrancheValue := ask.Tranches[x].Price * ask.Tranches[x].Amount currentValue := totalTrancheValue + nominal.Sold - currentAmounts := cumulativeAmounts + ll.linkedList[x].Amount + currentAmounts := cumulativeAmounts + ask.Tranches[x].Amount nominal.AverageOrderCost = currentValue / currentAmounts percent := math.CalculatePercentageGainOrLoss(nominal.AverageOrderCost, refPrice) @@ -550,19 +546,19 @@ func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement comparative := targetCost * cumulativeAmounts comparativeDiff := comparative - nominal.Sold - trancheTargetPriceDiff := ll.linkedList[x].Price - targetCost + trancheTargetPriceDiff := ask.Tranches[x].Price - targetCost trancheAmountExpectation := comparativeDiff / trancheTargetPriceDiff nominal.NominalPercentage = slippage - nominal.Sold += trancheAmountExpectation * ll.linkedList[x].Price + nominal.Sold += trancheAmountExpectation * ask.Tranches[x].Price nominal.Purchased += trancheAmountExpectation nominal.AverageOrderCost = nominal.Sold / nominal.Purchased - nominal.EndPrice = ll.linkedList[x].Price + nominal.EndPrice = ask.Tranches[x].Price return nominal, nil } - nominal.EndPrice = ll.linkedList[x].Price + nominal.EndPrice = ask.Tranches[x].Price nominal.Sold = currentValue - nominal.Purchased += ll.linkedList[x].Amount + nominal.Purchased += ask.Tranches[x].Amount nominal.NominalPercentage = percent if slippage == percent { return nominal, nil @@ -576,7 +572,7 @@ func (ll *asks) liftAsksByNominalSlippage(slippage, refPrice float64) (*Movement // liftAsksByImpactSlippage lifts the asks by the required impact slippage // percentage, calculated from the reference price and returns orderbook // movement details. -func (ll *asks) liftAsksByImpactSlippage(slippage, refPrice float64) (*Movement, error) { +func (ask *askTranches) liftAsksByImpactSlippage(slippage, refPrice float64) (*Movement, error) { if slippage <= 0 { return nil, errInvalidImpactSlippage } @@ -585,22 +581,22 @@ func (ll *asks) liftAsksByImpactSlippage(slippage, refPrice float64) (*Movement, return nil, errInvalidReferencePrice } - if len(ll.linkedList) == 0 { + if len(ask.Tranches) == 0 { return nil, errNoLiquidity } impact := &Movement{StartPrice: refPrice, EndPrice: refPrice} - for x := range ll.linkedList { - percent := math.CalculatePercentageGainOrLoss(ll.linkedList[x].Price, refPrice) + for x := range ask.Tranches { + percent := math.CalculatePercentageGainOrLoss(ask.Tranches[x].Price, refPrice) impact.ImpactPercentage = percent - impact.EndPrice = ll.linkedList[x].Price + impact.EndPrice = ask.Tranches[x].Price if slippage <= percent { // Don't include this tranche amount as this consumes the tranche // book price, thus obtaining a higher percentage impact. return impact, nil } - impact.Sold += ll.linkedList[x].Amount * ll.linkedList[x].Price - impact.Purchased += ll.linkedList[x].Amount + impact.Sold += ask.Tranches[x].Amount * ask.Tranches[x].Price + impact.Purchased += ask.Tranches[x].Amount impact.AverageOrderCost = impact.Sold / impact.Purchased } impact.FullBookSideConsumed = true diff --git a/exchanges/orderbook/calculator.go b/exchanges/orderbook/calculator.go index e862a1a4d45..b984e56e8fe 100644 --- a/exchanges/orderbook/calculator.go +++ b/exchanges/orderbook/calculator.go @@ -21,7 +21,7 @@ type WhaleBombResult struct { MinimumPrice float64 MaximumPrice float64 PercentageGainOrLoss float64 - Orders Items + Orders Tranches Status string } @@ -175,7 +175,7 @@ type DeploymentAction struct { TranchePositionPrice float64 BaseAmount float64 QuoteAmount float64 - Tranches Items + Tranches Tranches FullLiquidityUsed bool } @@ -201,7 +201,7 @@ func (b *Base) buy(quote float64) (*DeploymentAction, error) { } } subAmount := quote / b.Asks[x].Price - action.Tranches = append(action.Tranches, Item{ + action.Tranches = append(action.Tranches, Tranche{ Price: b.Asks[x].Price, Amount: subAmount, }) @@ -238,7 +238,7 @@ func (b *Base) sell(base float64) (*DeploymentAction, error) { action.FullLiquidityUsed = true } } - action.Tranches = append(action.Tranches, Item{ + action.Tranches = append(action.Tranches, Tranche{ Price: b.Bids[x].Price, Amount: base, }) @@ -279,16 +279,16 @@ func (b *Base) GetAveragePrice(buy bool, amount float64) (float64, error) { // FindNominalAmount finds the nominal amount spent in terms of the quote // If the orderbook doesn't have enough liquidity it returns a non zero // remaining amount value -func (elem Items) FindNominalAmount(amount float64) (aggNominalAmount, remainingAmount float64) { +func (ts Tranches) FindNominalAmount(amount float64) (aggNominalAmount, remainingAmount float64) { remainingAmount = amount - for x := range elem { - if remainingAmount <= elem[x].Amount { - aggNominalAmount += elem[x].Price * remainingAmount + for x := range ts { + if remainingAmount <= ts[x].Amount { + aggNominalAmount += ts[x].Price * remainingAmount remainingAmount = 0 break } - aggNominalAmount += elem[x].Price * elem[x].Amount - remainingAmount -= elem[x].Amount + aggNominalAmount += ts[x].Price * ts[x].Amount + remainingAmount -= ts[x].Amount } return aggNominalAmount, remainingAmount } diff --git a/exchanges/orderbook/calculator_test.go b/exchanges/orderbook/calculator_test.go index 434699d8319..714ce445bc9 100644 --- a/exchanges/orderbook/calculator_test.go +++ b/exchanges/orderbook/calculator_test.go @@ -13,11 +13,11 @@ func testSetup() Base { return Base{ Exchange: "a", Pair: currency.NewPair(currency.BTC, currency.USD), - Asks: []Item{ + Asks: []Tranche{ {Price: 7000, Amount: 1}, {Price: 7001, Amount: 2}, }, - Bids: []Item{ + Bids: []Tranche{ {Price: 6999, Amount: 1}, {Price: 6998, Amount: 2}, }, @@ -507,14 +507,14 @@ func TestGetAveragePrice(t *testing.T) { t.Error(err) } b.Pair = cp - b.Bids = []Item{} + b.Bids = []Tranche{} _, err = b.GetAveragePrice(false, 5) if errors.Is(errNotEnoughLiquidity, err) { t.Error("expected: %w, received %w", errNotEnoughLiquidity, err) } b = Base{} b.Pair = cp - b.Asks = []Item{ + b.Asks = []Tranche{ {Amount: 5, Price: 1}, {Amount: 5, Price: 2}, {Amount: 5, Price: 3}, @@ -545,7 +545,7 @@ func TestGetAveragePrice(t *testing.T) { } func TestFindNominalAmount(t *testing.T) { - b := Items{ + b := Tranches{ {Amount: 5, Price: 1}, {Amount: 5, Price: 2}, {Amount: 5, Price: 3}, @@ -555,7 +555,7 @@ func TestFindNominalAmount(t *testing.T) { if nomAmt != 30 && remainingAmt != 0 { t.Errorf("invalid return") } - b = Items{} + b = Tranches{} nomAmt, remainingAmt = b.FindNominalAmount(15) if nomAmt != 0 && remainingAmt != 30 { t.Errorf("invalid return") diff --git a/exchanges/orderbook/depth.go b/exchanges/orderbook/depth.go index 38e8855e378..eb47c9f4a65 100644 --- a/exchanges/orderbook/depth.go +++ b/exchanges/orderbook/depth.go @@ -26,16 +26,15 @@ var ( ) // Outbound restricts outbound usage of depth. NOTE: Type assert to -// *orderbook.Depth or alternatively retrieve orderbook.Unsafe type to access -// underlying linked list. +// *orderbook.Depth. type Outbound interface { Retrieve() (*Base, error) } -// Depth defines a linked list of orderbook items +// Depth defines a store of orderbook tranches type Depth struct { - asks - bids + askTranches + bidTranches // // unexported stack of nodes // stack *stack @@ -53,14 +52,8 @@ type Depth struct { m sync.Mutex } -// NewDepth returns a new depth item -func NewDepth(id uuid.UUID) *Depth { - return &Depth{ - // stack: newStack(), - _ID: id, - mux: service.Mux, - } -} +// NewDepth returns a new orderbook depth +func NewDepth(id uuid.UUID) *Depth { return &Depth{_ID: id, mux: service.Mux} } // Publish alerts any subscribed routines using a dispatch mux func (d *Depth) Publish() { @@ -78,8 +71,8 @@ func (d *Depth) Retrieve() (*Base, error) { return nil, d.validationError } return &Base{ - Bids: d.bids.retrieve(0), - Asks: d.asks.retrieve(0), + Bids: d.bidTranches.retrieve(0), + Asks: d.askTranches.retrieve(0), Exchange: d.exchange, Asset: d.asset, Pair: d.pair, @@ -94,7 +87,7 @@ func (d *Depth) Retrieve() (*Base, error) { } // LoadSnapshot flushes the bids and asks with a snapshot -func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated time.Time, updateByREST bool) error { +func (d *Depth) LoadSnapshot(bids, asks []Tranche, lastUpdateID int64, lastUpdated time.Time, updateByREST bool) error { d.m.Lock() defer d.m.Unlock() if lastUpdated.IsZero() { @@ -107,8 +100,8 @@ func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated d.lastUpdateID = lastUpdateID d.lastUpdated = lastUpdated d.restSnapshot = updateByREST - d.bids.load(bids) - d.asks.load(asks) + d.bidTranches.load(bids) + d.askTranches.load(asks) d.validationError = nil d.Alert() return nil @@ -119,8 +112,8 @@ func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated func (d *Depth) invalidate(withReason error) error { d.lastUpdateID = 0 d.lastUpdated = time.Time{} - d.bids.load(nil) - d.asks.load(nil) + d.bidTranches.load(nil) + d.askTranches.load(nil) d.validationError = fmt.Errorf("%s %s %s Reason: [%w]", d.exchange, d.pair, @@ -159,10 +152,10 @@ func (d *Depth) UpdateBidAskByPrice(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - d.bids.updateInsertByPrice(update.Bids, d.options.maxDepth) + d.bidTranches.updateInsertByPrice(update.Bids, d.options.maxDepth) } if len(update.Asks) != 0 { - d.asks.updateInsertByPrice(update.Asks, d.options.maxDepth) + d.askTranches.updateInsertByPrice(update.Asks, d.options.maxDepth) } d.updateAndAlert(update) return nil @@ -182,13 +175,13 @@ func (d *Depth) UpdateBidAskByID(update *Update) error { } if len(update.Bids) != 0 { - err := d.bids.updateByID(update.Bids) + err := d.bidTranches.updateByID(update.Bids) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.updateByID(update.Asks) + err := d.askTranches.updateByID(update.Asks) if err != nil { return d.invalidate(err) } @@ -209,13 +202,13 @@ func (d *Depth) DeleteBidAskByID(update *Update, bypassErr bool) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.deleteByID(update.Bids, bypassErr) + err := d.bidTranches.deleteByID(update.Bids, bypassErr) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.deleteByID(update.Asks, bypassErr) + err := d.askTranches.deleteByID(update.Asks, bypassErr) if err != nil { return d.invalidate(err) } @@ -236,13 +229,13 @@ func (d *Depth) InsertBidAskByID(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.insertUpdates(update.Bids) + err := d.bidTranches.insertUpdates(update.Bids) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.insertUpdates(update.Asks) + err := d.askTranches.insertUpdates(update.Asks) if err != nil { return d.invalidate(err) } @@ -263,13 +256,13 @@ func (d *Depth) UpdateInsertByID(update *Update) error { errLastUpdatedNotSet) } if len(update.Bids) != 0 { - err := d.bids.updateInsertByID(update.Bids) + err := d.bidTranches.updateInsertByID(update.Bids) if err != nil { return d.invalidate(err) } } if len(update.Asks) != 0 { - err := d.asks.updateInsertByID(update.Asks) + err := d.askTranches.updateInsertByID(update.Asks) if err != nil { return d.invalidate(err) } @@ -305,7 +298,7 @@ func (d *Depth) GetName() string { return d.exchange } -// IsRESTSnapshot returns if the depth item was updated via REST +// IsRESTSnapshot returns if the depth was updated via REST func (d *Depth) IsRESTSnapshot() (bool, error) { d.m.Lock() defer d.m.Unlock() @@ -339,7 +332,7 @@ func (d *Depth) GetAskLength() (int, error) { if d.validationError != nil { return 0, d.validationError } - return len(d.asks.linkedList), nil + return len(d.askTranches.Tranches), nil } // GetBidLength returns length of bids @@ -349,7 +342,7 @@ func (d *Depth) GetBidLength() (int, error) { if d.validationError != nil { return 0, d.validationError } - return len(d.bids.linkedList), nil + return len(d.bidTranches.Tranches), nil } // TotalBidAmounts returns the total amount of bids and the total orderbook @@ -360,7 +353,7 @@ func (d *Depth) TotalBidAmounts() (liquidity, value float64, err error) { if d.validationError != nil { return 0, 0, d.validationError } - liquidity, value = d.bids.amount() + liquidity, value = d.bidTranches.amount() return liquidity, value, nil } @@ -372,7 +365,7 @@ func (d *Depth) TotalAskAmounts() (liquidity, value float64, err error) { if d.validationError != nil { return 0, 0, d.validationError } - liquidity, value = d.asks.amount() + liquidity, value = d.askTranches.amount() return liquidity, value, nil } @@ -393,7 +386,7 @@ func (d *Depth) HitTheBidsByNominalSlippage(maxSlippage, refPrice float64) (*Mov if d.validationError != nil { return nil, d.validationError } - return d.bids.hitBidsByNominalSlippage(maxSlippage, refPrice) + return d.bidTranches.hitBidsByNominalSlippage(maxSlippage, refPrice) } // HitTheBidsByNominalSlippageFromMid hits the bids by the required nominal @@ -409,7 +402,7 @@ func (d *Depth) HitTheBidsByNominalSlippageFromMid(maxSlippage float64) (*Moveme if err != nil { return nil, err } - return d.bids.hitBidsByNominalSlippage(maxSlippage, mid) + return d.bidTranches.hitBidsByNominalSlippage(maxSlippage, mid) } // HitTheBidsByNominalSlippageFromBest hits the bids by the required nominal @@ -421,11 +414,11 @@ func (d *Depth) HitTheBidsByNominalSlippageFromBest(maxSlippage float64) (*Movem if d.validationError != nil { return nil, d.validationError } - head, err := d.bids.getHeadPriceNoLock() + head, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return nil, err } - return d.bids.hitBidsByNominalSlippage(maxSlippage, head) + return d.bidTranches.hitBidsByNominalSlippage(maxSlippage, head) } // LiftTheAsksByNominalSlippage lifts the asks by the required nominal slippage @@ -437,7 +430,7 @@ func (d *Depth) LiftTheAsksByNominalSlippage(maxSlippage, refPrice float64) (*Mo if d.validationError != nil { return nil, d.validationError } - return d.asks.liftAsksByNominalSlippage(maxSlippage, refPrice) + return d.askTranches.liftAsksByNominalSlippage(maxSlippage, refPrice) } // LiftTheAsksByNominalSlippageFromMid lifts the asks by the required nominal @@ -453,7 +446,7 @@ func (d *Depth) LiftTheAsksByNominalSlippageFromMid(maxSlippage float64) (*Movem if err != nil { return nil, err } - return d.asks.liftAsksByNominalSlippage(maxSlippage, mid) + return d.askTranches.liftAsksByNominalSlippage(maxSlippage, mid) } // LiftTheAsksByNominalSlippageFromBest lifts the asks by the required nominal @@ -465,11 +458,11 @@ func (d *Depth) LiftTheAsksByNominalSlippageFromBest(maxSlippage float64) (*Move if d.validationError != nil { return nil, d.validationError } - head, err := d.asks.getHeadPriceNoLock() + head, err := d.askTranches.getHeadPriceNoLock() if err != nil { return nil, err } - return d.asks.liftAsksByNominalSlippage(maxSlippage, head) + return d.askTranches.liftAsksByNominalSlippage(maxSlippage, head) } // HitTheBidsByImpactSlippage hits the bids by the required impact slippage @@ -481,7 +474,7 @@ func (d *Depth) HitTheBidsByImpactSlippage(maxSlippage, refPrice float64) (*Move if d.validationError != nil { return nil, d.validationError } - return d.bids.hitBidsByImpactSlippage(maxSlippage, refPrice) + return d.bidTranches.hitBidsByImpactSlippage(maxSlippage, refPrice) } // HitTheBidsByImpactSlippageFromMid hits the bids by the required impact @@ -497,7 +490,7 @@ func (d *Depth) HitTheBidsByImpactSlippageFromMid(maxSlippage float64) (*Movemen if err != nil { return nil, err } - return d.bids.hitBidsByImpactSlippage(maxSlippage, mid) + return d.bidTranches.hitBidsByImpactSlippage(maxSlippage, mid) } // HitTheBidsByImpactSlippageFromBest hits the bids by the required impact @@ -509,11 +502,11 @@ func (d *Depth) HitTheBidsByImpactSlippageFromBest(maxSlippage float64) (*Moveme if d.validationError != nil { return nil, d.validationError } - head, err := d.bids.getHeadPriceNoLock() + head, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return nil, err } - return d.bids.hitBidsByImpactSlippage(maxSlippage, head) + return d.bidTranches.hitBidsByImpactSlippage(maxSlippage, head) } // LiftTheAsksByImpactSlippage lifts the asks by the required impact slippage @@ -525,7 +518,7 @@ func (d *Depth) LiftTheAsksByImpactSlippage(maxSlippage, refPrice float64) (*Mov if d.validationError != nil { return nil, d.validationError } - return d.asks.liftAsksByImpactSlippage(maxSlippage, refPrice) + return d.askTranches.liftAsksByImpactSlippage(maxSlippage, refPrice) } // LiftTheAsksByImpactSlippageFromMid lifts the asks by the required impact @@ -541,7 +534,7 @@ func (d *Depth) LiftTheAsksByImpactSlippageFromMid(maxSlippage float64) (*Moveme if err != nil { return nil, err } - return d.asks.liftAsksByImpactSlippage(maxSlippage, mid) + return d.askTranches.liftAsksByImpactSlippage(maxSlippage, mid) } // LiftTheAsksByImpactSlippageFromBest lifts the asks by the required impact @@ -553,11 +546,11 @@ func (d *Depth) LiftTheAsksByImpactSlippageFromBest(maxSlippage float64) (*Movem if d.validationError != nil { return nil, d.validationError } - head, err := d.asks.getHeadPriceNoLock() + head, err := d.askTranches.getHeadPriceNoLock() if err != nil { return nil, err } - return d.asks.liftAsksByImpactSlippage(maxSlippage, head) + return d.askTranches.liftAsksByImpactSlippage(maxSlippage, head) } // HitTheBids derives full orderbook slippage information from reference price @@ -570,9 +563,9 @@ func (d *Depth) HitTheBids(amount, refPrice float64, purchase bool) (*Movement, return nil, d.validationError } if purchase { - return d.bids.getMovementByQuotation(amount, refPrice, false) + return d.bidTranches.getMovementByQuotation(amount, refPrice, false) } - return d.bids.getMovementByBase(amount, refPrice, false) + return d.bidTranches.getMovementByBase(amount, refPrice, false) } // HitTheBidsFromMid derives full orderbook slippage information from mid price @@ -589,9 +582,9 @@ func (d *Depth) HitTheBidsFromMid(amount float64, purchase bool) (*Movement, err return nil, err } if purchase { - return d.bids.getMovementByQuotation(amount, mid, false) + return d.bidTranches.getMovementByQuotation(amount, mid, false) } - return d.bids.getMovementByBase(amount, mid, false) + return d.bidTranches.getMovementByBase(amount, mid, false) } // HitTheBidsFromBest derives full orderbook slippage information from best bid @@ -603,14 +596,14 @@ func (d *Depth) HitTheBidsFromBest(amount float64, purchase bool) (*Movement, er if d.validationError != nil { return nil, d.validationError } - head, err := d.bids.getHeadPriceNoLock() + head, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return nil, err } if purchase { - return d.bids.getMovementByQuotation(amount, head, false) + return d.bidTranches.getMovementByQuotation(amount, head, false) } - return d.bids.getMovementByBase(amount, head, false) + return d.bidTranches.getMovementByBase(amount, head, false) } // LiftTheAsks derives full orderbook slippage information from reference price @@ -623,9 +616,9 @@ func (d *Depth) LiftTheAsks(amount, refPrice float64, purchase bool) (*Movement, return nil, d.validationError } if purchase { - return d.asks.getMovementByBase(amount, refPrice, true) + return d.askTranches.getMovementByBase(amount, refPrice, true) } - return d.asks.getMovementByQuotation(amount, refPrice, true) + return d.askTranches.getMovementByQuotation(amount, refPrice, true) } // LiftTheAsksFromMid derives full orderbook slippage information from mid price @@ -642,9 +635,9 @@ func (d *Depth) LiftTheAsksFromMid(amount float64, purchase bool) (*Movement, er return nil, err } if purchase { - return d.asks.getMovementByBase(amount, mid, true) + return d.askTranches.getMovementByBase(amount, mid, true) } - return d.asks.getMovementByQuotation(amount, mid, true) + return d.askTranches.getMovementByQuotation(amount, mid, true) } // LiftTheAsksFromBest derives full orderbook slippage information from best ask @@ -656,14 +649,14 @@ func (d *Depth) LiftTheAsksFromBest(amount float64, purchase bool) (*Movement, e if d.validationError != nil { return nil, d.validationError } - head, err := d.asks.getHeadPriceNoLock() + head, err := d.askTranches.getHeadPriceNoLock() if err != nil { return nil, err } if purchase { - return d.asks.getMovementByBase(amount, head, true) + return d.askTranches.getMovementByBase(amount, head, true) } - return d.asks.getMovementByQuotation(amount, head, true) + return d.askTranches.getMovementByQuotation(amount, head, true) } // GetMidPrice returns the mid price between the ask and bid spread @@ -678,11 +671,11 @@ func (d *Depth) GetMidPrice() (float64, error) { // getMidPriceNoLock is an unprotected helper that gets mid price func (d *Depth) getMidPriceNoLock() (float64, error) { - bidHead, err := d.bids.getHeadPriceNoLock() + bidHead, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return 0, err } - askHead, err := d.asks.getHeadPriceNoLock() + askHead, err := d.askTranches.getHeadPriceNoLock() if err != nil { return 0, err } @@ -696,7 +689,7 @@ func (d *Depth) GetBestBid() (float64, error) { if d.validationError != nil { return 0, d.validationError } - return d.bids.getHeadPriceNoLock() + return d.bidTranches.getHeadPriceNoLock() } // GetBestAsk returns the best ask price @@ -706,7 +699,7 @@ func (d *Depth) GetBestAsk() (float64, error) { if d.validationError != nil { return 0, d.validationError } - return d.asks.getHeadPriceNoLock() + return d.askTranches.getHeadPriceNoLock() } // GetSpreadAmount returns the spread as a quotation amount @@ -716,11 +709,11 @@ func (d *Depth) GetSpreadAmount() (float64, error) { if d.validationError != nil { return 0, d.validationError } - askHead, err := d.asks.getHeadPriceNoLock() + askHead, err := d.askTranches.getHeadPriceNoLock() if err != nil { return 0, err } - bidHead, err := d.bids.getHeadPriceNoLock() + bidHead, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return 0, err } @@ -734,11 +727,11 @@ func (d *Depth) GetSpreadPercentage() (float64, error) { if d.validationError != nil { return 0, d.validationError } - askHead, err := d.asks.getHeadPriceNoLock() + askHead, err := d.askTranches.getHeadPriceNoLock() if err != nil { return 0, err } - bidHead, err := d.bids.getHeadPriceNoLock() + bidHead, err := d.bidTranches.getHeadPriceNoLock() if err != nil { return 0, err } @@ -752,11 +745,11 @@ func (d *Depth) GetImbalance() (float64, error) { if d.validationError != nil { return 0, d.validationError } - askVolume, err := d.asks.getHeadVolumeNoLock() + askVolume, err := d.askTranches.getHeadVolumeNoLock() if err != nil { return 0, err } - bidVolume, err := d.bids.getHeadVolumeNoLock() + bidVolume, err := d.bidTranches.getHeadVolumeNoLock() if err != nil { return 0, err } @@ -767,7 +760,7 @@ func (d *Depth) GetImbalance() (float64, error) { // count is 0, it will return the entire orderbook. Count == 1 will retrieve the // best bid and ask. If the required count exceeds the orderbook depth, it will // return the entire orderbook. -func (d *Depth) GetTranches(count int) (ask, bid []Item, err error) { +func (d *Depth) GetTranches(count int) (ask, bid []Tranche, err error) { if count < 0 { return nil, nil, errInvalidBookDepth } @@ -776,7 +769,7 @@ func (d *Depth) GetTranches(count int) (ask, bid []Item, err error) { if d.validationError != nil { return nil, nil, d.validationError } - return d.asks.retrieve(count), d.bids.retrieve(count), nil + return d.askTranches.retrieve(count), d.bidTranches.retrieve(count), nil } // GetPair returns the pair associated with the depth diff --git a/exchanges/orderbook/depth_test.go b/exchanges/orderbook/depth_test.go index 06410f2917f..95f6d65eab0 100644 --- a/exchanges/orderbook/depth_test.go +++ b/exchanges/orderbook/depth_test.go @@ -28,14 +28,14 @@ func TestGetLength(t *testing.T) { _, err = d.GetAskLength() assert.ErrorIs(t, err, ErrOrderbookInvalid, "GetAskLength should error with invalid depth") - err = d.LoadSnapshot([]Item{{Price: 1337}}, nil, 0, time.Now(), true) + err = d.LoadSnapshot([]Tranche{{Price: 1337}}, nil, 0, time.Now(), true) assert.NoError(t, err, "LoadSnapshot should not error") askLen, err := d.GetAskLength() assert.NoError(t, err, "GetAskLength should not error") assert.Zero(t, askLen, "ask length should be zero") - d.asks.load([]Item{{Price: 1337}}) + d.askTranches.load([]Tranche{{Price: 1337}}) askLen, err = d.GetAskLength() assert.NoError(t, err, "GetAskLength should not error") @@ -48,14 +48,14 @@ func TestGetLength(t *testing.T) { _, err = d.GetBidLength() assert.ErrorIs(t, err, ErrOrderbookInvalid, "GetBidLength should error with invalid depth") - err = d.LoadSnapshot(nil, []Item{{Price: 1337}}, 0, time.Now(), true) + err = d.LoadSnapshot(nil, []Tranche{{Price: 1337}}, 0, time.Now(), true) assert.NoError(t, err, "LoadSnapshot should not error") bidLen, err := d.GetBidLength() assert.NoError(t, err, "GetBidLength should not error") assert.Zero(t, bidLen, "bid length should be zero") - d.bids.load([]Item{{Price: 1337}}) + d.bidTranches.load([]Tranche{{Price: 1337}}) bidLen, err = d.GetBidLength() assert.NoError(t, err, "GetBidLength should not error") @@ -65,8 +65,8 @@ func TestGetLength(t *testing.T) { func TestRetrieve(t *testing.T) { t.Parallel() d := NewDepth(id) - d.asks.load([]Item{{Price: 1337}}) - d.bids.load([]Item{{Price: 1337}}) + d.askTranches.load([]Tranche{{Price: 1337}}) + d.bidTranches.load([]Tranche{{Price: 1337}}) d.options = options{ exchange: "THE BIG ONE!!!!!!", pair: currency.NewPair(currency.THETA, currency.USD), @@ -125,8 +125,8 @@ func TestTotalAmounts(t *testing.T) { assert.Zero(t, liquidity, "total ask liquidity should be zero") assert.Zero(t, value, "total ask value should be zero") - d.asks.load([]Item{{Price: 1337, Amount: 1}}) - d.bids.load([]Item{{Price: 1337, Amount: 10}}) + d.askTranches.load([]Tranche{{Price: 1337, Amount: 1}}) + d.bidTranches.load([]Tranche{{Price: 1337, Amount: 10}}) liquidity, value, err = d.TotalBidAmounts() assert.NoError(t, err, "TotalBidAmounts should not error") @@ -142,10 +142,10 @@ func TestTotalAmounts(t *testing.T) { func TestLoadSnapshot(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Time{}, false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1}}, Tranches{{Price: 1337, Amount: 10}}, 0, time.Time{}, false) assert.ErrorIs(t, err, errLastUpdatedNotSet, "LoadSnapshot should error correctly") - err = d.LoadSnapshot(Items{{Price: 1337, Amount: 2}}, Items{{Price: 1338, Amount: 10}}, 0, time.Now(), false) + err = d.LoadSnapshot(Tranches{{Price: 1337, Amount: 2}}, Tranches{{Price: 1338, Amount: 10}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") ob, err := d.Retrieve() @@ -164,7 +164,7 @@ func TestInvalidate(t *testing.T) { d.pair = currency.NewPair(currency.BTC, currency.WABI) d.asset = asset.Spot - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1}}, Tranches{{Price: 1337, Amount: 10}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") ob, err := d.Retrieve() @@ -192,7 +192,7 @@ func TestInvalidate(t *testing.T) { func TestUpdateBidAskByPrice(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1338, Amount: 10, ID: 2}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1338, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") err = d.UpdateBidAskByPrice(&Update{}) @@ -202,8 +202,8 @@ func TestUpdateBidAskByPrice(t *testing.T) { assert.NoError(t, err, "UpdateBidAskByPrice should not error") updates := &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 1}}, - Asks: Items{{Price: 1338, Amount: 3, ID: 2}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 1}}, + Asks: Tranches{{Price: 1338, Amount: 3, ID: 2}}, UpdateID: 1, UpdateTime: time.Now(), } @@ -216,8 +216,8 @@ func TestUpdateBidAskByPrice(t *testing.T) { assert.Equal(t, 2.0, ob.Bids[0].Amount, "Bids amount should be correct") updates = &Update{ - Bids: Items{{Price: 1337, Amount: 0, ID: 1}}, - Asks: Items{{Price: 1338, Amount: 0, ID: 2}}, + Bids: Tranches{{Price: 1337, Amount: 0, ID: 1}}, + Asks: Tranches{{Price: 1338, Amount: 0, ID: 2}}, UpdateID: 2, UpdateTime: time.Now(), } @@ -236,12 +236,12 @@ func TestUpdateBidAskByPrice(t *testing.T) { func TestDeleteBidAskByID(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates := &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 1}}, - Asks: Items{{Price: 1337, Amount: 2, ID: 2}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 1}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 2}}, } err = d.DeleteBidAskByID(updates, false) @@ -257,21 +257,21 @@ func TestDeleteBidAskByID(t *testing.T) { assert.Empty(t, ob.Bids, "Bids should be empty") updates = &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 1}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 1}}, UpdateTime: time.Now(), } err = d.DeleteBidAskByID(updates, false) assert.ErrorIs(t, err, errIDCannotBeMatched, "DeleteBidAskByID should error correctly") updates = &Update{ - Asks: Items{{Price: 1337, Amount: 2, ID: 2}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 2}}, UpdateTime: time.Now(), } err = d.DeleteBidAskByID(updates, false) assert.ErrorIs(t, err, errIDCannotBeMatched, "DeleteBidAskByID should error correctly") updates = &Update{ - Asks: Items{{Price: 1337, Amount: 2, ID: 2}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 2}}, UpdateTime: time.Now(), } err = d.DeleteBidAskByID(updates, true) @@ -281,12 +281,12 @@ func TestDeleteBidAskByID(t *testing.T) { func TestUpdateBidAskByID(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates := &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 1}}, - Asks: Items{{Price: 1337, Amount: 2, ID: 2}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 1}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 2}}, } err = d.UpdateBidAskByID(updates) @@ -302,7 +302,7 @@ func TestUpdateBidAskByID(t *testing.T) { assert.Equal(t, 2.0, ob.Bids[0].Amount, "First bid amount should be correct") updates = &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 666}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 666}}, UpdateTime: time.Now(), } // random unmatching IDs @@ -310,7 +310,7 @@ func TestUpdateBidAskByID(t *testing.T) { assert.ErrorIs(t, err, errIDCannotBeMatched, "UpdateBidAskByID should error correctly") updates = &Update{ - Asks: Items{{Price: 1337, Amount: 2, ID: 69}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 69}}, UpdateTime: time.Now(), } err = d.UpdateBidAskByID(updates) @@ -320,11 +320,11 @@ func TestUpdateBidAskByID(t *testing.T) { func TestInsertBidAskByID(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates := &Update{ - Asks: Items{{Price: 1337, Amount: 2, ID: 3}}, + Asks: Tranches{{Price: 1337, Amount: 2, ID: 3}}, } err = d.InsertBidAskByID(updates) assert.ErrorIs(t, err, errLastUpdatedNotSet, "InsertBidAskByID should error correctly") @@ -334,23 +334,23 @@ func TestInsertBidAskByID(t *testing.T) { err = d.InsertBidAskByID(updates) assert.ErrorIs(t, err, errCollisionDetected, "InsertBidAskByID should error correctly on collision") - err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err = d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates = &Update{ - Bids: Items{{Price: 1337, Amount: 2, ID: 3}}, + Bids: Tranches{{Price: 1337, Amount: 2, ID: 3}}, UpdateTime: time.Now(), } err = d.InsertBidAskByID(updates) assert.ErrorIs(t, err, errCollisionDetected, "InsertBidAskByID should error correctly on collision") - err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err = d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates = &Update{ - Bids: Items{{Price: 1338, Amount: 2, ID: 3}}, - Asks: Items{{Price: 1336, Amount: 2, ID: 4}}, + Bids: Tranches{{Price: 1338, Amount: 2, ID: 3}}, + Asks: Tranches{{Price: 1336, Amount: 2, ID: 4}}, UpdateTime: time.Now(), } err = d.InsertBidAskByID(updates) @@ -365,12 +365,12 @@ func TestInsertBidAskByID(t *testing.T) { func TestUpdateInsertByID(t *testing.T) { t.Parallel() d := NewDepth(id) - err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err := d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates := &Update{ - Bids: Items{{Price: 1338, Amount: 0, ID: 3}}, - Asks: Items{{Price: 1336, Amount: 2, ID: 4}}, + Bids: Tranches{{Price: 1338, Amount: 0, ID: 3}}, + Asks: Tranches{{Price: 1336, Amount: 2, ID: 4}}, } err = d.UpdateInsertByID(updates) assert.ErrorIs(t, err, errLastUpdatedNotSet, "UpdateInsertByID should error correctly") @@ -383,12 +383,12 @@ func TestUpdateInsertByID(t *testing.T) { _, err = d.Retrieve() assert.ErrorIs(t, err, ErrOrderbookInvalid, "Retrieve should error correctly") - err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err = d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates = &Update{ - Bids: Items{{Price: 1338, Amount: 2, ID: 3}}, - Asks: Items{{Price: 1336, Amount: 0, ID: 4}}, + Bids: Tranches{{Price: 1338, Amount: 2, ID: 3}}, + Asks: Tranches{{Price: 1336, Amount: 0, ID: 4}}, UpdateTime: time.Now(), } err = d.UpdateInsertByID(updates) @@ -398,12 +398,12 @@ func TestUpdateInsertByID(t *testing.T) { _, err = d.Retrieve() assert.ErrorIs(t, err, ErrOrderbookInvalid, "Retrieve should error correctly") - err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) + err = d.LoadSnapshot(Tranches{{Price: 1337, Amount: 1, ID: 1}}, Tranches{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false) assert.NoError(t, err, "LoadSnapshot should not error") updates = &Update{ - Bids: Items{{Price: 1338, Amount: 2, ID: 3}}, - Asks: Items{{Price: 1336, Amount: 2, ID: 4}}, + Bids: Tranches{{Price: 1338, Amount: 2, ID: 3}}, + Asks: Tranches{{Price: 1336, Amount: 2, ID: 4}}, UpdateTime: time.Now(), } err = d.UpdateInsertByID(updates) diff --git a/exchanges/orderbook/orderbook.go b/exchanges/orderbook/orderbook.go index d5a8ca5eee3..03cce25ce47 100644 --- a/exchanges/orderbook/orderbook.go +++ b/exchanges/orderbook/orderbook.go @@ -146,8 +146,8 @@ func (s *Service) GetDepth(exchange string, p currency.Pair, a asset.Item) (*Dep return book, nil } -// Retrieve gets orderbook depth data from the associated linked list and -// returns the base equivalent copy +// Retrieve gets orderbook depth data from the stored tranches and returns the +// base equivalent copy func (s *Service) Retrieve(exchange string, p currency.Pair, a asset.Item) (*Base, error) { if p.IsEmpty() { return nil, currency.ErrCurrencyPairEmpty @@ -238,10 +238,10 @@ func (b *Base) Verify() error { // checker defines specific functionality to determine ascending/descending // validation -type checker func(current Item, previous Item) error +type checker func(current Tranche, previous Tranche) error // asc specifically defines ascending price check -var asc = func(current Item, previous Item) error { +var asc = func(current Tranche, previous Tranche) error { if current.Price < previous.Price { return errPriceOutOfOrder } @@ -249,7 +249,7 @@ var asc = func(current Item, previous Item) error { } // dsc specifically defines descending price check -var dsc = func(current Item, previous Item) error { +var dsc = func(current Tranche, previous Tranche) error { if current.Price > previous.Price { return errPriceOutOfOrder } @@ -257,7 +257,7 @@ var dsc = func(current Item, previous Item) error { } // checkAlignment validates full orderbook -func checkAlignment(depth Items, fundingRate, priceDuplication, isIDAligned, requiresChecksumString bool, c checker, exch string) error { +func checkAlignment(depth Tranches, fundingRate, priceDuplication, isIDAligned, requiresChecksumString bool, c checker, exch string) error { for i := range depth { if depth[i].Price == 0 { switch { @@ -327,25 +327,25 @@ func (b *Base) Process() error { // using a sort algorithm as the algorithm could be impeded by a worst case time // complexity when elements are shifted as opposed to just swapping element // values. -func (elem *Items) Reverse() { - eLen := len(*elem) +func (ts *Tranches) Reverse() { + eLen := len(*ts) var target int for i := eLen/2 - 1; i >= 0; i-- { target = eLen - 1 - i - (*elem)[i], (*elem)[target] = (*elem)[target], (*elem)[i] + (*ts)[i], (*ts)[target] = (*ts)[target], (*ts)[i] } } // SortAsks sorts ask items to the correct ascending order if pricing values are // scattered. If order from exchange is descending consider using the Reverse // function. -func (elem *Items) SortAsks() { - sort.Sort(byOBPrice(*elem)) +func (elem Tranches) SortAsks() { + sort.Slice(elem, func(i, j int) bool { return elem[i].Price < elem[j].Price }) } // SortBids sorts bid items to the correct descending order if pricing values // are scattered. If order from exchange is ascending consider using the Reverse // function. -func (elem *Items) SortBids() { - sort.Sort(sort.Reverse(byOBPrice(*elem))) +func (elem Tranches) SortBids() { + sort.Slice(elem, func(i, j int) bool { return elem[i].Price > elem[j].Price }) } diff --git a/exchanges/orderbook/orderbook_test.go b/exchanges/orderbook/orderbook_test.go index 00cdadb474c..da9c454580e 100644 --- a/exchanges/orderbook/orderbook_test.go +++ b/exchanges/orderbook/orderbook_test.go @@ -35,7 +35,7 @@ func TestSubscribeToExchangeOrderbooks(t *testing.T) { Pair: p, Asset: asset.Spot, Exchange: "SubscribeToExchangeOrderbooks", - Bids: []Item{{Price: 100, Amount: 1}, {Price: 99, Amount: 1}}, + Bids: []Tranche{{Price: 100, Amount: 1}, {Price: 99, Amount: 1}}, } err = b.Process() @@ -63,19 +63,19 @@ func TestVerify(t *testing.T) { t.Fatalf("expecting %v error but received %v", nil, err) } - b.Asks = []Item{{ID: 1337, Price: 99, Amount: 1}, {ID: 1337, Price: 100, Amount: 1}} + b.Asks = []Tranche{{ID: 1337, Price: 99, Amount: 1}, {ID: 1337, Price: 100, Amount: 1}} err = b.Verify() if !errors.Is(err, errIDDuplication) { t.Fatalf("expecting %s error but received %v", errIDDuplication, err) } - b.Asks = []Item{{Price: 100, Amount: 1}, {Price: 100, Amount: 1}} + b.Asks = []Tranche{{Price: 100, Amount: 1}, {Price: 100, Amount: 1}} err = b.Verify() if !errors.Is(err, errDuplication) { t.Fatalf("expecting %s error but received %v", errDuplication, err) } - b.Asks = []Item{{Price: 100, Amount: 1}, {Price: 99, Amount: 1}} + b.Asks = []Tranche{{Price: 100, Amount: 1}, {Price: 99, Amount: 1}} b.IsFundingRate = true err = b.Verify() if !errors.Is(err, errPeriodUnset) { @@ -88,31 +88,31 @@ func TestVerify(t *testing.T) { t.Fatalf("expecting %s error but received %v", errPriceOutOfOrder, err) } - b.Asks = []Item{{Price: 100, Amount: 1}, {Price: 100, Amount: 0}} + b.Asks = []Tranche{{Price: 100, Amount: 1}, {Price: 100, Amount: 0}} err = b.Verify() if !errors.Is(err, errAmountInvalid) { t.Fatalf("expecting %s error but received %v", errAmountInvalid, err) } - b.Asks = []Item{{Price: 100, Amount: 1}, {Price: 0, Amount: 100}} + b.Asks = []Tranche{{Price: 100, Amount: 1}, {Price: 0, Amount: 100}} err = b.Verify() if !errors.Is(err, errPriceNotSet) { t.Fatalf("expecting %s error but received %v", errPriceNotSet, err) } - b.Bids = []Item{{ID: 1337, Price: 100, Amount: 1}, {ID: 1337, Price: 99, Amount: 1}} + b.Bids = []Tranche{{ID: 1337, Price: 100, Amount: 1}, {ID: 1337, Price: 99, Amount: 1}} err = b.Verify() if !errors.Is(err, errIDDuplication) { t.Fatalf("expecting %s error but received %v", errIDDuplication, err) } - b.Bids = []Item{{Price: 100, Amount: 1}, {Price: 100, Amount: 1}} + b.Bids = []Tranche{{Price: 100, Amount: 1}, {Price: 100, Amount: 1}} err = b.Verify() if !errors.Is(err, errDuplication) { t.Fatalf("expecting %s error but received %v", errDuplication, err) } - b.Bids = []Item{{Price: 99, Amount: 1}, {Price: 100, Amount: 1}} + b.Bids = []Tranche{{Price: 99, Amount: 1}, {Price: 100, Amount: 1}} b.IsFundingRate = true err = b.Verify() if !errors.Is(err, errPeriodUnset) { @@ -125,13 +125,13 @@ func TestVerify(t *testing.T) { t.Fatalf("expecting %s error but received %v", errPriceOutOfOrder, err) } - b.Bids = []Item{{Price: 100, Amount: 1}, {Price: 100, Amount: 0}} + b.Bids = []Tranche{{Price: 100, Amount: 1}, {Price: 100, Amount: 0}} err = b.Verify() if !errors.Is(err, errAmountInvalid) { t.Fatalf("expecting %s error but received %v", errAmountInvalid, err) } - b.Bids = []Item{{Price: 100, Amount: 1}, {Price: 0, Amount: 100}} + b.Bids = []Tranche{{Price: 100, Amount: 1}, {Price: 0, Amount: 100}} err = b.Verify() if !errors.Is(err, errPriceNotSet) { t.Fatalf("expecting %s error but received %v", errPriceNotSet, err) @@ -146,7 +146,7 @@ func TestCalculateTotalBids(t *testing.T) { } base := Base{ Pair: curr, - Bids: []Item{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 100, Amount: 10}}, LastUpdated: time.Now(), } @@ -164,7 +164,7 @@ func TestCalculateTotalAsks(t *testing.T) { } base := Base{ Pair: curr, - Asks: []Item{{Price: 100, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, } a, b := base.TotalAsksAmount() @@ -180,8 +180,8 @@ func TestGetOrderbook(t *testing.T) { } base := &Base{ Pair: c, - Asks: []Item{{Price: 100, Amount: 10}}, - Bids: []Item{{Price: 200, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 200, Amount: 10}}, Exchange: "Exchange", Asset: asset.Spot, } @@ -239,8 +239,8 @@ func TestGetDepth(t *testing.T) { } base := &Base{ Pair: c, - Asks: []Item{{Price: 100, Amount: 10}}, - Bids: []Item{{Price: 200, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 200, Amount: 10}}, Exchange: "Exchange", Asset: asset.Spot, } @@ -298,8 +298,8 @@ func TestBaseGetDepth(t *testing.T) { } base := &Base{ Pair: c, - Asks: []Item{{Price: 100, Amount: 10}}, - Bids: []Item{{Price: 200, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 200, Amount: 10}}, Exchange: "Exchange", Asset: asset.Spot, } @@ -352,8 +352,8 @@ func TestCreateNewOrderbook(t *testing.T) { } base := &Base{ Pair: c, - Asks: []Item{{Price: 100, Amount: 10}}, - Bids: []Item{{Price: 200, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 200, Amount: 10}}, Exchange: "testCreateNewOrderbook", Asset: asset.Spot, } @@ -389,8 +389,8 @@ func TestProcessOrderbook(t *testing.T) { t.Fatal(err) } base := Base{ - Asks: []Item{{Price: 100, Amount: 10}}, - Bids: []Item{{Price: 200, Amount: 10}}, + Asks: []Tranche{{Price: 100, Amount: 10}}, + Bids: []Tranche{{Price: 200, Amount: 10}}, Exchange: "ProcessOrderbook", } @@ -458,7 +458,7 @@ func TestProcessOrderbook(t *testing.T) { t.Fatal("TestProcessOrderbook result pair is incorrect") } - base.Asks = []Item{{Price: 200, Amount: 200}} + base.Asks = []Tranche{{Price: 200, Amount: 200}} base.Asset = asset.Spot err = base.Process() if err != nil { @@ -475,7 +475,7 @@ func TestProcessOrderbook(t *testing.T) { t.Fatal("TestProcessOrderbook CalculateTotalsAsks incorrect values") } - base.Bids = []Item{{Price: 420, Amount: 200}} + base.Bids = []Tranche{{Price: 420, Amount: 200}} base.Exchange = "Blah" base.Asset = asset.CoinMarginedFutures err = base.Process() @@ -495,8 +495,8 @@ func TestProcessOrderbook(t *testing.T) { type quick struct { Name string P currency.Pair - Bids []Item - Asks []Item + Bids []Tranche + Asks []Tranche } var testArray []quick @@ -521,8 +521,8 @@ func TestProcessOrderbook(t *testing.T) { newPairs := currency.NewPair(currency.NewCode("BTC"+strconv.FormatInt(rand.Int63(), 10)), currency.NewCode("USD"+strconv.FormatInt(rand.Int63(), 10))) //nolint:gosec // no need to import crypo/rand for testing - asks := []Item{{Price: rand.Float64(), Amount: rand.Float64()}} //nolint:gosec // no need to import crypo/rand for testing - bids := []Item{{Price: rand.Float64(), Amount: rand.Float64()}} //nolint:gosec // no need to import crypo/rand for testing + asks := []Tranche{{Price: rand.Float64(), Amount: rand.Float64()}} //nolint:gosec // no need to import crypo/rand for testing + bids := []Tranche{{Price: rand.Float64(), Amount: rand.Float64()}} //nolint:gosec // no need to import crypo/rand for testing base := &Base{ Pair: newPairs, Asks: asks, @@ -579,12 +579,12 @@ func TestProcessOrderbook(t *testing.T) { wg.Wait() } -func deployUnorderedSlice() Items { - var items []Item +func deployUnorderedSlice() Tranches { + var ts []Tranche for i := 0; i < 1000; i++ { - items = append(items, Item{Amount: 1, Price: rand.Float64(), ID: rand.Int63()}) //nolint:gosec // Not needed in tests + ts = append(ts, Tranche{Amount: 1, Price: rand.Float64(), ID: rand.Int63()}) //nolint:gosec // Not needed in tests } - return items + return ts } func TestSorting(t *testing.T) { @@ -616,12 +616,12 @@ func TestSorting(t *testing.T) { } } -func deploySliceOrdered() Items { - var items []Item +func deploySliceOrdered() Tranches { + var ts []Tranche for i := 0; i < 1000; i++ { - items = append(items, Item{Amount: 1, Price: float64(i + 1), ID: rand.Int63()}) //nolint:gosec // Not needed in tests + ts = append(ts, Tranche{Amount: 1, Price: float64(i + 1), ID: rand.Int63()}) //nolint:gosec // Not needed in tests } - return items + return ts } func TestReverse(t *testing.T) { @@ -668,94 +668,77 @@ func BenchmarkReverse(b *testing.B) { } } -// 20209 56385 ns/op 49189 B/op 2 allocs/op +// 20209 56385 ns/op 49189 B/op 2 allocs/op (old) +// 385783 3000 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortAsksDecending(b *testing.B) { s := deploySliceOrdered() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortAsks() + copy(bucket, s) + bucket.SortAsks() } } -// 14924 79199 ns/op 49206 B/op 3 allocs/op +// 14924 79199 ns/op 49206 B/op 3 allocs/op (old) +// 372396 3001 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortBidsAscending(b *testing.B) { s := deploySliceOrdered() s.Reverse() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortBids() + copy(bucket, s) + bucket.SortBids() } } -// 9842 133761 ns/op 49194 B/op 2 allocs/op +// 9842 133761 ns/op 49194 B/op 2 allocs/op (old) +// 16233 76951 ns/op 167 B/op 3 allocs/op (new) func BenchmarkSortAsksStandard(b *testing.B) { s := deployUnorderedSlice() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortAsks() + copy(bucket, s) + bucket.SortAsks() } } -// 7058 155057 ns/op 49214 B/op 3 allocs/op +// 7058 155057 ns/op 49214 B/op 3 allocs/op (old) +// 15698 72859 ns/op 168 B/op 3 allocs/op (new) func BenchmarkSortBidsStandard(b *testing.B) { s := deployUnorderedSlice() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortBids() + copy(bucket, s) + bucket.SortBids() } } -// 20565 57001 ns/op 49188 B/op 2 allocs/op +// 20565 57001 ns/op 49188 B/op 2 allocs/op (old) +// 377113 3020 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortAsksAscending(b *testing.B) { s := deploySliceOrdered() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortAsks() + copy(bucket, s) + bucket.SortAsks() } } -// 12565 97257 ns/op 49208 B/op 3 allocs/op +// 12565 97257 ns/op 49208 B/op 3 allocs/op (old) +// 401788 3348 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortBidsDescending(b *testing.B) { s := deploySliceOrdered() s.Reverse() + bucket := make(Tranches, len(s)) for i := 0; i < b.N; i++ { - //nolint: gocritic - ts := append(s[:0:0], s...) - ts.SortBids() - } -} - -// 124867 8480 ns/op 49152 B/op 1 allocs/op -func BenchmarkDuplicatingSlice(b *testing.B) { - s := deploySliceOrdered() - for i := 0; i < b.N; i++ { - _ = append(s[:0:0], s...) - } -} - -// 122998 8441 ns/op 49152 B/op 1 allocs/op -func BenchmarkCopySlice(b *testing.B) { - s := deploySliceOrdered() - for i := 0; i < b.N; i++ { - cpy := make([]Item, len(s)) - copy(cpy, s) + copy(bucket, s) + bucket.SortBids() } } func TestCheckAlignment(t *testing.T) { t.Parallel() - itemWithFunding := Items{ - { - Amount: 1337, - Price: 0, - Period: 1337, - }, - } + itemWithFunding := Tranches{{Amount: 1337, Price: 0, Period: 1337}} err := checkAlignment(itemWithFunding, true, true, false, false, dsc, "Bitfinex") if err != nil { t.Error(err) diff --git a/exchanges/orderbook/orderbook_types.go b/exchanges/orderbook/orderbook_types.go index 07b2a467036..6ed7bd3da8e 100644 --- a/exchanges/orderbook/orderbook_types.go +++ b/exchanges/orderbook/orderbook_types.go @@ -55,8 +55,8 @@ type Exchange struct { ID uuid.UUID } -// Item stores the amount and price values -type Item struct { +// Tranche defines a segmented portions of an order or options book +type Tranche struct { Amount float64 // StrAmount is a string representation of the amount. e.g. 0.00000100 this // parsed as a float will constrict comparison to 1e-6 not 1e-8 or @@ -77,13 +77,10 @@ type Item struct { OrderCount int64 } -// Items defines a slice of orderbook items -type Items []Item - // Base holds the fields for the orderbook base type Base struct { - Bids Items - Asks Items + Bids Tranches + Asks Tranches Exchange string Pair currency.Pair @@ -115,12 +112,6 @@ type Base struct { ChecksumStringRequired bool } -type byOBPrice []Item - -func (a byOBPrice) Len() int { return len(a) } -func (a byOBPrice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byOBPrice) Less(i, j int) bool { return a[i].Price < a[j].Price } - type options struct { exchange string pair currency.Pair @@ -158,8 +149,8 @@ type Update struct { UpdateTime time.Time Asset asset.Item Action - Bids []Item - Asks []Item + Bids []Tranche + Asks []Tranche Pair currency.Pair // Checksum defines the expected value when the books have been verified Checksum uint32 diff --git a/exchanges/orderbook/linked_list_test.go b/exchanges/orderbook/tranches_test.go similarity index 79% rename from exchanges/orderbook/linked_list_test.go rename to exchanges/orderbook/tranches_test.go index 6c3481194ec..65d25d91d31 100644 --- a/exchanges/orderbook/linked_list_test.go +++ b/exchanges/orderbook/tranches_test.go @@ -9,54 +9,54 @@ import ( "github.com/stretchr/testify/assert" ) -var ask = Items{ - Item{Price: 1337, Amount: 1}, - Item{Price: 1338, Amount: 1}, - Item{Price: 1339, Amount: 1}, - Item{Price: 1340, Amount: 1}, - Item{Price: 1341, Amount: 1}, - Item{Price: 1342, Amount: 1}, - Item{Price: 1343, Amount: 1}, - Item{Price: 1344, Amount: 1}, - Item{Price: 1345, Amount: 1}, - Item{Price: 1346, Amount: 1}, - Item{Price: 1347, Amount: 1}, - Item{Price: 1348, Amount: 1}, - Item{Price: 1349, Amount: 1}, - Item{Price: 1350, Amount: 1}, - Item{Price: 1351, Amount: 1}, - Item{Price: 1352, Amount: 1}, - Item{Price: 1353, Amount: 1}, - Item{Price: 1354, Amount: 1}, - Item{Price: 1355, Amount: 1}, - Item{Price: 1356, Amount: 1}, +var ask = Tranches{ + {Price: 1337, Amount: 1}, + {Price: 1338, Amount: 1}, + {Price: 1339, Amount: 1}, + {Price: 1340, Amount: 1}, + {Price: 1341, Amount: 1}, + {Price: 1342, Amount: 1}, + {Price: 1343, Amount: 1}, + {Price: 1344, Amount: 1}, + {Price: 1345, Amount: 1}, + {Price: 1346, Amount: 1}, + {Price: 1347, Amount: 1}, + {Price: 1348, Amount: 1}, + {Price: 1349, Amount: 1}, + {Price: 1350, Amount: 1}, + {Price: 1351, Amount: 1}, + {Price: 1352, Amount: 1}, + {Price: 1353, Amount: 1}, + {Price: 1354, Amount: 1}, + {Price: 1355, Amount: 1}, + {Price: 1356, Amount: 1}, } -var bid = Items{ - Item{Price: 1336, Amount: 1}, - Item{Price: 1335, Amount: 1}, - Item{Price: 1334, Amount: 1}, - Item{Price: 1333, Amount: 1}, - Item{Price: 1332, Amount: 1}, - Item{Price: 1331, Amount: 1}, - Item{Price: 1330, Amount: 1}, - Item{Price: 1329, Amount: 1}, - Item{Price: 1328, Amount: 1}, - Item{Price: 1327, Amount: 1}, - Item{Price: 1326, Amount: 1}, - Item{Price: 1325, Amount: 1}, - Item{Price: 1324, Amount: 1}, - Item{Price: 1323, Amount: 1}, - Item{Price: 1322, Amount: 1}, - Item{Price: 1321, Amount: 1}, - Item{Price: 1320, Amount: 1}, - Item{Price: 1319, Amount: 1}, - Item{Price: 1318, Amount: 1}, - Item{Price: 1317, Amount: 1}, +var bid = Tranches{ + {Price: 1336, Amount: 1}, + {Price: 1335, Amount: 1}, + {Price: 1334, Amount: 1}, + {Price: 1333, Amount: 1}, + {Price: 1332, Amount: 1}, + {Price: 1331, Amount: 1}, + {Price: 1330, Amount: 1}, + {Price: 1329, Amount: 1}, + {Price: 1328, Amount: 1}, + {Price: 1327, Amount: 1}, + {Price: 1326, Amount: 1}, + {Price: 1325, Amount: 1}, + {Price: 1324, Amount: 1}, + {Price: 1323, Amount: 1}, + {Price: 1322, Amount: 1}, + {Price: 1321, Amount: 1}, + {Price: 1320, Amount: 1}, + {Price: 1319, Amount: 1}, + {Price: 1318, Amount: 1}, + {Price: 1317, Amount: 1}, } // Display displays depth content for tests -func (ll linkedList) display() { +func (ll Tranches) display() { for x := range ll { fmt.Printf("NODE: %+v %p \n", ll[x], &ll[x]) } @@ -64,10 +64,10 @@ func (ll linkedList) display() { } func TestLoad(t *testing.T) { - list := asks{} + list := askTranches{} Check(t, list, 0, 0, 0) - list.load(Items{ + list.load(Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -78,7 +78,7 @@ func TestLoad(t *testing.T) { Check(t, list, 6, 36, 6) - list.load(Items{ + list.load(Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -86,7 +86,7 @@ func TestLoad(t *testing.T) { Check(t, list, 3, 9, 3) - list.load(Items{ + list.load(Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -103,15 +103,15 @@ func TestLoad(t *testing.T) { // 27906781 42.4 ns/op 0 B/op 0 allocs/op (old) // 84119028 13.87 ns/op 0 B/op 0 allocs/op (new) func BenchmarkLoad(b *testing.B) { - ll := linkedList{} + ts := Tranches{} for i := 0; i < b.N; i++ { - ll.load(ask) + ts.load(ask) } } func TestUpdateInsertByPrice(t *testing.T) { - a := asks{} - asksSnapshot := Items{ + a := askTranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -122,26 +122,26 @@ func TestUpdateInsertByPrice(t *testing.T) { a.load(asksSnapshot) // Update one instance with matching price - a.updateInsertByPrice(Items{{Price: 1, Amount: 2}}, 0) + a.updateInsertByPrice(Tranches{{Price: 1, Amount: 2}}, 0) Check(t, a, 7, 37, 6) // Insert at head - a.updateInsertByPrice(Items{ + a.updateInsertByPrice(Tranches{ {Price: 0.5, Amount: 2}, }, 0) Check(t, a, 9, 38, 7) // Insert at tail - a.updateInsertByPrice(Items{ + a.updateInsertByPrice(Tranches{ {Price: 12, Amount: 2}, }, 0) Check(t, a, 11, 62, 8) // Insert between price and up to and beyond max allowable depth level - a.updateInsertByPrice(Items{ + a.updateInsertByPrice(Tranches{ {Price: 11.5, Amount: 2}, {Price: 10.5, Amount: 2}, {Price: 13, Amount: 2}, @@ -150,17 +150,17 @@ func TestUpdateInsertByPrice(t *testing.T) { Check(t, a, 15, 106, 10) // delete at tail - a.updateInsertByPrice(Items{{Price: 12, Amount: 0}}, 0) + a.updateInsertByPrice(Tranches{{Price: 12, Amount: 0}}, 0) Check(t, a, 13, 82, 9) // delete at mid - a.updateInsertByPrice(Items{{Price: 7, Amount: 0}}, 0) + a.updateInsertByPrice(Tranches{{Price: 7, Amount: 0}}, 0) Check(t, a, 12, 75, 8) // delete at head - a.updateInsertByPrice(Items{{Price: 0.5, Amount: 0}}, 0) + a.updateInsertByPrice(Tranches{{Price: 0.5, Amount: 0}}, 0) Check(t, a, 10, 74, 7) @@ -168,7 +168,7 @@ func TestUpdateInsertByPrice(t *testing.T) { a.load(nil) // rebuild everything again - a.updateInsertByPrice(Items{ + a.updateInsertByPrice(Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -179,8 +179,8 @@ func TestUpdateInsertByPrice(t *testing.T) { Check(t, a, 6, 36, 6) - b := bids{} - bidsSnapshot := Items{ + b := bidTranches{} + bidsSnapshot := Tranches{ {Price: 11, Amount: 1}, {Price: 9, Amount: 1}, {Price: 7, Amount: 1}, @@ -191,22 +191,22 @@ func TestUpdateInsertByPrice(t *testing.T) { b.load(bidsSnapshot) // Update one instance with matching price - b.updateInsertByPrice(Items{{Price: 11, Amount: 2}}, 0) + b.updateInsertByPrice(Tranches{{Price: 11, Amount: 2}}, 0) Check(t, b, 7, 47, 6) // Insert at head - b.updateInsertByPrice(Items{{Price: 12, Amount: 2}}, 0) + b.updateInsertByPrice(Tranches{{Price: 12, Amount: 2}}, 0) Check(t, b, 9, 71, 7) // Insert at tail - b.updateInsertByPrice(Items{{Price: 0.5, Amount: 2}}, 0) + b.updateInsertByPrice(Tranches{{Price: 0.5, Amount: 2}}, 0) Check(t, b, 11, 72, 8) // Insert between price and up to and beyond max allowable depth level - b.updateInsertByPrice(Items{ + b.updateInsertByPrice(Tranches{ {Price: 11.5, Amount: 2}, {Price: 10.5, Amount: 2}, {Price: 13, Amount: 2}, @@ -215,17 +215,17 @@ func TestUpdateInsertByPrice(t *testing.T) { Check(t, b, 15, 141, 10) // Insert between price and up to and beyond max allowable depth level - b.updateInsertByPrice(Items{{Price: 1, Amount: 0}}, 0) + b.updateInsertByPrice(Tranches{{Price: 1, Amount: 0}}, 0) Check(t, b, 14, 140, 9) // delete at mid - b.updateInsertByPrice(Items{{Price: 10.5, Amount: 0}}, 0) + b.updateInsertByPrice(Tranches{{Price: 10.5, Amount: 0}}, 0) Check(t, b, 12, 119, 8) // delete at head - b.updateInsertByPrice(Items{{Price: 13, Amount: 0}}, 0) + b.updateInsertByPrice(Tranches{{Price: 13, Amount: 0}}, 0) Check(t, b, 10, 93, 7) @@ -233,7 +233,7 @@ func TestUpdateInsertByPrice(t *testing.T) { b.load(nil) // rebuild everything again - b.updateInsertByPrice(Items{ + b.updateInsertByPrice(Tranches{ {Price: 1, Amount: 1}, {Price: 3, Amount: 1}, {Price: 5, Amount: 1}, @@ -248,10 +248,10 @@ func TestUpdateInsertByPrice(t *testing.T) { // 134830672 9.83 ns/op 0 B/op 0 allocs/op (old) // 206689897 5.761 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) { - a := asks{} + a := askTranches{} a.load(ask) - updates := Items{ + updates := Tranches{ { Price: 1337, // Amend Amount: 2, @@ -270,11 +270,11 @@ func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) { // 49763002 24.9 ns/op 0 B/op 0 allocs/op (old) // 25662849 45.32 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) { - a := asks{} + a := askTranches{} a.load(ask) - updates := Items{ + updates := Tranches{ { Price: 1337.5, // Insert Amount: 2, @@ -291,8 +291,8 @@ func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) { } func TestUpdateByID(t *testing.T) { - a := asks{} - asksSnapshot := Items{ + a := askTranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -302,7 +302,7 @@ func TestUpdateByID(t *testing.T) { } a.load(asksSnapshot) - err := a.updateByID(Items{ + err := a.updateByID(Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -316,14 +316,14 @@ func TestUpdateByID(t *testing.T) { Check(t, a, 6, 36, 6) - err = a.updateByID(Items{ + err = a.updateByID(Tranches{ {Price: 11, Amount: 1, ID: 1337}, }) if !errors.Is(err, errIDCannotBeMatched) { t.Fatalf("expecting %s but received %v", errIDCannotBeMatched, err) } - err = a.updateByID(Items{ // Simulate Bitmex updating + err = a.updateByID(Tranches{ // Simulate Bitmex updating {Price: 0, Amount: 1337, ID: 3}, }) if !errors.Is(err, nil) { @@ -346,8 +346,8 @@ func TestUpdateByID(t *testing.T) { // 46043871 25.9 ns/op 0 B/op 0 allocs/op (old) // 63445401 18.51 ns/op 0 B/op 0 allocs/op (new) func BenchmarkUpdateByID(b *testing.B) { - asks := linkedList{} - asksSnapshot := Items{ + asks := Tranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -366,8 +366,8 @@ func BenchmarkUpdateByID(b *testing.B) { } func TestDeleteByID(t *testing.T) { - a := asks{} - asksSnapshot := Items{ + a := askTranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -378,7 +378,7 @@ func TestDeleteByID(t *testing.T) { a.load(asksSnapshot) // Delete at head - err := a.deleteByID(Items{{Price: 1, Amount: 1, ID: 1}}, false) + err := a.deleteByID(Tranches{{Price: 1, Amount: 1, ID: 1}}, false) if err != nil { t.Fatal(err) } @@ -386,7 +386,7 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 5, 35, 5) // Delete at tail - err = a.deleteByID(Items{{Price: 1, Amount: 1, ID: 11}}, false) + err = a.deleteByID(Tranches{{Price: 1, Amount: 1, ID: 11}}, false) if err != nil { t.Fatal(err) } @@ -394,7 +394,7 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 4, 24, 4) // Delete in middle - err = a.deleteByID(Items{{Price: 1, Amount: 1, ID: 5}}, false) + err = a.deleteByID(Tranches{{Price: 1, Amount: 1, ID: 5}}, false) if err != nil { t.Fatal(err) } @@ -402,13 +402,13 @@ func TestDeleteByID(t *testing.T) { Check(t, a, 3, 19, 3) // Intentional error - err = a.deleteByID(Items{{Price: 11, Amount: 1, ID: 1337}}, false) + err = a.deleteByID(Tranches{{Price: 11, Amount: 1, ID: 1337}}, false) if !errors.Is(err, errIDCannotBeMatched) { t.Fatalf("expecting %s but received %v", errIDCannotBeMatched, err) } // Error bypass - err = a.deleteByID(Items{{Price: 11, Amount: 1, ID: 1337}}, true) + err = a.deleteByID(Tranches{{Price: 11, Amount: 1, ID: 1337}}, true) if err != nil { t.Fatal(err) } @@ -416,8 +416,8 @@ func TestDeleteByID(t *testing.T) { // 20476837 53.17 ns/op 0 B/op 0 allocs/op func BenchmarkDeleteByID(b *testing.B) { - asks := linkedList{} - asksSnapshot := Items{ + asks := Tranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -437,8 +437,8 @@ func BenchmarkDeleteByID(b *testing.B) { } func TestUpdateInsertByIDAsk(t *testing.T) { - a := asks{} - asksSnapshot := Items{ + a := askTranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -449,7 +449,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(asksSnapshot) // Update one instance with matching ID - err := a.updateInsertByID(Items{{Price: 1, Amount: 2, ID: 1}}) + err := a.updateInsertByID(Tranches{{Price: 1, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -460,7 +460,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(asksSnapshot) // Update all instances with matching ID in order - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 5, Amount: 2, ID: 5}, @@ -475,7 +475,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 72, 6) // Update all instances with matching ID in backwards - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 11, Amount: 2, ID: 11}, {Price: 9, Amount: 2, ID: 9}, {Price: 7, Amount: 2, ID: 7}, @@ -490,7 +490,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 72, 6) // Update all instances with matching ID all over the ship - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 11, Amount: 2, ID: 11}, {Price: 3, Amount: 2, ID: 3}, {Price: 7, Amount: 2, ID: 7}, @@ -505,7 +505,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 72, 6) // Update all instances move one before ID in middle - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 2, Amount: 2, ID: 5}, @@ -520,7 +520,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 66, 6) // Update all instances move one before ID at head - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: .5, Amount: 2, ID: 5}, @@ -538,7 +538,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(asksSnapshot) // Update all instances move one after ID - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 8, Amount: 2, ID: 5}, @@ -556,7 +556,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(asksSnapshot) // Update all instances move one after ID to tail - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 12, Amount: 2, ID: 5}, @@ -571,7 +571,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 12, 86, 6) // Update all instances then pop new instance - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 12, Amount: 2, ID: 5}, @@ -590,7 +590,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(asksSnapshot) // Update all instances pop at head - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 0.5, Amount: 2, ID: 0}, {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, @@ -606,7 +606,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 87, 7) // bookmark head and move to mid - err = a.updateInsertByID(Items{{Price: 7.5, Amount: 2, ID: 0}}) + err = a.updateInsertByID(Tranches{{Price: 7.5, Amount: 2, ID: 0}}) if err != nil { t.Fatal(err) } @@ -614,7 +614,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 101, 7) // bookmark head and move to tail - err = a.updateInsertByID(Items{{Price: 12.5, Amount: 2, ID: 1}}) + err = a.updateInsertByID(Tranches{{Price: 12.5, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -622,7 +622,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 124, 7) // move tail location to head - err = a.updateInsertByID(Items{{Price: 2.5, Amount: 2, ID: 1}}) + err = a.updateInsertByID(Tranches{{Price: 2.5, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -630,7 +630,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 104, 7) // move tail location to mid - err = a.updateInsertByID(Items{{Price: 8, Amount: 2, ID: 5}}) + err = a.updateInsertByID(Tranches{{Price: 8, Amount: 2, ID: 5}}) if err != nil { t.Fatal(err) } @@ -638,7 +638,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 14, 96, 7) // insert at tail dont match - err = a.updateInsertByID(Items{{Price: 30, Amount: 2, ID: 1234}}) + err = a.updateInsertByID(Tranches{{Price: 30, Amount: 2, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -646,7 +646,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 16, 156, 8) // insert between last and 2nd last - err = a.updateInsertByID(Items{{Price: 12, Amount: 2, ID: 12345}}) + err = a.updateInsertByID(Tranches{{Price: 12, Amount: 2, ID: 12345}}) if err != nil { t.Fatal(err) } @@ -654,7 +654,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 18, 180, 9) // readjust at end - err = a.updateInsertByID(Items{{Price: 29, Amount: 3, ID: 1234}}) + err = a.updateInsertByID(Tranches{{Price: 29, Amount: 3, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -662,7 +662,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { Check(t, a, 19, 207, 9) // readjust further and decrease price past tail - err = a.updateInsertByID(Items{{Price: 31, Amount: 3, ID: 1234}}) + err = a.updateInsertByID(Tranches{{Price: 31, Amount: 3, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -673,7 +673,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) { a.load(nil) // insert with no liquidity and jumbled - err = a.updateInsertByID(Items{ + err = a.updateInsertByID(Tranches{ {Price: 11, Amount: 2, ID: 11}, {Price: 9, Amount: 2, ID: 9}, {Price: 7, Amount: 2, ID: 7}, @@ -691,8 +691,8 @@ func TestUpdateInsertByIDAsk(t *testing.T) { // 21614455 81.74 ns/op 0 B/op 0 allocs/op func BenchmarkUpdateInsertByID_asks(b *testing.B) { - asks := linkedList{} - asksSnapshot := Items{ + asks := Tranches{} + asksSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -711,8 +711,8 @@ func BenchmarkUpdateInsertByID_asks(b *testing.B) { } func TestUpdateInsertByIDBids(t *testing.T) { - b := bids{} - bidsSnapshot := Items{ + b := bidTranches{} + bidsSnapshot := Tranches{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, {Price: 7, Amount: 1, ID: 7}, @@ -723,7 +723,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(bidsSnapshot) // Update one instance with matching ID - err := b.updateInsertByID(Items{{Price: 1, Amount: 2, ID: 1}}) + err := b.updateInsertByID(Tranches{{Price: 1, Amount: 2, ID: 1}}) if err != nil { t.Fatal(err) } @@ -734,7 +734,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(bidsSnapshot) // Update all instances with matching ID in order - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 5, Amount: 2, ID: 5}, @@ -749,7 +749,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 72, 6) // Update all instances with matching ID in backwards - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 11, Amount: 2, ID: 11}, {Price: 9, Amount: 2, ID: 9}, {Price: 7, Amount: 2, ID: 7}, @@ -764,7 +764,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 72, 6) // Update all instances with matching ID all over the ship - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 11, Amount: 2, ID: 11}, {Price: 3, Amount: 2, ID: 3}, {Price: 7, Amount: 2, ID: 7}, @@ -779,7 +779,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 72, 6) // Update all instances move one before ID in middle - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 2, Amount: 2, ID: 5}, @@ -794,7 +794,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 66, 6) // Update all instances move one before ID at head - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: .5, Amount: 2, ID: 5}, @@ -812,7 +812,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(bidsSnapshot) // Update all instances move one after ID - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 8, Amount: 2, ID: 5}, @@ -830,7 +830,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(bidsSnapshot) // Update all instances move one after ID to tail - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 12, Amount: 2, ID: 5}, @@ -845,7 +845,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 12, 86, 6) // Update all instances then pop new instance - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, {Price: 12, Amount: 2, ID: 5}, @@ -864,7 +864,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(bidsSnapshot) // Update all instances pop at tail - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 0.5, Amount: 2, ID: 0}, {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, @@ -880,7 +880,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 87, 7) // bookmark head and move to mid - err = b.updateInsertByID(Items{{Price: 9.5, Amount: 2, ID: 5}}) + err = b.updateInsertByID(Tranches{{Price: 9.5, Amount: 2, ID: 5}}) if err != nil { t.Fatal(err) } @@ -888,7 +888,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 82, 7) // bookmark head and move to tail - err = b.updateInsertByID(Items{{Price: 0.25, Amount: 2, ID: 11}}) + err = b.updateInsertByID(Tranches{{Price: 0.25, Amount: 2, ID: 11}}) if err != nil { t.Fatal(err) } @@ -896,7 +896,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 60.5, 7) // move tail location to head - err = b.updateInsertByID(Items{{Price: 10, Amount: 2, ID: 11}}) + err = b.updateInsertByID(Tranches{{Price: 10, Amount: 2, ID: 11}}) if err != nil { t.Fatal(err) } @@ -904,7 +904,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 80, 7) // move tail location to mid - err = b.updateInsertByID(Items{{Price: 7.5, Amount: 2, ID: 0}}) + err = b.updateInsertByID(Tranches{{Price: 7.5, Amount: 2, ID: 0}}) if err != nil { t.Fatal(err) } @@ -912,7 +912,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 14, 94, 7) // insert at head dont match - err = b.updateInsertByID(Items{{Price: 30, Amount: 2, ID: 1234}}) + err = b.updateInsertByID(Tranches{{Price: 30, Amount: 2, ID: 1234}}) if err != nil { t.Fatal(err) } @@ -920,21 +920,21 @@ func TestUpdateInsertByIDBids(t *testing.T) { Check(t, b, 16, 154, 8) // insert between last and 2nd last - err = b.updateInsertByID(Items{{Price: 1.5, Amount: 2, ID: 12345}}) + err = b.updateInsertByID(Tranches{{Price: 1.5, Amount: 2, ID: 12345}}) if err != nil { t.Fatal(err) } Check(t, b, 18, 157, 9) // readjust at end - err = b.updateInsertByID(Items{{Price: 1, Amount: 3, ID: 1}}) + err = b.updateInsertByID(Tranches{{Price: 1, Amount: 3, ID: 1}}) if err != nil { t.Fatal(err) } Check(t, b, 19, 158, 9) // readjust further and decrease price past tail - err = b.updateInsertByID(Items{{Price: .9, Amount: 3, ID: 1}}) + err = b.updateInsertByID(Tranches{{Price: .9, Amount: 3, ID: 1}}) if err != nil { t.Fatal(err) } @@ -944,7 +944,7 @@ func TestUpdateInsertByIDBids(t *testing.T) { b.load(nil) // insert with no liquidity and jumbled - err = b.updateInsertByID(Items{ + err = b.updateInsertByID(Tranches{ {Price: 0.5, Amount: 2, ID: 0}, {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, @@ -962,8 +962,8 @@ func TestUpdateInsertByIDBids(t *testing.T) { // 20328886 59.94 ns/op 0 B/op 0 allocs/op func BenchmarkUpdateInsertByID_bids(b *testing.B) { - bids := linkedList{} - bidsSnapshot := Items{ + bids := Tranches{} + bidsSnapshot := Tranches{ {Price: 0.5, Amount: 2, ID: 0}, {Price: 1, Amount: 2, ID: 1}, {Price: 3, Amount: 2, ID: 3}, @@ -983,8 +983,8 @@ func BenchmarkUpdateInsertByID_bids(b *testing.B) { } func TestInsertUpdatesBid(t *testing.T) { - b := bids{} - bidsSnapshot := Items{ + b := bidTranches{} + bidsSnapshot := Tranches{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, {Price: 7, Amount: 1, ID: 7}, @@ -994,7 +994,7 @@ func TestInsertUpdatesBid(t *testing.T) { } b.load(bidsSnapshot) - err := b.insertUpdates(Items{ + err := b.insertUpdates(Tranches{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, {Price: 7, Amount: 1, ID: 7}, @@ -1009,7 +1009,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 6, 36, 6) // Insert at head - err = b.insertUpdates(Items{{Price: 12, Amount: 1, ID: 11}}) + err = b.insertUpdates(Tranches{{Price: 12, Amount: 1, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1017,7 +1017,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 7, 48, 7) // Insert at tail - err = b.insertUpdates(Items{{Price: 0.5, Amount: 1, ID: 12}}) + err = b.insertUpdates(Tranches{{Price: 0.5, Amount: 1, ID: 12}}) if err != nil { t.Fatal(err) } @@ -1025,7 +1025,7 @@ func TestInsertUpdatesBid(t *testing.T) { Check(t, b, 8, 48.5, 8) // Insert at mid - err = b.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) + err = b.insertUpdates(Tranches{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1036,7 +1036,7 @@ func TestInsertUpdatesBid(t *testing.T) { b.load(nil) // Add one at head - err = b.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) + err = b.insertUpdates(Tranches{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1045,8 +1045,8 @@ func TestInsertUpdatesBid(t *testing.T) { } func TestInsertUpdatesAsk(t *testing.T) { - a := asks{} - askSnapshot := Items{ + a := askTranches{} + askSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -1056,7 +1056,7 @@ func TestInsertUpdatesAsk(t *testing.T) { } a.load(askSnapshot) - err := a.insertUpdates(Items{ + err := a.insertUpdates(Tranches{ {Price: 11, Amount: 1, ID: 11}, {Price: 9, Amount: 1, ID: 9}, {Price: 7, Amount: 1, ID: 7}, @@ -1071,7 +1071,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 6, 36, 6) // Insert at tail - err = a.insertUpdates(Items{{Price: 12, Amount: 1, ID: 11}}) + err = a.insertUpdates(Tranches{{Price: 12, Amount: 1, ID: 11}}) if err != nil { t.Fatal(err) } @@ -1079,7 +1079,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 7, 48, 7) // Insert at head - err = a.insertUpdates(Items{{Price: 0.5, Amount: 1, ID: 12}}) + err = a.insertUpdates(Tranches{{Price: 0.5, Amount: 1, ID: 12}}) if err != nil { t.Fatal(err) } @@ -1087,7 +1087,7 @@ func TestInsertUpdatesAsk(t *testing.T) { Check(t, a, 8, 48.5, 8) // Insert at mid - err = a.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) + err = a.insertUpdates(Tranches{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1098,7 +1098,7 @@ func TestInsertUpdatesAsk(t *testing.T) { a.load(nil) // Add one at head - err = a.insertUpdates(Items{{Price: 5.5, Amount: 1, ID: 13}}) + err = a.insertUpdates(Tranches{{Price: 5.5, Amount: 1, ID: 13}}) if err != nil { t.Fatal(err) } @@ -1109,65 +1109,65 @@ func TestInsertUpdatesAsk(t *testing.T) { // check checks depth values after an update has taken place func Check(t *testing.T, depth interface{}, liquidity, value float64, expectedLen int) { t.Helper() - b, isBid := depth.(bids) - a, isAsk := depth.(asks) + b, isBid := depth.(bidTranches) + a, isAsk := depth.(askTranches) - var ll linkedList + var ts Tranches switch { case isBid: - ll = b.linkedList + ts = b.Tranches case isAsk: - ll = a.linkedList + ts = a.Tranches default: t.Fatal("value passed in is not of type bids or asks") } - liquidityTotal, valueTotal := ll.amount() + liquidityTotal, valueTotal := ts.amount() if liquidityTotal != liquidity { - ll.display() + ts.display() t.Fatalf("mismatched liquidity expecting %v but received %v", liquidity, liquidityTotal) } if valueTotal != value { - ll.display() + ts.display() t.Fatalf("mismatched total value expecting %v but received %v", value, valueTotal) } - if len(ll) != expectedLen { - ll.display() + if len(ts) != expectedLen { + ts.display() t.Fatalf("mismatched expected length count expecting %v but received %v", expectedLen, - len(ll)) + len(ts)) } - if len(ll) == 0 { + if len(ts) == 0 { return } var price float64 - for x := range ll { + for x := range ts { switch { case price == 0: - price = ll[x].Price - case isBid && price < ll[x].Price: - ll.display() + price = ts[x].Price + case isBid && price < ts[x].Price: + ts.display() t.Fatal("Bid pricing out of order should be descending") - case isAsk && price > ll[x].Price: - ll.display() + case isAsk && price > ts[x].Price: + ts.display() t.Fatal("Ask pricing out of order should be ascending") default: - price = ll[x].Price + price = ts[x].Price } } } func TestAmount(t *testing.T) { - a := asks{} - askSnapshot := Items{ + a := askTranches{} + askSnapshot := Tranches{ {Price: 1, Amount: 1, ID: 1}, {Price: 3, Amount: 1, ID: 3}, {Price: 5, Amount: 1, ID: 5}, @@ -1193,7 +1193,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { Name string BaseAmount float64 ReferencePrice float64 - BidLiquidity Items + BidLiquidity Tranches ExpectedNominal float64 ExpectedImpact float64 ExpectedCost float64 @@ -1216,7 +1216,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { }, { Name: "thrasher test", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, BaseAmount: 10, ReferencePrice: 10000, ExpectedNominal: 0.8999999999999999, @@ -1225,7 +1225,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { }, { Name: "consume first tranche", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, BaseAmount: 2, ReferencePrice: 10000, ExpectedNominal: 0, @@ -1234,7 +1234,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { }, { Name: "consume most of first tranche", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, BaseAmount: 1.5, ReferencePrice: 10000, ExpectedNominal: 0, @@ -1243,7 +1243,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { }, { Name: "consume full liquidity", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, BaseAmount: 12, ReferencePrice: 10000, ExpectedNominal: 1.0833333333333395, @@ -1261,7 +1261,7 @@ func TestGetMovementByBaseAmount(t *testing.T) { if err != nil { t.Fatal(err) } - movement, err := depth.bids.getMovementByBase(tt.BaseAmount, tt.ReferencePrice, false) + movement, err := depth.bidTranches.getMovementByBase(tt.BaseAmount, tt.ReferencePrice, false) if !errors.Is(err, tt.ExpectedError) { t.Fatalf("received: '%v' but expected: '%v'", err, tt.ExpectedError) } @@ -1304,7 +1304,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { Name string NominalSlippage float64 ReferencePrice float64 - BidLiquidity Items + BidLiquidity Tranches ExpectedShift *Movement ExpectedError error }{ @@ -1331,7 +1331,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { }, { Name: "thrasher test", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, NominalSlippage: 1, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1345,7 +1345,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { }, { Name: "consume first tranche - take one amount out of second", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, NominalSlippage: 0.33333333333334, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1359,7 +1359,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { }, { Name: "consume full liquidity", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, NominalSlippage: 10, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1374,7 +1374,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { }, { Name: "scotts lovely slippery slippage requirements", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, NominalSlippage: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000001, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1395,7 +1395,7 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) { err := depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Now(), true) assert.NoError(t, err, "LoadSnapshot should not error") - base, err := depth.bids.hitBidsByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice) + base, err := depth.bidTranches.hitBidsByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice) if tt.ExpectedError != nil { assert.ErrorIs(t, err, tt.ExpectedError, "Should error correctly") } else { @@ -1426,7 +1426,7 @@ func TestGetBaseAmountFromImpact(t *testing.T) { Name string ImpactSlippage float64 ReferencePrice float64 - BidLiquidity Items + BidLiquidity Tranches ExpectedShift *Movement ExpectedError error }{ @@ -1452,7 +1452,7 @@ func TestGetBaseAmountFromImpact(t *testing.T) { }, { Name: "thrasher test", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, ImpactSlippage: 1, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1466,7 +1466,7 @@ func TestGetBaseAmountFromImpact(t *testing.T) { }, { Name: "consume first tranche and second tranche", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, ImpactSlippage: 2, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1480,7 +1480,7 @@ func TestGetBaseAmountFromImpact(t *testing.T) { }, { Name: "consume full liquidity", - BidLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, + BidLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 9900, Amount: 7}, {Price: 9800, Amount: 3}}, ImpactSlippage: 10, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1504,7 +1504,7 @@ func TestGetBaseAmountFromImpact(t *testing.T) { if err != nil { t.Fatal(err) } - base, err := depth.bids.hitBidsByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice) + base, err := depth.bidTranches.hitBidsByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice) if !errors.Is(err, tt.ExpectedError) { t.Fatalf("%s received: '%v' but expected: '%v'", tt.Name, err, tt.ExpectedError) } @@ -1522,7 +1522,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { Name string QuoteAmount float64 ReferencePrice float64 - AskLiquidity Items + AskLiquidity Tranches ExpectedNominal float64 ExpectedImpact float64 ExpectedCost float64 @@ -1545,7 +1545,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { }, { Name: "thrasher test", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, QuoteAmount: 100900, ReferencePrice: 10000, ExpectedNominal: 0.8999999999999999, @@ -1554,7 +1554,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { }, { Name: "consume first tranche", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, QuoteAmount: 20000, ReferencePrice: 10000, ExpectedNominal: 0, @@ -1563,7 +1563,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { }, { Name: "consume most of first tranche", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, QuoteAmount: 15000, ReferencePrice: 10000, ExpectedNominal: 0, @@ -1572,7 +1572,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { }, { Name: "consume full liquidity", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, QuoteAmount: 121300, ReferencePrice: 10000, ExpectedNominal: 1.0833333333333395, @@ -1590,7 +1590,7 @@ func TestGetMovementByQuoteAmount(t *testing.T) { if err != nil { t.Fatal(err) } - movement, err := depth.asks.getMovementByQuotation(tt.QuoteAmount, tt.ReferencePrice, false) + movement, err := depth.askTranches.getMovementByQuotation(tt.QuoteAmount, tt.ReferencePrice, false) if !errors.Is(err, tt.ExpectedError) { t.Fatalf("received: '%v' but expected: '%v'", err, tt.ExpectedError) } @@ -1622,7 +1622,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { Name string NominalSlippage float64 ReferencePrice float64 - AskLiquidity Items + AskLiquidity Tranches ExpectedShift *Movement ExpectedError error }{ @@ -1644,7 +1644,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { }, { Name: "consume first tranche - one amount on second tranche", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, NominalSlippage: 0.33333333333334, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1658,7 +1658,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { }, { Name: "last tranche total agg meeting 1 percent nominally", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, NominalSlippage: 1, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1672,7 +1672,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { }, { Name: "take full second tranche", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, NominalSlippage: 0.7777777777777738, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1686,7 +1686,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { }, { Name: "consume full liquidity", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, NominalSlippage: 10, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1701,7 +1701,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { }, { Name: "scotts lovely slippery slippage requirements", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, NominalSlippage: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000001, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1722,7 +1722,7 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) { err := depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Now(), true) assert.NoError(t, err, "LoadSnapshot should not error") - quote, err := depth.asks.liftAsksByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice) + quote, err := depth.askTranches.liftAsksByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice) if tt.ExpectedError != nil { assert.ErrorIs(t, err, tt.ExpectedError, "Should error correctly") } else { @@ -1738,7 +1738,7 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { Name string ImpactSlippage float64 ReferencePrice float64 - AskLiquidity Items + AskLiquidity Tranches ExpectedShift *Movement ExpectedError error }{ @@ -1760,7 +1760,7 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { }, { Name: "thrasher test", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, ImpactSlippage: 1, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1774,7 +1774,7 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { }, { Name: "consume first tranche and second tranche", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, ImpactSlippage: 2, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1788,7 +1788,7 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { }, { Name: "consume full liquidity", - AskLiquidity: Items{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, + AskLiquidity: Tranches{{Price: 10000, Amount: 2}, {Price: 10100, Amount: 7}, {Price: 10200, Amount: 3}}, ImpactSlippage: 10, ReferencePrice: 10000, ExpectedShift: &Movement{ @@ -1811,7 +1811,7 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { err := depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Now(), true) assert.NoError(t, err, "LoadSnapshot should not error") - quote, err := depth.asks.liftAsksByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice) + quote, err := depth.askTranches.liftAsksByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice) if tt.ExpectedError != nil { assert.ErrorIs(t, err, tt.ExpectedError, "Should error correctly") } else { @@ -1824,10 +1824,10 @@ func TestGetQuoteAmountFromImpact(t *testing.T) { func TestGetHeadPrice(t *testing.T) { t.Parallel() depth := NewDepth(id) - if _, err := depth.bids.getHeadPriceNoLock(); !errors.Is(err, errNoLiquidity) { + if _, err := depth.bidTranches.getHeadPriceNoLock(); !errors.Is(err, errNoLiquidity) { t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) } - if _, err := depth.asks.getHeadPriceNoLock(); !errors.Is(err, errNoLiquidity) { + if _, err := depth.askTranches.getHeadPriceNoLock(); !errors.Is(err, errNoLiquidity) { t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity) } err := depth.LoadSnapshot(bid, ask, 0, time.Now(), true) @@ -1835,7 +1835,7 @@ func TestGetHeadPrice(t *testing.T) { t.Fatalf("failed to load snapshot: %s", err) } - val, err := depth.bids.getHeadPriceNoLock() + val, err := depth.bidTranches.getHeadPriceNoLock() if !errors.Is(err, nil) { t.Fatalf("received: '%v' but expected: '%v'", err, nil) } @@ -1844,7 +1844,7 @@ func TestGetHeadPrice(t *testing.T) { t.Fatal("unexpected value") } - val, err = depth.asks.getHeadPriceNoLock() + val, err = depth.askTranches.getHeadPriceNoLock() if !errors.Is(err, nil) { t.Fatalf("received: '%v' but expected: '%v'", err, nil) } From 704f88f6edf7ace14e3ce11077f019bae8b24071 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 10:56:56 +1100 Subject: [PATCH 03/13] roll out acrost exchanges --- cmd/exchange_template/wrapper_file.tmpl | 8 +- engine/helpers_test.go | 2 +- engine/rpcserver_test.go | 12 +-- exchanges/alphapoint/alphapoint_wrapper.go | 8 +- exchanges/binance/binance_websocket.go | 16 ++-- exchanges/binance/binance_wrapper.go | 8 +- exchanges/binanceus/binanceus_websocket.go | 16 ++-- exchanges/binanceus/binanceus_wrapper.go | 8 +- exchanges/bitfinex/bitfinex_test.go | 8 +- exchanges/bitfinex/bitfinex_websocket.go | 18 ++--- exchanges/bitfinex/bitfinex_wrapper.go | 16 ++-- exchanges/bitflyer/bitflyer_wrapper.go | 8 +- exchanges/bithumb/bithumb_wrapper.go | 8 +- exchanges/bithumb/bithumb_ws_orderbook.go | 14 ++-- exchanges/bitmex/bitmex_websocket.go | 12 +-- exchanges/bitmex/bitmex_wrapper.go | 8 +- exchanges/bitstamp/bitstamp_test.go | 4 +- exchanges/bitstamp/bitstamp_websocket.go | 16 ++-- exchanges/bitstamp/bitstamp_wrapper.go | 8 +- exchanges/btcmarkets/btcmarkets_test.go | 4 +- exchanges/btcmarkets/btcmarkets_types.go | 2 +- exchanges/btcmarkets/btcmarkets_websocket.go | 14 ++-- exchanges/btcmarkets/btcmarkets_wrapper.go | 8 +- exchanges/btse/btse_websocket.go | 8 +- exchanges/btse/btse_wrapper.go | 8 +- exchanges/bybit/bybit.go | 4 +- exchanges/bybit/bybit_types.go | 4 +- exchanges/bybit/bybit_websocket.go | 4 +- exchanges/bybit/bybit_wrapper.go | 8 +- .../coinbasepro/coinbasepro_websocket.go | 16 ++-- exchanges/coinbasepro/coinbasepro_wrapper.go | 8 +- exchanges/coinut/coinut_websocket.go | 12 +-- exchanges/coinut/coinut_wrapper.go | 8 +- exchanges/exmo/exmo_wrapper.go | 8 +- exchanges/gateio/gateio_websocket.go | 12 +-- exchanges/gateio/gateio_wrapper.go | 8 +- exchanges/gateio/gateio_ws_futures.go | 16 ++-- exchanges/gateio/gateio_ws_option.go | 12 +-- exchanges/gemini/gemini_websocket.go | 6 +- exchanges/gemini/gemini_wrapper.go | 8 +- exchanges/hitbtc/hitbtc_websocket.go | 16 ++-- exchanges/hitbtc/hitbtc_wrapper.go | 8 +- exchanges/huobi/huobi_websocket.go | 8 +- exchanges/huobi/huobi_wrapper.go | 24 +++--- exchanges/itbit/itbit_wrapper.go | 8 +- exchanges/kraken/kraken_test.go | 4 +- exchanges/kraken/kraken_websocket.go | 16 ++-- exchanges/kraken/kraken_wrapper.go | 16 ++-- exchanges/kucoin/kucoin.go | 6 +- exchanges/kucoin/kucoin_futures.go | 6 +- exchanges/kucoin/kucoin_types.go | 16 ++-- exchanges/kucoin/kucoin_websocket.go | 16 ++-- exchanges/lbank/lbank_wrapper.go | 8 +- exchanges/okcoin/okcoin_websocket.go | 10 +-- exchanges/okcoin/okcoin_wrapper.go | 4 +- exchanges/okx/okx_websocket.go | 10 +-- exchanges/okx/okx_wrapper.go | 8 +- exchanges/poloniex/poloniex_websocket.go | 12 +-- exchanges/poloniex/poloniex_wrapper.go | 8 +- exchanges/stream/buffer/buffer.go | 4 +- exchanges/stream/buffer/buffer_test.go | 74 +++++++++---------- exchanges/yobit/yobit_wrapper.go | 4 +- gctscript/wrappers/validator/validator.go | 4 +- 63 files changed, 333 insertions(+), 333 deletions(-) diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl index d57f96b5451..dc575071e0b 100644 --- a/cmd/exchange_template/wrapper_file.tmpl +++ b/cmd/exchange_template/wrapper_file.tmpl @@ -300,17 +300,17 @@ func ({{.Variable}} *{{.CapitalName}}) UpdateOrderbook(ctx context.Context, pair return book, err } - book.Bids = make([]orderbook.Item, len(orderbookNew.Bids)) + book.Bids = make([]orderbook.Tranche, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Quantity, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make([]orderbook.Item, len(orderbookNew.Asks)) + book.Asks = make([]orderbook.Tranche, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderBookNew.Asks[x].Quantity, Price: orderBookNew.Asks[x].Price, } diff --git a/engine/helpers_test.go b/engine/helpers_test.go index 7ea96fbf353..1a6d37b71b5 100644 --- a/engine/helpers_test.go +++ b/engine/helpers_test.go @@ -759,7 +759,7 @@ func TestGetSpecificOrderbook(t *testing.T) { base := orderbook.Base{ Pair: currency.NewPair(currency.BTC, currency.USD), - Bids: []orderbook.Item{{Price: 1000, Amount: 1}}, + Bids: []orderbook.Tranche{{Price: 1000, Amount: 1}}, Exchange: "Bitstamp", Asset: asset.Spot, } diff --git a/engine/rpcserver_test.go b/engine/rpcserver_test.go index c1f1a08b605..b3f0c70e498 100644 --- a/engine/rpcserver_test.go +++ b/engine/rpcserver_test.go @@ -3461,13 +3461,13 @@ func TestGetOrderbookMovement(t *testing.T) { t.Fatal(err) } - bid := []orderbook.Item{ + bid := []orderbook.Tranche{ {Price: 10, Amount: 1}, {Price: 9, Amount: 1}, {Price: 8, Amount: 1}, {Price: 7, Amount: 1}, } - ask := []orderbook.Item{ + ask := []orderbook.Tranche{ {Price: 11, Amount: 1}, {Price: 12, Amount: 1}, {Price: 13, Amount: 1}, @@ -3574,13 +3574,13 @@ func TestGetOrderbookAmountByNominal(t *testing.T) { t.Fatal(err) } - bid := []orderbook.Item{ + bid := []orderbook.Tranche{ {Price: 10, Amount: 1}, {Price: 9, Amount: 1}, {Price: 8, Amount: 1}, {Price: 7, Amount: 1}, } - ask := []orderbook.Item{ + ask := []orderbook.Tranche{ {Price: 11, Amount: 1}, {Price: 12, Amount: 1}, {Price: 13, Amount: 1}, @@ -3680,13 +3680,13 @@ func TestGetOrderbookAmountByImpact(t *testing.T) { t.Fatal(err) } - bid := []orderbook.Item{ + bid := []orderbook.Tranche{ {Price: 10, Amount: 1}, {Price: 9, Amount: 1}, {Price: 8, Amount: 1}, {Price: 7, Amount: 1}, } - ask := []orderbook.Item{ + ask := []orderbook.Tranche{ {Price: 11, Amount: 1}, {Price: 12, Amount: 1}, {Price: 13, Amount: 1}, diff --git a/exchanges/alphapoint/alphapoint_wrapper.go b/exchanges/alphapoint/alphapoint_wrapper.go index 36c212de598..4cbbd161e58 100644 --- a/exchanges/alphapoint/alphapoint_wrapper.go +++ b/exchanges/alphapoint/alphapoint_wrapper.go @@ -222,17 +222,17 @@ func (a *Alphapoint) UpdateOrderbook(ctx context.Context, p currency.Pair, asset return orderBook, err } - orderBook.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + orderBook.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - orderBook.Bids[x] = orderbook.Item{ + orderBook.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Quantity, Price: orderbookNew.Bids[x].Price, } } - orderBook.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + orderBook.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - orderBook.Asks[x] = orderbook.Item{ + orderBook.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Quantity, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/binance/binance_websocket.go b/exchanges/binance/binance_websocket.go index bffe11b0089..03623928d6f 100644 --- a/exchanges/binance/binance_websocket.go +++ b/exchanges/binance/binance_websocket.go @@ -493,18 +493,18 @@ func (b *Binance) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *OrderBoo Exchange: b.Name, LastUpdateID: orderbookNew.LastUpdateID, VerifyOrderbook: b.CanVerifyOrderbook, - Bids: make(orderbook.Items, len(orderbookNew.Bids)), - Asks: make(orderbook.Items, len(orderbookNew.Asks)), + Bids: make(orderbook.Tranches, len(orderbookNew.Bids)), + Asks: make(orderbook.Tranches, len(orderbookNew.Asks)), LastUpdated: time.Now(), // Time not provided in REST book. } for i := range orderbookNew.Bids { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Amount: orderbookNew.Bids[i].Quantity, Price: orderbookNew.Bids[i].Price, } } for i := range orderbookNew.Asks { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Amount: orderbookNew.Asks[i].Quantity, Price: orderbookNew.Asks[i].Price, } @@ -652,7 +652,7 @@ func (b *Binance) Unsubscribe(channelsToUnsubscribe []subscription.Subscription) // ProcessUpdate processes the websocket orderbook update func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error { - updateBid := make([]orderbook.Item, len(ws.UpdateBids)) + updateBid := make([]orderbook.Tranche, len(ws.UpdateBids)) for i := range ws.UpdateBids { price, ok := ws.UpdateBids[i][0].(string) if !ok { @@ -670,10 +670,10 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep if err != nil { return err } - updateBid[i] = orderbook.Item{Price: p, Amount: a} + updateBid[i] = orderbook.Tranche{Price: p, Amount: a} } - updateAsk := make([]orderbook.Item, len(ws.UpdateAsks)) + updateAsk := make([]orderbook.Tranche, len(ws.UpdateAsks)) for i := range ws.UpdateAsks { price, ok := ws.UpdateAsks[i][0].(string) if !ok { @@ -691,7 +691,7 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep if err != nil { return err } - updateAsk[i] = orderbook.Item{Price: p, Amount: a} + updateAsk[i] = orderbook.Tranche{Price: p, Amount: a} } return b.Websocket.Orderbook.Update(&orderbook.Update{ diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index d981fa4b2f3..afa0fe48ff0 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -615,16 +615,16 @@ func (b *Binance) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Quantity, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Quantity, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/binanceus/binanceus_websocket.go b/exchanges/binanceus/binanceus_websocket.go index 8f4d5c3cd6e..59803e1144d 100644 --- a/exchanges/binanceus/binanceus_websocket.go +++ b/exchanges/binanceus/binanceus_websocket.go @@ -672,7 +672,7 @@ func (bi *Binanceus) SynchroniseWebsocketOrderbook() { // ProcessUpdate processes the websocket orderbook update func (bi *Binanceus) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error { - updateBid := make([]orderbook.Item, len(ws.UpdateBids)) + updateBid := make([]orderbook.Tranche, len(ws.UpdateBids)) for i := range ws.UpdateBids { price := ws.UpdateBids[i][0] p, err := strconv.ParseFloat(price, 64) @@ -684,10 +684,10 @@ func (bi *Binanceus) ProcessUpdate(cp currency.Pair, a asset.Item, ws *Websocket if err != nil { return err } - updateBid[i] = orderbook.Item{Price: p, Amount: a} + updateBid[i] = orderbook.Tranche{Price: p, Amount: a} } - updateAsk := make([]orderbook.Item, len(ws.UpdateAsks)) + updateAsk := make([]orderbook.Tranche, len(ws.UpdateAsks)) for i := range ws.UpdateAsks { price := ws.UpdateAsks[i][0] p, err := strconv.ParseFloat(price, 64) @@ -699,7 +699,7 @@ func (bi *Binanceus) ProcessUpdate(cp currency.Pair, a asset.Item, ws *Websocket if err != nil { return err } - updateAsk[i] = orderbook.Item{Price: p, Amount: a} + updateAsk[i] = orderbook.Tranche{Price: p, Amount: a} } return bi.Websocket.Orderbook.Update(&orderbook.Update{ @@ -844,18 +844,18 @@ func (bi *Binanceus) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *Order Exchange: bi.Name, LastUpdateID: orderbookNew.LastUpdateID, VerifyOrderbook: bi.CanVerifyOrderbook, - Bids: make(orderbook.Items, len(orderbookNew.Bids)), - Asks: make(orderbook.Items, len(orderbookNew.Asks)), + Bids: make(orderbook.Tranches, len(orderbookNew.Bids)), + Asks: make(orderbook.Tranches, len(orderbookNew.Asks)), LastUpdated: time.Now(), // Time not provided in REST book. } for i := range orderbookNew.Bids { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Amount: orderbookNew.Bids[i].Quantity, Price: orderbookNew.Bids[i].Price, } } for i := range orderbookNew.Asks { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Amount: orderbookNew.Asks[i].Quantity, Price: orderbookNew.Asks[i].Price, } diff --git a/exchanges/binanceus/binanceus_wrapper.go b/exchanges/binanceus/binanceus_wrapper.go index c11ad1ad4f4..54461b51cb3 100644 --- a/exchanges/binanceus/binanceus_wrapper.go +++ b/exchanges/binanceus/binanceus_wrapper.go @@ -379,16 +379,16 @@ func (bi *Binanceus) UpdateOrderbook(ctx context.Context, pair currency.Pair, as if err != nil { return book, err } - book.Bids = make([]orderbook.Item, len(orderbookNew.Bids)) + book.Bids = make([]orderbook.Tranche, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Quantity, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make([]orderbook.Item, len(orderbookNew.Asks)) + book.Asks = make([]orderbook.Tranche, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Quantity, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index c2bba90d00b..c8f324312bc 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -1759,7 +1759,7 @@ func TestGetHistoricTrades(t *testing.T) { } var testOb = orderbook.Base{ - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ {Price: 0.05005, Amount: 0.00000500}, {Price: 0.05010, Amount: 0.00000500}, {Price: 0.05015, Amount: 0.00000500}, @@ -1771,7 +1771,7 @@ var testOb = orderbook.Base{ {Price: 0.05045, Amount: 0.00000500}, {Price: 0.05050, Amount: 0.00000500}, }, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ {Price: 0.05000, Amount: 0.00000500}, {Price: 0.04995, Amount: 0.00000500}, {Price: 0.04990, Amount: 0.00000500}, @@ -1793,7 +1793,7 @@ func TestChecksum(t *testing.T) { } func TestReOrderbyID(t *testing.T) { - asks := []orderbook.Item{ + asks := []orderbook.Tranche{ {ID: 4, Price: 100, Amount: 0.00000500}, {ID: 3, Price: 100, Amount: 0.00000500}, {ID: 2, Price: 100, Amount: 0.00000500}, @@ -1813,7 +1813,7 @@ func TestReOrderbyID(t *testing.T) { } } - bids := []orderbook.Item{ + bids := []orderbook.Tranche{ {ID: 4, Price: 100, Amount: 0.00000500}, {ID: 3, Price: 100, Amount: 0.00000500}, {ID: 2, Price: 100, Amount: 0.00000500}, diff --git a/exchanges/bitfinex/bitfinex_websocket.go b/exchanges/bitfinex/bitfinex_websocket.go index e1010eb1061..a2a3ecfa1b5 100644 --- a/exchanges/bitfinex/bitfinex_websocket.go +++ b/exchanges/bitfinex/bitfinex_websocket.go @@ -1471,10 +1471,10 @@ func (b *Bitfinex) WsInsertSnapshot(p currency.Pair, assetType asset.Item, books return errors.New("no orderbooks submitted") } var book orderbook.Base - book.Bids = make(orderbook.Items, 0, len(books)) - book.Asks = make(orderbook.Items, 0, len(books)) + book.Bids = make(orderbook.Tranches, 0, len(books)) + book.Asks = make(orderbook.Tranches, 0, len(books)) for i := range books { - item := orderbook.Item{ + item := orderbook.Tranche{ ID: books[i].ID, Amount: books[i].Amount, Price: books[i].Price, @@ -1513,13 +1513,13 @@ func (b *Bitfinex) WsUpdateOrderbook(c *subscription.Subscription, p currency.Pa orderbookUpdate := orderbook.Update{ Asset: assetType, Pair: p, - Bids: make([]orderbook.Item, 0, len(book)), - Asks: make([]orderbook.Item, 0, len(book)), + Bids: make([]orderbook.Tranche, 0, len(book)), + Asks: make([]orderbook.Tranche, 0, len(book)), UpdateTime: time.Now(), // Not included in update } for i := range book { - item := orderbook.Item{ + item := orderbook.Tranche{ ID: book[i].ID, Amount: book[i].Amount, Price: book[i].Price, @@ -2088,7 +2088,7 @@ func validateCRC32(book *orderbook.Base, token int) error { reOrderByID(book.Asks) // RO precision calculation is based on order ID's and amount values - var bids, asks []orderbook.Item + var bids, asks []orderbook.Tranche for i := 0; i < 25; i++ { if i < len(book.Bids) { bids = append(bids, book.Bids[i]) @@ -2142,10 +2142,10 @@ func validateCRC32(book *orderbook.Base, token int) error { // reOrderByID sub sorts orderbook items by its corresponding ID when price // levels are the same. TODO: Deprecate and shift to buffer level insertion // based off ascending ID. -func reOrderByID(depth []orderbook.Item) { +func reOrderByID(depth []orderbook.Tranche) { subSort: for x := 0; x < len(depth); { - var subset []orderbook.Item + var subset []orderbook.Tranche // Traverse forward elements for y := x + 1; y < len(depth); y++ { if depth[x].Price == depth[y].Price && diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index de10d725518..0c31924ac5f 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -426,18 +426,18 @@ func (b *Bitfinex) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy } if assetType == asset.MarginFunding { o.IsFundingRate = true - o.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + o.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - o.Asks[x] = orderbook.Item{ + o.Asks[x] = orderbook.Tranche{ ID: orderbookNew.Asks[x].OrderID, Price: orderbookNew.Asks[x].Rate, Amount: orderbookNew.Asks[x].Amount, Period: int64(orderbookNew.Asks[x].Period), } } - o.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + o.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - o.Bids[x] = orderbook.Item{ + o.Bids[x] = orderbook.Tranche{ ID: orderbookNew.Bids[x].OrderID, Price: orderbookNew.Bids[x].Rate, Amount: orderbookNew.Bids[x].Amount, @@ -445,17 +445,17 @@ func (b *Bitfinex) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy } } } else { - o.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + o.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - o.Asks[x] = orderbook.Item{ + o.Asks[x] = orderbook.Tranche{ ID: orderbookNew.Asks[x].OrderID, Price: orderbookNew.Asks[x].Price, Amount: orderbookNew.Asks[x].Amount, } } - o.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + o.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - o.Bids[x] = orderbook.Item{ + o.Bids[x] = orderbook.Tranche{ ID: orderbookNew.Bids[x].OrderID, Price: orderbookNew.Bids[x].Price, Amount: orderbookNew.Bids[x].Amount, diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index a08a89cf0c4..8a4d5e2a64d 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -272,17 +272,17 @@ func (b *Bitflyer) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy return book, err } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Price: orderbookNew.Asks[x].Price, Amount: orderbookNew.Asks[x].Size, } } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Price: orderbookNew.Bids[x].Price, Amount: orderbookNew.Bids[x].Size, } diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index 5dbc314674d..9efc0e88b48 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -314,17 +314,17 @@ func (b *Bithumb) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Data.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Data.Bids)) for i := range orderbookNew.Data.Bids { - book.Bids[i] = orderbook.Item{ + book.Bids[i] = orderbook.Tranche{ Amount: orderbookNew.Data.Bids[i].Quantity, Price: orderbookNew.Data.Bids[i].Price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Data.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Data.Asks)) for i := range orderbookNew.Data.Asks { - book.Asks[i] = orderbook.Item{ + book.Asks[i] = orderbook.Tranche{ Amount: orderbookNew.Data.Asks[i].Quantity, Price: orderbookNew.Data.Asks[i].Price, } diff --git a/exchanges/bithumb/bithumb_ws_orderbook.go b/exchanges/bithumb/bithumb_ws_orderbook.go index a5ea0b75589..a89d7d41263 100644 --- a/exchanges/bithumb/bithumb_ws_orderbook.go +++ b/exchanges/bithumb/bithumb_ws_orderbook.go @@ -25,10 +25,10 @@ const ( ) func (b *Bithumb) processBooks(updates *WsOrderbooks) error { - bids := make([]orderbook.Item, 0, len(updates.List)) - asks := make([]orderbook.Item, 0, len(updates.List)) + bids := make([]orderbook.Tranche, 0, len(updates.List)) + asks := make([]orderbook.Tranche, 0, len(updates.List)) for x := range updates.List { - i := orderbook.Item{Price: updates.List[x].Price, Amount: updates.List[x].Quantity} + i := orderbook.Tranche{Price: updates.List[x].Price, Amount: updates.List[x].Quantity} if updates.List[x].OrderSide == "bid" { bids = append(bids, i) continue @@ -426,16 +426,16 @@ func (b *Bithumb) SeedLocalCache(ctx context.Context, p currency.Pair) error { // SeedLocalCacheWithBook seeds the local orderbook cache func (b *Bithumb) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error { var newOrderBook orderbook.Base - newOrderBook.Bids = make(orderbook.Items, len(o.Data.Bids)) + newOrderBook.Bids = make(orderbook.Tranches, len(o.Data.Bids)) for i := range o.Data.Bids { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Amount: o.Data.Bids[i].Quantity, Price: o.Data.Bids[i].Price, } } - newOrderBook.Asks = make(orderbook.Items, len(o.Data.Asks)) + newOrderBook.Asks = make(orderbook.Tranches, len(o.Data.Asks)) for i := range o.Data.Asks { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Amount: o.Data.Asks[i].Quantity, Price: o.Data.Asks[i].Price, } diff --git a/exchanges/bitmex/bitmex_websocket.go b/exchanges/bitmex/bitmex_websocket.go index 6d04c106039..64841be014f 100644 --- a/exchanges/bitmex/bitmex_websocket.go +++ b/exchanges/bitmex/bitmex_websocket.go @@ -476,12 +476,12 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, p currency. switch action { case bitmexActionInitialData: book := orderbook.Base{ - Asks: make(orderbook.Items, 0, len(data)), - Bids: make(orderbook.Items, 0, len(data)), + Asks: make(orderbook.Tranches, 0, len(data)), + Bids: make(orderbook.Tranches, 0, len(data)), } for i := range data { - item := orderbook.Item{ + item := orderbook.Tranche{ Price: data[i].Price, Amount: float64(data[i].Size), ID: data[i].ID, @@ -514,10 +514,10 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, p currency. return err } - asks := make([]orderbook.Item, 0, len(data)) - bids := make([]orderbook.Item, 0, len(data)) + asks := make([]orderbook.Tranche, 0, len(data)) + bids := make([]orderbook.Tranche, 0, len(data)) for i := range data { - nItem := orderbook.Item{ + nItem := orderbook.Tranche{ Price: data[i].Price, Amount: float64(data[i].Size), ID: data[i].ID, diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 151f1ef28e9..c8b642bb7c0 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -481,17 +481,17 @@ func (b *Bitmex) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Asks = make(orderbook.Items, 0, len(orderbookNew)) - book.Bids = make(orderbook.Items, 0, len(orderbookNew)) + book.Asks = make(orderbook.Tranches, 0, len(orderbookNew)) + book.Bids = make(orderbook.Tranches, 0, len(orderbookNew)) for i := range orderbookNew { switch { case strings.EqualFold(orderbookNew[i].Side, order.Sell.String()): - book.Asks = append(book.Asks, orderbook.Item{ + book.Asks = append(book.Asks, orderbook.Tranche{ Amount: float64(orderbookNew[i].Size), Price: orderbookNew[i].Price, }) case strings.EqualFold(orderbookNew[i].Side, order.Buy.String()): - book.Bids = append(book.Bids, orderbook.Item{ + book.Bids = append(book.Bids, orderbook.Tranche{ Amount: float64(orderbookNew[i].Size), Price: orderbookNew[i].Price, }) diff --git a/exchanges/bitstamp/bitstamp_test.go b/exchanges/bitstamp/bitstamp_test.go index 81abe4852c7..68c8b67d18f 100644 --- a/exchanges/bitstamp/bitstamp_test.go +++ b/exchanges/bitstamp/bitstamp_test.go @@ -932,7 +932,7 @@ func TestOrderbookZeroBidPrice(t *testing.T) { filterOrderbookZeroBidPrice(ob) - ob.Bids = orderbook.Items{ + ob.Bids = orderbook.Tranches{ {Price: 69, Amount: 1337}, {Price: 0, Amount: 69}, } @@ -943,7 +943,7 @@ func TestOrderbookZeroBidPrice(t *testing.T) { t.Error("invalid orderbook bid values") } - ob.Bids = orderbook.Items{ + ob.Bids = orderbook.Tranches{ {Price: 59, Amount: 1337}, {Price: 42, Amount: 8595}, } diff --git a/exchanges/bitstamp/bitstamp_websocket.go b/exchanges/bitstamp/bitstamp_websocket.go index ab5465b574d..af49325744f 100644 --- a/exchanges/bitstamp/bitstamp_websocket.go +++ b/exchanges/bitstamp/bitstamp_websocket.go @@ -329,8 +329,8 @@ func (b *Bitstamp) wsUpdateOrderbook(update *websocketOrderBook, p currency.Pair } obUpdate := &orderbook.Base{ - Bids: make(orderbook.Items, len(update.Bids)), - Asks: make(orderbook.Items, len(update.Asks)), + Bids: make(orderbook.Tranches, len(update.Bids)), + Asks: make(orderbook.Tranches, len(update.Asks)), Pair: p, LastUpdated: time.UnixMicro(update.Microtimestamp), Asset: assetType, @@ -347,7 +347,7 @@ func (b *Bitstamp) wsUpdateOrderbook(update *websocketOrderBook, p currency.Pair if err != nil { return err } - obUpdate.Asks[i] = orderbook.Item{Price: target, Amount: amount} + obUpdate.Asks[i] = orderbook.Tranche{Price: target, Amount: amount} } for i := range update.Bids { target, err := strconv.ParseFloat(update.Bids[i][0], 64) @@ -358,7 +358,7 @@ func (b *Bitstamp) wsUpdateOrderbook(update *websocketOrderBook, p currency.Pair if err != nil { return err } - obUpdate.Bids[i] = orderbook.Item{Price: target, Amount: amount} + obUpdate.Bids[i] = orderbook.Tranche{Price: target, Amount: amount} } filterOrderbookZeroBidPrice(obUpdate) return b.Websocket.Orderbook.LoadSnapshot(obUpdate) @@ -385,19 +385,19 @@ func (b *Bitstamp) seedOrderBook(ctx context.Context) error { Asset: asset.Spot, Exchange: b.Name, VerifyOrderbook: b.CanVerifyOrderbook, - Bids: make(orderbook.Items, len(orderbookSeed.Bids)), - Asks: make(orderbook.Items, len(orderbookSeed.Asks)), + Bids: make(orderbook.Tranches, len(orderbookSeed.Bids)), + Asks: make(orderbook.Tranches, len(orderbookSeed.Asks)), LastUpdated: time.Unix(orderbookSeed.Timestamp, 0), } for i := range orderbookSeed.Asks { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Price: orderbookSeed.Asks[i].Price, Amount: orderbookSeed.Asks[i].Amount, } } for i := range orderbookSeed.Bids { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Price: orderbookSeed.Bids[i].Price, Amount: orderbookSeed.Bids[i].Amount, } diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 888fae0b395..940010cee30 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -360,9 +360,9 @@ func (b *Bitstamp) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price, } @@ -370,9 +370,9 @@ func (b *Bitstamp) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTy filterOrderbookZeroBidPrice(book) - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Amount, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index 06753f4cdcb..37c154994af 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -836,11 +836,11 @@ func TestGetHistoricTrades(t *testing.T) { func TestChecksum(t *testing.T) { b := &orderbook.Base{ - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ {Price: 0.3965, Amount: 44149.815}, {Price: 0.3967, Amount: 16000.0}, }, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ {Price: 0.396, Amount: 51.0}, {Price: 0.396, Amount: 25.0}, {Price: 0.3958, Amount: 18570.0}, diff --git a/exchanges/btcmarkets/btcmarkets_types.go b/exchanges/btcmarkets/btcmarkets_types.go index 8b212695368..f104f6acb4c 100644 --- a/exchanges/btcmarkets/btcmarkets_types.go +++ b/exchanges/btcmarkets/btcmarkets_types.go @@ -441,4 +441,4 @@ type CandleResponse [][6]string // WebsocketOrderbook defines a specific websocket orderbook type to directly // unmarshal json. -type WebsocketOrderbook orderbook.Items +type WebsocketOrderbook orderbook.Tranches diff --git a/exchanges/btcmarkets/btcmarkets_websocket.go b/exchanges/btcmarkets/btcmarkets_websocket.go index 8c979b4d79b..1e90e106374 100644 --- a/exchanges/btcmarkets/btcmarkets_websocket.go +++ b/exchanges/btcmarkets/btcmarkets_websocket.go @@ -79,7 +79,7 @@ func (w *WebsocketOrderbook) UnmarshalJSON(data []byte) error { return err } - *w = WebsocketOrderbook(make(orderbook.Items, len(resp))) + *w = WebsocketOrderbook(make(orderbook.Tranches, len(resp))) for x := range resp { sPrice, ok := resp[x][0].(string) if !ok { @@ -107,7 +107,7 @@ func (w *WebsocketOrderbook) UnmarshalJSON(data []byte) error { return fmt.Errorf("count float64 %w", errTypeAssertionFailure) } - (*w)[x] = orderbook.Item{ + (*w)[x] = orderbook.Tranche{ Amount: amount, Price: price, OrderCount: int64(count), @@ -137,8 +137,8 @@ func (b *BTCMarkets) wsHandleData(respRaw []byte) error { if ob.Snapshot { err = b.Websocket.Orderbook.LoadSnapshot(&orderbook.Base{ Pair: ob.Currency, - Bids: orderbook.Items(ob.Bids), - Asks: orderbook.Items(ob.Asks), + Bids: orderbook.Tranches(ob.Bids), + Asks: orderbook.Tranches(ob.Asks), LastUpdated: ob.Timestamp, LastUpdateID: ob.SnapshotID, Asset: asset.Spot, @@ -150,8 +150,8 @@ func (b *BTCMarkets) wsHandleData(respRaw []byte) error { UpdateTime: ob.Timestamp, UpdateID: ob.SnapshotID, Asset: asset.Spot, - Bids: orderbook.Items(ob.Bids), - Asks: orderbook.Items(ob.Asks), + Bids: orderbook.Tranches(ob.Bids), + Asks: orderbook.Tranches(ob.Asks), Pair: ob.Currency, Checksum: ob.Checksum, }) @@ -465,7 +465,7 @@ func checksum(ob *orderbook.Base, checksum uint32) error { } // concat concatenates price and amounts together for checksum processing -func concat(liquidity orderbook.Items) string { +func concat(liquidity orderbook.Tranches) string { length := 10 if len(liquidity) < 10 { length = len(liquidity) diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 17ee7277c0a..2aeac533fbe 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -337,17 +337,17 @@ func (b *BTCMarkets) UpdateOrderbook(ctx context.Context, p currency.Pair, asset return book, err } - book.Bids = make(orderbook.Items, len(tempResp.Bids)) + book.Bids = make(orderbook.Tranches, len(tempResp.Bids)) for x := range tempResp.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: tempResp.Bids[x].Volume, Price: tempResp.Bids[x].Price, } } - book.Asks = make(orderbook.Items, len(tempResp.Asks)) + book.Asks = make(orderbook.Tranches, len(tempResp.Asks)) for y := range tempResp.Asks { - book.Asks[y] = orderbook.Item{ + book.Asks[y] = orderbook.Tranche{ Amount: tempResp.Asks[y].Volume, Price: tempResp.Asks[y].Price, } diff --git a/exchanges/btse/btse_websocket.go b/exchanges/btse/btse_websocket.go index 41f25c95e35..f13374ded9d 100644 --- a/exchanges/btse/btse_websocket.go +++ b/exchanges/btse/btse_websocket.go @@ -277,8 +277,8 @@ func (b *BTSE) wsHandleData(respRaw []byte) error { return err } newOB := orderbook.Base{ - Bids: make(orderbook.Items, 0, len(t.Data.BuyQuote)), - Asks: make(orderbook.Items, 0, len(t.Data.SellQuote)), + Bids: make(orderbook.Tranches, 0, len(t.Data.BuyQuote)), + Asks: make(orderbook.Tranches, 0, len(t.Data.SellQuote)), } var price, amount float64 for i := range t.Data.SellQuote { @@ -295,7 +295,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error { if b.orderbookFilter(price, amount) { continue } - newOB.Asks = append(newOB.Asks, orderbook.Item{ + newOB.Asks = append(newOB.Asks, orderbook.Tranche{ Price: price, Amount: amount, }) @@ -314,7 +314,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error { if b.orderbookFilter(price, amount) { continue } - newOB.Bids = append(newOB.Bids, orderbook.Item{ + newOB.Bids = append(newOB.Bids, orderbook.Tranche{ Price: price, Amount: amount, }) diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index f7ec3c8f702..548cf2d5724 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -392,22 +392,22 @@ func (b *BTSE) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType a return book, err } - book.Bids = make(orderbook.Items, 0, len(a.BuyQuote)) + book.Bids = make(orderbook.Tranches, 0, len(a.BuyQuote)) for x := range a.BuyQuote { if b.orderbookFilter(a.BuyQuote[x].Price, a.BuyQuote[x].Size) { continue } - book.Bids = append(book.Bids, orderbook.Item{ + book.Bids = append(book.Bids, orderbook.Tranche{ Price: a.BuyQuote[x].Price, Amount: a.BuyQuote[x].Size, }) } - book.Asks = make(orderbook.Items, 0, len(a.SellQuote)) + book.Asks = make(orderbook.Tranches, 0, len(a.SellQuote)) for x := range a.SellQuote { if b.orderbookFilter(a.SellQuote[x].Price, a.SellQuote[x].Size) { continue } - book.Asks = append(book.Asks, orderbook.Item{ + book.Asks = append(book.Asks, orderbook.Tranche{ Price: a.SellQuote[x].Price, Amount: a.SellQuote[x].Size, }) diff --git a/exchanges/bybit/bybit.go b/exchanges/bybit/bybit.go index ef0a6052b1d..87ffead71c9 100644 --- a/exchanges/bybit/bybit.go +++ b/exchanges/bybit/bybit.go @@ -2525,9 +2525,9 @@ func (by *Bybit) GetBrokerEarning(ctx context.Context, businessType, cursor stri return resp.List, by.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, "/v5/broker/earning-record", params, nil, &resp, defaultEPL) } -func processOB(ob [][2]string) ([]orderbook.Item, error) { +func processOB(ob [][2]string) ([]orderbook.Tranche, error) { var err error - o := make([]orderbook.Item, len(ob)) + o := make([]orderbook.Tranche, len(ob)) for x := range ob { o[x].Amount, err = strconv.ParseFloat(ob[x][1], 64) if err != nil { diff --git a/exchanges/bybit/bybit_types.go b/exchanges/bybit/bybit_types.go index 739d07d879d..ada24d273a9 100644 --- a/exchanges/bybit/bybit_types.go +++ b/exchanges/bybit/bybit_types.go @@ -1732,8 +1732,8 @@ type ServerTime struct { // Orderbook stores the orderbook data type Orderbook struct { UpdateID int64 - Bids []orderbook.Item - Asks []orderbook.Item + Bids []orderbook.Tranche + Asks []orderbook.Tranche Symbol string GenerationTime time.Time } diff --git a/exchanges/bybit/bybit_websocket.go b/exchanges/bybit/bybit_websocket.go index 857fd690afe..68f4a01fc7f 100644 --- a/exchanges/bybit/bybit_websocket.go +++ b/exchanges/bybit/bybit_websocket.go @@ -823,7 +823,7 @@ func (by *Bybit) wsProcessOrderbook(assetType asset.Item, resp *WebsocketRespons if err != nil { return err } - asks := make([]orderbook.Item, len(result.Asks)) + asks := make([]orderbook.Tranche, len(result.Asks)) for i := range result.Asks { asks[i].Price, err = strconv.ParseFloat(result.Asks[i][0], 64) if err != nil { @@ -834,7 +834,7 @@ func (by *Bybit) wsProcessOrderbook(assetType asset.Item, resp *WebsocketRespons return err } } - bids := make([]orderbook.Item, len(result.Bids)) + bids := make([]orderbook.Tranche, len(result.Bids)) for i := range result.Bids { bids[i].Price, err = strconv.ParseFloat(result.Bids[i][0], 64) if err != nil { diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index 28d4f15041d..e0ea50af4f0 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -558,17 +558,17 @@ func (by *Bybit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType Pair: p, Asset: assetType, VerifyOrderbook: by.CanVerifyOrderbook, - Bids: make([]orderbook.Item, len(orderbookNew.Bids)), - Asks: make([]orderbook.Item, len(orderbookNew.Asks)), + Bids: make([]orderbook.Tranche, len(orderbookNew.Bids)), + Asks: make([]orderbook.Tranche, len(orderbookNew.Asks)), } for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price, } } for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Amount, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/coinbasepro/coinbasepro_websocket.go b/exchanges/coinbasepro/coinbasepro_websocket.go index e4b02b764d8..2b45d72b66e 100644 --- a/exchanges/coinbasepro/coinbasepro_websocket.go +++ b/exchanges/coinbasepro/coinbasepro_websocket.go @@ -286,8 +286,8 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot *WebsocketOrderbookSnapshot) erro base := orderbook.Base{ Pair: pair, - Bids: make(orderbook.Items, len(snapshot.Bids)), - Asks: make(orderbook.Items, len(snapshot.Asks)), + Bids: make(orderbook.Tranches, len(snapshot.Bids)), + Asks: make(orderbook.Tranches, len(snapshot.Asks)), } for i := range snapshot.Bids { @@ -301,7 +301,7 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot *WebsocketOrderbookSnapshot) erro if err != nil { return err } - base.Bids[i] = orderbook.Item{Price: price, Amount: amount} + base.Bids[i] = orderbook.Tranche{Price: price, Amount: amount} } for i := range snapshot.Asks { @@ -315,7 +315,7 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot *WebsocketOrderbookSnapshot) erro if err != nil { return err } - base.Asks[i] = orderbook.Item{Price: price, Amount: amount} + base.Asks[i] = orderbook.Tranche{Price: price, Amount: amount} } base.Asset = asset.Spot @@ -337,8 +337,8 @@ func (c *CoinbasePro) ProcessUpdate(update *WebsocketL2Update) error { return err } - asks := make(orderbook.Items, 0, len(update.Changes)) - bids := make(orderbook.Items, 0, len(update.Changes)) + asks := make(orderbook.Tranches, 0, len(update.Changes)) + bids := make(orderbook.Tranches, 0, len(update.Changes)) for i := range update.Changes { price, err := strconv.ParseFloat(update.Changes[i][1], 64) @@ -350,9 +350,9 @@ func (c *CoinbasePro) ProcessUpdate(update *WebsocketL2Update) error { return err } if update.Changes[i][0] == order.Buy.Lower() { - bids = append(bids, orderbook.Item{Price: price, Amount: volume}) + bids = append(bids, orderbook.Tranche{Price: price, Amount: volume}) } else { - asks = append(asks, orderbook.Item{Price: price, Amount: volume}) + asks = append(asks, orderbook.Tranche{Price: price, Amount: volume}) } } diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index 47a20d9ed95..4cc7327f775 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -373,17 +373,17 @@ func (c *CoinbasePro) UpdateOrderbook(ctx context.Context, p currency.Pair, asse return book, common.GetTypeAssertError("OrderbookL1L2", orderbookNew) } - book.Bids = make(orderbook.Items, len(obNew.Bids)) + book.Bids = make(orderbook.Tranches, len(obNew.Bids)) for x := range obNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: obNew.Bids[x].Amount, Price: obNew.Bids[x].Price, } } - book.Asks = make(orderbook.Items, len(obNew.Asks)) + book.Asks = make(orderbook.Tranches, len(obNew.Asks)) for x := range obNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: obNew.Asks[x].Amount, Price: obNew.Asks[x].Price, } diff --git a/exchanges/coinut/coinut_websocket.go b/exchanges/coinut/coinut_websocket.go index 2453816e9ce..e66567042ad 100644 --- a/exchanges/coinut/coinut_websocket.go +++ b/exchanges/coinut/coinut_websocket.go @@ -517,17 +517,17 @@ func (c *COINUT) WsGetInstruments() (Instruments, error) { // WsProcessOrderbookSnapshot processes the orderbook snapshot func (c *COINUT) WsProcessOrderbookSnapshot(ob *WsOrderbookSnapshot) error { - bids := make([]orderbook.Item, len(ob.Buy)) + bids := make([]orderbook.Tranche, len(ob.Buy)) for i := range ob.Buy { - bids[i] = orderbook.Item{ + bids[i] = orderbook.Tranche{ Amount: ob.Buy[i].Volume, Price: ob.Buy[i].Price, } } - asks := make([]orderbook.Item, len(ob.Sell)) + asks := make([]orderbook.Tranche, len(ob.Sell)) for i := range ob.Sell { - asks[i] = orderbook.Item{ + asks[i] = orderbook.Tranche{ Amount: ob.Sell[i].Volume, Price: ob.Sell[i].Price, } @@ -590,9 +590,9 @@ func (c *COINUT) WsProcessOrderbookUpdate(update *WsOrderbookUpdate) error { UpdateTime: time.Now(), // No time sent } if strings.EqualFold(update.Side, order.Buy.Lower()) { - bufferUpdate.Bids = []orderbook.Item{{Price: update.Price, Amount: update.Volume}} + bufferUpdate.Bids = []orderbook.Tranche{{Price: update.Price, Amount: update.Volume}} } else { - bufferUpdate.Asks = []orderbook.Item{{Price: update.Price, Amount: update.Volume}} + bufferUpdate.Asks = []orderbook.Tranche{{Price: update.Price, Amount: update.Volume}} } return c.Websocket.Orderbook.Update(bufferUpdate) } diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index 503c2909461..5c7a48e2f99 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -433,17 +433,17 @@ func (c *COINUT) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Buy)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Buy)) for x := range orderbookNew.Buy { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Buy[x].Quantity, Price: orderbookNew.Buy[x].Price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Sell)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Sell)) for x := range orderbookNew.Sell { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Sell[x].Quantity, Price: orderbookNew.Sell[x].Price, } diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index 0137cbbe2e7..a91ef1e5df7 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -289,7 +289,7 @@ func (e *EXMO) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType a continue } - book.Asks = make(orderbook.Items, len(data.Ask)) + book.Asks = make(orderbook.Tranches, len(data.Ask)) for y := range data.Ask { var price, amount float64 price, err = strconv.ParseFloat(data.Ask[y][0], 64) @@ -302,13 +302,13 @@ func (e *EXMO) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType a return book, err } - book.Asks[y] = orderbook.Item{ + book.Asks[y] = orderbook.Tranche{ Price: price, Amount: amount, } } - book.Bids = make(orderbook.Items, len(data.Bid)) + book.Bids = make(orderbook.Tranches, len(data.Bid)) for y := range data.Bid { var price, amount float64 price, err = strconv.ParseFloat(data.Bid[y][0], 64) @@ -321,7 +321,7 @@ func (e *EXMO) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType a return book, err } - book.Bids[y] = orderbook.Item{ + book.Bids[y] = orderbook.Tranche{ Price: price, Amount: amount, } diff --git a/exchanges/gateio/gateio_websocket.go b/exchanges/gateio/gateio_websocket.go index c26d04afe7c..6d43a550c33 100644 --- a/exchanges/gateio/gateio_websocket.go +++ b/exchanges/gateio/gateio_websocket.go @@ -290,8 +290,8 @@ func (g *Gateio) processOrderbookTicker(incoming []byte) error { Pair: data.CurrencyPair, Asset: asset.Spot, LastUpdated: time.UnixMilli(data.UpdateTimeMS), - Bids: []orderbook.Item{{Price: data.BestBidPrice.Float64(), Amount: data.BestBidAmount.Float64()}}, - Asks: []orderbook.Item{{Price: data.BestAskPrice.Float64(), Amount: data.BestAskAmount.Float64()}}, + Bids: []orderbook.Tranche{{Price: data.BestBidPrice.Float64(), Amount: data.BestBidAmount.Float64()}}, + Asks: []orderbook.Tranche{{Price: data.BestAskPrice.Float64(), Amount: data.BestAskAmount.Float64()}}, }) } @@ -326,7 +326,7 @@ func (g *Gateio) processOrderbookUpdate(incoming []byte) error { UpdateTime: data.UpdateTimeMs.Time(), Pair: data.CurrencyPair, } - updates.Asks = make([]orderbook.Item, len(data.Asks)) + updates.Asks = make([]orderbook.Tranche, len(data.Asks)) for x := range data.Asks { updates.Asks[x].Price, err = strconv.ParseFloat(data.Asks[x][0], 64) if err != nil { @@ -337,7 +337,7 @@ func (g *Gateio) processOrderbookUpdate(incoming []byte) error { return err } } - updates.Bids = make([]orderbook.Item, len(data.Bids)) + updates.Bids = make([]orderbook.Tranche, len(data.Bids)) for x := range data.Bids { updates.Bids[x].Price, err = strconv.ParseFloat(data.Bids[x][0], 64) if err != nil { @@ -392,7 +392,7 @@ func (g *Gateio) processOrderbookSnapshot(incoming []byte) error { LastUpdateID: data.LastUpdateID, VerifyOrderbook: g.CanVerifyOrderbook, } - bases.Asks = make([]orderbook.Item, len(data.Asks)) + bases.Asks = make([]orderbook.Tranche, len(data.Asks)) for x := range data.Asks { bases.Asks[x].Price, err = strconv.ParseFloat(data.Asks[x][0], 64) if err != nil { @@ -403,7 +403,7 @@ func (g *Gateio) processOrderbookSnapshot(incoming []byte) error { return err } } - bases.Bids = make([]orderbook.Item, len(data.Bids)) + bases.Bids = make([]orderbook.Tranche, len(data.Bids)) for x := range data.Bids { bases.Bids[x].Price, err = strconv.ParseFloat(data.Bids[x][0], 64) if err != nil { diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index 924da1dcbc4..f491c546f65 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -712,16 +712,16 @@ func (g *Gateio) UpdateOrderbook(ctx context.Context, p currency.Pair, a asset.I LastUpdateID: orderbookNew.ID, LastUpdated: orderbookNew.Update.Time(), } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price.Float64(), } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Amount, Price: orderbookNew.Asks[x].Price.Float64(), } diff --git a/exchanges/gateio/gateio_ws_futures.go b/exchanges/gateio/gateio_ws_futures.go index c0411a5816c..56327326428 100644 --- a/exchanges/gateio/gateio_ws_futures.go +++ b/exchanges/gateio/gateio_ws_futures.go @@ -550,12 +550,12 @@ func (g *Gateio) processFuturesAndOptionsOrderbookUpdate(incoming []byte, assetT Pair: data.ContractName, Asset: assetType, } - updates.Asks = make([]orderbook.Item, len(data.Asks)) + updates.Asks = make([]orderbook.Tranche, len(data.Asks)) for x := range data.Asks { updates.Asks[x].Amount = data.Asks[x].Size updates.Asks[x].Price = data.Asks[x].Price.Float64() } - updates.Bids = make([]orderbook.Item, len(data.Bids)) + updates.Bids = make([]orderbook.Tranche, len(data.Bids)) for x := range data.Bids { updates.Bids[x].Amount = data.Bids[x].Size updates.Bids[x].Price = data.Bids[x].Price.Float64() @@ -580,12 +580,12 @@ func (g *Gateio) processFuturesOrderbookSnapshot(event string, incoming []byte, LastUpdated: data.TimestampInMs.Time(), VerifyOrderbook: g.CanVerifyOrderbook, } - base.Asks = make([]orderbook.Item, len(data.Asks)) + base.Asks = make([]orderbook.Tranche, len(data.Asks)) for x := range data.Asks { base.Asks[x].Amount = data.Asks[x].Size base.Asks[x].Price = data.Asks[x].Price.Float64() } - base.Bids = make([]orderbook.Item, len(data.Bids)) + base.Bids = make([]orderbook.Tranche, len(data.Bids)) for x := range data.Bids { base.Bids[x].Amount = data.Bids[x].Size base.Bids[x].Price = data.Bids[x].Price.Float64() @@ -597,19 +597,19 @@ func (g *Gateio) processFuturesOrderbookSnapshot(event string, incoming []byte, if err != nil { return err } - dataMap := map[string][2][]orderbook.Item{} + dataMap := map[string][2][]orderbook.Tranche{} for x := range data { ab, ok := dataMap[data[x].CurrencyPair] if !ok { - ab = [2][]orderbook.Item{} + ab = [2][]orderbook.Tranche{} } if data[x].Amount > 0 { - ab[1] = append(ab[1], orderbook.Item{ + ab[1] = append(ab[1], orderbook.Tranche{ Price: data[x].Price.Float64(), Amount: data[x].Amount, }) } else { - ab[0] = append(ab[0], orderbook.Item{ + ab[0] = append(ab[0], orderbook.Tranche{ Price: data[x].Price.Float64(), Amount: -data[x].Amount, }) diff --git a/exchanges/gateio/gateio_ws_option.go b/exchanges/gateio/gateio_ws_option.go index d5340f0c350..aad643b9a0a 100644 --- a/exchanges/gateio/gateio_ws_option.go +++ b/exchanges/gateio/gateio_ws_option.go @@ -562,12 +562,12 @@ func (g *Gateio) processOptionsOrderbookSnapshotPushData(event string, incoming LastUpdated: data.Timestamp.Time(), VerifyOrderbook: g.CanVerifyOrderbook, } - base.Asks = make([]orderbook.Item, len(data.Asks)) + base.Asks = make([]orderbook.Tranche, len(data.Asks)) for x := range data.Asks { base.Asks[x].Amount = data.Asks[x].Size base.Asks[x].Price = data.Asks[x].Price.Float64() } - base.Bids = make([]orderbook.Item, len(data.Bids)) + base.Bids = make([]orderbook.Tranche, len(data.Bids)) for x := range data.Bids { base.Bids[x].Amount = data.Bids[x].Size base.Bids[x].Price = data.Bids[x].Price.Float64() @@ -579,18 +579,18 @@ func (g *Gateio) processOptionsOrderbookSnapshotPushData(event string, incoming if err != nil { return err } - dataMap := map[string][2][]orderbook.Item{} + dataMap := map[string][2][]orderbook.Tranche{} for x := range data { ab, ok := dataMap[data[x].CurrencyPair] if !ok { - ab = [2][]orderbook.Item{} + ab = [2][]orderbook.Tranche{} } if data[x].Amount > 0 { - ab[1] = append(ab[1], orderbook.Item{ + ab[1] = append(ab[1], orderbook.Tranche{ Price: data[x].Price.Float64(), Amount: data[x].Amount, }) } else { - ab[0] = append(ab[0], orderbook.Item{ + ab[0] = append(ab[0], orderbook.Tranche{ Price: data[x].Price.Float64(), Amount: -data[x].Amount, }) } diff --git a/exchanges/gemini/gemini_websocket.go b/exchanges/gemini/gemini_websocket.go index 913c856ddd4..5ecbbb78a35 100644 --- a/exchanges/gemini/gemini_websocket.go +++ b/exchanges/gemini/gemini_websocket.go @@ -530,8 +530,8 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error { return err } - bids := make([]orderbook.Item, 0, len(result.Changes)) - asks := make([]orderbook.Item, 0, len(result.Changes)) + bids := make([]orderbook.Tranche, 0, len(result.Changes)) + asks := make([]orderbook.Tranche, 0, len(result.Changes)) for x := range result.Changes { price, err := strconv.ParseFloat(result.Changes[x][1], 64) @@ -542,7 +542,7 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error { if err != nil { return err } - obItem := orderbook.Item{ + obItem := orderbook.Tranche{ Amount: amount, Price: price, } diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index fee75d6b1a2..a6032d7881f 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -372,17 +372,17 @@ func (g *Gemini) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Amount, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/hitbtc/hitbtc_websocket.go b/exchanges/hitbtc/hitbtc_websocket.go index 705f584f01c..3663c4ac5d3 100644 --- a/exchanges/hitbtc/hitbtc_websocket.go +++ b/exchanges/hitbtc/hitbtc_websocket.go @@ -300,17 +300,17 @@ func (h *HitBTC) WsProcessOrderbookSnapshot(ob *WsOrderbook) error { } newOrderBook := orderbook.Base{ - Bids: make(orderbook.Items, len(ob.Params.Bid)), - Asks: make(orderbook.Items, len(ob.Params.Ask)), + Bids: make(orderbook.Tranches, len(ob.Params.Bid)), + Asks: make(orderbook.Tranches, len(ob.Params.Ask)), } for i := range ob.Params.Bid { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Amount: ob.Params.Bid[i].Size, Price: ob.Params.Bid[i].Price, } } for i := range ob.Params.Ask { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Amount: ob.Params.Ask[i].Size, Price: ob.Params.Ask[i].Price, } @@ -422,17 +422,17 @@ func (h *HitBTC) WsProcessOrderbookUpdate(update *WsOrderbook) error { return nil } - bids := make(orderbook.Items, len(update.Params.Bid)) + bids := make(orderbook.Tranches, len(update.Params.Bid)) for i := range update.Params.Bid { - bids[i] = orderbook.Item{ + bids[i] = orderbook.Tranche{ Price: update.Params.Bid[i].Price, Amount: update.Params.Bid[i].Size, } } - asks := make(orderbook.Items, len(update.Params.Ask)) + asks := make(orderbook.Tranches, len(update.Params.Ask)) for i := range update.Params.Ask { - asks[i] = orderbook.Item{ + asks[i] = orderbook.Tranche{ Price: update.Params.Ask[i].Price, Amount: update.Params.Ask[i].Size, } diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index 3b65fe649b5..3a1ab403acd 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -323,16 +323,16 @@ func (h *HitBTC) UpdateOrderbook(ctx context.Context, c currency.Pair, assetType return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Amount, Price: orderbookNew.Asks[x].Price, } diff --git a/exchanges/huobi/huobi_websocket.go b/exchanges/huobi/huobi_websocket.go index f601b03dbc2..2df9231d832 100644 --- a/exchanges/huobi/huobi_websocket.go +++ b/exchanges/huobi/huobi_websocket.go @@ -470,7 +470,7 @@ func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error { return err } - bids := make(orderbook.Items, len(update.Tick.Bids)) + bids := make(orderbook.Tranches, len(update.Tick.Bids)) for i := range update.Tick.Bids { price, ok := update.Tick.Bids[i][0].(float64) if !ok { @@ -480,13 +480,13 @@ func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error { if !ok { return errors.New("unable to type assert bid amount") } - bids[i] = orderbook.Item{ + bids[i] = orderbook.Tranche{ Price: price, Amount: amount, } } - asks := make(orderbook.Items, len(update.Tick.Asks)) + asks := make(orderbook.Tranches, len(update.Tick.Asks)) for i := range update.Tick.Asks { price, ok := update.Tick.Asks[i][0].(float64) if !ok { @@ -496,7 +496,7 @@ func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error { if !ok { return errors.New("unable to type assert ask amount") } - asks[i] = orderbook.Item{ + asks[i] = orderbook.Tranche{ Price: price, Amount: amount, } diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 62cada36bd0..44b8237da27 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -605,16 +605,16 @@ func (h *HUOBI) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x][1], Price: orderbookNew.Bids[x][0], } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x][1], Price: orderbookNew.Asks[x][0], } @@ -627,16 +627,16 @@ func (h *HUOBI) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Asks[x].Quantity, Price: orderbookNew.Asks[x].Price, } } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for y := range orderbookNew.Bids { - book.Bids[y] = orderbook.Item{ + book.Bids[y] = orderbook.Tranche{ Amount: orderbookNew.Bids[y].Quantity, Price: orderbookNew.Bids[y].Price, } @@ -649,17 +649,17 @@ func (h *HUOBI) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Asks = make(orderbook.Items, len(orderbookNew.Tick.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Tick.Asks)) for x := range orderbookNew.Tick.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderbookNew.Tick.Asks[x][1], Price: orderbookNew.Tick.Asks[x][0], } } - book.Bids = make(orderbook.Items, len(orderbookNew.Tick.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Tick.Bids)) for y := range orderbookNew.Tick.Bids { - book.Bids[y] = orderbook.Item{ + book.Bids[y] = orderbook.Tranche{ Amount: orderbookNew.Tick.Bids[y][1], Price: orderbookNew.Tick.Bids[y][0], } diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index a585353ab7e..c2ee3e2edec 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -211,7 +211,7 @@ func (i *ItBit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Bids = make(orderbook.Items, len(orderbookNew.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { var price, amount float64 price, err = strconv.ParseFloat(orderbookNew.Bids[x][0], 64) @@ -222,13 +222,13 @@ func (i *ItBit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if err != nil { return book, err } - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: amount, Price: price, } } - book.Asks = make(orderbook.Items, len(orderbookNew.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookNew.Asks)) for x := range orderbookNew.Asks { var price, amount float64 price, err = strconv.ParseFloat(orderbookNew.Asks[x][0], 64) @@ -239,7 +239,7 @@ func (i *ItBit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if err != nil { return book, err } - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: amount, Price: price, } diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index 29418e383e8..53c43028e1c 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -2044,7 +2044,7 @@ func TestGetHistoricTrades(t *testing.T) { } var testOb = orderbook.Base{ - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ // NOTE: 0.00000500 float64 == 0.000005 {Price: 0.05005, StrPrice: "0.05005", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05010, StrPrice: "0.05010", Amount: 0.00000500, StrAmount: "0.00000500"}, @@ -2057,7 +2057,7 @@ var testOb = orderbook.Base{ {Price: 0.05045, StrPrice: "0.05045", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.05050, StrPrice: "0.05050", Amount: 0.00000500, StrAmount: "0.00000500"}, }, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ {Price: 0.05000, StrPrice: "0.05000", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04995, StrPrice: "0.04995", Amount: 0.00000500, StrAmount: "0.00000500"}, {Price: 0.04990, StrPrice: "0.04990", Amount: 0.00000500, StrAmount: "0.00000500"}, diff --git a/exchanges/kraken/kraken_websocket.go b/exchanges/kraken/kraken_websocket.go index e7913668412..815e4eb6b5c 100644 --- a/exchanges/kraken/kraken_websocket.go +++ b/exchanges/kraken/kraken_websocket.go @@ -882,8 +882,8 @@ func (k *Kraken) wsProcessOrderBookPartial(channelData *WebsocketChannelData, as Pair: channelData.Pair, Asset: asset.Spot, VerifyOrderbook: k.CanVerifyOrderbook, - Bids: make(orderbook.Items, len(bidData)), - Asks: make(orderbook.Items, len(askData)), + Bids: make(orderbook.Tranches, len(bidData)), + Asks: make(orderbook.Tranches, len(askData)), MaxDepth: channelData.MaxDepth, ChecksumStringRequired: true, } @@ -923,7 +923,7 @@ func (k *Kraken) wsProcessOrderBookPartial(channelData *WebsocketChannelData, as if err != nil { return err } - base.Asks[i] = orderbook.Item{ + base.Asks[i] = orderbook.Tranche{ Amount: amount, StrAmount: amountStr, Price: price, @@ -968,7 +968,7 @@ func (k *Kraken) wsProcessOrderBookPartial(channelData *WebsocketChannelData, as return err } - base.Bids[i] = orderbook.Item{ + base.Bids[i] = orderbook.Tranche{ Amount: amount, StrAmount: amountStr, Price: price, @@ -990,8 +990,8 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData, ask update := orderbook.Update{ Asset: asset.Spot, Pair: channelData.Pair, - Bids: make([]orderbook.Item, len(bidData)), - Asks: make([]orderbook.Item, len(askData)), + Bids: make([]orderbook.Tranche, len(bidData)), + Asks: make([]orderbook.Tranche, len(askData)), } // Calculating checksum requires incoming decimal place checks for both @@ -1036,7 +1036,7 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData, ask return err } - update.Asks[i] = orderbook.Item{ + update.Asks[i] = orderbook.Tranche{ Amount: amount, StrAmount: amountStr, Price: price, @@ -1086,7 +1086,7 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData, ask return err } - update.Bids[i] = orderbook.Item{ + update.Bids[i] = orderbook.Tranche{ Amount: amount, StrAmount: amountStr, Price: price, diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index f2314180542..633bb95a5d8 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -520,16 +520,16 @@ func (k *Kraken) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if err != nil { return book, err } - book.Bids = make([]orderbook.Item, len(orderbookNew.Bids)) + book.Bids = make([]orderbook.Tranche, len(orderbookNew.Bids)) for x := range orderbookNew.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderbookNew.Bids[x].Amount, Price: orderbookNew.Bids[x].Price, } } - book.Asks = make([]orderbook.Item, len(orderbookNew.Asks)) + book.Asks = make([]orderbook.Tranche, len(orderbookNew.Asks)) for y := range orderbookNew.Asks { - book.Asks[y] = orderbook.Item{ + book.Asks[y] = orderbook.Tranche{ Amount: orderbookNew.Asks[y].Amount, Price: orderbookNew.Asks[y].Price, } @@ -540,16 +540,16 @@ func (k *Kraken) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if err != nil { return book, err } - book.Asks = make([]orderbook.Item, len(futuresOB.Orderbook.Asks)) + book.Asks = make([]orderbook.Tranche, len(futuresOB.Orderbook.Asks)) for x := range futuresOB.Orderbook.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Price: futuresOB.Orderbook.Asks[x][0], Amount: futuresOB.Orderbook.Asks[x][1], } } - book.Bids = make([]orderbook.Item, len(futuresOB.Orderbook.Bids)) + book.Bids = make([]orderbook.Tranche, len(futuresOB.Orderbook.Bids)) for y := range futuresOB.Orderbook.Bids { - book.Bids[y] = orderbook.Item{ + book.Bids[y] = orderbook.Tranche{ Price: futuresOB.Orderbook.Bids[y][0], Amount: futuresOB.Orderbook.Bids[y][1], } diff --git a/exchanges/kucoin/kucoin.go b/exchanges/kucoin/kucoin.go index 2c71d13cc0a..5f0c3753153 100644 --- a/exchanges/kucoin/kucoin.go +++ b/exchanges/kucoin/kucoin.go @@ -189,8 +189,8 @@ func (ku *Kucoin) GetMarketList(ctx context.Context) ([]string, error) { return resp, ku.SendHTTPRequest(ctx, exchange.RestSpot, defaultSpotEPL, kucoinGetMarketList, &resp) } -func processOB(ob [][2]string) ([]orderbook.Item, error) { - o := make([]orderbook.Item, len(ob)) +func processOB(ob [][2]string) ([]orderbook.Tranche, error) { + o := make([]orderbook.Tranche, len(ob)) for x := range ob { amount, err := strconv.ParseFloat(ob[x][1], 64) if err != nil { @@ -200,7 +200,7 @@ func processOB(ob [][2]string) ([]orderbook.Item, error) { if err != nil { return nil, err } - o[x] = orderbook.Item{ + o[x] = orderbook.Tranche{ Price: price, Amount: amount, } diff --git a/exchanges/kucoin/kucoin_futures.go b/exchanges/kucoin/kucoin_futures.go index 2778143b2c1..a606cc6cfd0 100644 --- a/exchanges/kucoin/kucoin_futures.go +++ b/exchanges/kucoin/kucoin_futures.go @@ -791,10 +791,10 @@ func (ku *Kucoin) CancelFuturesTransferOut(ctx context.Context, applyID string) return ku.SendAuthHTTPRequest(ctx, exchange.RestFutures, defaultFuturesEPL, http.MethodDelete, common.EncodeURLValues(kucoinFuturesCancelTransferOut, params), nil, &resp) } -func processFuturesOB(ob [][2]float64) []orderbook.Item { - o := make([]orderbook.Item, len(ob)) +func processFuturesOB(ob [][2]float64) []orderbook.Tranche { + o := make([]orderbook.Tranche, len(ob)) for x := range ob { - o[x] = orderbook.Item{ + o[x] = orderbook.Tranche{ Price: ob[x][0], Amount: ob[x][1], } diff --git a/exchanges/kucoin/kucoin_types.go b/exchanges/kucoin/kucoin_types.go index 1f40c15e23d..779ef3b5ef9 100644 --- a/exchanges/kucoin/kucoin_types.go +++ b/exchanges/kucoin/kucoin_types.go @@ -135,8 +135,8 @@ type Stats24hrs struct { // Orderbook stores the orderbook data type Orderbook struct { Sequence int64 - Bids []orderbook.Item - Asks []orderbook.Item + Bids []orderbook.Tranche + Asks []orderbook.Tranche Time time.Time } @@ -1105,8 +1105,8 @@ type WsFuturesExecutionData struct { // WsOrderbookLevel5 represents an orderbook push data with depth level 5. type WsOrderbookLevel5 struct { Sequence int64 `json:"sequence"` - Asks []orderbook.Item `json:"asks"` - Bids []orderbook.Item `json:"bids"` + Asks []orderbook.Tranche `json:"asks"` + Bids []orderbook.Tranche `json:"bids"` PushTimestamp convert.ExchangeTime `json:"ts"` Timestamp convert.ExchangeTime `json:"timestamp"` } @@ -1127,16 +1127,16 @@ func (a *WsOrderbookLevel5Response) ExtractOrderbookItems() *WsOrderbookLevel5 { Sequence: a.Sequence, PushTimestamp: a.PushTimestamp, } - resp.Asks = make([]orderbook.Item, len(a.Asks)) + resp.Asks = make([]orderbook.Tranche, len(a.Asks)) for x := range a.Asks { - resp.Asks[x] = orderbook.Item{ + resp.Asks[x] = orderbook.Tranche{ Price: a.Asks[x][0].Float64(), Amount: a.Asks[x][1].Float64(), } } - resp.Bids = make([]orderbook.Item, len(a.Bids)) + resp.Bids = make([]orderbook.Tranche, len(a.Bids)) for x := range a.Bids { - resp.Bids[x] = orderbook.Item{ + resp.Bids[x] = orderbook.Tranche{ Price: a.Bids[x][0].Float64(), Amount: a.Bids[x][1].Float64(), } diff --git a/exchanges/kucoin/kucoin_websocket.go b/exchanges/kucoin/kucoin_websocket.go index 3f8a0c783ca..3d44228ef12 100644 --- a/exchanges/kucoin/kucoin_websocket.go +++ b/exchanges/kucoin/kucoin_websocket.go @@ -1204,7 +1204,7 @@ func (ku *Kucoin) setupOrderbookManager() { // ProcessUpdate processes the websocket orderbook update func (ku *Kucoin) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook) error { - updateBid := make([]orderbook.Item, len(ws.Changes.Bids)) + updateBid := make([]orderbook.Tranche, len(ws.Changes.Bids)) for i := range ws.Changes.Bids { p, err := strconv.ParseFloat(ws.Changes.Bids[i][0], 64) if err != nil { @@ -1221,10 +1221,10 @@ func (ku *Kucoin) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook) return err } } - updateBid[i] = orderbook.Item{Price: p, Amount: a, ID: sequence} + updateBid[i] = orderbook.Tranche{Price: p, Amount: a, ID: sequence} } - updateAsk := make([]orderbook.Item, len(ws.Changes.Asks)) + updateAsk := make([]orderbook.Tranche, len(ws.Changes.Asks)) for i := range ws.Changes.Asks { p, err := strconv.ParseFloat(ws.Changes.Asks[i][0], 64) if err != nil { @@ -1241,7 +1241,7 @@ func (ku *Kucoin) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WsOrderbook) return err } } - updateAsk[i] = orderbook.Item{Price: p, Amount: a, ID: sequence} + updateAsk[i] = orderbook.Tranche{Price: p, Amount: a, ID: sequence} } return ku.Websocket.Orderbook.Update(&orderbook.Update{ @@ -1363,17 +1363,17 @@ func (ku *Kucoin) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *Orderboo LastUpdated: time.Now(), LastUpdateID: orderbookNew.Sequence, VerifyOrderbook: ku.CanVerifyOrderbook, - Bids: make(orderbook.Items, len(orderbookNew.Bids)), - Asks: make(orderbook.Items, len(orderbookNew.Asks)), + Bids: make(orderbook.Tranches, len(orderbookNew.Bids)), + Asks: make(orderbook.Tranches, len(orderbookNew.Asks)), } for i := range orderbookNew.Bids { - newOrderBook.Bids[i] = orderbook.Item{ + newOrderBook.Bids[i] = orderbook.Tranche{ Amount: orderbookNew.Bids[i].Amount, Price: orderbookNew.Bids[i].Price, } } for i := range orderbookNew.Asks { - newOrderBook.Asks[i] = orderbook.Item{ + newOrderBook.Asks[i] = orderbook.Tranche{ Amount: orderbookNew.Asks[i].Amount, Price: orderbookNew.Asks[i].Price, } diff --git a/exchanges/lbank/lbank_wrapper.go b/exchanges/lbank/lbank_wrapper.go index 0e09c47201e..0c7fa85e1fc 100644 --- a/exchanges/lbank/lbank_wrapper.go +++ b/exchanges/lbank/lbank_wrapper.go @@ -265,7 +265,7 @@ func (l *Lbank) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType return book, err } - book.Asks = make(orderbook.Items, len(a.Data.Asks)) + book.Asks = make(orderbook.Tranches, len(a.Data.Asks)) for i := range a.Data.Asks { price, convErr := strconv.ParseFloat(a.Data.Asks[i][0], 64) if convErr != nil { @@ -275,12 +275,12 @@ func (l *Lbank) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if convErr != nil { return book, convErr } - book.Asks[i] = orderbook.Item{ + book.Asks[i] = orderbook.Tranche{ Price: price, Amount: amount, } } - book.Bids = make(orderbook.Items, len(a.Data.Bids)) + book.Bids = make(orderbook.Tranches, len(a.Data.Bids)) for i := range a.Data.Bids { price, convErr := strconv.ParseFloat(a.Data.Bids[i][0], 64) if convErr != nil { @@ -290,7 +290,7 @@ func (l *Lbank) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType if convErr != nil { return book, convErr } - book.Bids[i] = orderbook.Item{ + book.Bids[i] = orderbook.Tranche{ Price: price, Amount: amount, } diff --git a/exchanges/okcoin/okcoin_websocket.go b/exchanges/okcoin/okcoin_websocket.go index e714aba7d10..04ac1938e55 100644 --- a/exchanges/okcoin/okcoin_websocket.go +++ b/exchanges/okcoin/okcoin_websocket.go @@ -504,12 +504,12 @@ func (o *Okcoin) wsProcessOrderbook(respRaw []byte, obChannel string) error { Exchange: o.Name, LastUpdated: resp.Data[0].Timestamp.Time(), } - base.Asks = make([]orderbook.Item, len(resp.Data[0].Asks)) + base.Asks = make([]orderbook.Tranche, len(resp.Data[0].Asks)) for a := range resp.Data[0].Asks { base.Asks[a].Amount = resp.Data[0].Asks[a][1].Float64() base.Asks[a].Price = resp.Data[0].Asks[a][0].Float64() } - base.Bids = make([]orderbook.Item, len(resp.Data[0].Bids)) + base.Bids = make([]orderbook.Tranche, len(resp.Data[0].Bids)) for b := range resp.Data[0].Bids { base.Bids[b].Amount = resp.Data[0].Bids[b][1].Float64() base.Bids[b].Price = resp.Data[0].Bids[b][0].Float64() @@ -697,12 +697,12 @@ func (o *Okcoin) wsProcessCandles(respRaw []byte) error { // AppendWsOrderbookItems adds websocket orderbook data bid/asks into an // orderbook item array -func (o *Okcoin) AppendWsOrderbookItems(entries [][2]types.Number) ([]orderbook.Item, error) { - items := make([]orderbook.Item, len(entries)) +func (o *Okcoin) AppendWsOrderbookItems(entries [][2]types.Number) ([]orderbook.Tranche, error) { + items := make([]orderbook.Tranche, len(entries)) for j := range entries { amount := entries[j][1].Float64() price := entries[j][0].Float64() - items[j] = orderbook.Item{Amount: amount, Price: price} + items[j] = orderbook.Tranche{Amount: amount, Price: price} } return items, nil } diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index 8519cdc1b11..e791a81492b 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -432,7 +432,7 @@ func (o *Okcoin) UpdateOrderbook(ctx context.Context, p currency.Pair, a asset.I if err != nil { return nil, err } - book.Bids = make(orderbook.Items, len(orderbookList.Bids)) + book.Bids = make(orderbook.Tranches, len(orderbookList.Bids)) for x := range orderbookList.Bids { book.Bids[x].Amount, err = strconv.ParseFloat(orderbookList.Bids[x][1], 64) if err != nil { @@ -443,7 +443,7 @@ func (o *Okcoin) UpdateOrderbook(ctx context.Context, p currency.Pair, a asset.I return book, err } } - book.Asks = make(orderbook.Items, len(orderbookList.Asks)) + book.Asks = make(orderbook.Tranches, len(orderbookList.Asks)) for x := range orderbookList.Asks { book.Asks[x].Amount, err = strconv.ParseFloat(orderbookList.Asks[x][1], 64) if err != nil { diff --git a/exchanges/okx/okx_websocket.go b/exchanges/okx/okx_websocket.go index af43c2ce922..05c993c8a04 100644 --- a/exchanges/okx/okx_websocket.go +++ b/exchanges/okx/okx_websocket.go @@ -755,7 +755,7 @@ func (ok *Okx) wsProcessOrderbook5(data []byte) error { return err } - asks := make([]orderbook.Item, len(resp.Data[0].Asks)) + asks := make([]orderbook.Tranche, len(resp.Data[0].Asks)) for x := range resp.Data[0].Asks { asks[x].Price, err = strconv.ParseFloat(resp.Data[0].Asks[x][0], 64) if err != nil { @@ -768,7 +768,7 @@ func (ok *Okx) wsProcessOrderbook5(data []byte) error { } } - bids := make([]orderbook.Item, len(resp.Data[0].Bids)) + bids := make([]orderbook.Tranche, len(resp.Data[0].Bids)) for x := range resp.Data[0].Bids { bids[x].Price, err = strconv.ParseFloat(resp.Data[0].Bids[x][0], 64) if err != nil { @@ -929,8 +929,8 @@ func (ok *Okx) WsProcessUpdateOrderbook(data WsOrderBookData, pair currency.Pair } // AppendWsOrderbookItems adds websocket orderbook data bid/asks into an orderbook item array -func (ok *Okx) AppendWsOrderbookItems(entries [][4]string) ([]orderbook.Item, error) { - items := make([]orderbook.Item, len(entries)) +func (ok *Okx) AppendWsOrderbookItems(entries [][4]string) ([]orderbook.Tranche, error) { + items := make([]orderbook.Tranche, len(entries)) for j := range entries { amount, err := strconv.ParseFloat(entries[j][1], 64) if err != nil { @@ -940,7 +940,7 @@ func (ok *Okx) AppendWsOrderbookItems(entries [][4]string) ([]orderbook.Item, er if err != nil { return nil, err } - items[j] = orderbook.Item{Amount: amount, Price: price} + items[j] = orderbook.Tranche{Amount: amount, Price: price} } return items, nil } diff --git a/exchanges/okx/okx_wrapper.go b/exchanges/okx/okx_wrapper.go index dbc49b73a12..841002cd062 100644 --- a/exchanges/okx/okx_wrapper.go +++ b/exchanges/okx/okx_wrapper.go @@ -495,16 +495,16 @@ func (ok *Okx) UpdateOrderbook(ctx context.Context, pair currency.Pair, assetTyp if err != nil { return nil, err } - book.Bids = make(orderbook.Items, len(orderBookD.Bids)) + book.Bids = make(orderbook.Tranches, len(orderBookD.Bids)) for x := range orderBookD.Bids { - book.Bids[x] = orderbook.Item{ + book.Bids[x] = orderbook.Tranche{ Amount: orderBookD.Bids[x].BaseCurrencies, Price: orderBookD.Bids[x].DepthPrice, } } - book.Asks = make(orderbook.Items, len(orderBookD.Asks)) + book.Asks = make(orderbook.Tranches, len(orderBookD.Asks)) for x := range orderBookD.Asks { - book.Asks[x] = orderbook.Item{ + book.Asks[x] = orderbook.Tranche{ Amount: orderBookD.Asks[x].NumberOfContracts, Price: orderBookD.Asks[x].DepthPrice, } diff --git a/exchanges/poloniex/poloniex_websocket.go b/exchanges/poloniex/poloniex_websocket.go index 1be429a58ef..74bdc8178d6 100644 --- a/exchanges/poloniex/poloniex_websocket.go +++ b/exchanges/poloniex/poloniex_websocket.go @@ -434,7 +434,7 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error { } var book orderbook.Base - book.Asks = make(orderbook.Items, 0, len(askData)) + book.Asks = make(orderbook.Tranches, 0, len(askData)) for price, volume := range askData { var p float64 p, err = strconv.ParseFloat(price, 64) @@ -451,10 +451,10 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error { if err != nil { return err } - book.Asks = append(book.Asks, orderbook.Item{Price: p, Amount: a}) + book.Asks = append(book.Asks, orderbook.Tranche{Price: p, Amount: a}) } - book.Bids = make(orderbook.Items, 0, len(bidData)) + book.Bids = make(orderbook.Tranches, 0, len(bidData)) for price, volume := range bidData { var p float64 p, err = strconv.ParseFloat(price, 64) @@ -471,7 +471,7 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error { if err != nil { return err } - book.Bids = append(book.Bids, orderbook.Item{Price: p, Amount: a}) + book.Bids = append(book.Bids, orderbook.Tranche{Price: p, Amount: a}) } // Both sides are completely out of order - sort needs to be used @@ -533,9 +533,9 @@ func (p *Poloniex) WsProcessOrderbookUpdate(sequenceNumber float64, data []inter UpdateTime: time.UnixMilli(tsMilli), } if bs == 1 { - update.Bids = []orderbook.Item{{Price: price, Amount: volume}} + update.Bids = []orderbook.Tranche{{Price: price, Amount: volume}} } else { - update.Asks = []orderbook.Item{{Price: price, Amount: volume}} + update.Asks = []orderbook.Tranche{{Price: price, Amount: volume}} } return p.Websocket.Orderbook.Update(update) } diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index 97eb9293d56..7082c2a624f 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -356,17 +356,17 @@ func (p *Poloniex) UpdateOrderbook(ctx context.Context, pair currency.Pair, asse VerifyOrderbook: p.CanVerifyOrderbook, } - book.Bids = make(orderbook.Items, len(data.Bids)) + book.Bids = make(orderbook.Tranches, len(data.Bids)) for y := range data.Bids { - book.Bids[y] = orderbook.Item{ + book.Bids[y] = orderbook.Tranche{ Amount: data.Bids[y].Amount, Price: data.Bids[y].Price, } } - book.Asks = make(orderbook.Items, len(data.Asks)) + book.Asks = make(orderbook.Tranches, len(data.Asks)) for y := range data.Asks { - book.Asks[y] = orderbook.Item{ + book.Asks[y] = orderbook.Tranche{ Amount: data.Asks[y].Amount, Price: data.Asks[y].Price, } diff --git a/exchanges/stream/buffer/buffer.go b/exchanges/stream/buffer/buffer.go index 57c2b5fd437..c2fb1ce36ed 100644 --- a/exchanges/stream/buffer/buffer.go +++ b/exchanges/stream/buffer/buffer.go @@ -87,7 +87,7 @@ func (w *Orderbook) validate(u *orderbook.Update) error { } // Update updates a stored pointer to an orderbook.Depth struct containing a -// linked list, this switches between the usage of a buffered update +// bid and ask Tranches, this switches between the usage of a buffered update func (w *Orderbook) Update(u *orderbook.Update) error { if err := w.validate(u); err != nil { return err @@ -304,7 +304,7 @@ func (o *orderbookHolder) updateByIDAndAction(updts *orderbook.Update) error { // LoadSnapshot loads initial snapshot of orderbook data from websocket func (w *Orderbook) LoadSnapshot(book *orderbook.Base) error { - // Checks if book can deploy to linked list + // Checks if book can deploy to depth err := book.Verify() if err != nil { return err diff --git a/exchanges/stream/buffer/buffer_test.go b/exchanges/stream/buffer/buffer_test.go index 3378ebe30ba..3a57e6e46bf 100644 --- a/exchanges/stream/buffer/buffer_test.go +++ b/exchanges/stream/buffer/buffer_test.go @@ -15,7 +15,7 @@ import ( ) var ( - itemArray = [][]orderbook.Item{ + itemArray = [][]orderbook.Tranche{ {{Price: 1000, Amount: 1, ID: 1000}}, {{Price: 2000, Amount: 1, ID: 2000}}, {{Price: 3000, Amount: 1, ID: 3000}}, @@ -31,9 +31,9 @@ const ( exchangeName = "exchangeTest" ) -func createSnapshot() (holder *Orderbook, asks, bids orderbook.Items, err error) { - asks = orderbook.Items{{Price: 4000, Amount: 1, ID: 6}} - bids = orderbook.Items{{Price: 4000, Amount: 1, ID: 6}} +func createSnapshot() (holder *Orderbook, asks, bids orderbook.Tranches, err error) { + asks = orderbook.Tranches{{Price: 4000, Amount: 1, ID: 6}} + bids = orderbook.Tranches{{Price: 4000, Amount: 1, ID: 6}} book := &orderbook.Base{ Exchange: exchangeName, @@ -62,15 +62,15 @@ func createSnapshot() (holder *Orderbook, asks, bids orderbook.Items, err error) return holder, asks, bids, err } -func bidAskGenerator() []orderbook.Item { - var response []orderbook.Item +func bidAskGenerator() []orderbook.Tranche { + var response []orderbook.Tranche randIterator := 100 for i := 0; i < randIterator; i++ { price := float64(rand.Intn(1000)) //nolint:gosec // no need to import crypo/rand for testing if price == 0 { price = 1 } - response = append(response, orderbook.Item{ + response = append(response, orderbook.Tranche{ Amount: float64(rand.Intn(10)), //nolint:gosec // no need to import crypo/rand for testing Price: price, ID: int64(i), @@ -464,7 +464,7 @@ func TestOrderbookLastUpdateID(t *testing.T) { // this update invalidates the book err = holder.Update(&orderbook.Update{ - Asks: []orderbook.Item{{Price: 999999}}, + Asks: []orderbook.Tranche{{Price: 999999}}, Pair: cp, UpdateID: -1, Asset: asset.Spot, @@ -498,7 +498,7 @@ func TestOrderbookLastUpdateID(t *testing.T) { // out of order err = holder.Update(&orderbook.Update{ - Asks: []orderbook.Item{{Price: 999999}}, + Asks: []orderbook.Tranche{{Price: 999999}}, Pair: cp, UpdateID: 1, Asset: asset.Spot, @@ -521,10 +521,10 @@ func TestRunUpdateWithoutSnapshot(t *testing.T) { t.Parallel() var holder Orderbook var snapShot1 orderbook.Base - asks := []orderbook.Item{ + asks := []orderbook.Tranche{ {Price: 4000, Amount: 1, ID: 8}, } - bids := []orderbook.Item{ + bids := []orderbook.Tranche{ {Price: 5999, Amount: 1, ID: 8}, {Price: 4000, Amount: 1, ID: 9}, } @@ -550,8 +550,8 @@ func TestRunUpdateWithoutAnyUpdates(t *testing.T) { t.Parallel() var obl Orderbook var snapShot1 orderbook.Base - snapShot1.Asks = []orderbook.Item{} - snapShot1.Bids = []orderbook.Item{} + snapShot1.Asks = []orderbook.Tranche{} + snapShot1.Bids = []orderbook.Tranche{} snapShot1.Asset = asset.Spot snapShot1.Pair = cp obl.exchangeName = exchangeName @@ -593,10 +593,10 @@ func TestLoadSnapshot(t *testing.T) { obl.ob = make(map[key.PairAsset]*orderbookHolder) var snapShot1 orderbook.Base snapShot1.Exchange = "SnapshotWithOverride" - asks := []orderbook.Item{ + asks := []orderbook.Tranche{ {Price: 4000, Amount: 1, ID: 8}, } - bids := []orderbook.Item{ + bids := []orderbook.Tranche{ {Price: 4000, Amount: 1, ID: 9}, } snapShot1.Asks = asks @@ -633,7 +633,7 @@ func TestInsertingSnapShots(t *testing.T) { holder.ob = make(map[key.PairAsset]*orderbookHolder) var snapShot1 orderbook.Base snapShot1.Exchange = "WSORDERBOOKTEST1" - asks := []orderbook.Item{ + asks := []orderbook.Tranche{ {Price: 6000, Amount: 1, ID: 1}, {Price: 6001, Amount: 0.5, ID: 2}, {Price: 6002, Amount: 2, ID: 3}, @@ -647,7 +647,7 @@ func TestInsertingSnapShots(t *testing.T) { {Price: 6010, Amount: 7, ID: 11}, } - bids := []orderbook.Item{ + bids := []orderbook.Tranche{ {Price: 5999, Amount: 1, ID: 12}, {Price: 5998, Amount: 0.5, ID: 13}, {Price: 5997, Amount: 2, ID: 14}, @@ -672,7 +672,7 @@ func TestInsertingSnapShots(t *testing.T) { } var snapShot2 orderbook.Base snapShot2.Exchange = "WSORDERBOOKTEST2" - asks = []orderbook.Item{ + asks = []orderbook.Tranche{ {Price: 51, Amount: 1, ID: 1}, {Price: 52, Amount: 0.5, ID: 2}, {Price: 53, Amount: 2, ID: 3}, @@ -686,7 +686,7 @@ func TestInsertingSnapShots(t *testing.T) { {Price: 60, Amount: 7, ID: 11}, } - bids = []orderbook.Item{ + bids = []orderbook.Tranche{ {Price: 49, Amount: 1, ID: 12}, {Price: 48, Amount: 0.5, ID: 13}, {Price: 47, Amount: 2, ID: 14}, @@ -716,7 +716,7 @@ func TestInsertingSnapShots(t *testing.T) { } var snapShot3 orderbook.Base snapShot3.Exchange = "WSORDERBOOKTEST3" - asks = []orderbook.Item{ + asks = []orderbook.Tranche{ {Price: 511, Amount: 1, ID: 1}, {Price: 52, Amount: 0.5, ID: 2}, {Price: 53, Amount: 2, ID: 3}, @@ -730,7 +730,7 @@ func TestInsertingSnapShots(t *testing.T) { {Price: 60, Amount: 7, ID: 11}, } - bids = []orderbook.Item{ + bids = []orderbook.Tranche{ {Price: 49, Amount: 1, ID: 12}, {Price: 48, Amount: 0.5, ID: 13}, {Price: 47, Amount: 2, ID: 14}, @@ -911,10 +911,10 @@ func TestEnsureMultipleUpdatesViaPrice(t *testing.T) { } } -func deploySliceOrdered(size int) orderbook.Items { - var items []orderbook.Item +func deploySliceOrdered(size int) orderbook.Tranches { + var items []orderbook.Tranche for i := 0; i < size; i++ { - items = append(items, orderbook.Item{Amount: 1, Price: rand.Float64() + float64(i), ID: rand.Int63()}) //nolint:gosec // Not needed for tests + items = append(items, orderbook.Tranche{Amount: 1, Price: rand.Float64() + float64(i), ID: rand.Int63()}) //nolint:gosec // Not needed for tests } return items } @@ -957,7 +957,7 @@ func TestUpdateByIDAndAction(t *testing.T) { err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.Amend, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ { Price: 100, ID: 6969, @@ -975,14 +975,14 @@ func TestUpdateByIDAndAction(t *testing.T) { // append to slice err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.UpdateInsert, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ { Price: 0, ID: 1337, Amount: 1, }, }, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ { Price: 100, ID: 1337, @@ -1010,14 +1010,14 @@ func TestUpdateByIDAndAction(t *testing.T) { // Change amount err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.UpdateInsert, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ { Price: 0, ID: 1337, Amount: 100, }, }, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ { Price: 100, ID: 1337, @@ -1046,14 +1046,14 @@ func TestUpdateByIDAndAction(t *testing.T) { // Change price level err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.UpdateInsert, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ { Price: 100, ID: 1337, Amount: 99, }, }, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ { Price: 0, ID: 1337, @@ -1086,7 +1086,7 @@ func TestUpdateByIDAndAction(t *testing.T) { // Delete - not found err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.Delete, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ { Price: 0, ID: 1337, @@ -1105,7 +1105,7 @@ func TestUpdateByIDAndAction(t *testing.T) { // Delete - found err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.Delete, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ asks[0], }, UpdateTime: time.Now(), @@ -1126,7 +1126,7 @@ func TestUpdateByIDAndAction(t *testing.T) { // Apply update err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.Amend, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ {ID: 123456}, }, }) @@ -1152,7 +1152,7 @@ func TestUpdateByIDAndAction(t *testing.T) { err = holder.updateByIDAndAction(&orderbook.Update{ Action: orderbook.Amend, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ update, }, UpdateTime: time.Now(), @@ -1181,10 +1181,10 @@ func TestFlushOrderbook(t *testing.T) { var snapShot1 orderbook.Base snapShot1.Exchange = "Snapshooooot" - asks := []orderbook.Item{ + asks := []orderbook.Tranche{ {Price: 4000, Amount: 1, ID: 8}, } - bids := []orderbook.Item{ + bids := []orderbook.Tranche{ {Price: 4000, Amount: 1, ID: 9}, } snapShot1.Asks = asks diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 553cb81f8fd..76ee16b1949 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -257,7 +257,7 @@ func (y *Yobit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType for i := range orderbookNew.Bids { book.Bids = append(book.Bids, - orderbook.Item{ + orderbook.Tranche{ Price: orderbookNew.Bids[i][0], Amount: orderbookNew.Bids[i][1], }) @@ -265,7 +265,7 @@ func (y *Yobit) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType for i := range orderbookNew.Asks { book.Asks = append(book.Asks, - orderbook.Item{ + orderbook.Tranche{ Price: orderbookNew.Asks[i][0], Amount: orderbookNew.Asks[i][1], }) diff --git a/gctscript/wrappers/validator/validator.go b/gctscript/wrappers/validator/validator.go index 94b58912b38..6e8cb621ba4 100644 --- a/gctscript/wrappers/validator/validator.go +++ b/gctscript/wrappers/validator/validator.go @@ -55,13 +55,13 @@ func (w Wrapper) Orderbook(_ context.Context, exch string, pair currency.Pair, i Exchange: exch, Asset: item, Pair: pair, - Bids: []orderbook.Item{ + Bids: []orderbook.Tranche{ { Amount: 1, Price: 1, }, }, - Asks: []orderbook.Item{ + Asks: []orderbook.Tranche{ { Amount: 1, Price: 1, From 7296992825a4746852728d3819b87808d32b5bf9 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 12:30:39 +1100 Subject: [PATCH 04/13] linterino --- exchanges/orderbook/Tranches.go | 12 ++++++------ exchanges/orderbook/orderbook.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/exchanges/orderbook/Tranches.go b/exchanges/orderbook/Tranches.go index 017b426168a..071ef9b787c 100644 --- a/exchanges/orderbook/Tranches.go +++ b/exchanges/orderbook/Tranches.go @@ -110,20 +110,20 @@ func (ts Tranches) amount() (liquidity, value float64) { return } -// retrieve returns a a slice of contents from the stored Tranches up to the +// retrieve returns a slice of contents from the stored Tranches up to the // count length. If count is zero or greater than the length of the stored // Tranches, the entire slice is returned. -func (ll Tranches) retrieve(count int) Tranches { - if count == 0 || len(ll) <= count { +func (ts Tranches) retrieve(count int) Tranches { + if count == 0 || len(ts) <= count { // In this situation we have to allocate a new slice to prevent the // caller from modifying the underlying array. - bucket := make(Tranches, len(ll)) - copy(bucket, ll) + bucket := make(Tranches, len(ts)) + copy(bucket, ts) return bucket } // This will auto allocate a slice because it is a reduction of the // underlying array. - return ll[:count] + return ts[:count] } // updateInsertByPrice amends, inserts, moves and cleaves length of depth by diff --git a/exchanges/orderbook/orderbook.go b/exchanges/orderbook/orderbook.go index 03cce25ce47..bd6afbceb67 100644 --- a/exchanges/orderbook/orderbook.go +++ b/exchanges/orderbook/orderbook.go @@ -339,13 +339,13 @@ func (ts *Tranches) Reverse() { // SortAsks sorts ask items to the correct ascending order if pricing values are // scattered. If order from exchange is descending consider using the Reverse // function. -func (elem Tranches) SortAsks() { - sort.Slice(elem, func(i, j int) bool { return elem[i].Price < elem[j].Price }) +func (ts Tranches) SortAsks() { + sort.Slice(ts, func(i, j int) bool { return ts[i].Price < ts[j].Price }) } // SortBids sorts bid items to the correct descending order if pricing values // are scattered. If order from exchange is ascending consider using the Reverse // function. -func (elem Tranches) SortBids() { - sort.Slice(elem, func(i, j int) bool { return elem[i].Price > elem[j].Price }) +func (ts Tranches) SortBids() { + sort.Slice(ts, func(i, j int) bool { return ts[i].Price > ts[j].Price }) } From bf1ddfd22043b8fd2abb62c99f0b18551811fbd7 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 12:32:20 +1100 Subject: [PATCH 05/13] rn silly billy label --- exchanges/orderbook/Tranches.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exchanges/orderbook/Tranches.go b/exchanges/orderbook/Tranches.go index 071ef9b787c..13dc642b4f1 100644 --- a/exchanges/orderbook/Tranches.go +++ b/exchanges/orderbook/Tranches.go @@ -129,7 +129,7 @@ func (ts Tranches) retrieve(count int) Tranches { // updateInsertByPrice amends, inserts, moves and cleaves length of depth by // updates func (ts *Tranches) updateInsertByPrice(updts Tranches, maxChainLength int, compare func(float64, float64) bool) { -updateroo: +updates: for x := range updts { for y := range *ts { switch { @@ -146,14 +146,14 @@ updateroo: (*ts)[y].Amount = updts[x].Amount (*ts)[y].StrAmount = updts[x].StrAmount } - continue updateroo + continue updates case compare((*ts)[y].Price, updts[x].Price): if updts[x].Amount > 0 { *ts = append(*ts, Tranche{}) // Extend copy((*ts)[y+1:], (*ts)[y:]) // Copy elements from index y onwards one position to the right (*ts)[y] = updts[x] // Insert updts[x] at index y } - continue updateroo + continue updates } } if updts[x].Amount > 0 { @@ -221,7 +221,7 @@ updates: // insertUpdates inserts new updates for bids or asks based on price level func (ts *Tranches) insertUpdates(updts Tranches, comp comparison) error { -updaterino: +updates: for x := range updts { if len(*ts) == 0 { *ts = append(*ts, updts[x]) @@ -234,7 +234,7 @@ updaterino: return fmt.Errorf("%w for price %f", errCollisionDetected, updts[x].Price) case comp((*ts)[y].Price, updts[x].Price): // price at correct spot *ts = append((*ts)[:y], append([]Tranche{updts[x]}, (*ts)[y:]...)...) - continue updaterino + continue updates } } *ts = append(*ts, updts[x]) From a92c4270a822dd0d39268864aaa7aa6aaf04e875 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 12:35:22 +1100 Subject: [PATCH 06/13] linter strikes AAAAAGAIN! --- exchanges/orderbook/tranches_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exchanges/orderbook/tranches_test.go b/exchanges/orderbook/tranches_test.go index 65d25d91d31..4a8103db3e4 100644 --- a/exchanges/orderbook/tranches_test.go +++ b/exchanges/orderbook/tranches_test.go @@ -56,9 +56,9 @@ var bid = Tranches{ } // Display displays depth content for tests -func (ll Tranches) display() { - for x := range ll { - fmt.Printf("NODE: %+v %p \n", ll[x], &ll[x]) +func (ts Tranches) display() { + for x := range ts { + fmt.Printf("Tranche: %+v %p \n", ts[x], &ts[x]) } fmt.Println() } From a65b4719ef8962414644056e49c274d809992b91 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 14:02:24 +1100 Subject: [PATCH 07/13] fix some things --- exchanges/orderbook/Tranches.go | 24 ++++++++++++------------ exchanges/orderbook/tranches_test.go | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/exchanges/orderbook/Tranches.go b/exchanges/orderbook/Tranches.go index 13dc642b4f1..0e333983b42 100644 --- a/exchanges/orderbook/Tranches.go +++ b/exchanges/orderbook/Tranches.go @@ -89,7 +89,12 @@ updates: continue } - *ts = append((*ts)[:y], (*ts)[y+1:]...) + if y < len(*ts) { + copy((*ts)[y:], (*ts)[y+1:]) + *ts = (*ts)[:len(*ts)-1] + } else { + *ts = append((*ts)[:y], (*ts)[y+1:]...) + } continue updates } if !bypassErr { @@ -114,16 +119,10 @@ func (ts Tranches) amount() (liquidity, value float64) { // count length. If count is zero or greater than the length of the stored // Tranches, the entire slice is returned. func (ts Tranches) retrieve(count int) Tranches { - if count == 0 || len(ts) <= count { - // In this situation we have to allocate a new slice to prevent the - // caller from modifying the underlying array. - bucket := make(Tranches, len(ts)) - copy(bucket, ts) - return bucket - } - // This will auto allocate a slice because it is a reduction of the - // underlying array. - return ts[:count] + if count == 0 || count >= len(ts) { + count = len(ts) + } + return append(Tranches{}, ts[:count]...) } // updateInsertByPrice amends, inserts, moves and cleaves length of depth by @@ -139,7 +138,8 @@ updates: if y+1 == len(*ts) { *ts = (*ts)[:y] } else { - *ts = append((*ts)[:y], (*ts)[y+1:]...) + copy((*ts)[y:], (*ts)[y+1:]) + *ts = (*ts)[:len(*ts)-1] } } else { // Update diff --git a/exchanges/orderbook/tranches_test.go b/exchanges/orderbook/tranches_test.go index 4a8103db3e4..ee75b9adeec 100644 --- a/exchanges/orderbook/tranches_test.go +++ b/exchanges/orderbook/tranches_test.go @@ -414,7 +414,7 @@ func TestDeleteByID(t *testing.T) { } } -// 20476837 53.17 ns/op 0 B/op 0 allocs/op +// 26724331 44.69 ns/op 0 B/op 0 allocs/op func BenchmarkDeleteByID(b *testing.B) { asks := Tranches{} asksSnapshot := Tranches{ @@ -1870,3 +1870,21 @@ func TestFinalizeFields(t *testing.T) { assert.NoError(t, err, "finalizeFields should not error") assert.InDelta(t, 717.0, mov.SlippageCost, 0.000000001, "SlippageCost should be correct") } + +// 8384302 150.9 ns/op 480 B/op 1 allocs/op +func BenchmarkRetrieve(b *testing.B) { + asks := Tranches{} + asksSnapshot := Tranches{ + {Price: 1, Amount: 1, ID: 1}, + {Price: 3, Amount: 1, ID: 3}, + {Price: 5, Amount: 1, ID: 5}, + {Price: 7, Amount: 1, ID: 7}, + {Price: 9, Amount: 1, ID: 9}, + {Price: 11, Amount: 1, ID: 11}, + } + asks.load(asksSnapshot) + + for i := 0; i < b.N; i++ { + _ = asks.retrieve(6) + } +} From 96446305a4c4d2b9315c777df6e85d777898c583 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Fri, 2 Feb 2024 14:13:39 +1100 Subject: [PATCH 08/13] rm comment --- exchanges/orderbook/depth.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/exchanges/orderbook/depth.go b/exchanges/orderbook/depth.go index eb47c9f4a65..e58ce0a8c59 100644 --- a/exchanges/orderbook/depth.go +++ b/exchanges/orderbook/depth.go @@ -36,9 +36,6 @@ type Depth struct { askTranches bidTranches - // // unexported stack of nodes - // stack *stack - alert.Notice mux *dispatch.Mux From bc039c9ccdc116946363a8f6d0013cf28167e8d0 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 5 Feb 2024 16:22:41 +1100 Subject: [PATCH 09/13] Add actual comparison from master to branch benchmark for sorting algorithms --- exchanges/orderbook/orderbook_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/exchanges/orderbook/orderbook_test.go b/exchanges/orderbook/orderbook_test.go index da9c454580e..ad3c1a75779 100644 --- a/exchanges/orderbook/orderbook_test.go +++ b/exchanges/orderbook/orderbook_test.go @@ -668,7 +668,7 @@ func BenchmarkReverse(b *testing.B) { } } -// 20209 56385 ns/op 49189 B/op 2 allocs/op (old) +// 361266 3556 ns/op 24 B/op 1 allocs/op (old) // 385783 3000 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortAsksDecending(b *testing.B) { s := deploySliceOrdered() @@ -679,7 +679,7 @@ func BenchmarkSortAsksDecending(b *testing.B) { } } -// 14924 79199 ns/op 49206 B/op 3 allocs/op (old) +// 266998 4292 ns/op 40 B/op 2 allocs/op (old) // 372396 3001 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortBidsAscending(b *testing.B) { s := deploySliceOrdered() @@ -691,7 +691,7 @@ func BenchmarkSortBidsAscending(b *testing.B) { } } -// 9842 133761 ns/op 49194 B/op 2 allocs/op (old) +// 22119 46532 ns/op 35 B/op 1 allocs/op (old) // 16233 76951 ns/op 167 B/op 3 allocs/op (new) func BenchmarkSortAsksStandard(b *testing.B) { s := deployUnorderedSlice() @@ -702,7 +702,7 @@ func BenchmarkSortAsksStandard(b *testing.B) { } } -// 7058 155057 ns/op 49214 B/op 3 allocs/op (old) +// 19504 62518 ns/op 53 B/op 2 allocs/op (old) // 15698 72859 ns/op 168 B/op 3 allocs/op (new) func BenchmarkSortBidsStandard(b *testing.B) { s := deployUnorderedSlice() @@ -713,7 +713,7 @@ func BenchmarkSortBidsStandard(b *testing.B) { } } -// 20565 57001 ns/op 49188 B/op 2 allocs/op (old) +// 376708 3559 ns/op 24 B/op 1 allocs/op (old) // 377113 3020 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortAsksAscending(b *testing.B) { s := deploySliceOrdered() @@ -724,7 +724,7 @@ func BenchmarkSortAsksAscending(b *testing.B) { } } -// 12565 97257 ns/op 49208 B/op 3 allocs/op (old) +// 262874 4364 ns/op 40 B/op 2 allocs/op (old) // 401788 3348 ns/op 152 B/op 3 allocs/op (new) func BenchmarkSortBidsDescending(b *testing.B) { s := deploySliceOrdered() From 56d8496f5ca7a8f3013d5c7ab048f34f946ff8c3 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 5 Feb 2024 16:33:20 +1100 Subject: [PATCH 10/13] lower case via git mv YAAY! --- exchanges/orderbook/{Tranches.go => tranches.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exchanges/orderbook/{Tranches.go => tranches.go} (100%) diff --git a/exchanges/orderbook/Tranches.go b/exchanges/orderbook/tranches.go similarity index 100% rename from exchanges/orderbook/Tranches.go rename to exchanges/orderbook/tranches.go From a52c2f4ba4604093f8cb05a4e6aca8d3fc131ada Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 5 Feb 2024 16:44:11 +1100 Subject: [PATCH 11/13] drop code --- exchanges/orderbook/tranches.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/exchanges/orderbook/tranches.go b/exchanges/orderbook/tranches.go index 0e333983b42..b077440a15d 100644 --- a/exchanges/orderbook/tranches.go +++ b/exchanges/orderbook/tranches.go @@ -46,13 +46,8 @@ func (ts *Tranches) load(incoming Tranches) { *ts = (*ts)[:len(incoming)] // Flush excess return } - if len(incoming) > cap(*ts) { - *ts = make([]Tranche, len(incoming)) // Extend - copy(*ts, incoming) // Copy - return - } - *ts = (*ts)[:0] // Flush - *ts = append(*ts, incoming...) // Append + *ts = make([]Tranche, len(incoming)) // Extend + copy(*ts, incoming) // Copy } // updateByID amends price by corresponding ID and returns an error if not found From 5355274b8388dec9be1d59cbd2c78d8c4ca93cea Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 18 Mar 2024 10:56:50 +1100 Subject: [PATCH 12/13] convert type name --- exchanges/kucoin/kucoin_websocket.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exchanges/kucoin/kucoin_websocket.go b/exchanges/kucoin/kucoin_websocket.go index ec5ee337467..a11aba0def0 100644 --- a/exchanges/kucoin/kucoin_websocket.go +++ b/exchanges/kucoin/kucoin_websocket.go @@ -879,13 +879,13 @@ func (ku *Kucoin) processOrderbook(respData []byte, symbol, topic string) error return err } - asks := make([]orderbook.Item, len(response.Asks)) + asks := make([]orderbook.Tranche, len(response.Asks)) for x := range response.Asks { asks[x].Price = response.Asks[x][0].Float64() asks[x].Amount = response.Asks[x][1].Float64() } - bids := make([]orderbook.Item, len(response.Bids)) + bids := make([]orderbook.Tranche, len(response.Bids)) for x := range response.Bids { bids[x].Price = response.Bids[x][0].Float64() bids[x].Amount = response.Bids[x][1].Float64() From 8cca05f1628451aebac648c14bbd4f9069b0b9d8 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Mon, 18 Mar 2024 10:59:24 +1100 Subject: [PATCH 13/13] glorious: nits --- exchanges/kraken/kraken_test.go | 2 +- exchanges/orderbook/depth.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index e2e6795f3a4..920e6664ea5 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -2151,7 +2151,7 @@ func TestWsOrderbookMax10Depth(t *testing.T) { err := k.wsHandleData([]byte(websocketLUNAEUROrderbookUpdates[x])) // TODO: Known issue with LUNA pairs and big number float precision // storage and checksum calc. Might need to store raw strings as fields - // in the orderbook.Item struct. + // in the orderbook.Tranche struct. // Required checksum: 7465000014735432016076747100005084881400000007476000097005027047670474990000293338023886300750000004333333333333375020000152914844934167507000014652990542161752500007370728572000475400000670061645671407546000098022663603417745900007102987806720745800001593557686404000745200003375861179634000743500003156650585902777434000030172726079999999743200006461149653837000743100001042285966000000074300000403660461058200074200000369021657320475740500001674242117790510 if err != nil && x != len(websocketLUNAEUROrderbookUpdates)-1 { t.Fatal(err) diff --git a/exchanges/orderbook/depth.go b/exchanges/orderbook/depth.go index e58ce0a8c59..13fd1cfcd48 100644 --- a/exchanges/orderbook/depth.go +++ b/exchanges/orderbook/depth.go @@ -50,7 +50,9 @@ type Depth struct { } // NewDepth returns a new orderbook depth -func NewDepth(id uuid.UUID) *Depth { return &Depth{_ID: id, mux: service.Mux} } +func NewDepth(id uuid.UUID) *Depth { + return &Depth{_ID: id, mux: service.Mux} +} // Publish alerts any subscribed routines using a dispatch mux func (d *Depth) Publish() {