code.vegaprotocol.io/vega@v0.79.0/core/matching/cached_orderbook.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package matching 17 18 import ( 19 "context" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/num" 25 "code.vegaprotocol.io/vega/logging" 26 ) 27 28 type CachedOrderBook struct { 29 *OrderBook 30 cache BookCache 31 } 32 33 func NewCachedOrderBook( 34 log *logging.Logger, config Config, market string, auction bool, peggedCounterNotify func(int64), 35 ) *CachedOrderBook { 36 return &CachedOrderBook{ 37 OrderBook: NewOrderBook(log, config, market, auction, peggedCounterNotify), 38 cache: NewBookCache(), 39 } 40 } 41 42 func (b *CachedOrderBook) SetOffbookSource(obs OffbookSource) { 43 b.OrderBook.SetOffbookSource(obs) 44 } 45 46 func (b *CachedOrderBook) LoadState(ctx context.Context, payload *types.Payload) ([]types.StateProvider, error) { 47 providers, err := b.OrderBook.LoadState(ctx, payload) 48 if err != nil { 49 return providers, err 50 } 51 52 if b.auction { 53 b.cache.Invalidate() 54 b.log.Info("restoring orderbook cache for", logging.String("marketID", b.marketID)) 55 b.GetIndicativePriceAndVolume() 56 } 57 58 return providers, err 59 } 60 61 func (b *CachedOrderBook) EnterAuction() []*types.Order { 62 b.cache.Invalidate() 63 return b.OrderBook.EnterAuction() 64 } 65 66 func (b *CachedOrderBook) LeaveAuction( 67 at time.Time, 68 ) ([]*types.OrderConfirmation, []*types.Order, error) { 69 b.cache.Invalidate() 70 return b.OrderBook.LeaveAuction(at) 71 } 72 73 func (b *CachedOrderBook) CancelAllOrders( 74 party string, 75 ) ([]*types.OrderCancellationConfirmation, error) { 76 b.cache.Invalidate() 77 return b.OrderBook.CancelAllOrders(party) 78 } 79 80 func (b *CachedOrderBook) maybeInvalidateDuringAuction(orderID string) { 81 bestBid, errBestBid := b.GetBestBidPrice() 82 bestAsk, errBestAsk := b.GetBestAskPrice() 83 // if any of side have not best price, let's invalidate 84 if errBestBid != nil || errBestAsk != nil { 85 b.cache.Invalidate() 86 return 87 } 88 89 order, ok := b.ordersByID[orderID] 90 if !ok { 91 b.log.Panic("could not find order in order book", logging.OrderID(orderID)) 92 } 93 94 // only invalidate cache if it gets in the 95 // uncrossing range 96 switch order.Side { 97 case types.SideBuy: 98 if order.Price.GTE(bestAsk) { 99 b.cache.Invalidate() 100 } 101 case types.SideSell: 102 if order.Price.LTE(bestBid) { 103 b.cache.Invalidate() 104 } 105 } 106 } 107 108 func (b *CachedOrderBook) maybeInvalidateDuringAuctionNewOrder(order *types.Order) { 109 bestBid, errBestBid := b.GetBestBidPrice() 110 bestAsk, errBestAsk := b.GetBestAskPrice() 111 // if any of side have not best price, let's invalidate 112 if errBestBid != nil || errBestAsk != nil { 113 b.cache.Invalidate() 114 return 115 } 116 117 // only invalidate cache if it gets in the 118 // uncrossing range 119 switch order.Side { 120 case types.SideBuy: 121 if order.Price.GTE(bestAsk) { 122 b.cache.Invalidate() 123 } 124 case types.SideSell: 125 if order.Price.LTE(bestBid) { 126 b.cache.Invalidate() 127 } 128 } 129 } 130 131 func (b *CachedOrderBook) CancelOrder(order *types.Order) (*types.OrderCancellationConfirmation, error) { 132 if !b.InAuction() { 133 b.cache.Invalidate() 134 } else { 135 b.maybeInvalidateDuringAuction(order.ID) 136 } 137 return b.OrderBook.CancelOrder(order) 138 } 139 140 func (b *CachedOrderBook) RemoveOrder(order string) (*types.Order, error) { 141 if !b.InAuction() { 142 b.cache.Invalidate() 143 } else { 144 b.maybeInvalidateDuringAuction(order) 145 } 146 return b.OrderBook.RemoveOrder(order) 147 } 148 149 func (b *CachedOrderBook) AmendOrder( 150 originalOrder, amendedOrder *types.Order, 151 ) error { 152 if !b.InAuction() { 153 b.cache.Invalidate() 154 } else { 155 b.maybeInvalidateDuringAuction(amendedOrder.ID) 156 } 157 return b.OrderBook.AmendOrder(originalOrder, amendedOrder) 158 } 159 160 func (b *CachedOrderBook) ReplaceOrder(rm, rpl *types.Order) (*types.OrderConfirmation, error) { 161 if !b.InAuction() { 162 b.cache.Invalidate() 163 } else { 164 b.maybeInvalidateDuringAuction(rpl.ID) 165 } 166 return b.OrderBook.ReplaceOrder(rm, rpl) 167 } 168 169 func (b *CachedOrderBook) SubmitOrder( 170 order *types.Order, 171 ) (*types.OrderConfirmation, error) { 172 if !b.InAuction() { 173 b.cache.Invalidate() 174 } else { 175 b.maybeInvalidateDuringAuctionNewOrder(order) 176 } 177 return b.OrderBook.SubmitOrder(order) 178 } 179 180 func (b *CachedOrderBook) DeleteOrder( 181 order *types.Order, 182 ) (*types.Order, error) { 183 if !b.InAuction() { 184 b.cache.Invalidate() 185 } else { 186 b.maybeInvalidateDuringAuction(order.ID) 187 } 188 return b.OrderBook.DeleteOrder(order) 189 } 190 191 func (b *CachedOrderBook) RemoveDistressedOrders( 192 parties []events.MarketPosition, 193 ) ([]*types.Order, error) { 194 b.cache.Invalidate() 195 return b.OrderBook.RemoveDistressedOrders(parties) 196 } 197 198 func (b *CachedOrderBook) GetIndicativePriceAndVolume() (*num.Uint, uint64, types.Side) { 199 price, cachedPriceOk := b.cache.GetIndicativePrice() 200 volume, cachedVolOk := b.cache.GetIndicativeVolume() 201 side, cachedSideOk := b.cache.GetIndicativeUncrossingSide() 202 if !cachedPriceOk || !cachedVolOk || !cachedSideOk { 203 r := b.OrderBook.GetIndicativePriceAndVolume() 204 price, volume, side = r.price, r.volume, r.side 205 206 b.cache.SetIndicativePrice(price.Clone()) 207 b.cache.SetIndicativeVolume(volume) 208 b.cache.SetIndicativeUncrossingSide(side) 209 } 210 return price, volume, side 211 } 212 213 func (b *CachedOrderBook) GetIndicativePrice() *num.Uint { 214 price, ok := b.cache.GetIndicativePrice() 215 216 if !ok { 217 price = b.OrderBook.GetIndicativePrice() 218 b.cache.SetIndicativePrice(price.Clone()) 219 } 220 return price 221 } 222 223 func (b *CachedOrderBook) UpdateAMM(party string) { 224 if !b.auction { 225 return 226 } 227 228 b.cache.Invalidate() 229 b.OrderBook.UpdateAMM(party) 230 }