code.vegaprotocol.io/vega@v0.79.0/datanode/entities/market_depth.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 entities 17 18 import ( 19 "errors" 20 "sort" 21 22 "code.vegaprotocol.io/vega/core/types" 23 "code.vegaprotocol.io/vega/libs/num" 24 "code.vegaprotocol.io/vega/protos/vega" 25 ) 26 27 type PriceLevel struct { 28 // Price of the price level 29 Price *num.Uint 30 // How many orders are at this level 31 TotalOrders uint64 32 // How much volume is at this level 33 TotalVolume uint64 34 // How much volume from AMM's are at this level 35 TotalAMMVolume uint64 36 // How much estimated volume from AMM's are at this level 37 TotalEstimatedAMMVolume uint64 38 // What side of the book is this level 39 Side types.Side 40 } 41 42 type MarketDepth struct { 43 // Which market is this for 44 MarketID string 45 // All of the orders in the order book 46 LiveOrders map[string]*types.Order 47 // Just the buy side of the book 48 BuySide []*PriceLevel 49 // Just the sell side of the book 50 SellSide []*PriceLevel 51 // All price levels that have changed in the last update 52 Changes []*PriceLevel 53 // Sequence number is an increment-only value to identify a state 54 // of the market depth in time. Used when trying to match updates 55 // to a snapshot dump 56 SequenceNumber uint64 57 // PreviousSequenceNumber is the sequence number of the last published update. 'Changes' include 58 // updates from all events with a sequence number > PreviousSequenceNumber and <= SequenceNumber 59 PreviousSequenceNumber uint64 60 } 61 62 func (md *MarketDepth) ToProto(limit uint64) *vega.MarketDepth { 63 buyLimit := uint64(len(md.BuySide)) 64 sellLimit := uint64(len(md.SellSide)) 65 if limit > 0 { 66 buyLimit = min(buyLimit, limit) 67 sellLimit = min(sellLimit, limit) 68 } 69 70 buyPtr := make([]*types.PriceLevel, buyLimit) 71 sellPtr := make([]*types.PriceLevel, sellLimit) 72 73 // Copy the data across 74 for index, pl := range md.BuySide[:buyLimit] { 75 buyPtr[index] = &types.PriceLevel{ 76 Volume: pl.TotalVolume, 77 NumberOfOrders: pl.TotalOrders, 78 Price: pl.Price.Clone(), 79 AMMVolume: pl.TotalAMMVolume, 80 AMMVolumeEstimated: pl.TotalEstimatedAMMVolume, 81 } 82 } 83 84 for index, pl := range md.SellSide[:sellLimit] { 85 sellPtr[index] = &types.PriceLevel{ 86 Volume: pl.TotalVolume, 87 NumberOfOrders: pl.TotalOrders, 88 Price: pl.Price.Clone(), 89 AMMVolume: pl.TotalAMMVolume, 90 AMMVolumeEstimated: pl.TotalEstimatedAMMVolume, 91 } 92 } 93 94 return &types.MarketDepth{ 95 MarketId: md.MarketID, 96 Buy: types.PriceLevels(buyPtr).IntoProto(), 97 Sell: types.PriceLevels(sellPtr).IntoProto(), 98 SequenceNumber: md.SequenceNumber, 99 } 100 } 101 102 func (md *MarketDepth) AddAMMOrder(order *types.Order, estimated bool) { 103 md.addOrder(order, estimated) 104 } 105 106 func (md *MarketDepth) AddOrderUpdate(order *types.Order, estimated bool) { 107 // Do we know about this order already? 108 originalOrder := md.orderExists(order.ID) 109 if originalOrder != nil { 110 // Check to see if we are updating the order or removing it 111 if order.Status == types.OrderStatusCancelled || 112 order.Status == types.OrderStatusExpired || 113 order.Status == types.OrderStatusStopped || 114 order.Status == types.OrderStatusFilled || 115 order.Status == types.OrderStatusPartiallyFilled || 116 order.Status == types.OrderStatusRejected || 117 order.Status == types.OrderStatusParked { 118 md.removeOrder(originalOrder, estimated) 119 } else { 120 md.updateOrder(originalOrder, order) 121 } 122 } else { 123 if order.TrueRemaining() > 0 && order.Status == types.OrderStatusActive { 124 md.addOrder(order, estimated) 125 } 126 } 127 } 128 129 func (md *MarketDepth) orderExists(orderID string) *types.Order { 130 return md.LiveOrders[orderID] 131 } 132 133 func (md *MarketDepth) addOrder(order *types.Order, estimated bool) { 134 // Cache the orderID 135 orderCopy := order.Clone() 136 md.LiveOrders[order.ID] = orderCopy 137 138 // Update the price level 139 pl := md.GetPriceLevel(order.Side, order.Price) 140 141 if pl == nil { 142 pl = md.createNewPriceLevel(order, estimated) 143 } else if order.GeneratedOffbook { 144 if estimated { 145 pl.TotalEstimatedAMMVolume += order.TrueRemaining() 146 } else { 147 pl.TotalAMMVolume += order.TrueRemaining() 148 } 149 } else { 150 pl.TotalOrders++ 151 pl.TotalVolume += order.TrueRemaining() 152 } 153 md.Changes = append(md.Changes, pl) 154 } 155 156 func (md *MarketDepth) removeOrder(order *types.Order, estimated bool) error { 157 // Find the price level 158 pl := md.GetPriceLevel(order.Side, order.Price) 159 160 if pl == nil { 161 return errors.New("unknown pricelevel") 162 } 163 // Update the values 164 if order.GeneratedOffbook { 165 if estimated { 166 pl.TotalEstimatedAMMVolume -= order.TrueRemaining() 167 } else { 168 pl.TotalAMMVolume -= order.TrueRemaining() 169 } 170 } else { 171 pl.TotalOrders-- 172 pl.TotalVolume -= order.TrueRemaining() 173 } 174 175 // See if we can remove this price level 176 if pl.TotalOrders == 0 { 177 md.removePriceLevel(order) 178 } 179 180 md.Changes = append(md.Changes, pl) 181 182 // Remove the orderID from the list of live orders 183 delete(md.LiveOrders, order.ID) 184 return nil 185 } 186 187 func (md *MarketDepth) updateOrder(originalOrder, newOrder *types.Order) { 188 // If the price is the same, we can update the original order 189 if originalOrder.Price.EQ(newOrder.Price) { 190 if newOrder.TrueRemaining() == 0 { 191 md.removeOrder(newOrder, false) 192 } else { 193 // Update 194 pl := md.GetPriceLevel(originalOrder.Side, originalOrder.Price) 195 pl.TotalVolume += newOrder.TrueRemaining() - originalOrder.TrueRemaining() 196 originalOrder.Remaining = newOrder.Remaining 197 if originalOrder.IcebergOrder != nil { 198 originalOrder.IcebergOrder = newOrder.IcebergOrder.Clone() 199 } 200 originalOrder.Size = newOrder.Size 201 md.Changes = append(md.Changes, pl) 202 } 203 } else { 204 md.removeOrder(originalOrder, false) 205 if newOrder.TrueRemaining() > 0 { 206 md.addOrder(newOrder, false) 207 } 208 } 209 } 210 211 func (md *MarketDepth) createNewPriceLevel(order *types.Order, estimated bool) *PriceLevel { 212 pl := &PriceLevel{ 213 Price: order.Price.Clone(), 214 Side: order.Side, 215 } 216 217 if order.GeneratedOffbook { 218 if estimated { 219 pl.TotalEstimatedAMMVolume = order.TrueRemaining() 220 } else { 221 pl.TotalAMMVolume = order.TrueRemaining() 222 } 223 } else { 224 pl.TotalOrders = 1 225 pl.TotalVolume = order.TrueRemaining() 226 } 227 228 if order.Side == types.SideBuy { 229 index := sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(order.Price) }) 230 if index < len(md.BuySide) { 231 // We need to go midslice 232 md.BuySide = append(md.BuySide, nil) 233 copy(md.BuySide[index+1:], md.BuySide[index:]) 234 md.BuySide[index] = pl 235 } else { 236 // We can tag on the end 237 md.BuySide = append(md.BuySide, pl) 238 } 239 } else { 240 index := sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(order.Price) }) 241 if index < len(md.SellSide) { 242 // We need to go midslice 243 md.SellSide = append(md.SellSide, nil) 244 copy(md.SellSide[index+1:], md.SellSide[index:]) 245 md.SellSide[index] = pl 246 } else { 247 // We can tag on the end 248 md.SellSide = append(md.SellSide, pl) 249 } 250 } 251 return pl 252 } 253 254 func (md *MarketDepth) GetPriceLevel(side types.Side, price *num.Uint) *PriceLevel { 255 var i int 256 if side == types.SideBuy { 257 // buy side levels should be ordered in descending 258 i = sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(price) }) 259 if i < len(md.BuySide) && md.BuySide[i].Price.EQ(price) { 260 return md.BuySide[i] 261 } 262 } else { 263 // sell side levels should be ordered in ascending 264 i = sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(price) }) 265 if i < len(md.SellSide) && md.SellSide[i].Price.EQ(price) { 266 return md.SellSide[i] 267 } 268 } 269 return nil 270 } 271 272 func (md *MarketDepth) removePriceLevel(order *types.Order) { 273 var i int 274 if order.Side == types.SideBuy { 275 // buy side levels should be ordered in descending 276 i = sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(order.Price) }) 277 if i < len(md.BuySide) && md.BuySide[i].Price.EQ(order.Price) { 278 copy(md.BuySide[i:], md.BuySide[i+1:]) 279 md.BuySide[len(md.BuySide)-1] = nil 280 md.BuySide = md.BuySide[:len(md.BuySide)-1] 281 } 282 } else { 283 // sell side levels should be ordered in ascending 284 i = sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(order.Price) }) 285 // we found the level just return it. 286 if i < len(md.SellSide) && md.SellSide[i].Price.EQ(order.Price) { 287 copy(md.SellSide[i:], md.SellSide[i+1:]) 288 md.SellSide[len(md.SellSide)-1] = nil 289 md.SellSide = md.SellSide[:len(md.SellSide)-1] 290 } 291 } 292 } 293 294 // Returns the min of 2 uint64s. 295 func min(x, y uint64) uint64 { 296 if y < x { 297 return y 298 } 299 return x 300 }