code.vegaprotocol.io/vega@v0.79.0/datanode/service/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 service 17 18 import ( 19 "context" 20 "sync" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/datanode/entities" 25 "code.vegaprotocol.io/vega/datanode/utils" 26 "code.vegaprotocol.io/vega/libs/num" 27 "code.vegaprotocol.io/vega/logging" 28 "code.vegaprotocol.io/vega/protos/vega" 29 ) 30 31 type OrderStore interface { 32 GetLiveOrders(ctx context.Context) ([]entities.Order, error) 33 } 34 35 type AMMStore interface { 36 ListActive(ctx context.Context) ([]entities.AMMPool, error) 37 } 38 39 type Positions interface { 40 GetByMarketAndParty(ctx context.Context, marketID string, partyID string) (entities.Position, error) 41 } 42 43 type AssetStore interface { 44 GetByID(ctx context.Context, id string) (entities.Asset, error) 45 } 46 47 type ammCache struct { 48 priceFactor num.Decimal // the price factor for this market 49 ammOrders map[string][]*types.Order // map amm id -> expanded orders, so we can remove them if amended 50 activeAMMs map[string]entities.AMMPool // map amm id -> amm definition, so we can refresh its expansion 51 estimatedOrder map[string]struct{} // order-id -> whether it was an estimated order 52 53 // the lowest/highest bounds of all AMMs 54 lowestBound num.Decimal 55 highestBound num.Decimal 56 57 // reference -> calculation levels, if the reference point hasn't changed we can avoid the busy task 58 // of recalculating them 59 levels map[string][]*level 60 } 61 62 func (c *ammCache) addAMM(a entities.AMMPool) { 63 c.activeAMMs[a.AmmPartyID.String()] = a 64 65 low := a.ParametersBase 66 if a.ParametersLowerBound != nil { 67 low = *a.ParametersLowerBound 68 } 69 70 if c.lowestBound.IsZero() { 71 c.lowestBound = low 72 } else { 73 c.lowestBound = num.MinD(c.lowestBound, low) 74 } 75 76 high := a.ParametersBase 77 if a.ParametersUpperBound != nil { 78 high = *a.ParametersUpperBound 79 } 80 c.highestBound = num.MaxD(c.highestBound, high) 81 } 82 83 func (c *ammCache) removeAMM(ammParty string) { 84 delete(c.activeAMMs, ammParty) 85 delete(c.ammOrders, ammParty) 86 87 // now we need to recalculate the lowest/highest 88 89 c.lowestBound = num.DecimalZero() 90 c.highestBound = num.DecimalZero() 91 for _, a := range c.activeAMMs { 92 low := a.ParametersBase 93 if a.ParametersLowerBound != nil { 94 low = *a.ParametersLowerBound 95 } 96 if c.lowestBound.IsZero() { 97 c.lowestBound = low 98 } else { 99 c.lowestBound = num.MinD(c.lowestBound, low) 100 } 101 102 high := a.ParametersBase 103 if a.ParametersUpperBound != nil { 104 high = *a.ParametersUpperBound 105 } 106 c.lowestBound = num.MaxD(c.highestBound, high) 107 } 108 } 109 110 type MarketDepth struct { 111 log *logging.Logger 112 cfg MarketDepthConfig 113 marketDepths map[string]*entities.MarketDepth 114 orderStore OrderStore 115 ammStore AMMStore 116 assetStore AssetStore 117 markets MarketStore 118 marketData MarketDataStore 119 positions Positions 120 depthObserver utils.Observer[*types.MarketDepth] 121 updateObserver utils.Observer[*types.MarketDepthUpdate] 122 mu sync.RWMutex 123 sequenceNumber uint64 124 125 ammCache map[string]*ammCache 126 } 127 128 func NewMarketDepth( 129 cfg MarketDepthConfig, 130 orderStore OrderStore, 131 ammStore AMMStore, 132 marketData MarketDataStore, 133 positions Positions, 134 assets AssetStore, 135 markets MarketStore, 136 logger *logging.Logger, 137 ) *MarketDepth { 138 return &MarketDepth{ 139 log: logger, 140 cfg: cfg, 141 marketDepths: map[string]*entities.MarketDepth{}, 142 orderStore: orderStore, 143 ammStore: ammStore, 144 marketData: marketData, 145 positions: positions, 146 assetStore: assets, 147 markets: markets, 148 depthObserver: utils.NewObserver[*types.MarketDepth]("market_depth", logger, 100, 100), 149 updateObserver: utils.NewObserver[*types.MarketDepthUpdate]("market_depth_update", logger, 100, 100), 150 ammCache: map[string]*ammCache{}, 151 } 152 } 153 154 func (m *MarketDepth) Initialise(ctx context.Context) error { 155 liveOrders, err := m.orderStore.GetLiveOrders(ctx) 156 if err != nil { 157 return err 158 } 159 160 // process the live orders and initialize market depths from database data 161 for _, liveOrder := range liveOrders { 162 order, err := types.OrderFromProto(liveOrder.ToProto()) 163 if err != nil { 164 panic(err) 165 } 166 m.AddOrder(order, liveOrder.VegaTime, liveOrder.SeqNum) 167 } 168 169 m.InitialiseAMMs(ctx) 170 171 return nil 172 } 173 174 func (m *MarketDepth) PublishAtEndOfBlock() { 175 m.publishChanges() 176 } 177 178 func (m *MarketDepth) publishChanges() { 179 m.mu.Lock() 180 defer m.mu.Unlock() 181 for marketID, md := range m.marketDepths { 182 buyPtr := []*types.PriceLevel{} 183 sellPtr := []*types.PriceLevel{} 184 185 // No need to notify anyone if nothing has changed 186 if len(md.Changes) == 0 { 187 continue 188 } 189 190 // Send out market depth updates to any listeners 191 for _, pl := range md.Changes { 192 if pl.Side == types.SideBuy { 193 buyPtr = append(buyPtr, &types.PriceLevel{ 194 Price: pl.Price.Clone(), 195 NumberOfOrders: pl.TotalOrders, 196 Volume: pl.TotalVolume, 197 }) 198 } else { 199 sellPtr = append(sellPtr, &types.PriceLevel{ 200 Price: pl.Price.Clone(), 201 NumberOfOrders: pl.TotalOrders, 202 Volume: pl.TotalVolume, 203 }) 204 } 205 } 206 207 marketDepthUpdate := &types.MarketDepthUpdate{ 208 MarketId: marketID, 209 Buy: types.PriceLevels(buyPtr).IntoProto(), 210 Sell: types.PriceLevels(sellPtr).IntoProto(), 211 SequenceNumber: md.SequenceNumber, 212 PreviousSequenceNumber: md.PreviousSequenceNumber, 213 } 214 215 m.updateObserver.Notify([]*types.MarketDepthUpdate{marketDepthUpdate}) 216 m.depthObserver.Notify([]*types.MarketDepth{md.ToProto(0)}) 217 218 // Clear the list of changes 219 md.Changes = make([]*entities.PriceLevel, 0, len(md.Changes)) 220 md.PreviousSequenceNumber = md.SequenceNumber 221 } 222 } 223 224 func (m *MarketDepth) sequential(t time.Time, sequenceNumber uint64) bool { 225 // we truncate the vegaTime by microsecond because Postgres only supports microsecond 226 // granularity for time. In order to be able to reproduce the same sequence numbers regardless 227 // the source, we have to truncate the time to microsecond granularity 228 n := uint64(t.Truncate(time.Microsecond).UnixNano()) + sequenceNumber 229 230 if m.sequenceNumber > n { 231 // This update is older than the current MarketDepth 232 return false 233 } 234 235 m.sequenceNumber = n 236 return true 237 } 238 239 func (m *MarketDepth) AddOrder(order *types.Order, vegaTime time.Time, sequenceNumber uint64) { 240 m.mu.Lock() 241 defer m.mu.Unlock() 242 243 // Non persistent and network orders do not matter 244 if order.Type == types.OrderTypeMarket || 245 order.TimeInForce == types.OrderTimeInForceFOK || 246 order.TimeInForce == types.OrderTimeInForceIOC { 247 return 248 } 249 250 // Orders that where not valid are ignored 251 if order.Status == types.OrderStatusUnspecified { 252 return 253 } 254 255 if !m.sequential(vegaTime, sequenceNumber) { 256 return 257 } 258 259 if m.isAMMOrder(order) { 260 // this AMM order has come through the orders stream, it can only mean that it has traded so we need to refresh its depth 261 m.onAMMTraded(order.Party, order.MarketID) 262 return 263 } 264 265 md := m.getDepth(order.MarketID) 266 md.AddOrderUpdate(order, false) 267 md.SequenceNumber = m.sequenceNumber 268 } 269 270 func (m *MarketDepth) getDepth(marketID string) *entities.MarketDepth { 271 // See if we already have a MarketDepth item for this market 272 if md := m.marketDepths[marketID]; md != nil { 273 return md 274 } 275 276 // First time we have an update for this market 277 // so we need to create a new MarketDepth 278 md := &entities.MarketDepth{ 279 MarketID: marketID, 280 LiveOrders: map[string]*types.Order{}, 281 } 282 md.SequenceNumber = m.sequenceNumber 283 m.marketDepths[marketID] = md 284 return md 285 } 286 287 // GetMarketDepth builds up the structure to be sent out to any market depth listeners. 288 func (m *MarketDepth) GetMarketDepth(market string, limit uint64) *types.MarketDepth { 289 m.mu.RLock() 290 defer m.mu.RUnlock() 291 md, ok := m.marketDepths[market] 292 if !ok || md == nil { 293 // When a market is new with no orders there will not be any market depth/order book 294 // so we do not need to try and calculate the depth cumulative volumes etc 295 return &types.MarketDepth{ 296 MarketId: market, 297 Buy: []*vega.PriceLevel{}, 298 Sell: []*vega.PriceLevel{}, 299 } 300 } 301 302 return md.ToProto(limit) 303 } 304 305 func (m *MarketDepth) ObserveDepth(ctx context.Context, retries int, marketIds []string) (<-chan []*types.MarketDepth, uint64) { 306 markets := map[string]bool{} 307 for _, id := range marketIds { 308 markets[id] = true 309 } 310 311 ch, ref := m.depthObserver.Observe(ctx, 312 retries, 313 func(md *types.MarketDepth) bool { return markets[md.MarketId] }) 314 return ch, ref 315 } 316 317 func (m *MarketDepth) ObserveDepthUpdates(ctx context.Context, retries int, marketIds []string) (<-chan []*types.MarketDepthUpdate, uint64) { 318 markets := map[string]bool{} 319 for _, id := range marketIds { 320 markets[id] = true 321 } 322 323 ch, ref := m.updateObserver.Observe(ctx, 324 retries, 325 func(md *types.MarketDepthUpdate) bool { return markets[md.MarketId] }) 326 return ch, ref 327 } 328 329 /*****************************************************************************/ 330 /* FUNCTIONS TO HELP WITH UNIT TESTING */ 331 /*****************************************************************************/ 332 333 func (m *MarketDepth) GetAllOrders(market string) map[string]*types.Order { 334 md := m.marketDepths[market] 335 if md != nil { 336 return md.LiveOrders 337 } 338 return nil 339 } 340 341 // GetOrderCount returns the number of live orders for the given market. 342 func (m *MarketDepth) GetOrderCount(market string) int64 { 343 var liveOrders int64 344 var bookOrders uint64 345 md := m.marketDepths[market] 346 if md != nil { 347 liveOrders = int64(len(md.LiveOrders)) 348 349 for _, pl := range md.BuySide { 350 bookOrders += pl.TotalOrders 351 } 352 353 for _, pl := range md.SellSide { 354 bookOrders += pl.TotalOrders 355 } 356 357 if liveOrders != int64(bookOrders) { 358 return -1 359 } 360 return liveOrders 361 } 362 return 0 363 } 364 365 // GetVolumeAtPrice returns the order volume at the given price level. 366 func (m *MarketDepth) GetVolumeAtPrice(market string, side types.Side, price uint64) uint64 { 367 md := m.marketDepths[market] 368 if md != nil { 369 pl := md.GetPriceLevel(side, num.NewUint(price)) 370 if pl == nil { 371 return 0 372 } 373 return pl.TotalVolume + pl.TotalAMMVolume 374 } 375 return 0 376 } 377 378 // GetVolumeAtPrice returns the order volume at the given price level. 379 func (m *MarketDepth) GetEstimatedVolumeAtPrice(market string, side types.Side, price uint64) uint64 { 380 md := m.marketDepths[market] 381 if md != nil { 382 pl := md.GetPriceLevel(side, num.NewUint(price)) 383 if pl == nil { 384 return 0 385 } 386 return pl.TotalEstimatedAMMVolume 387 } 388 return 0 389 } 390 391 // GetTotalVolume returns the total volume in the order book. 392 func (m *MarketDepth) GetTotalVolume(market string) int64 { 393 var volume int64 394 md := m.marketDepths[market] 395 if md != nil { 396 for _, pl := range md.BuySide { 397 volume += int64(pl.TotalVolume) + int64(pl.TotalAMMVolume) + int64(pl.TotalEstimatedAMMVolume) 398 } 399 400 for _, pl := range md.SellSide { 401 volume += int64(pl.TotalVolume) + int64(pl.TotalAMMVolume) + int64(pl.TotalEstimatedAMMVolume) 402 } 403 return volume 404 } 405 return 0 406 } 407 408 // GetAMMVolume returns the total volume in the order book. 409 func (m *MarketDepth) GetAMMVolume(market string, estimated bool) int64 { 410 var volume int64 411 md := m.marketDepths[market] 412 if md != nil { 413 for _, pl := range md.BuySide { 414 if estimated { 415 volume += int64(pl.TotalEstimatedAMMVolume) 416 continue 417 } 418 volume += int64(pl.TotalAMMVolume) 419 } 420 421 for _, pl := range md.SellSide { 422 if estimated { 423 volume += int64(pl.TotalEstimatedAMMVolume) 424 continue 425 } 426 volume += int64(pl.TotalAMMVolume) 427 } 428 return volume 429 } 430 return 0 431 } 432 433 // GetAMMVolume returns the total volume in the order book. 434 func (m *MarketDepth) GetTotalAMMVolume(market string) int64 { 435 return m.GetAMMVolume(market, true) + m.GetAMMVolume(market, false) 436 } 437 438 // GetOrderCountAtPrice returns the number of orders at the given price level. 439 func (m *MarketDepth) GetOrderCountAtPrice(market string, side types.Side, price uint64) uint64 { 440 md := m.marketDepths[market] 441 if md != nil { 442 pl := md.GetPriceLevel(side, num.NewUint(price)) 443 if pl == nil { 444 return 0 445 } 446 return pl.TotalOrders 447 } 448 return 0 449 } 450 451 // GetPriceLevels returns the number of non empty price levels. 452 func (m *MarketDepth) GetPriceLevels(market string) int { 453 return m.GetBuyPriceLevels(market) + m.GetSellPriceLevels(market) 454 } 455 456 // GetBestBidPrice returns the highest bid price in the book. 457 func (m *MarketDepth) GetBestBidPrice(market string) *num.Uint { 458 md := m.marketDepths[market] 459 if md != nil { 460 if len(md.BuySide) > 0 { 461 return md.BuySide[0].Price.Clone() 462 } 463 } 464 return num.UintZero() 465 } 466 467 // GetBestAskPrice returns the highest bid price in the book. 468 func (m *MarketDepth) GetBestAskPrice(market string) *num.Uint { 469 md := m.marketDepths[market] 470 if md != nil { 471 if len(md.SellSide) > 0 { 472 return md.SellSide[0].Price.Clone() 473 } 474 } 475 return num.UintZero() 476 } 477 478 // GetBuyPriceLevels returns the number of non empty buy price levels. 479 func (m *MarketDepth) GetBuyPriceLevels(market string) int { 480 md := m.marketDepths[market] 481 if md != nil { 482 return len(md.BuySide) 483 } 484 return 0 485 } 486 487 // GetSellPriceLevels returns the number of non empty sell price levels. 488 func (m *MarketDepth) GetSellPriceLevels(market string) int { 489 md := m.marketDepths[market] 490 if md != nil { 491 return len(md.SellSide) 492 } 493 return 0 494 }