code.vegaprotocol.io/vega@v0.79.0/core/subscribers/market_depth_test.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_test 17 18 import ( 19 "context" 20 "testing" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/core/subscribers" 24 "code.vegaprotocol.io/vega/core/types" 25 "code.vegaprotocol.io/vega/libs/num" 26 27 "github.com/stretchr/testify/assert" 28 ) 29 30 func getTestMDB(t *testing.T, ctx context.Context) *subscribers.MarketDepthBuilder { 31 t.Helper() 32 return subscribers.NewMarketDepthBuilder(ctx, nil, true) 33 } 34 35 func buildOrder(id string, side types.Side, orderType types.OrderType, price uint64, size uint64, remaining uint64) *types.Order { 36 order := &types.Order{ 37 ID: id, 38 Side: side, 39 Type: orderType, 40 Price: num.NewUint(price), 41 OriginalPrice: num.NewUint(price), 42 Size: size, 43 Remaining: remaining, 44 TimeInForce: types.OrderTimeInForceGTC, 45 Status: types.OrderStatusActive, 46 MarketID: "M", 47 } 48 return order 49 } 50 51 //nolint:unparam 52 func newPeggedOrder(reference types.PeggedReference, offset uint64) *types.PeggedOrder { 53 return &types.PeggedOrder{ 54 Reference: reference, 55 Offset: num.NewUint(offset), 56 } 57 } 58 59 func TestBuyPriceLevels(t *testing.T) { 60 ctx := context.Background() 61 mdb := getTestMDB(t, ctx) 62 63 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 9, 9) 64 event1 := events.NewOrderEvent(ctx, order1) 65 mdb.Push(event1) 66 67 order2 := buildOrder("Order2", types.SideBuy, types.OrderTypeLimit, 102, 7, 7) 68 event2 := events.NewOrderEvent(ctx, order2) 69 mdb.Push(event2) 70 71 order3 := buildOrder("Order3", types.SideBuy, types.OrderTypeLimit, 101, 8, 8) 72 event3 := events.NewOrderEvent(ctx, order3) 73 mdb.Push(event3) 74 75 order4 := buildOrder("Order4", types.SideBuy, types.OrderTypeLimit, 99, 10, 10) 76 event4 := events.NewOrderEvent(ctx, order4) 77 mdb.Push(event4) 78 79 // add some icebergs too 80 order5 := buildOrder("Order5", types.SideBuy, types.OrderTypeLimit, 98, 10, 10) 81 order5.IcebergOrder = &types.IcebergOrder{ReservedRemaining: 50} 82 event5 := events.NewOrderEvent(ctx, order5) 83 mdb.Push(event5) 84 85 assert.Equal(t, 5, mdb.GetBuyPriceLevels("M")) 86 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 87 assert.Equal(t, int64(5), mdb.GetOrderCount("M")) 88 89 assert.Equal(t, uint64(7), mdb.GetVolumeAtPrice("M", types.SideBuy, 102)) 90 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 102)) 91 92 assert.Equal(t, uint64(8), mdb.GetVolumeAtPrice("M", types.SideBuy, 101)) 93 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 101)) 94 95 assert.Equal(t, uint64(9), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 96 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 97 98 assert.Equal(t, uint64(10), mdb.GetVolumeAtPrice("M", types.SideBuy, 99)) 99 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 99)) 100 101 assert.Equal(t, uint64(60), mdb.GetVolumeAtPrice("M", types.SideBuy, 98)) 102 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 98)) 103 } 104 105 func TestSellPriceLevels(t *testing.T) { 106 ctx := context.Background() 107 mdb := getTestMDB(t, ctx) 108 109 order1 := buildOrder("Order1", types.SideSell, types.OrderTypeLimit, 100, 9, 9) 110 event1 := events.NewOrderEvent(ctx, order1) 111 mdb.Push(event1) 112 113 order2 := buildOrder("Order2", types.SideSell, types.OrderTypeLimit, 102, 7, 7) 114 event2 := events.NewOrderEvent(ctx, order2) 115 mdb.Push(event2) 116 117 order3 := buildOrder("Order3", types.SideSell, types.OrderTypeLimit, 101, 8, 8) 118 event3 := events.NewOrderEvent(ctx, order3) 119 mdb.Push(event3) 120 121 order4 := buildOrder("Order4", types.SideSell, types.OrderTypeLimit, 99, 10, 10) 122 event4 := events.NewOrderEvent(ctx, order4) 123 mdb.Push(event4) 124 125 // add some icebergs too 126 order5 := buildOrder("Order5", types.SideSell, types.OrderTypeLimit, 98, 10, 10) 127 order5.IcebergOrder = &types.IcebergOrder{ReservedRemaining: 50} 128 event5 := events.NewOrderEvent(ctx, order5) 129 mdb.Push(event5) 130 131 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 132 assert.Equal(t, 5, mdb.GetSellPriceLevels("M")) 133 assert.Equal(t, int64(5), mdb.GetOrderCount("M")) 134 135 assert.Equal(t, uint64(7), mdb.GetVolumeAtPrice("M", types.SideSell, 102)) 136 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideSell, 102)) 137 138 assert.Equal(t, uint64(8), mdb.GetVolumeAtPrice("M", types.SideSell, 101)) 139 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideSell, 101)) 140 141 assert.Equal(t, uint64(9), mdb.GetVolumeAtPrice("M", types.SideSell, 100)) 142 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideSell, 100)) 143 144 assert.Equal(t, uint64(10), mdb.GetVolumeAtPrice("M", types.SideSell, 99)) 145 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideSell, 99)) 146 147 assert.Equal(t, uint64(60), mdb.GetVolumeAtPrice("M", types.SideSell, 98)) 148 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideSell, 98)) 149 } 150 151 func TestAddOrderToEmptyBook(t *testing.T) { 152 ctx := context.Background() 153 mdb := getTestMDB(t, ctx) 154 155 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 156 event := events.NewOrderEvent(ctx, order) 157 mdb.Push(event) 158 159 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 160 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 161 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 162 163 assert.Equal(t, uint64(10), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 164 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 165 } 166 167 func TestCancelOrder(t *testing.T) { 168 ctx := context.Background() 169 mdb := getTestMDB(t, ctx) 170 171 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 172 event := events.NewOrderEvent(ctx, order) 173 mdb.Push(event) 174 175 cancelorder := *order 176 cancelorder.Status = types.OrderStatusCancelled 177 event2 := events.NewOrderEvent(ctx, &cancelorder) 178 mdb.Push(event2) 179 180 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 181 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 182 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 183 184 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 185 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 186 } 187 188 func TestCancelIcebergOrder(t *testing.T) { 189 ctx := context.Background() 190 mdb := getTestMDB(t, ctx) 191 192 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 193 order.IcebergOrder = &types.IcebergOrder{ReservedRemaining: 50} 194 event := events.NewOrderEvent(ctx, order) 195 mdb.Push(event) 196 197 cancelorder := *order 198 cancelorder.Status = types.OrderStatusCancelled 199 event2 := events.NewOrderEvent(ctx, &cancelorder) 200 mdb.Push(event2) 201 202 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 203 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 204 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 205 206 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 207 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 208 } 209 210 func TestStoppedOrder(t *testing.T) { 211 ctx := context.Background() 212 mdb := getTestMDB(t, ctx) 213 214 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 215 event := events.NewOrderEvent(ctx, order) 216 mdb.Push(event) 217 218 cancelorder := *order 219 cancelorder.Status = types.OrderStatusStopped 220 event2 := events.NewOrderEvent(ctx, &cancelorder) 221 mdb.Push(event2) 222 223 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 224 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 225 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 226 227 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 228 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 229 } 230 231 func TestExpiredOrder(t *testing.T) { 232 ctx := context.Background() 233 mdb := getTestMDB(t, ctx) 234 235 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 236 event := events.NewOrderEvent(ctx, order) 237 mdb.Push(event) 238 239 cancelorder := *order 240 cancelorder.Status = types.OrderStatusExpired 241 event2 := events.NewOrderEvent(ctx, &cancelorder) 242 mdb.Push(event2) 243 244 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 245 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 246 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 247 248 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 249 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 250 } 251 252 func TestAmendOrderPrice(t *testing.T) { 253 ctx := context.Background() 254 mdb := getTestMDB(t, ctx) 255 256 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 257 event := events.NewOrderEvent(ctx, order) 258 mdb.Push(event) 259 260 order2 := buildOrder("Order2", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 261 event2 := events.NewOrderEvent(ctx, order2) 262 mdb.Push(event2) 263 264 // Amend the price to force a change in price level 265 amendorder := *order 266 amendorder.Price = num.NewUint(90) 267 amendorder.OriginalPrice = num.NewUint(90) 268 event3 := events.NewOrderEvent(ctx, &amendorder) 269 mdb.Push(event3) 270 271 assert.Equal(t, 2, mdb.GetBuyPriceLevels("M")) 272 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 273 assert.Equal(t, int64(2), mdb.GetOrderCount("M")) 274 275 assert.Equal(t, uint64(10), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 276 assert.Equal(t, uint64(10), mdb.GetVolumeAtPrice("M", types.SideBuy, 90)) 277 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 278 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 90)) 279 } 280 281 func TestAmendOrderVolumeUp(t *testing.T) { 282 ctx := context.Background() 283 mdb := getTestMDB(t, ctx) 284 285 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 286 event := events.NewOrderEvent(ctx, order) 287 mdb.Push(event) 288 289 amendorder := *order 290 amendorder.Size = 20 291 amendorder.Remaining = 20 292 event2 := events.NewOrderEvent(ctx, &amendorder) 293 mdb.Push(event2) 294 295 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 296 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 297 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 298 299 assert.Equal(t, uint64(20), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 300 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 301 } 302 303 func TestAmendOrderVolumeDown(t *testing.T) { 304 ctx := context.Background() 305 mdb := getTestMDB(t, ctx) 306 307 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 308 event := events.NewOrderEvent(ctx, order) 309 mdb.Push(event) 310 311 amendorder := *order 312 amendorder.Size = 5 313 amendorder.Remaining = 5 314 event2 := events.NewOrderEvent(ctx, &amendorder) 315 mdb.Push(event2) 316 317 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 318 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 319 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 320 321 assert.Equal(t, uint64(5), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 322 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 323 } 324 325 func TestAmendOrderVolumeDownToZero(t *testing.T) { 326 ctx := context.Background() 327 mdb := getTestMDB(t, ctx) 328 329 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 330 event := events.NewOrderEvent(ctx, order) 331 mdb.Push(event) 332 333 amendorder := *order 334 amendorder.Size = 0 335 amendorder.Remaining = 0 336 event2 := events.NewOrderEvent(ctx, &amendorder) 337 mdb.Push(event2) 338 339 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 340 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 341 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 342 343 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 344 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 345 } 346 347 func TestPartialFill(t *testing.T) { 348 ctx := context.Background() 349 mdb := getTestMDB(t, ctx) 350 351 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 352 event := events.NewOrderEvent(ctx, order) 353 mdb.Push(event) 354 355 pforder := *order 356 pforder.Remaining = 5 357 event2 := events.NewOrderEvent(ctx, &pforder) 358 mdb.Push(event2) 359 360 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 361 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 362 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 363 364 assert.Equal(t, uint64(5), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 365 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 366 } 367 368 func TestIOCPartialFill(t *testing.T) { 369 ctx := context.Background() 370 mdb := getTestMDB(t, ctx) 371 372 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 5) 373 order.Status = types.OrderStatusPartiallyFilled 374 order.TimeInForce = types.OrderTimeInForceIOC 375 event := events.NewOrderEvent(ctx, order) 376 mdb.Push(event) 377 378 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 379 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 380 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 381 382 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 383 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 384 } 385 386 func TestFullyFill(t *testing.T) { 387 ctx := context.Background() 388 mdb := getTestMDB(t, ctx) 389 390 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 391 event := events.NewOrderEvent(ctx, order) 392 mdb.Push(event) 393 394 fforder := *order 395 fforder.Remaining = 0 396 fforder.Status = types.OrderStatusFilled 397 event2 := events.NewOrderEvent(ctx, &fforder) 398 mdb.Push(event2) 399 400 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 401 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 402 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 403 404 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 405 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 406 } 407 408 func TestMarketOrder(t *testing.T) { 409 ctx := context.Background() 410 mdb := getTestMDB(t, ctx) 411 412 // market orders should not stay on the book 413 marketorder := buildOrder("Order1", types.SideBuy, types.OrderTypeMarket, 100, 10, 10) 414 event1 := events.NewOrderEvent(ctx, marketorder) 415 mdb.Push(event1) 416 417 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 418 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 419 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 420 421 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 422 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 423 } 424 425 func TestFOKOrder(t *testing.T) { 426 ctx := context.Background() 427 mdb := getTestMDB(t, ctx) 428 429 // FOK orders do not stay on the book 430 fokorder := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 431 fokorder.TimeInForce = types.OrderTimeInForceFOK 432 event := events.NewOrderEvent(ctx, fokorder) 433 mdb.Push(event) 434 435 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 436 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 437 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 438 439 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 440 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 441 } 442 443 func TestIOCOrder(t *testing.T) { 444 ctx := context.Background() 445 mdb := getTestMDB(t, ctx) 446 447 // IOC orders do not stay on the book 448 iocorder := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 449 iocorder.TimeInForce = types.OrderTimeInForceIOC 450 event := events.NewOrderEvent(ctx, iocorder) 451 mdb.Push(event) 452 453 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 454 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 455 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 456 457 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 458 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 459 } 460 461 func TestRejectedOrder(t *testing.T) { 462 ctx := context.Background() 463 mdb := getTestMDB(t, ctx) 464 465 // Rejected orders should be ignored 466 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 467 order.Status = types.OrderStatusRejected 468 event := events.NewOrderEvent(ctx, order) 469 mdb.Push(event) 470 471 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 472 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 473 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 474 475 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 476 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 477 } 478 479 func TestInvalidOrder(t *testing.T) { 480 ctx := context.Background() 481 mdb := getTestMDB(t, ctx) 482 483 // Invalid orders should be ignored 484 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 485 order.Status = types.OrderStatusUnspecified 486 event := events.NewOrderEvent(ctx, order) 487 mdb.Push(event) 488 489 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 490 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 491 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 492 493 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 494 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 495 } 496 497 func TestPartialMatchOrders(t *testing.T) { 498 ctx := context.Background() 499 mdb := getTestMDB(t, ctx) 500 501 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 502 event1 := events.NewOrderEvent(ctx, order1) 503 mdb.Push(event1) 504 order2 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 8) 505 event2 := events.NewOrderEvent(ctx, order2) 506 mdb.Push(event2) 507 508 order3 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 5) 509 event3 := events.NewOrderEvent(ctx, order3) 510 mdb.Push(event3) 511 order4 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 1) 512 event4 := events.NewOrderEvent(ctx, order4) 513 mdb.Push(event4) 514 515 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 516 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 517 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 518 519 assert.Equal(t, uint64(1), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 520 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 521 } 522 523 func TestFullyMatchOrders(t *testing.T) { 524 ctx := context.Background() 525 mdb := getTestMDB(t, ctx) 526 527 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 528 event1 := events.NewOrderEvent(ctx, order1) 529 mdb.Push(event1) 530 order2 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 8) 531 event2 := events.NewOrderEvent(ctx, order2) 532 mdb.Push(event2) 533 534 order3 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 5) 535 event3 := events.NewOrderEvent(ctx, order3) 536 mdb.Push(event3) 537 order4 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 0) 538 order4.Status = types.OrderStatusFilled 539 event4 := events.NewOrderEvent(ctx, order4) 540 mdb.Push(event4) 541 542 assert.Equal(t, 0, mdb.GetBuyPriceLevels("M")) 543 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 544 assert.Equal(t, int64(0), mdb.GetOrderCount("M")) 545 546 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 547 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 548 } 549 550 func TestRemovingPriceLevels(t *testing.T) { 551 ctx := context.Background() 552 mdb := getTestMDB(t, ctx) 553 554 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 10) 555 event1 := events.NewOrderEvent(ctx, order1) 556 mdb.Push(event1) 557 order2 := buildOrder("Order2", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 558 event2 := events.NewOrderEvent(ctx, order2) 559 mdb.Push(event2) 560 order3 := buildOrder("Order3", types.SideBuy, types.OrderTypeLimit, 102, 10, 10) 561 event3 := events.NewOrderEvent(ctx, order3) 562 mdb.Push(event3) 563 564 order4 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 0) 565 order4.Status = types.OrderStatusFilled 566 event4 := events.NewOrderEvent(ctx, order4) 567 mdb.Push(event4) 568 569 assert.Equal(t, 2, mdb.GetBuyPriceLevels("M")) 570 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 571 assert.Equal(t, int64(2), mdb.GetOrderCount("M")) 572 573 assert.Equal(t, uint64(0), mdb.GetVolumeAtPrice("M", types.SideBuy, 101)) 574 assert.Equal(t, uint64(0), mdb.GetOrderCountAtPrice("M", types.SideBuy, 101)) 575 } 576 577 func TestMarketDepthFields(t *testing.T) { 578 ctx := context.Background() 579 mdb := getTestMDB(t, ctx) 580 581 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 10) 582 event1 := events.NewOrderEvent(ctx, order1) 583 mdb.Push(event1) 584 585 md, err := mdb.GetMarketDepth(ctx, "M", 0) 586 assert.Nil(t, err) 587 assert.NotNil(t, md) 588 589 assert.Equal(t, "M", md.MarketId) 590 assert.Equal(t, 1, len(md.GetBuy())) 591 592 priceLevels := md.GetBuy() 593 pl := priceLevels[0] 594 assert.NotNil(t, pl) 595 assert.Equal(t, uint64(1), pl.NumberOfOrders) 596 assert.Equal(t, "101", pl.Price) 597 assert.Equal(t, uint64(10), pl.Volume) 598 } 599 600 func TestParkingOrder(t *testing.T) { 601 ctx := context.Background() 602 mdb := getTestMDB(t, ctx) 603 604 // Create a valid and live pegged order 605 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 10) 606 order1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 607 event1 := events.NewOrderEvent(ctx, order1) 608 mdb.Push(event1) 609 610 // Park it 611 order2 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 0, 10, 10) 612 order2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 613 order2.Status = types.OrderStatusParked 614 event2 := events.NewOrderEvent(ctx, order2) 615 mdb.Push(event2) 616 617 md, err := mdb.GetMarketDepth(ctx, "M", 0) 618 assert.Nil(t, err) 619 assert.NotNil(t, md) 620 621 assert.Equal(t, "M", md.MarketId) 622 assert.Equal(t, 0, len(md.GetBuy())) 623 assert.Equal(t, 0, len(md.GetSell())) 624 625 // Unpark it 626 order3 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 10) 627 order3.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 628 order3.Status = types.OrderStatusActive 629 event3 := events.NewOrderEvent(ctx, order3) 630 mdb.Push(event3) 631 632 md2, err := mdb.GetMarketDepth(ctx, "M", 0) 633 assert.Nil(t, err) 634 assert.NotNil(t, md2) 635 636 assert.Equal(t, "M", md2.MarketId) 637 assert.Equal(t, 1, len(md2.GetBuy())) 638 assert.Equal(t, 0, len(md2.GetSell())) 639 } 640 641 func TestParkedOrder(t *testing.T) { 642 ctx := context.Background() 643 mdb := getTestMDB(t, ctx) 644 645 // Create a parked pegged order which should not go on the depth book 646 order1 := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 101, 10, 10) 647 order1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 648 order1.Status = types.OrderStatusParked 649 event1 := events.NewOrderEvent(ctx, order1) 650 mdb.Push(event1) 651 652 md, err := mdb.GetMarketDepth(ctx, "M", 0) 653 assert.Nil(t, err) 654 assert.NotNil(t, md) 655 656 assert.Equal(t, "M", md.MarketId) 657 assert.Equal(t, 0, len(md.GetBuy())) 658 assert.Equal(t, 0, len(md.GetSell())) 659 } 660 661 func TestParkedOrder2(t *testing.T) { 662 ctx := context.Background() 663 mdb := getTestMDB(t, ctx) 664 665 // Create parked pegged order 666 order1 := buildOrder("Pegged1", types.SideBuy, types.OrderTypeLimit, 0, 10, 10) 667 order1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 668 order1.Status = types.OrderStatusParked 669 event1 := events.NewOrderEvent(ctx, order1) 670 mdb.Push(event1) 671 672 // Create normal order 673 order2 := buildOrder("Normal1", types.SideBuy, types.OrderTypeLimit, 100, 1, 1) 674 event2 := events.NewOrderEvent(ctx, order2) 675 mdb.Push(event2) 676 677 // Unpark pegged order 678 order3 := buildOrder("Pegged1", types.SideBuy, types.OrderTypeLimit, 99, 10, 10) 679 order3.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 680 order3.Status = types.OrderStatusActive 681 event3 := events.NewOrderEvent(ctx, order3) 682 mdb.Push(event3) 683 684 // Cancel normal order 685 order4 := buildOrder("Normal1", types.SideBuy, types.OrderTypeLimit, 100, 1, 1) 686 order4.Status = types.OrderStatusCancelled 687 event4 := events.NewOrderEvent(ctx, order4) 688 mdb.Push(event4) 689 690 // Park pegged order 691 order5 := buildOrder("Pegged1", types.SideBuy, types.OrderTypeLimit, 99, 10, 10) 692 order5.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 693 order5.Status = types.OrderStatusParked 694 event5 := events.NewOrderEvent(ctx, order5) 695 mdb.Push(event5) 696 697 // Create normal order 698 order6 := buildOrder("Normal2", types.SideBuy, types.OrderTypeLimit, 100, 1, 1) 699 event6 := events.NewOrderEvent(ctx, order6) 700 mdb.Push(event6) 701 702 // Unpark pegged order 703 order7 := buildOrder("Pegged1", types.SideBuy, types.OrderTypeLimit, 99, 10, 10) 704 order7.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 705 order7.Status = types.OrderStatusActive 706 event7 := events.NewOrderEvent(ctx, order7) 707 mdb.Push(event7) 708 709 // Fill normal order 710 order8 := buildOrder("Normal2", types.SideBuy, types.OrderTypeLimit, 100, 1, 0) 711 order8.Status = types.OrderStatusFilled 712 event8 := events.NewOrderEvent(ctx, order8) 713 mdb.Push(event8) 714 715 // Create new matching order 716 order9 := buildOrder("Normal3", types.SideSell, types.OrderTypeLimit, 100, 1, 0) 717 order9.Status = types.OrderStatusFilled 718 event9 := events.NewOrderEvent(ctx, order9) 719 mdb.Push(event9) 720 721 // Park pegged order 722 order10 := buildOrder("Pegged1", types.SideBuy, types.OrderTypeLimit, 99, 10, 10) 723 order10.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1) 724 order10.Status = types.OrderStatusParked 725 event10 := events.NewOrderEvent(ctx, order10) 726 mdb.Push(event10) 727 728 md, err := mdb.GetMarketDepth(ctx, "M", 0) 729 assert.Nil(t, err) 730 assert.NotNil(t, md) 731 732 assert.Equal(t, "M", md.MarketId) 733 assert.Equal(t, 0, len(md.GetBuy())) 734 assert.Equal(t, 0, len(md.GetSell())) 735 } 736 737 func TestIcebergRefresh(t *testing.T) { 738 ctx := context.Background() 739 mdb := getTestMDB(t, ctx) 740 741 order := buildOrder("Order1", types.SideBuy, types.OrderTypeLimit, 100, 10, 10) 742 order.IcebergOrder = &types.IcebergOrder{ReservedRemaining: 50} 743 event := events.NewOrderEvent(ctx, order) 744 mdb.Push(event) 745 746 // pretend the iceberg refreshed, so its remaining increased and reserve went down 747 amendorder := *order 748 amendorder.Size = 60 749 amendorder.Remaining = 15 750 amendorder.IcebergOrder.ReservedRemaining = 40 751 event2 := events.NewOrderEvent(ctx, &amendorder) 752 mdb.Push(event2) 753 754 assert.Equal(t, 1, mdb.GetBuyPriceLevels("M")) 755 assert.Equal(t, 0, mdb.GetSellPriceLevels("M")) 756 assert.Equal(t, int64(1), mdb.GetOrderCount("M")) 757 758 assert.Equal(t, uint64(55), mdb.GetVolumeAtPrice("M", types.SideBuy, 100)) 759 assert.Equal(t, uint64(1), mdb.GetOrderCountAtPrice("M", types.SideBuy, 100)) 760 }