code.vegaprotocol.io/vega@v0.79.0/core/subscribers/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 subscribers 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 "sort" 23 "sync" 24 25 "code.vegaprotocol.io/vega/core/events" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/logging" 29 ptypes "code.vegaprotocol.io/vega/protos/vega" 30 ) 31 32 type OE interface { 33 events.Event 34 Order() *ptypes.Order 35 } 36 37 type CO interface { 38 events.Event 39 OrderIDs() []string 40 MarketID() string 41 } 42 43 type priceLevel struct { 44 // Price of the price level 45 price *num.Uint 46 // How many orders are at this level 47 totalOrders uint64 48 // How much volume is at this level 49 totalVolume uint64 50 // What side of the book is this level 51 side types.Side 52 } 53 54 // MarketDepth holds all the details about a single markets MarketDepth. 55 type MarketDepth struct { 56 // Which market is this for 57 marketID string 58 // All of the orders in the order book 59 liveOrders map[string]*types.Order 60 // Just the buy side of the book 61 buySide []*priceLevel 62 // Just the sell side of the book 63 sellSide []*priceLevel 64 // All price levels that have changed in the last update 65 changes []*priceLevel 66 // Sequence number is an increment-only value to identify a state 67 // of the market depth in time. Used when trying to match updates 68 // to a snapshot dump 69 sequenceNumber uint64 70 } 71 72 // MarketDepthBuilder is a subscriber of order events 73 // used to build the live market depth structure. 74 type MarketDepthBuilder struct { 75 *Base 76 mu sync.RWMutex 77 // Map of all the markets to their market depth 78 marketDepths map[string]*MarketDepth 79 // Incrementing counter for subscriberID 80 subscriberID uint64 81 // Map of subscriberIds to their channels 82 subscribers map[uint64]chan<- *types.MarketDepthUpdate 83 // Logger 84 log *logging.Logger 85 } 86 87 // NewMarketDepthBuilder constructor to create a market depth subscriber. 88 func NewMarketDepthBuilder(ctx context.Context, log *logging.Logger, ack bool) *MarketDepthBuilder { 89 mdb := MarketDepthBuilder{ 90 Base: NewBase(ctx, 10, ack), 91 log: log, 92 marketDepths: map[string]*MarketDepth{}, 93 subscribers: map[uint64]chan<- *types.MarketDepthUpdate{}, 94 } 95 96 if mdb.isRunning() { 97 go mdb.loop(mdb.ctx) 98 } 99 return &mdb 100 } 101 102 func (mdb *MarketDepthBuilder) loop(ctx context.Context) { 103 for { 104 select { 105 case <-ctx.Done(): 106 mdb.Halt() 107 return 108 case e := <-mdb.ch: 109 if mdb.isRunning() { 110 mdb.Push(e...) 111 } 112 } 113 } 114 } 115 116 // Push takes order messages and applied them to the makret depth structure. 117 func (mdb *MarketDepthBuilder) Push(evts ...events.Event) { 118 for _, e := range evts { 119 switch et := e.(type) { 120 case OE: 121 order, _ := types.OrderFromProto(et.Order()) 122 mdb.updateMarketDepth(order) 123 case CO: 124 for _, o := range mdb.applyOrderCancellations(et) { 125 mdb.updateMarketDepth(o) 126 } 127 default: 128 mdb.log.Panic("Unknown event type in market depth builder", logging.String("Type", et.Type().String())) 129 } 130 } 131 } 132 133 func (mdb *MarketDepthBuilder) applyOrderCancellations(evt CO) []*types.Order { 134 mdb.mu.Lock() 135 defer mdb.mu.Unlock() 136 137 mktOrders, ok := mdb.marketDepths[evt.MarketID()] 138 if !ok { 139 return nil 140 } 141 orders := []*types.Order{} 142 for _, oid := range evt.OrderIDs() { 143 if o := mktOrders.orderExists(oid); o != nil { 144 cpy := o.Clone() 145 cpy.Status = types.OrderStatusCancelled 146 orders = append(orders, cpy) 147 } 148 } 149 return orders 150 } 151 152 // Types returns all the message types this subscriber wants to receive. 153 func (mdb *MarketDepthBuilder) Types() []events.Type { 154 ret := []events.Type{ 155 events.OrderEvent, 156 events.CancelledOrdersEvent, 157 } 158 return ret 159 } 160 161 func (md *MarketDepth) orderExists(orderID string) *types.Order { 162 return md.liveOrders[orderID] 163 } 164 165 func (md *MarketDepth) removeOrder(order *types.Order) error { 166 // Find the price level 167 pl := md.getPriceLevel(order.Side, order.Price) 168 169 if pl == nil { 170 return errors.New("unknown pricelevel") 171 } 172 // Update the values 173 pl.totalOrders-- 174 pl.totalVolume -= order.TrueRemaining() 175 176 // See if we can remove this price level 177 if pl.totalOrders == 0 { 178 md.removePriceLevel(order) 179 } 180 181 md.changes = append(md.changes, pl) 182 183 // Remove the orderID from the list of live orders 184 delete(md.liveOrders, order.ID) 185 return nil 186 } 187 188 func (md *MarketDepth) createNewPriceLevel(order *types.Order) *priceLevel { 189 pl := &priceLevel{ 190 price: order.Price.Clone(), 191 totalOrders: 1, 192 totalVolume: order.TrueRemaining(), 193 side: order.Side, 194 } 195 196 if order.Side == types.SideBuy { 197 index := sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(order.Price) }) 198 if index < len(md.buySide) { 199 // We need to go midslice 200 md.buySide = append(md.buySide, nil) 201 copy(md.buySide[index+1:], md.buySide[index:]) 202 md.buySide[index] = pl 203 } else { 204 // We can tag on the end 205 md.buySide = append(md.buySide, pl) 206 } 207 } else { 208 index := sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(order.Price) }) 209 if index < len(md.sellSide) { 210 // We need to go midslice 211 md.sellSide = append(md.sellSide, nil) 212 copy(md.sellSide[index+1:], md.sellSide[index:]) 213 md.sellSide[index] = pl 214 } else { 215 // We can tag on the end 216 md.sellSide = append(md.sellSide, pl) 217 } 218 } 219 return pl 220 } 221 222 func (md *MarketDepth) addOrder(order *types.Order) { 223 // Cache the orderID 224 orderCopy := order.Clone() 225 md.liveOrders[order.ID] = orderCopy 226 227 // Update the price level 228 pl := md.getPriceLevel(order.Side, order.Price) 229 230 if pl == nil { 231 pl = md.createNewPriceLevel(order) 232 } else { 233 pl.totalOrders++ 234 pl.totalVolume += order.TrueRemaining() 235 } 236 md.changes = append(md.changes, pl) 237 } 238 239 func (md *MarketDepth) updateOrder(originalOrder, newOrder *types.Order) { 240 // If the price is the same, we can update the original order 241 if originalOrder.Price.EQ(newOrder.Price) { 242 if newOrder.TrueRemaining() == 0 { 243 md.removeOrder(newOrder) 244 } else { 245 // Update 246 pl := md.getPriceLevel(originalOrder.Side, originalOrder.Price) 247 pl.totalVolume += newOrder.TrueRemaining() - originalOrder.TrueRemaining() 248 originalOrder.Remaining = newOrder.Remaining 249 originalOrder.Size = newOrder.Size 250 251 // copy across iceberg reserves 252 if originalOrder.IcebergOrder != nil { 253 originalOrder.IcebergOrder = newOrder.IcebergOrder.Clone() 254 } 255 md.changes = append(md.changes, pl) 256 } 257 } else { 258 md.removeOrder(originalOrder) 259 if newOrder.TrueRemaining() > 0 { 260 md.addOrder(newOrder) 261 } 262 } 263 } 264 265 func (md *MarketDepth) getPriceLevel(side types.Side, price *num.Uint) *priceLevel { 266 var i int 267 if side == types.SideBuy { 268 // buy side levels should be ordered in descending 269 i = sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(price) }) 270 if i < len(md.buySide) && md.buySide[i].price.EQ(price) { 271 return md.buySide[i] 272 } 273 } else { 274 // sell side levels should be ordered in ascending 275 i = sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(price) }) 276 if i < len(md.sellSide) && md.sellSide[i].price.EQ(price) { 277 return md.sellSide[i] 278 } 279 } 280 return nil 281 } 282 283 func (md *MarketDepth) removePriceLevel(order *types.Order) { 284 var i int 285 if order.Side == types.SideBuy { 286 // buy side levels should be ordered in descending 287 i = sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(order.Price) }) 288 if i < len(md.buySide) && md.buySide[i].price.EQ(order.Price) { 289 copy(md.buySide[i:], md.buySide[i+1:]) 290 md.buySide[len(md.buySide)-1] = nil 291 md.buySide = md.buySide[:len(md.buySide)-1] 292 } 293 } else { 294 // sell side levels should be ordered in ascending 295 i = sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(order.Price) }) 296 // we found the level just return it. 297 if i < len(md.sellSide) && md.sellSide[i].price.EQ(order.Price) { 298 copy(md.sellSide[i:], md.sellSide[i+1:]) 299 md.sellSide[len(md.sellSide)-1] = nil 300 md.sellSide = md.sellSide[:len(md.sellSide)-1] 301 } 302 } 303 } 304 305 func (mdb *MarketDepthBuilder) updateMarketDepth(order *types.Order) { 306 mdb.mu.Lock() 307 defer mdb.mu.Unlock() 308 309 // Non persistent and network orders do not matter 310 if order.Type == types.OrderTypeMarket || 311 order.TimeInForce == types.OrderTimeInForceFOK || 312 order.TimeInForce == types.OrderTimeInForceIOC { 313 return 314 } 315 316 // Orders that where not valid are ignored 317 if order.Status == types.OrderStatusUnspecified { 318 return 319 } 320 321 // See if we already have a MarketDepth item for this market 322 md := mdb.marketDepths[order.MarketID] 323 if md == nil { 324 // First time we have an update for this market 325 // so we need to create a new MarketDepth 326 md = &MarketDepth{ 327 marketID: order.MarketID, 328 liveOrders: map[string]*types.Order{}, 329 } 330 mdb.marketDepths[order.MarketID] = md 331 } 332 333 // Initialise changes slice ready for new items 334 md.changes = []*priceLevel{} 335 336 // Do we know about this order already? 337 originalOrder := md.orderExists(order.ID) 338 if originalOrder != nil { 339 // Check to see if we are updating the order or removing it 340 if order.Status == types.OrderStatusCancelled || 341 order.Status == types.OrderStatusExpired || 342 order.Status == types.OrderStatusStopped || 343 order.Status == types.OrderStatusFilled || 344 order.Status == types.OrderStatusPartiallyFilled || 345 order.Status == types.OrderStatusRejected || 346 order.Status == types.OrderStatusParked { 347 md.removeOrder(originalOrder) 348 } else { 349 md.updateOrder(originalOrder, order) 350 } 351 } else { 352 if order.TrueRemaining() > 0 && order.Status == types.OrderStatusActive { 353 md.addOrder(order) 354 } 355 } 356 357 // If nothing changed we can stop here 358 if len(md.changes) == 0 { 359 return 360 } 361 md.sequenceNumber++ 362 363 buyPtr := []*types.PriceLevel{} 364 sellPtr := []*types.PriceLevel{} 365 366 // Send out market depth updates to any listeners 367 for _, pl := range md.changes { 368 if pl.side == types.SideBuy { 369 buyPtr = append(buyPtr, &types.PriceLevel{ 370 Price: pl.price.Clone(), 371 NumberOfOrders: pl.totalOrders, 372 Volume: pl.totalVolume, 373 }) 374 } else { 375 sellPtr = append(sellPtr, &types.PriceLevel{ 376 Price: pl.price.Clone(), 377 NumberOfOrders: pl.totalOrders, 378 Volume: pl.totalVolume, 379 }) 380 } 381 } 382 383 marketDepthUpdate := &types.MarketDepthUpdate{ 384 MarketId: order.MarketID, 385 Buy: types.PriceLevels(buyPtr).IntoProto(), 386 Sell: types.PriceLevels(sellPtr).IntoProto(), 387 SequenceNumber: md.sequenceNumber, 388 } 389 390 for _, channel := range mdb.subscribers { 391 channel <- marketDepthUpdate 392 } 393 394 // Clear the list of changes 395 md.changes = make([]*priceLevel, 0, len(md.changes)) 396 } 397 398 // Returns the min of 2 uint64s. 399 func min(x, y uint64) uint64 { 400 if y < x { 401 return y 402 } 403 return x 404 } 405 406 // GetMarketDepth builds up the structure to be sent out to any market depth listeners. 407 func (mdb *MarketDepthBuilder) GetMarketDepth(ctx context.Context, market string, limit uint64) (*types.MarketDepth, error) { 408 mdb.mu.RLock() 409 defer mdb.mu.RUnlock() 410 md, ok := mdb.marketDepths[market] 411 if !ok || md == nil { 412 // When a market is new with no orders there will not be any market depth/order book 413 // so we do not need to try and calculate the depth cumulative volumes etc 414 return &types.MarketDepth{ 415 MarketId: market, 416 Buy: []*ptypes.PriceLevel{}, 417 Sell: []*ptypes.PriceLevel{}, 418 }, nil 419 } 420 421 buyLimit := uint64(len(md.buySide)) 422 sellLimit := uint64(len(md.sellSide)) 423 if limit > 0 { 424 buyLimit = min(buyLimit, limit) 425 sellLimit = min(sellLimit, limit) 426 } 427 428 buyPtr := make([]*types.PriceLevel, buyLimit) 429 sellPtr := make([]*types.PriceLevel, sellLimit) 430 431 // Copy the data across 432 for index, pl := range md.buySide[:buyLimit] { 433 buyPtr[index] = &types.PriceLevel{ 434 Volume: pl.totalVolume, 435 NumberOfOrders: pl.totalOrders, 436 Price: pl.price.Clone(), 437 } 438 } 439 440 for index, pl := range md.sellSide[:sellLimit] { 441 sellPtr[index] = &types.PriceLevel{ 442 Volume: pl.totalVolume, 443 NumberOfOrders: pl.totalOrders, 444 Price: pl.price.Clone(), 445 } 446 } 447 448 return &types.MarketDepth{ 449 MarketId: market, 450 Buy: types.PriceLevels(buyPtr).IntoProto(), 451 Sell: types.PriceLevels(sellPtr).IntoProto(), 452 SequenceNumber: md.sequenceNumber, 453 }, nil 454 } 455 456 /*****************************************************************************/ 457 /* FUNCTIONS TO HELP WITH UNIT TESTING */ 458 /*****************************************************************************/ 459 460 func (mdb *MarketDepthBuilder) GetAllOrders(market string) map[string]*types.Order { 461 if md := mdb.marketDepths[market]; md != nil { 462 return md.liveOrders 463 } 464 return nil 465 } 466 467 // GetOrderCount returns the number of live orders for the given market. 468 func (mdb *MarketDepthBuilder) GetOrderCount(market string) int64 { 469 var ( 470 liveOrders int64 471 bookOrders uint64 472 ) 473 if md := mdb.marketDepths[market]; md != nil { 474 liveOrders = int64(len(md.liveOrders)) 475 476 for _, pl := range md.buySide { 477 bookOrders += pl.totalOrders 478 } 479 480 for _, pl := range md.sellSide { 481 bookOrders += pl.totalOrders 482 } 483 484 if liveOrders != int64(bookOrders) { 485 return -1 486 } 487 return liveOrders 488 } 489 return 0 490 } 491 492 // GetVolumeAtPrice returns the order volume at the given price level. 493 func (mdb *MarketDepthBuilder) GetVolumeAtPrice(market string, side types.Side, price uint64) uint64 { 494 if md := mdb.marketDepths[market]; md != nil { 495 pl := md.getPriceLevel(side, num.NewUint(price)) 496 if pl == nil { 497 return 0 498 } 499 return pl.totalVolume 500 } 501 return 0 502 } 503 504 // GetTotalVolume returns the total volume in the order book. 505 func (mdb *MarketDepthBuilder) GetTotalVolume(market string) int64 { 506 var volume int64 507 if md := mdb.marketDepths[market]; md != nil { 508 for _, pl := range md.buySide { 509 volume += int64(pl.totalVolume) 510 } 511 512 for _, pl := range md.sellSide { 513 volume += int64(pl.totalVolume) 514 } 515 return volume 516 } 517 return 0 518 } 519 520 // GetOrderCountAtPrice returns the number of orders at the given price level. 521 func (mdb *MarketDepthBuilder) GetOrderCountAtPrice(market string, side types.Side, price uint64) uint64 { 522 if md := mdb.marketDepths[market]; md != nil { 523 pl := md.getPriceLevel(side, num.NewUint(price)) 524 if pl == nil { 525 return 0 526 } 527 return pl.totalOrders 528 } 529 return 0 530 } 531 532 // GetPriceLevels returns the number of non empty price levels. 533 func (mdb *MarketDepthBuilder) GetPriceLevels(market string) int { 534 return mdb.GetBuyPriceLevels(market) + mdb.GetSellPriceLevels(market) 535 } 536 537 // GetBestBidPrice returns the highest bid price in the book. 538 func (mdb *MarketDepthBuilder) GetBestBidPrice(market string) *num.Uint { 539 md := mdb.marketDepths[market] 540 if md != nil { 541 if len(md.buySide) > 0 { 542 return md.buySide[0].price.Clone() 543 } 544 } 545 return num.UintZero() 546 } 547 548 // GetBestAskPrice returns the highest bid price in the book. 549 func (mdb *MarketDepthBuilder) GetBestAskPrice(market string) *num.Uint { 550 md := mdb.marketDepths[market] 551 if md != nil { 552 if len(md.sellSide) > 0 { 553 return md.sellSide[0].price.Clone() 554 } 555 } 556 return num.UintZero() 557 } 558 559 // GetBuyPriceLevels returns the number of non empty buy price levels. 560 func (mdb *MarketDepthBuilder) GetBuyPriceLevels(market string) int { 561 if md := mdb.marketDepths[market]; md != nil { 562 return len(md.buySide) 563 } 564 return 0 565 } 566 567 // GetSellPriceLevels returns the number of non empty sell price levels. 568 func (mdb *MarketDepthBuilder) GetSellPriceLevels(market string) int { 569 if md := mdb.marketDepths[market]; md != nil { 570 return len(md.sellSide) 571 } 572 return 0 573 } 574 575 // Subscribe allows a client to register for updates of the market depth book. 576 func (mdb *MarketDepthBuilder) Subscribe(updates chan<- *types.MarketDepthUpdate) uint64 { 577 mdb.mu.Lock() 578 defer mdb.mu.Unlock() 579 580 mdb.subscriberID++ 581 mdb.subscribers[mdb.subscriberID] = updates 582 583 return mdb.subscriberID 584 } 585 586 // Unsubscribe allows the client to unregister interest in market depth updates. 587 func (mdb *MarketDepthBuilder) Unsubscribe(id uint64) error { 588 mdb.mu.Lock() 589 defer mdb.mu.Unlock() 590 591 if len(mdb.subscribers) == 0 { 592 return nil 593 } 594 595 if _, exists := mdb.subscribers[id]; exists { 596 delete(mdb.subscribers, id) 597 return nil 598 } 599 600 return fmt.Errorf("subscriber to market depth updates does not exist with id: %d", id) 601 }