mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-21 23:16:49 +00:00
orderbook: Check assignment of time values and reject if not set (#1318)
* orderbook: Check assignment of time values and reject if not set. * linter: fix * buffer: additional linter winter fixter * Implement through pending exchanges * finished push * linty: minty * gomod: tidy * thrasher: nits * glorious: nits * orderbook: purge type now in favour of external call allocation * orderbook: push last param * orderbook: only 1 unlock call is needed --------- Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
This commit is contained in:
@@ -3461,7 +3461,10 @@ func TestGetOrderbookMovement(t *testing.T) {
|
||||
{Price: 13, Amount: 1},
|
||||
{Price: 14, Amount: 1},
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = s.GetOrderbookMovement(context.Background(), req)
|
||||
if err.Error() != "quote amount invalid" {
|
||||
@@ -3571,7 +3574,10 @@ func TestGetOrderbookAmountByNominal(t *testing.T) {
|
||||
{Price: 13, Amount: 1},
|
||||
{Price: 14, Amount: 1},
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nominal, err := s.GetOrderbookAmountByNominal(context.Background(), req)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -3674,7 +3680,10 @@ func TestGetOrderbookAmountByImpact(t *testing.T) {
|
||||
{Price: 13, Amount: 1},
|
||||
{Price: 14, Amount: 1},
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req.ImpactPercentage = 9.090909090909092
|
||||
impact, err := s.GetOrderbookAmountByImpact(context.Background(), req)
|
||||
|
||||
@@ -2123,7 +2123,7 @@ func TestWsDepthUpdate(t *testing.T) {
|
||||
|
||||
p := currency.NewPairWithDelimiter("BTC", "USDT", "-")
|
||||
if err := b.SeedLocalCacheWithBook(p, &book); err != nil {
|
||||
t.Error(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := b.wsHandleData(update1); err != nil {
|
||||
|
||||
@@ -494,6 +494,7 @@ func (b *Binance) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *OrderBoo
|
||||
VerifyOrderbook: b.CanVerifyOrderbook,
|
||||
Bids: make(orderbook.Items, len(orderbookNew.Bids)),
|
||||
Asks: make(orderbook.Items, len(orderbookNew.Asks)),
|
||||
LastUpdated: time.Now(), // Time not provided in REST book.
|
||||
}
|
||||
for i := range orderbookNew.Bids {
|
||||
newOrderBook.Bids[i] = orderbook.Item{
|
||||
|
||||
@@ -1450,7 +1450,7 @@ func TestWebsocketOrderBookDepthDiffStream(t *testing.T) {
|
||||
|
||||
p := currency.NewPairWithDelimiter("BTC", "USDT", "-")
|
||||
if err := bi.SeedLocalCacheWithBook(p, &book); err != nil {
|
||||
t.Error(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := bi.wsHandleData(update1); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -845,6 +845,7 @@ func (bi *Binanceus) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *Order
|
||||
VerifyOrderbook: bi.CanVerifyOrderbook,
|
||||
Bids: make(orderbook.Items, len(orderbookNew.Bids)),
|
||||
Asks: make(orderbook.Items, len(orderbookNew.Asks)),
|
||||
LastUpdated: time.Now(), // Time not provided in REST book.
|
||||
}
|
||||
for i := range orderbookNew.Bids {
|
||||
newOrderBook.Bids[i] = orderbook.Item{
|
||||
|
||||
@@ -1439,7 +1439,7 @@ func (b *Bitfinex) WsInsertSnapshot(p currency.Pair, assetType asset.Item, books
|
||||
book.PriceDuplication = true
|
||||
book.IsFundingRate = fundingRate
|
||||
book.VerifyOrderbook = b.CanVerifyOrderbook
|
||||
book.LastUpdated = time.Now()
|
||||
book.LastUpdated = time.Now() // Not included in snapshot
|
||||
return b.Websocket.Orderbook.LoadSnapshot(&book)
|
||||
}
|
||||
|
||||
@@ -1451,7 +1451,7 @@ func (b *Bitfinex) WsUpdateOrderbook(p currency.Pair, assetType asset.Item, book
|
||||
Pair: p,
|
||||
Bids: make([]orderbook.Item, 0, len(book)),
|
||||
Asks: make([]orderbook.Item, 0, len(book)),
|
||||
UpdateTime: time.Now(),
|
||||
UpdateTime: time.Now(), // Not included in update
|
||||
}
|
||||
|
||||
for i := range book {
|
||||
|
||||
@@ -941,7 +941,7 @@ func TestWSOrderbookHandling(t *testing.T) {
|
||||
"attributes":{"id":"sorted","symbol":"grouped"},
|
||||
"action":"partial",
|
||||
"data":[
|
||||
{"symbol":"ETHUSD","id":17999992000,"side":"Sell","size":100,"price":80},
|
||||
{"symbol":"ETHUSD","id":17999992000,"side":"Sell","size":100,"price":80,"timestamp":"2017-04-04T22:16:38.461Z"},
|
||||
{"symbol":"ETHUSD","id":17999993000,"side":"Sell","size":20,"price":70},
|
||||
{"symbol":"ETHUSD","id":17999994000,"side":"Sell","size":10,"price":60},
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy","size":10,"price":50},
|
||||
@@ -958,7 +958,7 @@ func TestWSOrderbookHandling(t *testing.T) {
|
||||
"table":"orderBookL2_25",
|
||||
"action":"update",
|
||||
"data":[
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy","size":5}
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy","size":5,"timestamp":"2017-04-04T22:16:38.461Z"}
|
||||
]
|
||||
}`)
|
||||
err = b.wsHandleData(pressXToJSON)
|
||||
@@ -981,7 +981,7 @@ func TestWSOrderbookHandling(t *testing.T) {
|
||||
"table":"orderBookL2_25",
|
||||
"action":"delete",
|
||||
"data":[
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy"}
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy","timestamp":"2017-04-04T22:16:38.461Z"}
|
||||
]
|
||||
}`)
|
||||
err = b.wsHandleData(pressXToJSON)
|
||||
@@ -993,7 +993,7 @@ func TestWSOrderbookHandling(t *testing.T) {
|
||||
"table":"orderBookL2_25",
|
||||
"action":"delete",
|
||||
"data":[
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy"}
|
||||
{"symbol":"ETHUSD","id":17999995000,"side":"Buy","timestamp":"2017-04-04T22:16:38.461Z"}
|
||||
]
|
||||
}`)
|
||||
err = b.wsHandleData(pressXToJSON)
|
||||
|
||||
@@ -322,11 +322,12 @@ type Order struct {
|
||||
|
||||
// OrderBookL2 contains order book l2
|
||||
type OrderBookL2 struct {
|
||||
ID int64 `json:"id"`
|
||||
Price float64 `json:"price"`
|
||||
Side string `json:"side"`
|
||||
Size int64 `json:"size"`
|
||||
Symbol string `json:"symbol"`
|
||||
ID int64 `json:"id"`
|
||||
Price float64 `json:"price"`
|
||||
Side string `json:"side"`
|
||||
Size int64 `json:"size"`
|
||||
Symbol string `json:"symbol"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// Position Summary of Open and Closed Positions
|
||||
|
||||
@@ -500,6 +500,7 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, p currency.
|
||||
book.Pair = p
|
||||
book.Exchange = b.Name
|
||||
book.VerifyOrderbook = b.CanVerifyOrderbook
|
||||
book.LastUpdated = data[0].Timestamp
|
||||
|
||||
err := b.Websocket.Orderbook.LoadSnapshot(&book)
|
||||
if err != nil {
|
||||
@@ -528,11 +529,12 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, p currency.
|
||||
}
|
||||
|
||||
err = b.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
Pair: p,
|
||||
Asset: a,
|
||||
Action: updateAction,
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
Pair: p,
|
||||
Asset: a,
|
||||
Action: updateAction,
|
||||
UpdateTime: data[0].Timestamp,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -143,7 +143,9 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof(log.WebsocketMgr, "%v subscribed to %v", b.Name, strings.Join(subscribe.Channel, ", "))
|
||||
if b.Verbose {
|
||||
log.Infof(log.WebsocketMgr, "%v subscribed to %v", b.Name, strings.Join(subscribe.Channel, ", "))
|
||||
}
|
||||
case "login":
|
||||
var login WsLoginAcknowledgement
|
||||
err = json.Unmarshal(respRaw, &login)
|
||||
@@ -151,7 +153,9 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
return err
|
||||
}
|
||||
b.Websocket.SetCanUseAuthenticatedEndpoints(login.Success)
|
||||
log.Infof(log.WebsocketMgr, "%v websocket authenticated: %v", b.Name, login.Success)
|
||||
if b.Verbose {
|
||||
log.Infof(log.WebsocketMgr, "%v websocket authenticated: %v", b.Name, login.Success)
|
||||
}
|
||||
default:
|
||||
return errors.New(b.Name + stream.UnhandledMessage + string(respRaw))
|
||||
}
|
||||
@@ -265,7 +269,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
})
|
||||
}
|
||||
return trade.AddTradesToBuffer(b.Name, trades...)
|
||||
case strings.Contains(topic, "orderBookL2Api"):
|
||||
case strings.Contains(topic, "orderBookL2Api"): // TODO: Fix orderbook updates.
|
||||
var t wsOrderBook
|
||||
err = json.Unmarshal(respRaw, &t)
|
||||
if err != nil {
|
||||
@@ -328,6 +332,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
newOB.Exchange = b.Name
|
||||
newOB.Asks.Reverse() // Reverse asks for correct alignment
|
||||
newOB.VerifyOrderbook = b.CanVerifyOrderbook
|
||||
newOB.LastUpdated = time.Now() // NOTE: Temp to fix test.
|
||||
err = b.Websocket.Orderbook.LoadSnapshot(&newOB)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -852,7 +852,8 @@ func TestWsOrderbook(t *testing.T) {
|
||||
"type": "snapshot",
|
||||
"product_id": "BTC-USD",
|
||||
"bids": [["10101.10", "0.45054140"]],
|
||||
"asks": [["10102.55", "0.57753524"]]
|
||||
"asks": [["10102.55", "0.57753524"]],
|
||||
"time":"2023-08-15T06:46:55.376250Z"
|
||||
}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
@@ -862,7 +863,7 @@ func TestWsOrderbook(t *testing.T) {
|
||||
pressXToJSON = []byte(`{
|
||||
"type": "l2update",
|
||||
"product_id": "BTC-USD",
|
||||
"time": "2019-08-14T20:42:27.265Z",
|
||||
"time": "2023-08-15T06:46:57.933713Z",
|
||||
"changes": [
|
||||
[
|
||||
"buy",
|
||||
|
||||
@@ -441,13 +441,14 @@ type WebsocketOrderbookSnapshot struct {
|
||||
Type string `json:"type"`
|
||||
Bids [][2]string `json:"bids"`
|
||||
Asks [][2]string `json:"asks"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
// WebsocketL2Update defines an update on the L2 orderbooks
|
||||
type WebsocketL2Update struct {
|
||||
Type string `json:"type"`
|
||||
ProductID string `json:"product_id"`
|
||||
Time string `json:"time"`
|
||||
Time time.Time `json:"time"`
|
||||
Changes [][3]string `json:"changes"`
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ func (c *CoinbasePro) wsHandleData(respRaw []byte) error {
|
||||
}
|
||||
|
||||
case "snapshot":
|
||||
snapshot := WebsocketOrderbookSnapshot{}
|
||||
var snapshot WebsocketOrderbookSnapshot
|
||||
err := json.Unmarshal(respRaw, &snapshot)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -112,9 +112,8 @@ func (c *CoinbasePro) wsHandleData(respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "l2update":
|
||||
update := WebsocketL2Update{}
|
||||
var update WebsocketL2Update
|
||||
err := json.Unmarshal(respRaw, &update)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -291,30 +290,30 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot *WebsocketOrderbookSnapshot) erro
|
||||
}
|
||||
|
||||
for i := range snapshot.Bids {
|
||||
price, err := strconv.ParseFloat(snapshot.Bids[i][0], 64)
|
||||
var price float64
|
||||
price, err = strconv.ParseFloat(snapshot.Bids[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseFloat(snapshot.Bids[i][1], 64)
|
||||
var amount float64
|
||||
amount, err = strconv.ParseFloat(snapshot.Bids[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
base.Bids[i] = orderbook.Item{Price: price, Amount: amount}
|
||||
}
|
||||
|
||||
for i := range snapshot.Asks {
|
||||
price, err := strconv.ParseFloat(snapshot.Asks[i][0], 64)
|
||||
var price float64
|
||||
price, err = strconv.ParseFloat(snapshot.Asks[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseFloat(snapshot.Asks[i][1], 64)
|
||||
var amount float64
|
||||
amount, err = strconv.ParseFloat(snapshot.Asks[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
base.Asks[i] = orderbook.Item{Price: price, Amount: amount}
|
||||
}
|
||||
|
||||
@@ -322,7 +321,7 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot *WebsocketOrderbookSnapshot) erro
|
||||
base.Pair = pair
|
||||
base.Exchange = c.Name
|
||||
base.VerifyOrderbook = c.CanVerifyOrderbook
|
||||
|
||||
base.LastUpdated = snapshot.Time
|
||||
return c.Websocket.Orderbook.LoadSnapshot(&base)
|
||||
}
|
||||
|
||||
@@ -337,11 +336,6 @@ func (c *CoinbasePro) ProcessUpdate(update *WebsocketL2Update) error {
|
||||
return err
|
||||
}
|
||||
|
||||
timestamp, err := time.Parse(time.RFC3339, update.Time)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asks := make(orderbook.Items, 0, len(update.Changes))
|
||||
bids := make(orderbook.Items, 0, len(update.Changes))
|
||||
|
||||
@@ -365,14 +359,18 @@ func (c *CoinbasePro) ProcessUpdate(update *WebsocketL2Update) error {
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
Pair: p,
|
||||
UpdateTime: timestamp,
|
||||
UpdateTime: update.Time,
|
||||
Asset: asset.Spot,
|
||||
})
|
||||
}
|
||||
|
||||
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
|
||||
func (c *CoinbasePro) GenerateDefaultSubscriptions() ([]stream.ChannelSubscription, error) {
|
||||
var channels = []string{"heartbeat", "level2", "ticker", "user", "matches"}
|
||||
var channels = []string{"heartbeat",
|
||||
"level2_batch", /*Other orderbook feeds require authentication. This is batched in 50ms lots.*/
|
||||
"ticker",
|
||||
"user",
|
||||
"matches"}
|
||||
enabledCurrencies, err := c.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -557,6 +557,7 @@ func (c *COINUT) WsProcessOrderbookSnapshot(ob *WsOrderbookSnapshot) error {
|
||||
|
||||
newOrderBook.Asset = asset.Spot
|
||||
newOrderBook.Exchange = c.Name
|
||||
newOrderBook.LastUpdated = time.Now() // No time sent
|
||||
|
||||
return c.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
}
|
||||
@@ -582,9 +583,10 @@ func (c *COINUT) WsProcessOrderbookUpdate(update *WsOrderbookUpdate) error {
|
||||
}
|
||||
|
||||
bufferUpdate := &orderbook.Update{
|
||||
Pair: p,
|
||||
UpdateID: update.TransID,
|
||||
Asset: asset.Spot,
|
||||
Pair: p,
|
||||
UpdateID: update.TransID,
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(), // No time sent
|
||||
}
|
||||
if strings.EqualFold(update.Side, order.Buy.Lower()) {
|
||||
bufferUpdate.Bids = []orderbook.Item{{Price: update.Price, Amount: update.Volume}}
|
||||
|
||||
@@ -560,6 +560,7 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
newOrderBook.Pair = pair
|
||||
newOrderBook.Exchange = g.Name
|
||||
newOrderBook.VerifyOrderbook = g.CanVerifyOrderbook
|
||||
newOrderBook.LastUpdated = time.Now() // No time is sent
|
||||
err := g.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -569,10 +570,11 @@ func (g *Gemini) wsProcessUpdate(result *wsL2MarketData) error {
|
||||
return nil
|
||||
}
|
||||
err := g.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Pair: pair,
|
||||
Asset: asset.Spot,
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Pair: pair,
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(), // No time is sent
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -343,8 +343,9 @@ type WsOrderbook struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Size float64 `json:"size,string"`
|
||||
} `json:"bid"`
|
||||
Symbol string `json:"symbol"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Symbol string `json:"symbol"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
|
||||
@@ -332,10 +332,12 @@ func (h *HitBTC) WsProcessOrderbookSnapshot(ob *WsOrderbook) error {
|
||||
h.Websocket.DataHandler <- err
|
||||
return err
|
||||
}
|
||||
|
||||
newOrderBook.Asset = asset.Spot
|
||||
newOrderBook.Pair = p
|
||||
newOrderBook.Exchange = h.Name
|
||||
newOrderBook.VerifyOrderbook = h.CanVerifyOrderbook
|
||||
newOrderBook.LastUpdated = ob.Params.Timestamp
|
||||
|
||||
return h.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
}
|
||||
@@ -453,11 +455,12 @@ func (h *HitBTC) WsProcessOrderbookUpdate(update *WsOrderbook) error {
|
||||
}
|
||||
|
||||
return h.Websocket.Orderbook.Update(&orderbook.Update{
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Pair: p,
|
||||
UpdateID: update.Params.Sequence,
|
||||
Asset: asset.Spot,
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Pair: p,
|
||||
UpdateID: update.Params.Sequence,
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: update.Params.Timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -508,6 +508,7 @@ func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error {
|
||||
newOrderBook.Asset = asset.Spot
|
||||
newOrderBook.Exchange = h.Name
|
||||
newOrderBook.VerifyOrderbook = h.CanVerifyOrderbook
|
||||
newOrderBook.LastUpdated = time.UnixMilli(update.Timestamp)
|
||||
|
||||
return h.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/dispatch"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/alert"
|
||||
@@ -20,7 +21,8 @@ var (
|
||||
// ErrInvalidAction defines and error when an action is invalid
|
||||
ErrInvalidAction = errors.New("invalid action")
|
||||
|
||||
errInvalidBookDepth = errors.New("invalid book depth")
|
||||
errLastUpdatedNotSet = errors.New("last updated not set")
|
||||
errInvalidBookDepth = errors.New("invalid book depth")
|
||||
)
|
||||
|
||||
// Outbound restricts outbound usage of depth. NOTE: Type assert to
|
||||
@@ -91,16 +93,24 @@ 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) {
|
||||
func (d *Depth) LoadSnapshot(bids, asks []Item, lastUpdateID int64, lastUpdated time.Time, updateByREST bool) error {
|
||||
if lastUpdated.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
d.lastUpdateID = lastUpdateID
|
||||
d.lastUpdated = lastUpdated
|
||||
d.restSnapshot = updateByREST
|
||||
d.bids.load(bids, d.stack)
|
||||
d.asks.load(asks, d.stack)
|
||||
d.bids.load(bids, d.stack, lastUpdated)
|
||||
d.asks.load(asks, d.stack, lastUpdated)
|
||||
d.validationError = nil
|
||||
d.Alert()
|
||||
d.m.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// invalidate flushes all values back to zero so as to not allow strategy
|
||||
@@ -108,14 +118,14 @@ 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.stack)
|
||||
d.asks.load(nil, d.stack)
|
||||
d.validationError = fmt.Errorf("%s %s %s %w Reason: [%v]",
|
||||
tn := time.Now()
|
||||
d.bids.load(nil, d.stack, tn)
|
||||
d.asks.load(nil, d.stack, tn)
|
||||
d.validationError = fmt.Errorf("%s %s %s Reason: [%w]",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
ErrOrderbookInvalid,
|
||||
withReason)
|
||||
common.AppendError(ErrOrderbookInvalid, withReason))
|
||||
d.Alert()
|
||||
return d.validationError
|
||||
}
|
||||
@@ -138,21 +148,35 @@ func (d *Depth) IsValid() bool {
|
||||
|
||||
// UpdateBidAskByPrice updates the bid and ask spread by supplied updates, this
|
||||
// will trim total length of depth level to a specified supplied number
|
||||
func (d *Depth) UpdateBidAskByPrice(update *Update) {
|
||||
tn := getNow()
|
||||
func (d *Depth) UpdateBidAskByPrice(update *Update) error {
|
||||
if update.UpdateTime.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
if len(update.Bids) != 0 {
|
||||
d.bids.updateInsertByPrice(update.Bids, d.stack, d.options.maxDepth, tn)
|
||||
d.bids.updateInsertByPrice(update.Bids, d.stack, d.options.maxDepth, update.UpdateTime)
|
||||
}
|
||||
if len(update.Asks) != 0 {
|
||||
d.asks.updateInsertByPrice(update.Asks, d.stack, d.options.maxDepth, tn)
|
||||
d.asks.updateInsertByPrice(update.Asks, d.stack, d.options.maxDepth, update.UpdateTime)
|
||||
}
|
||||
d.updateAndAlert(update)
|
||||
d.m.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateBidAskByID amends details by ID
|
||||
func (d *Depth) UpdateBidAskByID(update *Update) error {
|
||||
if update.UpdateTime.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
defer d.m.Unlock()
|
||||
if len(update.Bids) != 0 {
|
||||
@@ -173,16 +197,23 @@ func (d *Depth) UpdateBidAskByID(update *Update) error {
|
||||
|
||||
// DeleteBidAskByID deletes a price level by ID
|
||||
func (d *Depth) DeleteBidAskByID(update *Update, bypassErr bool) error {
|
||||
if update.UpdateTime.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
defer d.m.Unlock()
|
||||
if len(update.Bids) != 0 {
|
||||
err := d.bids.deleteByID(update.Bids, d.stack, bypassErr)
|
||||
err := d.bids.deleteByID(update.Bids, d.stack, bypassErr, update.UpdateTime)
|
||||
if err != nil {
|
||||
return d.invalidate(err)
|
||||
}
|
||||
}
|
||||
if len(update.Asks) != 0 {
|
||||
err := d.asks.deleteByID(update.Asks, d.stack, bypassErr)
|
||||
err := d.asks.deleteByID(update.Asks, d.stack, bypassErr, update.UpdateTime)
|
||||
if err != nil {
|
||||
return d.invalidate(err)
|
||||
}
|
||||
@@ -193,6 +224,13 @@ func (d *Depth) DeleteBidAskByID(update *Update, bypassErr bool) error {
|
||||
|
||||
// InsertBidAskByID inserts new updates
|
||||
func (d *Depth) InsertBidAskByID(update *Update) error {
|
||||
if update.UpdateTime.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
defer d.m.Unlock()
|
||||
if len(update.Bids) != 0 {
|
||||
@@ -213,6 +251,13 @@ func (d *Depth) InsertBidAskByID(update *Update) error {
|
||||
|
||||
// UpdateInsertByID updates or inserts by ID at current price level.
|
||||
func (d *Depth) UpdateInsertByID(update *Update) error {
|
||||
if update.UpdateTime.IsZero() {
|
||||
return fmt.Errorf("%s %s %s %w",
|
||||
d.exchange,
|
||||
d.pair,
|
||||
d.asset,
|
||||
errLastUpdatedNotSet)
|
||||
}
|
||||
d.m.Lock()
|
||||
defer d.m.Unlock()
|
||||
if len(update.Bids) != 0 {
|
||||
|
||||
@@ -3,7 +3,6 @@ package orderbook
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -26,7 +25,10 @@ func TestGetLength(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 1337}}, nil, 0, time.Time{}, true)
|
||||
err = d.LoadSnapshot([]Item{{Price: 1337}}, nil, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
askLen, err := d.GetAskLength()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -37,7 +39,7 @@ func TestGetLength(t *testing.T) {
|
||||
t.Errorf("expected len %v, but received %v", 0, askLen)
|
||||
}
|
||||
|
||||
d.asks.load([]Item{{Price: 1337}}, d.stack)
|
||||
d.asks.load([]Item{{Price: 1337}}, d.stack, time.Now())
|
||||
|
||||
askLen, err = d.GetAskLength()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -58,7 +60,10 @@ func TestGetLength(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(nil, []Item{{Price: 1337}}, 0, time.Time{}, true)
|
||||
err = d.LoadSnapshot(nil, []Item{{Price: 1337}}, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bidLen, err := d.GetBidLength()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -69,7 +74,7 @@ func TestGetLength(t *testing.T) {
|
||||
t.Errorf("expected len %v, but received %v", 0, bidLen)
|
||||
}
|
||||
|
||||
d.bids.load([]Item{{Price: 1337}}, d.stack)
|
||||
d.bids.load([]Item{{Price: 1337}}, d.stack, time.Now())
|
||||
|
||||
bidLen, err = d.GetBidLength()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -84,8 +89,8 @@ func TestGetLength(t *testing.T) {
|
||||
func TestRetrieve(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.asks.load([]Item{{Price: 1337}}, d.stack)
|
||||
d.bids.load([]Item{{Price: 1337}}, d.stack)
|
||||
d.asks.load([]Item{{Price: 1337}}, d.stack, time.Now())
|
||||
d.bids.load([]Item{{Price: 1337}}, d.stack, time.Now())
|
||||
d.options = options{
|
||||
exchange: "THE BIG ONE!!!!!!",
|
||||
pair: currency.NewPair(currency.THETA, currency.USD),
|
||||
@@ -181,8 +186,8 @@ func TestTotalAmounts(t *testing.T) {
|
||||
value)
|
||||
}
|
||||
|
||||
d.asks.load([]Item{{Price: 1337, Amount: 1}}, d.stack)
|
||||
d.bids.load([]Item{{Price: 1337, Amount: 10}}, d.stack)
|
||||
d.asks.load([]Item{{Price: 1337, Amount: 1}}, d.stack, time.Now())
|
||||
d.bids.load([]Item{{Price: 1337, Amount: 10}}, d.stack, time.Now())
|
||||
|
||||
liquidity, value, err = d.TotalBidAmounts()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -214,7 +219,15 @@ func TestTotalAmounts(t *testing.T) {
|
||||
func TestLoadSnapshot(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Time{}, false)
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errLastUpdatedNotSet)
|
||||
}
|
||||
|
||||
err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ob, err := d.Retrieve()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -232,7 +245,10 @@ func TestInvalidate(t *testing.T) {
|
||||
d.exchange = "testexchange"
|
||||
d.pair = currency.NewPair(currency.BTC, currency.WABI)
|
||||
d.asset = asset.Spot
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1}}, Items{{Price: 1337, Amount: 10}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ob, err := d.Retrieve()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -243,18 +259,16 @@ func TestInvalidate(t *testing.T) {
|
||||
t.Fatalf("unexpected value")
|
||||
}
|
||||
|
||||
err = d.Invalidate(errors.New("random reason"))
|
||||
testReason := errors.New("random reason")
|
||||
|
||||
err = d.Invalidate(testReason)
|
||||
if !errors.Is(err, ErrOrderbookInvalid) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
_, err = d.Retrieve()
|
||||
if !errors.Is(err, ErrOrderbookInvalid) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
if err.Error() != "testexchange BTCWABI spot orderbook data integrity compromised Reason: [random reason]" {
|
||||
t.Fatal("unexpected string return")
|
||||
if !errors.Is(err, ErrOrderbookInvalid) && !errors.Is(err, testReason) {
|
||||
t.Fatalf("received: '%v' but expected: '%v' && '%v'", err, ErrOrderbookInvalid, testReason)
|
||||
}
|
||||
|
||||
d.validationError = nil
|
||||
@@ -272,17 +286,31 @@ func TestInvalidate(t *testing.T) {
|
||||
func TestUpdateBidAskByPrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = d.UpdateBidAskByPrice(&Update{})
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errLastUpdatedNotSet)
|
||||
}
|
||||
|
||||
// empty
|
||||
d.UpdateBidAskByPrice(&Update{})
|
||||
err = d.UpdateBidAskByPrice(&Update{UpdateTime: time.Now()})
|
||||
if err != nil {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
|
||||
updates := &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
UpdateID: 1,
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
UpdateID: 1,
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.UpdateBidAskByPrice(updates)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d.UpdateBidAskByPrice(updates)
|
||||
|
||||
ob, err := d.Retrieve()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -294,11 +322,15 @@ func TestUpdateBidAskByPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 0, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 0, ID: 2}},
|
||||
UpdateID: 2,
|
||||
Bids: Items{{Price: 1337, Amount: 0, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 0, ID: 2}},
|
||||
UpdateID: 2,
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.UpdateBidAskByPrice(updates)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d.UpdateBidAskByPrice(updates)
|
||||
|
||||
askLen, err := d.GetAskLength()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -318,13 +350,23 @@ func TestUpdateBidAskByPrice(t *testing.T) {
|
||||
func TestDeleteBidAskByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates := &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
}
|
||||
err := d.DeleteBidAskByID(updates, false)
|
||||
|
||||
err = d.DeleteBidAskByID(updates, false)
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errLastUpdatedNotSet)
|
||||
}
|
||||
|
||||
updates.UpdateTime = time.Now()
|
||||
err = d.DeleteBidAskByID(updates, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -339,23 +381,26 @@ func TestDeleteBidAskByID(t *testing.T) {
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.DeleteBidAskByID(updates, false)
|
||||
if !strings.Contains(err.Error(), errIDCannotBeMatched.Error()) {
|
||||
if !errors.Is(err, errIDCannotBeMatched) {
|
||||
t.Fatalf("error expected %v received %v", errIDCannotBeMatched, err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.DeleteBidAskByID(updates, false)
|
||||
if !strings.Contains(err.Error(), errIDCannotBeMatched.Error()) {
|
||||
if !errors.Is(err, errIDCannotBeMatched) {
|
||||
t.Fatalf("error expected %v received %v", errIDCannotBeMatched, err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.DeleteBidAskByID(updates, true)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -366,13 +411,23 @@ func TestDeleteBidAskByID(t *testing.T) {
|
||||
func TestUpdateBidAskByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates := &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 1}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 2}},
|
||||
}
|
||||
err := d.UpdateBidAskByID(updates)
|
||||
|
||||
err = d.UpdateBidAskByID(updates)
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errLastUpdatedNotSet)
|
||||
}
|
||||
|
||||
updates.UpdateTime = time.Now()
|
||||
err = d.UpdateBidAskByID(updates)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -387,19 +442,21 @@ func TestUpdateBidAskByID(t *testing.T) {
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 666}},
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 666}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
// random unmatching IDs
|
||||
err = d.UpdateBidAskByID(updates)
|
||||
if !strings.Contains(err.Error(), errIDCannotBeMatched.Error()) {
|
||||
if !errors.Is(err, errIDCannotBeMatched) {
|
||||
t.Fatalf("error expected %v received %v", errIDCannotBeMatched, err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 69}},
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 69}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.UpdateBidAskByID(updates)
|
||||
if !strings.Contains(err.Error(), errIDCannotBeMatched.Error()) {
|
||||
if !errors.Is(err, errIDCannotBeMatched) {
|
||||
t.Fatalf("error expected %v received %v", errIDCannotBeMatched, err)
|
||||
}
|
||||
}
|
||||
@@ -407,32 +464,50 @@ func TestUpdateBidAskByID(t *testing.T) {
|
||||
func TestInsertBidAskByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates := &Update{
|
||||
Asks: Items{{Price: 1337, Amount: 2, ID: 3}},
|
||||
}
|
||||
err = d.InsertBidAskByID(updates)
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errLastUpdatedNotSet)
|
||||
}
|
||||
|
||||
err := d.InsertBidAskByID(updates)
|
||||
if !strings.Contains(err.Error(), errCollisionDetected.Error()) {
|
||||
updates.UpdateTime = time.Now()
|
||||
|
||||
err = d.InsertBidAskByID(updates)
|
||||
if !errors.Is(err, errCollisionDetected) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errCollisionDetected)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 3}},
|
||||
Bids: Items{{Price: 1337, Amount: 2, ID: 3}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
|
||||
err = d.InsertBidAskByID(updates)
|
||||
if !strings.Contains(err.Error(), errCollisionDetected.Error()) {
|
||||
if !errors.Is(err, errCollisionDetected) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errCollisionDetected)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 2, ID: 4}},
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 2, ID: 4}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.InsertBidAskByID(updates)
|
||||
if err != nil {
|
||||
@@ -452,14 +527,23 @@ func TestInsertBidAskByID(t *testing.T) {
|
||||
func TestUpdateInsertByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := NewDepth(id)
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err := d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates := &Update{
|
||||
Bids: Items{{Price: 1338, Amount: 0, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 2, ID: 4}},
|
||||
}
|
||||
err := d.UpdateInsertByID(updates)
|
||||
if !strings.Contains(err.Error(), errAmountCannotBeLessOrEqualToZero.Error()) {
|
||||
err = d.UpdateInsertByID(updates)
|
||||
if !errors.Is(err, errLastUpdatedNotSet) {
|
||||
t.Fatalf("expected: %v but received: %v", errLastUpdatedNotSet, err)
|
||||
}
|
||||
|
||||
updates.UpdateTime = time.Now()
|
||||
err = d.UpdateInsertByID(updates)
|
||||
if !errors.Is(err, errAmountCannotBeLessOrEqualToZero) {
|
||||
t.Fatalf("expected: %v but received: %v", errAmountCannotBeLessOrEqualToZero, err)
|
||||
}
|
||||
|
||||
@@ -469,14 +553,18 @@ func TestUpdateInsertByID(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 0, ID: 4}},
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 0, ID: 4}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.UpdateInsertByID(updates)
|
||||
if !strings.Contains(err.Error(), errAmountCannotBeLessOrEqualToZero.Error()) {
|
||||
if !errors.Is(err, errAmountCannotBeLessOrEqualToZero) {
|
||||
t.Fatalf("expected: %v but received: %v", errAmountCannotBeLessOrEqualToZero, err)
|
||||
}
|
||||
|
||||
@@ -486,11 +574,15 @@ func TestUpdateInsertByID(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, ErrOrderbookInvalid)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Time{}, false)
|
||||
err = d.LoadSnapshot(Items{{Price: 1337, Amount: 1, ID: 1}}, Items{{Price: 1337, Amount: 10, ID: 2}}, 0, time.Now(), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updates = &Update{
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 2, ID: 4}},
|
||||
Bids: Items{{Price: 1338, Amount: 2, ID: 3}},
|
||||
Asks: Items{{Price: 1336, Amount: 2, ID: 4}},
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
err = d.UpdateInsertByID(updates)
|
||||
if err != nil {
|
||||
@@ -643,7 +735,10 @@ func TestHitTheBidsByNominalSlippage(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First tranche
|
||||
amt, err := depth.HitTheBidsByNominalSlippage(0, 1336)
|
||||
@@ -765,7 +860,11 @@ func TestHitTheBidsByNominalSlippageFromMid(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First price from mid point
|
||||
amt, err := depth.HitTheBidsByNominalSlippageFromMid(0.03741114852226)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -802,7 +901,11 @@ func TestHitTheBidsByNominalSlippageFromBest(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from best bid
|
||||
amt, err := depth.HitTheBidsByNominalSlippageFromBest(0.037425149700599)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -839,7 +942,10 @@ func TestLiftTheAsksByNominalSlippage(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price
|
||||
amt, err := depth.LiftTheAsksByNominalSlippage(0.037397157816006, 1337)
|
||||
@@ -876,7 +982,11 @@ func TestLiftTheAsksByNominalSlippageFromMid(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First price from mid point
|
||||
amt, err := depth.LiftTheAsksByNominalSlippageFromMid(0.074822297044519)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -913,7 +1023,11 @@ func TestLiftTheAsksByNominalSlippageFromBest(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from best bid
|
||||
amt, err := depth.LiftTheAsksByNominalSlippageFromBest(0.037397157816006)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -944,7 +1058,10 @@ func TestHitTheBidsByImpactSlippage(t *testing.T) {
|
||||
}
|
||||
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from best bid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.HitTheBidsByImpactSlippage(0.7485029940119761, 1336)
|
||||
@@ -981,7 +1098,10 @@ func TestHitTheBidsByImpactSlippageFromMid(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from mid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.HitTheBidsByImpactSlippageFromMid(0.7485029940119761)
|
||||
@@ -1016,7 +1136,10 @@ func TestHitTheBidsByImpactSlippageFromBest(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from mid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.HitTheBidsByImpactSlippageFromBest(0.7485029940119761)
|
||||
@@ -1047,7 +1170,10 @@ func TestLiftTheAsksByImpactSlippage(t *testing.T) {
|
||||
}
|
||||
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// First and second price from best bid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.LiftTheAsksByImpactSlippage(0.7479431563201197, 1337)
|
||||
@@ -1082,8 +1208,10 @@ func TestLiftTheAsksByImpactSlippageFromMid(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// First and second price from mid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.LiftTheAsksByImpactSlippageFromMid(0.7485029940119761)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -1117,8 +1245,10 @@ func TestLiftTheAsksByImpactSlippageFromBest(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// First and second price from mid - price level target 1326 (which should be kept)
|
||||
amt, err := depth.LiftTheAsksByImpactSlippageFromBest(0.7479431563201197)
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -1145,7 +1275,10 @@ func TestLiftTheAsksByImpactSlippageFromBest(t *testing.T) {
|
||||
func TestHitTheBids(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBids(20.1, 1336, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1211,7 +1344,10 @@ func TestHitTheBids_QuotationRequired(t *testing.T) {
|
||||
}
|
||||
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBids(26531, 1336, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1281,7 +1417,10 @@ func TestHitTheBidsFromMid(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBidsFromMid(20.1, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1346,7 +1485,10 @@ func TestHitTheBidsFromMid_QuotationRequired(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBidsFromMid(26531, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1411,7 +1553,10 @@ func TestHitTheBidsFromBest(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBidsFromBest(20.1, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1480,7 +1625,10 @@ func TestHitTheBidsFromBest_QuotationRequired(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.HitTheBidsFromBest(26531, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1540,7 +1688,10 @@ func TestHitTheBidsFromBest_QuotationRequired(t *testing.T) {
|
||||
func TestLiftTheAsks(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsks(26931, 1337, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1605,7 +1756,10 @@ func TestLiftTheAsks_BaseRequired(t *testing.T) {
|
||||
}
|
||||
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsks(21, 1337, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1674,7 +1828,10 @@ func TestLiftTheAsksFromMid(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsksFromMid(26931, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1743,7 +1900,10 @@ func TestLiftTheAsksFromMid_BaseRequired(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsksFromMid(21, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1812,7 +1972,10 @@ func TestLiftTheAsksFromBest(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsksFromBest(26931, false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1881,7 +2044,10 @@ func TestLiftTheAsksFromBest_BaseRequired(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mov, err := depth.LiftTheAsksFromBest(21, true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1949,7 +2115,10 @@ func TestGetMidPrice_Depth(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mid, err := depth.GetMidPrice()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1967,13 +2136,19 @@ func TestGetMidPriceNoLock_Depth(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, nil, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, nil, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = depth.getMidPriceNoLock()
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mid, err := depth.getMidPriceNoLock()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -2005,7 +2180,10 @@ func TestGetBestBidASk_Depth(t *testing.T) {
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mid, err := depth.GetBestBid()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -2036,15 +2214,19 @@ func TestGetSpreadAmount(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(nil, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(nil, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = depth.GetSpreadAmount()
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spread, err := depth.GetSpreadAmount()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -2069,15 +2251,19 @@ func TestGetSpreadPercentage(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(nil, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(nil, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = depth.GetSpreadPercentage()
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spread, err := depth.GetSpreadPercentage()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -2102,15 +2288,19 @@ func TestGetImbalance_Depth(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(nil, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(nil, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = depth.GetImbalance()
|
||||
if !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
imbalance, err := depth.GetImbalance()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -2148,7 +2338,10 @@ func TestGetTranches(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", len(bidT), 0)
|
||||
}
|
||||
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err = depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
askT, bidT, err = depth.GetTranches(0)
|
||||
if !errors.Is(err, nil) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package orderbook
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common/math"
|
||||
)
|
||||
@@ -40,7 +41,7 @@ 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) {
|
||||
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
|
||||
@@ -81,7 +82,7 @@ func (ll *linkedList) load(items Items, stack *stack) {
|
||||
// Push unused pointers back on stack
|
||||
for push != nil {
|
||||
pending := push.Next
|
||||
stack.Push(push, getNow())
|
||||
stack.Push(push, tn)
|
||||
ll.length--
|
||||
push = pending
|
||||
}
|
||||
@@ -111,14 +112,14 @@ updates:
|
||||
}
|
||||
|
||||
// deleteByID deletes reference by ID
|
||||
func (ll *linkedList) deleteByID(updts Items, stack *stack, bypassErr bool) error {
|
||||
func (ll *linkedList) deleteByID(updts Items, stack *stack, bypassErr bool, tn time.Time) error {
|
||||
updates:
|
||||
for x := range updts {
|
||||
for tip := &ll.head; *tip != nil; tip = &(*tip).Next {
|
||||
if updts[x].ID != (*tip).Value.ID {
|
||||
continue
|
||||
}
|
||||
stack.Push(deleteAtTip(ll, tip), getNow())
|
||||
stack.Push(deleteAtTip(ll, tip), tn)
|
||||
continue updates
|
||||
}
|
||||
if !bypassErr {
|
||||
@@ -133,7 +134,7 @@ updates:
|
||||
// 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) {
|
||||
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.
|
||||
@@ -156,7 +157,7 @@ func (ll *linkedList) cleanup(maxChainLength int, stack *stack) {
|
||||
for n != nil {
|
||||
pruned++
|
||||
pending := n.Next
|
||||
stack.Push(n, getNow())
|
||||
stack.Push(n, tn)
|
||||
n = pending
|
||||
}
|
||||
ll.length -= pruned
|
||||
@@ -185,7 +186,7 @@ func (ll *linkedList) retrieve(count int) Items {
|
||||
|
||||
// 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 now) {
|
||||
func (ll *linkedList) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, compare func(float64, float64) bool, tn time.Time) {
|
||||
for x := range updts {
|
||||
for tip := &ll.head; ; tip = &(*tip).Next {
|
||||
if *tip == nil {
|
||||
@@ -224,7 +225,7 @@ func (ll *linkedList) updateInsertByPrice(updts Items, stack *stack, maxChainLen
|
||||
}
|
||||
// Reduces length of total linked list chain to a maxChainLength value
|
||||
if maxChainLength != 0 && ll.length > maxChainLength {
|
||||
ll.cleanup(maxChainLength, stack)
|
||||
ll.cleanup(maxChainLength, stack, tn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +483,7 @@ 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 now) {
|
||||
func (ll *bids) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, tn time.Time) {
|
||||
ll.linkedList.updateInsertByPrice(updts, stack, maxChainLength, bidCompare, tn)
|
||||
}
|
||||
|
||||
@@ -618,7 +619,7 @@ 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 now) {
|
||||
func (ll *asks) updateInsertByPrice(updts Items, stack *stack, maxChainLength int, tn time.Time) {
|
||||
ll.linkedList.updateInsertByPrice(updts, stack, maxChainLength, askCompare, tn)
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestLoad(t *testing.T) {
|
||||
{Price: 7, Amount: 1},
|
||||
{Price: 9, Amount: 1},
|
||||
{Price: 11, Amount: 1},
|
||||
}, stack)
|
||||
}, stack, time.Now())
|
||||
|
||||
if stack.getCount() != 0 {
|
||||
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
|
||||
@@ -85,7 +85,7 @@ func TestLoad(t *testing.T) {
|
||||
{Price: 1, Amount: 1},
|
||||
{Price: 3, Amount: 1},
|
||||
{Price: 5, Amount: 1},
|
||||
}, stack)
|
||||
}, stack, time.Now())
|
||||
|
||||
if stack.getCount() != 3 {
|
||||
t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount())
|
||||
@@ -98,7 +98,7 @@ func TestLoad(t *testing.T) {
|
||||
{Price: 3, Amount: 1},
|
||||
{Price: 5, Amount: 1},
|
||||
{Price: 7, Amount: 1},
|
||||
}, stack)
|
||||
}, stack, time.Now())
|
||||
|
||||
if stack.getCount() != 2 {
|
||||
t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount())
|
||||
@@ -107,7 +107,7 @@ func TestLoad(t *testing.T) {
|
||||
Check(t, list, 4, 16, 4)
|
||||
|
||||
// purge entire list
|
||||
list.load(nil, stack)
|
||||
list.load(nil, stack, time.Now())
|
||||
|
||||
if stack.getCount() != 6 {
|
||||
t.Fatalf("incorrect stack count expected: %v received: %v", 6, stack.getCount())
|
||||
@@ -122,7 +122,7 @@ func BenchmarkLoad(b *testing.B) {
|
||||
ll := linkedList{}
|
||||
s := newStack()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ll.load(ask, s)
|
||||
ll.load(ask, s, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +137,12 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 9, Amount: 1},
|
||||
{Price: 11, Amount: 1},
|
||||
}
|
||||
a.load(asksSnapshot, stack)
|
||||
a.load(asksSnapshot, stack, time.Now())
|
||||
|
||||
// Update one instance with matching price
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 1, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 7, 37, 6)
|
||||
|
||||
@@ -153,7 +153,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// Insert at head
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 0.5, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 9, 38, 7)
|
||||
|
||||
@@ -164,7 +164,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// Insert at tail
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 12, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 11, 62, 8)
|
||||
|
||||
@@ -177,7 +177,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 11.5, Amount: 2},
|
||||
{Price: 10.5, Amount: 2},
|
||||
{Price: 13, Amount: 2},
|
||||
}, stack, 10, getNow())
|
||||
}, stack, 10, time.Now())
|
||||
|
||||
Check(t, a, 15, 106, 10)
|
||||
|
||||
@@ -188,7 +188,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// delete at tail
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 12, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 13, 82, 9)
|
||||
|
||||
@@ -199,7 +199,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// delete at mid
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 7, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 12, 75, 8)
|
||||
|
||||
@@ -210,7 +210,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// delete at head
|
||||
a.updateInsertByPrice(Items{
|
||||
{Price: 0.5, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 10, 74, 7)
|
||||
|
||||
@@ -219,7 +219,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
// purge if liquidity plunges to zero
|
||||
a.load(nil, stack)
|
||||
a.load(nil, stack, time.Now())
|
||||
|
||||
// rebuild everything again
|
||||
a.updateInsertByPrice(Items{
|
||||
@@ -229,7 +229,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 7, Amount: 1},
|
||||
{Price: 9, Amount: 1},
|
||||
{Price: 11, Amount: 1},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, a, 6, 36, 6)
|
||||
|
||||
@@ -246,12 +246,12 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 3, Amount: 1},
|
||||
{Price: 1, Amount: 1},
|
||||
}
|
||||
b.load(bidsSnapshot, stack)
|
||||
b.load(bidsSnapshot, stack, time.Now())
|
||||
|
||||
// Update one instance with matching price
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 11, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 7, 47, 6)
|
||||
|
||||
@@ -262,7 +262,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// Insert at head
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 12, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 9, 71, 7)
|
||||
|
||||
@@ -273,7 +273,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// Insert at tail
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 0.5, Amount: 2},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 11, 72, 8)
|
||||
|
||||
@@ -286,7 +286,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 11.5, Amount: 2},
|
||||
{Price: 10.5, Amount: 2},
|
||||
{Price: 13, Amount: 2},
|
||||
}, stack, 10, getNow())
|
||||
}, stack, 10, time.Now())
|
||||
|
||||
Check(t, b, 15, 141, 10)
|
||||
|
||||
@@ -297,7 +297,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// Insert between price and up to and beyond max allowable depth level
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 1, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 14, 140, 9)
|
||||
|
||||
@@ -308,7 +308,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// delete at mid
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 10.5, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 12, 119, 8)
|
||||
|
||||
@@ -319,7 +319,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
// delete at head
|
||||
b.updateInsertByPrice(Items{
|
||||
{Price: 13, Amount: 0},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 10, 93, 7)
|
||||
|
||||
@@ -328,7 +328,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
// purge if liquidity plunges to zero
|
||||
b.load(nil, stack)
|
||||
b.load(nil, stack, time.Now())
|
||||
|
||||
// rebuild everything again
|
||||
b.updateInsertByPrice(Items{
|
||||
@@ -338,7 +338,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
|
||||
{Price: 7, Amount: 1},
|
||||
{Price: 9, Amount: 1},
|
||||
{Price: 11, Amount: 1},
|
||||
}, stack, 0, getNow())
|
||||
}, stack, 0, time.Now())
|
||||
|
||||
Check(t, b, 6, 36, 6)
|
||||
|
||||
@@ -358,17 +358,17 @@ func TestCleanup(t *testing.T) {
|
||||
{Price: 9, Amount: 1},
|
||||
{Price: 11, Amount: 1},
|
||||
}
|
||||
a.load(asksSnapshot, stack)
|
||||
a.load(asksSnapshot, stack, time.Now())
|
||||
|
||||
a.cleanup(6, stack)
|
||||
a.cleanup(6, stack, time.Now())
|
||||
Check(t, a, 6, 36, 6)
|
||||
a.cleanup(5, stack)
|
||||
a.cleanup(5, stack, time.Now())
|
||||
Check(t, a, 5, 25, 5)
|
||||
a.cleanup(1, stack)
|
||||
a.cleanup(1, stack, time.Now())
|
||||
Check(t, a, 1, 1, 1)
|
||||
a.cleanup(10, stack)
|
||||
a.cleanup(10, stack, time.Now())
|
||||
Check(t, a, 1, 1, 1)
|
||||
a.cleanup(0, stack) // will purge, underlying checks are done elseware to prevent this
|
||||
a.cleanup(0, stack, time.Now()) // will purge, underlying checks are done elseware to prevent this
|
||||
Check(t, a, 0, 0, 0)
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) {
|
||||
a := asks{}
|
||||
stack := newStack()
|
||||
|
||||
a.load(ask, stack)
|
||||
a.load(ask, stack, time.Now())
|
||||
|
||||
updates := Items{
|
||||
{
|
||||
@@ -392,7 +392,7 @@ func BenchmarkUpdateInsertByPrice_Amend(b *testing.B) {
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
a.updateInsertByPrice(updates, stack, 0, getNow())
|
||||
a.updateInsertByPrice(updates, stack, 0, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) {
|
||||
a := asks{}
|
||||
stack := newStack()
|
||||
|
||||
a.load(ask, stack)
|
||||
a.load(ask, stack, time.Now())
|
||||
|
||||
updates := Items{
|
||||
{
|
||||
@@ -415,7 +415,7 @@ func BenchmarkUpdateInsertByPrice_Insert_Delete(b *testing.B) {
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
a.updateInsertByPrice(updates, stack, 0, getNow())
|
||||
a.updateInsertByPrice(updates, stack, 0, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,7 +430,7 @@ func TestUpdateByID(t *testing.T) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
err := a.updateByID(Items{
|
||||
{Price: 1, Amount: 1, ID: 1},
|
||||
@@ -485,7 +485,7 @@ func BenchmarkUpdateByID(b *testing.B) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
asks.load(asksSnapshot, s)
|
||||
asks.load(asksSnapshot, s, time.Now())
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := asks.updateByID(Items{
|
||||
@@ -513,12 +513,12 @@ func TestDeleteByID(t *testing.T) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Delete at head
|
||||
err := a.deleteByID(Items{
|
||||
{Price: 1, Amount: 1, ID: 1},
|
||||
}, s, false)
|
||||
}, s, false, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -528,7 +528,7 @@ func TestDeleteByID(t *testing.T) {
|
||||
// Delete at tail
|
||||
err = a.deleteByID(Items{
|
||||
{Price: 1, Amount: 1, ID: 11},
|
||||
}, s, false)
|
||||
}, s, false, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -538,7 +538,7 @@ func TestDeleteByID(t *testing.T) {
|
||||
// Delete in middle
|
||||
err = a.deleteByID(Items{
|
||||
{Price: 1, Amount: 1, ID: 5},
|
||||
}, s, false)
|
||||
}, s, false, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -548,7 +548,7 @@ func TestDeleteByID(t *testing.T) {
|
||||
// Intentional error
|
||||
err = a.deleteByID(Items{
|
||||
{Price: 11, Amount: 1, ID: 1337},
|
||||
}, s, false)
|
||||
}, s, false, time.Now())
|
||||
if !errors.Is(err, errIDCannotBeMatched) {
|
||||
t.Fatalf("expecting %s but received %v", errIDCannotBeMatched, err)
|
||||
}
|
||||
@@ -556,7 +556,7 @@ func TestDeleteByID(t *testing.T) {
|
||||
// Error bypass
|
||||
err = a.deleteByID(Items{
|
||||
{Price: 11, Amount: 1, ID: 1337},
|
||||
}, s, true)
|
||||
}, s, true, time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -573,7 +573,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Update one instance with matching ID
|
||||
err := a.updateInsertByID(Items{
|
||||
@@ -586,7 +586,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
Check(t, a, 7, 37, 6)
|
||||
|
||||
// Reset
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances with matching ID in order
|
||||
err = a.updateInsertByID(Items{
|
||||
@@ -664,7 +664,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
Check(t, a, 12, 63, 6)
|
||||
|
||||
// Reset
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances move one after ID
|
||||
err = a.updateInsertByID(Items{
|
||||
@@ -682,7 +682,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
Check(t, a, 12, 78, 6)
|
||||
|
||||
// Reset
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances move one after ID to tail
|
||||
err = a.updateInsertByID(Items{
|
||||
@@ -716,7 +716,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
Check(t, a, 14, 106, 7)
|
||||
|
||||
// Reset
|
||||
a.load(asksSnapshot, s)
|
||||
a.load(asksSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances pop at head
|
||||
err = a.updateInsertByID(Items{
|
||||
@@ -815,7 +815,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
|
||||
Check(t, a, 19, 213, 9)
|
||||
|
||||
// purge
|
||||
a.load(nil, s)
|
||||
a.load(nil, s, time.Now())
|
||||
|
||||
// insert with no liquidity and jumbled
|
||||
err = a.updateInsertByID(Items{
|
||||
@@ -845,7 +845,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
{Price: 3, Amount: 1, ID: 3},
|
||||
{Price: 1, Amount: 1, ID: 1},
|
||||
}
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
// Update one instance with matching ID
|
||||
err := b.updateInsertByID(Items{
|
||||
@@ -858,7 +858,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
Check(t, b, 7, 37, 6)
|
||||
|
||||
// Reset
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances with matching ID in order
|
||||
err = b.updateInsertByID(Items{
|
||||
@@ -936,7 +936,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
Check(t, b, 12, 63, 6)
|
||||
|
||||
// Reset
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances move one after ID
|
||||
err = b.updateInsertByID(Items{
|
||||
@@ -954,7 +954,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
Check(t, b, 12, 78, 6)
|
||||
|
||||
// Reset
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances move one after ID to tail
|
||||
err = b.updateInsertByID(Items{
|
||||
@@ -988,7 +988,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
Check(t, b, 14, 106, 7)
|
||||
|
||||
// Reset
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
// Update all instances pop at tail
|
||||
err = b.updateInsertByID(Items{
|
||||
@@ -1084,7 +1084,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
|
||||
Check(t, b, 19, 157.7, 9)
|
||||
|
||||
// purge
|
||||
b.load(nil, s)
|
||||
b.load(nil, s, time.Now())
|
||||
|
||||
// insert with no liquidity and jumbled
|
||||
err = b.updateInsertByID(Items{
|
||||
@@ -1114,7 +1114,7 @@ func TestInsertUpdatesBid(t *testing.T) {
|
||||
{Price: 3, Amount: 1, ID: 3},
|
||||
{Price: 1, Amount: 1, ID: 1},
|
||||
}
|
||||
b.load(bidsSnapshot, s)
|
||||
b.load(bidsSnapshot, s, time.Now())
|
||||
|
||||
err := b.insertUpdates(Items{
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
@@ -1161,7 +1161,7 @@ func TestInsertUpdatesBid(t *testing.T) {
|
||||
Check(t, b, 9, 54, 9)
|
||||
|
||||
// purge
|
||||
b.load(nil, s)
|
||||
b.load(nil, s, time.Now())
|
||||
|
||||
// Add one at head
|
||||
err = b.insertUpdates(Items{
|
||||
@@ -1185,7 +1185,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
a.load(askSnapshot, s)
|
||||
a.load(askSnapshot, s, time.Now())
|
||||
|
||||
err := a.insertUpdates(Items{
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
@@ -1232,7 +1232,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
|
||||
Check(t, a, 9, 54, 9)
|
||||
|
||||
// purge
|
||||
a.load(nil, s)
|
||||
a.load(nil, s, time.Now())
|
||||
|
||||
// Add one at head
|
||||
err = a.insertUpdates(Items{
|
||||
@@ -1353,7 +1353,7 @@ func TestAmount(t *testing.T) {
|
||||
{Price: 9, Amount: 1, ID: 9},
|
||||
{Price: 11, Amount: 1, ID: 11},
|
||||
}
|
||||
a.load(askSnapshot, s)
|
||||
a.load(askSnapshot, s, time.Now())
|
||||
|
||||
liquidity, value := a.amount()
|
||||
if liquidity != 6 {
|
||||
@@ -1545,7 +1545,10 @@ func TestGetMovementByBaseAmount(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
movement, err := depth.bids.getMovementByBase(tt.BaseAmount, tt.ReferencePrice, false)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, tt.ExpectedError)
|
||||
@@ -1666,7 +1669,10 @@ func TestGetBaseAmountFromNominalSlippage(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
base, err := depth.bids.hitBidsByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("%s received: '%v' but expected: '%v'",
|
||||
@@ -1775,7 +1781,10 @@ func TestGetBaseAmountFromImpact(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(tt.BidLiquidity, nil, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
base, err := depth.bids.hitBidsByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("%s received: '%v' but expected: '%v'", tt.Name, err, tt.ExpectedError)
|
||||
@@ -1858,7 +1867,10 @@ func TestGetMovementByQuoteAmount(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
movement, err := depth.asks.getMovementByQuotation(tt.QuoteAmount, tt.ReferencePrice, false)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, tt.ExpectedError)
|
||||
@@ -1988,7 +2000,10 @@ func TestGetQuoteAmountFromNominalSlippage(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load snapshot: %s", err)
|
||||
}
|
||||
quote, err := depth.asks.liftAsksByNominalSlippage(tt.NominalSlippage, tt.ReferencePrice)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("%s received: '%v' but expected: '%v'", tt.Name, err, tt.ExpectedError)
|
||||
@@ -2077,7 +2092,10 @@ func TestGetQuoteAmountFromImpact(t *testing.T) {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth := NewDepth(id)
|
||||
depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(nil, tt.AskLiquidity, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load snapshot: %s", err)
|
||||
}
|
||||
quote, err := depth.asks.liftAsksByImpactSlippage(tt.ImpactSlippage, tt.ReferencePrice)
|
||||
if !errors.Is(err, tt.ExpectedError) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, tt.ExpectedError)
|
||||
@@ -2099,7 +2117,10 @@ func TestGetHeadPrice(t *testing.T) {
|
||||
if _, err := depth.asks.getHeadPriceNoLock(); !errors.Is(err, errNoLiquidity) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
depth.LoadSnapshot(bid, ask, 0, time.Time{}, true)
|
||||
err := depth.LoadSnapshot(bid, ask, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load snapshot: %s", err)
|
||||
}
|
||||
|
||||
val, err := depth.bids.getHeadPriceNoLock()
|
||||
if !errors.Is(err, nil) {
|
||||
|
||||
@@ -40,24 +40,16 @@ func newStack() *stack {
|
||||
return s
|
||||
}
|
||||
|
||||
// now defines a time which is now to ensure no other values get passed in
|
||||
type now time.Time
|
||||
|
||||
// getNow returns the time at which it is called
|
||||
func getNow() now {
|
||||
return now(time.Now())
|
||||
}
|
||||
|
||||
// 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 now) {
|
||||
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 = time.Time(tn)
|
||||
n.shelved = tn
|
||||
n.Next = nil
|
||||
n.Prev = nil
|
||||
n.Value = Item{}
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestPushPop(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
s.Push(nSlice[i], getNow())
|
||||
s.Push(nSlice[i], time.Now())
|
||||
}
|
||||
|
||||
if s.getCount() != 100 {
|
||||
@@ -34,13 +34,13 @@ func TestCleaner(t *testing.T) {
|
||||
nSlice[i] = s.Pop()
|
||||
}
|
||||
|
||||
tn := getNow()
|
||||
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 = getNow()
|
||||
tn = time.Now()
|
||||
for i := 50; i < 100; i++ {
|
||||
s.Push(nSlice[i], tn)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func BenchmarkWithStack(b *testing.B) {
|
||||
stack := newStack()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
tn := getNow()
|
||||
tn := time.Now()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < 100000; j++ {
|
||||
n = stack.Pop()
|
||||
|
||||
@@ -77,8 +77,11 @@ func (s *Service) Update(b *Base) error {
|
||||
book.AssignOptions(b)
|
||||
m3[b.Pair.Quote.Item] = book
|
||||
}
|
||||
book.LoadSnapshot(b.Bids, b.Asks, b.LastUpdateID, b.LastUpdated, true)
|
||||
err := book.LoadSnapshot(b.Bids, b.Asks, b.LastUpdateID, b.LastUpdated, true)
|
||||
s.mu.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Mux.Publish(book, m1.ID)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,19 @@ func TestGetLiquidity(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Time{}, false)
|
||||
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)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 2}}, []Item{{Price: 2}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -69,7 +75,10 @@ func TestCheckBidLiquidity(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -85,7 +94,10 @@ func TestCheckAskLiquidity(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(nil, []Item{{Price: 2}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -100,7 +112,10 @@ func TestGetBestBid(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 2}}, nil, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -119,7 +134,10 @@ func TestGetBestAsk(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot(nil, []Item{{Price: 2}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -138,7 +156,10 @@ func TestGetMidPrice(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 1}}, []Item{{Price: 2}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -157,7 +178,10 @@ func TestGetSpread(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errNoLiquidity)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 1}}, []Item{{Price: 2}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -178,14 +202,20 @@ func TestGetImbalance(t *testing.T) {
|
||||
}
|
||||
|
||||
// unlikely event zero amounts
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 0}}, []Item{{Price: 2, Amount: 0}}, 0, time.Time{}, false)
|
||||
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
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1000}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -196,7 +226,10 @@ func TestGetImbalance(t *testing.T) {
|
||||
}
|
||||
|
||||
// balance skewed to bids
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 1000}}, []Item{{Price: 2, Amount: 1}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -207,7 +240,10 @@ func TestGetImbalance(t *testing.T) {
|
||||
}
|
||||
|
||||
// in balance
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Time{}, false)
|
||||
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)
|
||||
@@ -225,12 +261,18 @@ func TestIsStreaming(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", unsafe.IsStreaming(), true)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Time{}, 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)
|
||||
}
|
||||
|
||||
d.LoadSnapshot([]Item{{Price: 1, Amount: 1}}, []Item{{Price: 2, Amount: 1}}, 0, time.Time{}, 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)
|
||||
}
|
||||
|
||||
@@ -638,13 +638,13 @@ func TestWsPriceAggregateOrderbook(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pressXToJSON := []byte(`[148,827987828,[["i",{"currencyPair":"BTC_ETH","orderBook":[{"0.02311264":"2.20557811","1000.02022945":"1.00000000","1000.17618025":"0.00100000","1148.00000000":"0.04594689","1997.00000000":"2.00000000","2000.00000000":"0.00000206","3000.00000000":"0.00000137","3772.00000000":"0.65977073","4000.00000000":"0.00000103","5000.00000000":"0.10284089"},{"0.02310611":"21.20361406","0.00010000":"2052.10260000","0.00009726":"17.85554185","0.00009170":"10.00000000","0.00008800":"8.00000000","0.00008000":"2.02050000","0.00007186":"6.95811300","0.00006060":"130.00000000","0.00005126":"1070.00000000","0.00005120":"195.31250000","0.00005000":"2120.00000000","0.00004295":"202.34435389","0.00004168":"95.96928983","0.00004000":"200.00000000","0.00003638":"137.43815283","0.00003500":"114.28657143","0.00003492":"6.90074951","0.00003101":"500.00000000","0.00003100":"1000.00000000","0.00002560":"390.62500000","0.00002500":"20000.00000000","0.00002000":"55.00000000","0.00001280":"781.25000000","0.00001010":"50.00000000","0.00001005":"146.26965174","0.00001000":"12109.99999999","0.00000640":"1562.50000000","0.00000550":"800.00000000","0.00000500":"200.00000000","0.00000331":"1000.00000000","0.00000330":"11479.02727273","0.00000320":"3125.00000000","0.00000200":"1000.00000001","0.00000178":"65.00000000","0.00000170":"100.00000000","0.00000164":"210.17073171","0.00000160":"6250.00000000","0.00000100":"1999.00000000","0.00000095":"1612.31578947","0.00000090":"1111.11111111","0.00000080":"12500.00000000","0.00000054":"557.96296296","0.00000040":"25000.00000000","0.00000020":"50000.00000000","0.00000010":"200000.00000000","0.00000005":"200000.00000000","0.00000004":"2500.00000000","0.00000002":"556100.00000000","0.00000001":"1182263.00000000"}]}]]]`)
|
||||
pressXToJSON := []byte(`[50,141160924,[["i",{"currencyPair":"BTC_LTC","orderBook":[{"0.002784":"17.55","0.002786":"1.47","0.002792":"13.25","0.0028":"0.21","0.002804":"0.02","0.00281":"1.5","0.002811":"258.82","0.002812":"3.81","0.002817":"0.06","0.002824":"3","0.002825":"0.02","0.002836":"18.01","0.002837":"0.03","0.00284":"0.03","0.002842":"12.7","0.00285":"0.02","0.002852":"0.02","0.002855":"1.3","0.002857":"15.64","0.002864":"0.01"},{"0.002782":"45.93","0.002781":"1.46","0.002774":"13.34","0.002773":"0.04","0.002771":"0.05","0.002765":"6.21","0.002764":"3","0.00276":"10.77","0.002758":"3.11","0.002754":"0.02","0.002751":"288.94","0.00275":"24.06","0.002745":"187.27","0.002743":"0.04","0.002742":"0.96","0.002731":"0.06","0.00273":"12.13","0.002727":"0.02","0.002725":"0.03","0.002719":"1.09"}]}, "1692080077892"]]]`)
|
||||
err = p.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pressXToJSON = []byte(`[148,827984670,[["o",0,"0.02328500","0.00000000"],["o",0,"0.02328498","0.04303557"]]]`)
|
||||
pressXToJSON = []byte(`[50,141160925,[["o",1,"0.002742","0", "1692080078806"],["o",1,"0.002718","0.02", "1692080078806"]]]`)
|
||||
err = p.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -391,6 +391,20 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
errTypeAssertionFailure)
|
||||
}
|
||||
|
||||
if len(data) < 3 {
|
||||
return fmt.Errorf("%w for pair %v", errNotEnoughData, pair)
|
||||
}
|
||||
|
||||
ts, ok := data[2].(string)
|
||||
if !ok {
|
||||
return common.GetTypeAssertError("string", data[2], "timestamp string")
|
||||
}
|
||||
|
||||
tsMilli, err := strconv.ParseInt(ts, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oMap, ok := subDataMap["orderBook"]
|
||||
if !ok {
|
||||
return errors.New("could not find orderbook data in map")
|
||||
@@ -421,7 +435,8 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
var book orderbook.Base
|
||||
book.Asks = make(orderbook.Items, 0, len(askData))
|
||||
for price, volume := range askData {
|
||||
p, err := strconv.ParseFloat(price, 64)
|
||||
var p float64
|
||||
p, err = strconv.ParseFloat(price, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -430,7 +445,8 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
return fmt.Errorf("%w ask volume data not string",
|
||||
errTypeAssertionFailure)
|
||||
}
|
||||
a, err := strconv.ParseFloat(v, 64)
|
||||
var a float64
|
||||
a, err = strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -439,7 +455,8 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
|
||||
book.Bids = make(orderbook.Items, 0, len(bidData))
|
||||
for price, volume := range bidData {
|
||||
p, err := strconv.ParseFloat(price, 64)
|
||||
var p float64
|
||||
p, err = strconv.ParseFloat(price, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -448,7 +465,8 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
return fmt.Errorf("%w bid volume data not string",
|
||||
errTypeAssertionFailure)
|
||||
}
|
||||
a, err := strconv.ParseFloat(v, 64)
|
||||
var a float64
|
||||
a, err = strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -460,8 +478,7 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
book.Bids.SortBids()
|
||||
book.Asset = asset.Spot
|
||||
book.VerifyOrderbook = p.CanVerifyOrderbook
|
||||
|
||||
var err error
|
||||
book.LastUpdated = time.UnixMilli(tsMilli)
|
||||
book.Pair, err = currency.NewPairFromString(pair)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -473,7 +490,7 @@ func (p *Poloniex) WsProcessOrderbookSnapshot(data []interface{}) error {
|
||||
|
||||
// WsProcessOrderbookUpdate processes new orderbook updates
|
||||
func (p *Poloniex) WsProcessOrderbookUpdate(sequenceNumber float64, data []interface{}, pair currency.Pair) error {
|
||||
if len(data) < 4 {
|
||||
if len(data) < 5 {
|
||||
return errNotEnoughData
|
||||
}
|
||||
|
||||
@@ -497,10 +514,22 @@ func (p *Poloniex) WsProcessOrderbookUpdate(sequenceNumber float64, data []inter
|
||||
if !ok {
|
||||
return fmt.Errorf("%w buysell not float64", errTypeAssertionFailure)
|
||||
}
|
||||
|
||||
ts, ok := data[4].(string)
|
||||
if !ok {
|
||||
return common.GetTypeAssertError("string", data[2], "timestamp string")
|
||||
}
|
||||
|
||||
tsMilli, err := strconv.ParseInt(ts, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
update := &orderbook.Update{
|
||||
Pair: pair,
|
||||
Asset: asset.Spot,
|
||||
UpdateID: int64(sequenceNumber),
|
||||
Pair: pair,
|
||||
Asset: asset.Spot,
|
||||
UpdateID: int64(sequenceNumber),
|
||||
UpdateTime: time.UnixMilli(tsMilli),
|
||||
}
|
||||
if bs == 1 {
|
||||
update.Bids = []orderbook.Item{{Price: price, Amount: volume}}
|
||||
|
||||
@@ -245,7 +245,10 @@ func (w *Orderbook) processObUpdate(o *orderbookHolder, u *orderbook.Update) err
|
||||
if w.updateEntriesByID {
|
||||
return o.updateByIDAndAction(u)
|
||||
}
|
||||
o.updateByPrice(u)
|
||||
err := o.updateByPrice(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if w.checksum != nil {
|
||||
compare, err := o.ob.Retrieve()
|
||||
if err != nil {
|
||||
@@ -262,8 +265,8 @@ func (w *Orderbook) processObUpdate(o *orderbookHolder, u *orderbook.Update) err
|
||||
|
||||
// updateByPrice amends amount if match occurs by price, deletes if amount is
|
||||
// zero or less and inserts if not found.
|
||||
func (o *orderbookHolder) updateByPrice(updts *orderbook.Update) {
|
||||
o.ob.UpdateBidAskByPrice(updts)
|
||||
func (o *orderbookHolder) updateByPrice(updts *orderbook.Update) error {
|
||||
return o.ob.UpdateBidAskByPrice(updts)
|
||||
}
|
||||
|
||||
// updateByIDAndAction will receive an action to execute against the orderbook
|
||||
@@ -328,11 +331,15 @@ func (w *Orderbook) LoadSnapshot(book *orderbook.Base) error {
|
||||
}
|
||||
|
||||
holder.updateID = book.LastUpdateID
|
||||
holder.ob.LoadSnapshot(book.Bids,
|
||||
|
||||
err = holder.ob.LoadSnapshot(book.Bids,
|
||||
book.Asks,
|
||||
book.LastUpdateID,
|
||||
book.LastUpdated,
|
||||
false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if holder.ob.VerifyOrderbook {
|
||||
// This is used here so as to not retrieve book if verification is off.
|
||||
|
||||
@@ -41,6 +41,7 @@ func createSnapshot() (holder *Orderbook, asks, bids orderbook.Items, err error)
|
||||
Asset: asset.Spot,
|
||||
Pair: cp,
|
||||
PriceDuplication: true,
|
||||
LastUpdated: time.Now(),
|
||||
}
|
||||
|
||||
newBook := make(map[Key]*orderbookHolder)
|
||||
@@ -93,7 +94,10 @@ func BenchmarkUpdateBidsByPrice(b *testing.B) {
|
||||
Asset: asset.Spot,
|
||||
}
|
||||
holder := ob.ob[Key{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}]
|
||||
holder.updateByPrice(update)
|
||||
err = holder.updateByPrice(update)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +117,10 @@ func BenchmarkUpdateAsksByPrice(b *testing.B) {
|
||||
Asset: asset.Spot,
|
||||
}
|
||||
holder := ob.ob[Key{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}]
|
||||
holder.updateByPrice(update)
|
||||
err = holder.updateByPrice(update)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +247,7 @@ func TestUpdates(t *testing.T) {
|
||||
}
|
||||
|
||||
book := holder.ob[Key{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}]
|
||||
book.updateByPrice(&orderbook.Update{
|
||||
err = book.updateByPrice(&orderbook.Update{
|
||||
Bids: itemArray[5],
|
||||
Asks: itemArray[5],
|
||||
Pair: cp,
|
||||
@@ -251,7 +258,7 @@ func TestUpdates(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
book.updateByPrice(&orderbook.Update{
|
||||
err = book.updateByPrice(&orderbook.Update{
|
||||
Bids: itemArray[0],
|
||||
Asks: itemArray[0],
|
||||
Pair: cp,
|
||||
@@ -375,11 +382,12 @@ func TestSortIDs(t *testing.T) {
|
||||
asks := itemArray[i]
|
||||
bids := itemArray[i]
|
||||
err = holder.Update(&orderbook.Update{
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: int64(i),
|
||||
Asset: asset.Spot,
|
||||
Bids: bids,
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: int64(i),
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -420,10 +428,11 @@ func TestOutOfOrderIDs(t *testing.T) {
|
||||
for i := range itemArray {
|
||||
asks := itemArray[i]
|
||||
err = holder.Update(&orderbook.Update{
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: outOFOrderIDs[i],
|
||||
Asset: asset.Spot,
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: outOFOrderIDs[i],
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -454,10 +463,11 @@ func TestOrderbookLastUpdateID(t *testing.T) {
|
||||
|
||||
// this update invalidates the book
|
||||
err = holder.Update(&orderbook.Update{
|
||||
Asks: []orderbook.Item{{Price: 999999}},
|
||||
Pair: cp,
|
||||
UpdateID: -1,
|
||||
Asset: asset.Spot,
|
||||
Asks: []orderbook.Item{{Price: 999999}},
|
||||
Pair: cp,
|
||||
UpdateID: -1,
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if !errors.Is(err, orderbook.ErrOrderbookInvalid) {
|
||||
t.Fatalf("received: %v but expected: %v", err, orderbook.ErrOrderbookInvalid)
|
||||
@@ -474,10 +484,11 @@ func TestOrderbookLastUpdateID(t *testing.T) {
|
||||
for i := range itemArray {
|
||||
asks := itemArray[i]
|
||||
err = holder.Update(&orderbook.Update{
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: int64(i) + 1,
|
||||
Asset: asset.Spot,
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
UpdateID: int64(i) + 1,
|
||||
Asset: asset.Spot,
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -566,6 +577,7 @@ func TestRunSnapshotWithNoData(t *testing.T) {
|
||||
snapShot1.Pair = cp
|
||||
snapShot1.Exchange = "test"
|
||||
obl.exchangeName = "test"
|
||||
snapShot1.LastUpdated = time.Now()
|
||||
err := obl.LoadSnapshot(&snapShot1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -590,6 +602,7 @@ func TestLoadSnapshot(t *testing.T) {
|
||||
snapShot1.Bids = bids
|
||||
snapShot1.Asset = asset.Spot
|
||||
snapShot1.Pair = cp
|
||||
snapShot1.LastUpdated = time.Now()
|
||||
err := obl.LoadSnapshot(&snapShot1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -651,6 +664,7 @@ func TestInsertingSnapShots(t *testing.T) {
|
||||
snapShot1.Bids = bids
|
||||
snapShot1.Asset = asset.Spot
|
||||
snapShot1.Pair = cp
|
||||
snapShot1.LastUpdated = time.Now()
|
||||
err := holder.LoadSnapshot(&snapShot1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -694,6 +708,7 @@ func TestInsertingSnapShots(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
snapShot2.LastUpdated = time.Now()
|
||||
err = holder.LoadSnapshot(&snapShot2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -737,6 +752,7 @@ func TestInsertingSnapShots(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
snapShot3.LastUpdated = time.Now()
|
||||
err = holder.LoadSnapshot(&snapShot3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -873,7 +889,7 @@ func TestEnsureMultipleUpdatesViaPrice(t *testing.T) {
|
||||
|
||||
asks := bidAskGenerator()
|
||||
book := holder.ob[Key{Base: cp.Base.Item, Quote: cp.Quote.Item, Asset: asset.Spot}]
|
||||
book.updateByPrice(&orderbook.Update{
|
||||
err = book.updateByPrice(&orderbook.Update{
|
||||
Bids: asks,
|
||||
Asks: asks,
|
||||
Pair: cp,
|
||||
@@ -916,7 +932,10 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Time{}, true)
|
||||
err = book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ob, err := book.Retrieve()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -948,7 +967,10 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errAmendFailure)
|
||||
}
|
||||
|
||||
book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Time{}, true)
|
||||
err = book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// append to slice
|
||||
err = holder.updateByIDAndAction(&orderbook.Update{
|
||||
Action: orderbook.UpdateInsert,
|
||||
@@ -966,6 +988,7 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
Amount: 1,
|
||||
},
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1000,6 +1023,7 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
Amount: 100,
|
||||
},
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1035,6 +1059,7 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
Amount: 99,
|
||||
},
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1053,7 +1078,10 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
t.Fatal("did not adjust ask item placement and details")
|
||||
}
|
||||
|
||||
book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Time{}, true) //nolint:gocritic
|
||||
err = book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Now(), true) //nolint:gocritic
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Delete - not found
|
||||
err = holder.updateByIDAndAction(&orderbook.Update{
|
||||
Action: orderbook.Delete,
|
||||
@@ -1069,13 +1097,17 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errDeleteFailure)
|
||||
}
|
||||
|
||||
book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Time{}, true) //nolint:gocritic
|
||||
err = book.LoadSnapshot(append(bids[:0:0], bids...), append(asks[:0:0], asks...), 0, time.Now(), true) //nolint:gocritic
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Delete - found
|
||||
err = holder.updateByIDAndAction(&orderbook.Update{
|
||||
Action: orderbook.Delete,
|
||||
Asks: []orderbook.Item{
|
||||
asks[0],
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
@@ -1101,7 +1133,10 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, errAmendFailure)
|
||||
}
|
||||
|
||||
book.LoadSnapshot(bids, bids, 0, time.Time{}, true)
|
||||
err = book.LoadSnapshot(bids, bids, 0, time.Now(), true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ob, err = book.Retrieve()
|
||||
if !errors.Is(err, nil) {
|
||||
@@ -1119,6 +1154,7 @@ func TestUpdateByIDAndAction(t *testing.T) {
|
||||
Asks: []orderbook.Item{
|
||||
update,
|
||||
},
|
||||
UpdateTime: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -1154,6 +1190,7 @@ func TestFlushOrderbook(t *testing.T) {
|
||||
snapShot1.Bids = bids
|
||||
snapShot1.Asset = asset.Spot
|
||||
snapShot1.Pair = cp
|
||||
snapShot1.LastUpdated = time.Now()
|
||||
|
||||
err = w.FlushOrderbook(cp, asset.Spot)
|
||||
if err == nil {
|
||||
|
||||
@@ -133,6 +133,7 @@ func (z *ZB) wsHandleData(respRaw []byte) error {
|
||||
Pair: cPair,
|
||||
Exchange: z.Name,
|
||||
VerifyOrderbook: z.CanVerifyOrderbook,
|
||||
LastUpdated: time.Now(), // This is temp to pass test as the API is broken.
|
||||
}
|
||||
|
||||
for i := range depth.Asks {
|
||||
|
||||
Reference in New Issue
Block a user