code.vegaprotocol.io/vega@v0.79.0/core/matching/iceberg_orders_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 matching 17 18 import ( 19 "testing" 20 21 "code.vegaprotocol.io/vega/core/types" 22 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 23 "code.vegaprotocol.io/vega/libs/num" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func submitPeggedIcebergOrder(t *testing.T, book *tstOB, size, peak, minPeak uint64) (*types.Order, *types.OrderConfirmation) { 30 t.Helper() 31 o := &types.Order{ 32 ID: vgcrypto.RandomHash(), 33 Status: types.OrderStatusActive, 34 MarketID: book.marketID, 35 Party: "A", 36 Side: types.SideBuy, 37 Price: num.NewUint(100), 38 OriginalPrice: num.NewUint(100), 39 Size: size, 40 Remaining: size, 41 TimeInForce: types.OrderTimeInForceGTT, 42 Type: types.OrderTypeLimit, 43 ExpiresAt: 10, 44 PeggedOrder: &types.PeggedOrder{ 45 Reference: types.PeggedReferenceMid, 46 Offset: num.UintOne(), 47 }, 48 IcebergOrder: &types.IcebergOrder{ 49 PeakSize: peak, 50 MinimumVisibleSize: minPeak, 51 }, 52 } 53 confirm, err := book.SubmitOrder(o) 54 require.NoError(t, err) 55 return o, confirm 56 } 57 58 func submitIcebergOrder(t *testing.T, book *tstOB, size, peak, minPeak uint64, addToBook bool) (*types.Order, *types.OrderConfirmation) { 59 t.Helper() 60 o := &types.Order{ 61 ID: vgcrypto.RandomHash(), 62 Status: types.OrderStatusActive, 63 MarketID: book.marketID, 64 Party: "A", 65 Side: types.SideBuy, 66 Price: num.NewUint(100), 67 OriginalPrice: num.NewUint(100), 68 Size: size, 69 Remaining: size, 70 TimeInForce: types.OrderTimeInForceGTT, 71 Type: types.OrderTypeLimit, 72 ExpiresAt: 10, 73 IcebergOrder: &types.IcebergOrder{ 74 PeakSize: peak, 75 MinimumVisibleSize: minPeak, 76 }, 77 } 78 confirm, err := book.SubmitOrder(o) 79 require.NoError(t, err) 80 81 if addToBook { 82 // aggressive iceberg orders do not naturally sit on the book and are added a different way so 83 // we do that here 84 o.Remaining = peak 85 o.IcebergOrder.ReservedRemaining = size - peak 86 // book.SubmitIcebergOrder(o) 87 } 88 return o, confirm 89 } 90 91 func submitCrossedOrder(t *testing.T, book *tstOB, size uint64) (*types.Order, *types.OrderConfirmation) { 92 t.Helper() 93 o := &types.Order{ 94 ID: vgcrypto.RandomHash(), 95 Status: types.OrderStatusActive, 96 MarketID: book.marketID, 97 Party: "B", 98 Side: types.SideSell, 99 Price: num.NewUint(100), 100 OriginalPrice: num.NewUint(100), 101 Size: size, 102 Remaining: size, 103 TimeInForce: types.OrderTimeInForceGTC, 104 Type: types.OrderTypeLimit, 105 } 106 confirm, err := book.SubmitOrder(o) 107 require.NoError(t, err) 108 return o, confirm 109 } 110 111 func submitCrossedWashOrder(t *testing.T, book *tstOB, size uint64) (*types.Order, *types.OrderConfirmation) { 112 t.Helper() 113 o := &types.Order{ 114 ID: vgcrypto.RandomHash(), 115 Status: types.OrderStatusActive, 116 MarketID: book.marketID, 117 Party: "A", 118 Side: types.SideSell, 119 Price: num.NewUint(100), 120 OriginalPrice: num.NewUint(100), 121 Size: size, 122 Remaining: size, 123 TimeInForce: types.OrderTimeInForceGTC, 124 Type: types.OrderTypeLimit, 125 } 126 confirm, err := book.SubmitOrder(o) 127 require.NoError(t, err) 128 return o, confirm 129 } 130 131 func getTradesCrossedOrder(t *testing.T, book *tstOB, size uint64) []*types.Trade { 132 t.Helper() 133 o := &types.Order{ 134 ID: vgcrypto.RandomHash(), 135 Status: types.OrderStatusActive, 136 MarketID: book.marketID, 137 Party: "B", 138 Side: types.SideSell, 139 Price: num.NewUint(100), 140 OriginalPrice: num.NewUint(100), 141 Size: size, 142 Remaining: size, 143 TimeInForce: types.OrderTimeInForceGTC, 144 Type: types.OrderTypeLimit, 145 } 146 trades, err := book.GetTrades(o) 147 require.NoError(t, err) 148 return trades 149 } 150 151 func TestIcebergsFakeUncross(t *testing.T) { 152 market := "testMarket" 153 book := getTestOrderBook(t, market) 154 defer book.Finish() 155 156 // submit an iceberg order that sits on the book 157 iceberg, confirm := submitIcebergOrder(t, book, 100, 4, 2, false) 158 assert.Equal(t, 0, len(confirm.Trades)) 159 160 // check it is now on the book 161 _, err := book.GetOrderByID(iceberg.ID) 162 assert.NoError(t, err) 163 assert.Equal(t, uint64(100), book.getTotalBuyVolume()) 164 165 // check the peaks are proper 166 assert.Equal(t, uint64(4), iceberg.Remaining) 167 assert.Equal(t, uint64(96), iceberg.IcebergOrder.ReservedRemaining) 168 169 // submit an order bigger than the peak 170 trades := getTradesCrossedOrder(t, book, 10) 171 assert.Equal(t, 1, len(trades)) 172 assert.Equal(t, uint64(10), trades[0].Size) 173 174 // now submit it for real, and check refresh happens 175 o, confirm := submitCrossedOrder(t, book, 10) 176 assert.Equal(t, 1, len(confirm.Trades)) 177 assert.Equal(t, uint64(10), trades[0].Size) 178 assert.Equal(t, uint64(0), o.Remaining) 179 } 180 181 func TestIcebergFullPeakConsumedExactly(t *testing.T) { 182 market := "testMarket" 183 book := getTestOrderBook(t, market) 184 defer book.Finish() 185 186 // submit an iceberg order that sits on the book 187 iceberg, confirm := submitIcebergOrder(t, book, 100, 40, 10, false) 188 assert.Equal(t, 0, len(confirm.Trades)) 189 190 // check it is now on the book 191 _, err := book.GetOrderByID(iceberg.ID) 192 assert.NoError(t, err) 193 assert.Equal(t, uint64(100), book.getTotalBuyVolume()) 194 195 trades := getTradesCrossedOrder(t, book, 40) 196 assert.Equal(t, 1, len(trades)) 197 assert.Equal(t, uint64(40), trades[0].Size) 198 199 // now submit it and check it gets filled 200 o, confirm := submitCrossedOrder(t, book, 40) 201 assert.Equal(t, 1, len(confirm.Trades)) 202 assert.Equal(t, types.OrderStatusFilled, o.Status) 203 204 // check that the iceberg has been refreshed and book volume is back at 40 205 assert.Equal(t, 1, book.getNumberOfBuyLevels()) 206 assert.Equal(t, uint64(60), book.getTotalBuyVolume()) 207 assert.Equal(t, uint64(40), iceberg.Remaining) 208 assert.Equal(t, uint64(20), iceberg.IcebergOrder.ReservedRemaining) 209 } 210 211 func TestIcebergPeakAboveMinimum(t *testing.T) { 212 market := "testMarket" 213 book := getTestOrderBook(t, market) 214 defer book.Finish() 215 216 iceberg, confirm := submitIcebergOrder(t, book, 100, 4, 2, true) 217 assert.Equal(t, 0, len(confirm.Trades)) 218 219 // submit order that only takes a little off the peak 220 _, confirm = submitCrossedOrder(t, book, 1) 221 assert.Equal(t, 1, len(confirm.Trades)) 222 assert.Equal(t, 1, book.getNumberOfBuyLevels()) 223 assert.Equal(t, uint64(99), book.getTotalBuyVolume()) 224 225 // now submit another order that *will* remove the rest of the peak 226 _, confirm = submitCrossedOrder(t, book, 3) 227 assert.Equal(t, 1, len(confirm.Trades)) 228 229 assert.Equal(t, uint64(4), iceberg.Remaining) 230 assert.Equal(t, uint64(92), iceberg.IcebergOrder.ReservedRemaining) 231 assert.Equal(t, uint64(96), book.getTotalBuyVolume()) 232 } 233 234 func TestIcebergAggressiveTakesAll(t *testing.T) { 235 market := "testMarket" 236 book := getTestOrderBook(t, market) 237 defer book.Finish() 238 239 _, confirm := submitCrossedOrder(t, book, 10) 240 assert.Equal(t, 0, len(confirm.Trades)) 241 242 // submit the iceberg as an aggressive order and more than its peak is consumed 243 o, confirm := submitIcebergOrder(t, book, 50, 4, 2, false) 244 assert.Equal(t, 1, len(confirm.Trades)) 245 assert.Equal(t, uint64(10), confirm.Trades[0].Size) 246 247 // now check iceberg sits on the book with the correct peaks 248 assert.Equal(t, uint64(4), o.Remaining) 249 assert.Equal(t, uint64(36), o.IcebergOrder.ReservedRemaining) 250 assert.Equal(t, uint64(40), book.getTotalBuyVolume()) 251 } 252 253 func TestAggressiveIcebergFullyFilled(t *testing.T) { 254 market := "testMarket" 255 book := getTestOrderBook(t, market) 256 defer book.Finish() 257 258 _, confirm := submitCrossedOrder(t, book, 1000) 259 assert.Equal(t, 0, len(confirm.Trades)) 260 261 // submit the aggressice iceberg that will be fully filled 262 iceberg, confirm := submitIcebergOrder(t, book, 100, 4, 2, false) 263 assert.Equal(t, 1, len(confirm.Trades)) 264 265 // check that 266 assert.Equal(t, uint64(0), iceberg.Remaining) 267 assert.Equal(t, uint64(0), iceberg.IcebergOrder.ReservedRemaining) 268 assert.Equal(t, types.OrderStatusFilled, iceberg.Status) 269 assert.Equal(t, uint64(0), book.getTotalBuyVolume()) 270 assert.Equal(t, uint64(900), book.getTotalSellVolume()) 271 } 272 273 func TestIcebergPeakBelowMinimumNotZero(t *testing.T) { 274 market := "testMarket" 275 book := getTestOrderBook(t, market) 276 defer book.Finish() 277 278 iceberg, confirm := submitIcebergOrder(t, book, 100, 4, 2, true) 279 assert.Equal(t, 0, len(confirm.Trades)) 280 281 // submit an order that takes the berg below its minimum visible size, but is not zero 282 _, confirm = submitCrossedOrder(t, book, 3) 283 assert.Equal(t, 1, len(confirm.Trades)) 284 285 // check it refreshes properly 286 assert.Equal(t, types.OrderStatusActive, iceberg.Status) 287 assert.Equal(t, uint64(4), iceberg.Remaining) 288 assert.Equal(t, uint64(93), iceberg.IcebergOrder.ReservedRemaining) 289 assert.Equal(t, uint64(97), book.getTotalBuyVolume()) 290 291 // put in another order which will eat into the remaining 292 submitCrossedOrder(t, book, 10) 293 assert.Equal(t, uint64(4), iceberg.Remaining) 294 assert.Equal(t, uint64(83), iceberg.IcebergOrder.ReservedRemaining) 295 assert.Equal(t, uint64(87), book.getTotalBuyVolume()) 296 } 297 298 func TestIcebergRefreshToPartialPeak(t *testing.T) { 299 market := "testMarket" 300 book := getTestOrderBook(t, market) 301 defer book.Finish() 302 303 // submit an iceberg order that sits on the book with a big peak 304 iceberg, confirm := submitIcebergOrder(t, book, 100, 90, 2, true) 305 assert.Equal(t, 0, len(confirm.Trades)) 306 307 // expect the volume to be the peak size 308 assert.Equal(t, uint64(100), book.getTotalBuyVolume()) 309 310 // submit an order that takes almost the full peak 311 _, confirm = submitCrossedOrder(t, book, 89) 312 assert.Equal(t, 1, len(confirm.Trades)) 313 314 // remaining + reserved < peak size 315 assert.Equal(t, uint64(11), iceberg.Remaining) 316 assert.Equal(t, uint64(0), iceberg.IcebergOrder.ReservedRemaining) 317 assert.Equal(t, uint64(11), book.getTotalBuyVolume()) 318 319 // check we can now fill it and the iceberg is removed 320 _, confirm = submitCrossedOrder(t, book, 100) 321 assert.Equal(t, 1, len(confirm.Trades)) 322 assert.Equal(t, uint64(0), iceberg.Remaining) 323 assert.Equal(t, uint64(0), iceberg.IcebergOrder.ReservedRemaining) 324 assert.Equal(t, types.OrderStatusFilled, iceberg.Status) 325 assert.Equal(t, uint64(0), book.getTotalBuyVolume()) 326 } 327 328 func TestIcebergHiddenDistribution(t *testing.T) { 329 market := "testMarket" 330 book := getTestOrderBook(t, market) 331 defer book.Finish() 332 333 // submit 3 iceberg orders 334 iceberg1, confirm := submitIcebergOrder(t, book, 300, 100, 2, false) 335 assert.Equal(t, 0, len(confirm.Trades)) 336 337 iceberg2, confirm := submitIcebergOrder(t, book, 300, 200, 2, false) 338 assert.Equal(t, 0, len(confirm.Trades)) 339 340 iceberg3, _ := submitIcebergOrder(t, book, 200, 100, 2, false) 341 342 // submit a big order such that all three peaks are consumed (100 + 200 + 100 = 400) 343 // and the left over is 300 344 trades := getTradesCrossedOrder(t, book, 700) 345 assert.Equal(t, 3, len(trades)) 346 assert.Equal(t, uint64(250), trades[0].Size) 347 assert.Equal(t, uint64(275), trades[1].Size) 348 assert.Equal(t, uint64(175), trades[2].Size) 349 350 // now submit it for real 351 o, confirm := submitCrossedOrder(t, book, 700) 352 assert.Equal(t, 3, len(confirm.Trades)) 353 assert.Equal(t, types.OrderStatusFilled, o.Status) 354 355 // check iceberg one has been refresh properly 356 assert.Equal(t, uint64(50), iceberg1.Remaining) 357 assert.Equal(t, uint64(0), iceberg1.IcebergOrder.ReservedRemaining) 358 359 assert.Equal(t, uint64(25), iceberg2.Remaining) 360 assert.Equal(t, uint64(0), iceberg2.IcebergOrder.ReservedRemaining) 361 362 assert.Equal(t, uint64(25), iceberg3.Remaining) 363 assert.Equal(t, uint64(0), iceberg3.IcebergOrder.ReservedRemaining) 364 } 365 366 func TestIcebergHiddenDistributionCrumbs(t *testing.T) { 367 market := "testMarket" 368 book := getTestOrderBook(t, market) 369 defer book.Finish() 370 371 // submit 3 iceberg orders of equal sizes 372 iceberg1, _ := submitIcebergOrder(t, book, 500, 100, 2, false) 373 iceberg2, _ := submitIcebergOrder(t, book, 500, 100, 2, false) 374 iceberg3, _ := submitIcebergOrder(t, book, 500, 100, 100, false) 375 assert.Equal(t, uint64(1500), book.getTotalBuyVolume()) 376 377 // submit a big order such that all three peaks are consumed (100 + 100 + 100 = 300) 378 // and the left over is 100 to be divided between three 379 trades := getTradesCrossedOrder(t, book, 400) 380 assert.Equal(t, 3, len(trades)) 381 assert.Equal(t, uint64(134), trades[0].Size) 382 assert.Equal(t, uint64(133), trades[1].Size) 383 assert.Equal(t, uint64(133), trades[2].Size) 384 385 // now submit it for real 386 o, confirm := submitCrossedOrder(t, book, 400) 387 assert.Equal(t, 3, len(confirm.Trades)) 388 assert.Equal(t, types.OrderStatusFilled, o.Status) 389 390 // check iceberg one has been refresh properly 391 assert.Equal(t, uint64(100), iceberg1.Remaining) 392 assert.Equal(t, uint64(266), iceberg1.IcebergOrder.ReservedRemaining) 393 394 assert.Equal(t, uint64(100), iceberg2.Remaining) 395 assert.Equal(t, uint64(267), iceberg2.IcebergOrder.ReservedRemaining) 396 397 assert.Equal(t, uint64(100), iceberg3.Remaining) 398 assert.Equal(t, uint64(267), iceberg3.IcebergOrder.ReservedRemaining) 399 } 400 401 func TestIcebergHiddenDistributionFullyConsumed(t *testing.T) { 402 market := "testMarket" 403 book := getTestOrderBook(t, market) 404 defer book.Finish() 405 406 // submit 3 iceberg orders 407 iceberg1, confirm := submitIcebergOrder(t, book, 300, 100, 2, false) 408 assert.Equal(t, 0, len(confirm.Trades)) 409 410 iceberg2, confirm := submitIcebergOrder(t, book, 300, 200, 2, false) 411 assert.Equal(t, 0, len(confirm.Trades)) 412 413 iceberg3, _ := submitIcebergOrder(t, book, 200, 100, 2, false) 414 415 // submit a big order such that all three peaks are consumed (100 + 200 + 100 = 400) 416 // and all of the hidden volume (200 + 100 + 100 = 400) 417 trades := getTradesCrossedOrder(t, book, 1000) 418 assert.Equal(t, 3, len(trades)) 419 assert.Equal(t, uint64(300), trades[0].Size) 420 assert.Equal(t, uint64(300), trades[1].Size) 421 assert.Equal(t, uint64(200), trades[2].Size) 422 423 // now submit it for real 424 o, confirm := submitCrossedOrder(t, book, 1000) 425 assert.Equal(t, 3, len(confirm.Trades)) 426 assert.Equal(t, types.OrderStatusActive, o.Status) 427 assert.Equal(t, uint64(200), o.Remaining) 428 429 // check iceberg one has been refresh properly 430 assert.Equal(t, uint64(0), iceberg1.Remaining) 431 assert.Equal(t, uint64(0), iceberg1.IcebergOrder.ReservedRemaining) 432 assert.Equal(t, types.OrderStatusFilled, iceberg1.Status) 433 434 assert.Equal(t, uint64(0), iceberg2.Remaining) 435 assert.Equal(t, uint64(0), iceberg2.IcebergOrder.ReservedRemaining) 436 assert.Equal(t, types.OrderStatusFilled, iceberg2.Status) 437 438 assert.Equal(t, uint64(0), iceberg3.Remaining) 439 assert.Equal(t, uint64(0), iceberg3.IcebergOrder.ReservedRemaining) 440 assert.Equal(t, types.OrderStatusFilled, iceberg2.Status) 441 } 442 443 func TestIcebergHiddenDistributionPrimeHidden(t *testing.T) { 444 market := "testMarket" 445 book := getTestOrderBook(t, market) 446 defer book.Finish() 447 448 // submit 3 iceberg orders 449 iceberg1, confirm := submitIcebergOrder(t, book, 300, 43, 2, false) 450 assert.Equal(t, 0, len(confirm.Trades)) 451 452 iceberg2, confirm := submitIcebergOrder(t, book, 300, 67, 2, false) 453 assert.Equal(t, 0, len(confirm.Trades)) 454 455 iceberg3, _ := submitIcebergOrder(t, book, 200, 9, 2, false) 456 457 // submit a big order such that all three peaks are consumed (43 + 67 + 9 = 119) 458 // and the individual remaining hidden volumes are prime (257, 233, 191) such 459 // that the distributed amount will make nasty precision crumbs 460 trades := getTradesCrossedOrder(t, book, 250) 461 assert.Equal(t, 3, len(trades)) 462 assert.Equal(t, uint64(94), trades[0].Size) 463 assert.Equal(t, uint64(111), trades[1].Size) 464 assert.Equal(t, uint64(45), trades[2].Size) 465 466 // now submit it for real 467 o, confirm := submitCrossedOrder(t, book, 250) 468 assert.Equal(t, 3, len(confirm.Trades)) 469 assert.Equal(t, types.OrderStatusFilled, o.Status) 470 assert.Equal(t, uint64(0), o.Remaining) 471 472 // check iceberg one has been refresh properly 473 assert.Equal(t, uint64(43), iceberg1.Remaining) 474 assert.Equal(t, uint64(163), iceberg1.IcebergOrder.ReservedRemaining) 475 assert.Equal(t, types.OrderStatusActive, iceberg1.Status) 476 477 assert.Equal(t, uint64(67), iceberg2.Remaining) 478 assert.Equal(t, uint64(122), iceberg2.IcebergOrder.ReservedRemaining) 479 assert.Equal(t, types.OrderStatusActive, iceberg2.Status) 480 481 assert.Equal(t, uint64(9), iceberg3.Remaining) 482 assert.Equal(t, uint64(146), iceberg3.IcebergOrder.ReservedRemaining) 483 assert.Equal(t, types.OrderStatusActive, iceberg2.Status) 484 485 assert.Equal(t, uint64(550), book.getTotalBuyVolume()) 486 } 487 488 func TestIcebergTimePriorityLostOnRefresh(t *testing.T) { 489 market := "testMarket" 490 book := getTestOrderBook(t, market) 491 defer book.Finish() 492 493 // submit an iceberg order that sits on the book with a big peak 494 iceberg, confirm := submitIcebergOrder(t, book, 100, 10, 8, true) 495 assert.Equal(t, 0, len(confirm.Trades)) 496 497 // now submit a second order that will be next in line 498 iceberg2, confirm := submitIcebergOrder(t, book, 100, 100, 1, true) 499 assert.Equal(t, 0, len(confirm.Trades)) 500 501 // expect the volume to be the peak size 502 assert.Equal(t, uint64(200), book.getTotalBuyVolume()) 503 504 // submit a order that will take out some of the peak of the first iceberg, check its refreshed 505 _, confirm = submitCrossedOrder(t, book, 5) 506 assert.Equal(t, 1, len(confirm.Trades)) 507 assert.Equal(t, uint64(10), iceberg.Remaining) 508 assert.Equal(t, uint64(85), iceberg.IcebergOrder.ReservedRemaining) 509 510 // a new small order will match with the second iceberg 511 _, confirm = submitCrossedOrder(t, book, 1) 512 assert.Equal(t, 1, len(confirm.Trades)) 513 assert.Equal(t, iceberg2.ID, confirm.PassiveOrdersAffected[0].ID) 514 } 515 516 func TestAmendIceberg(t *testing.T) { 517 market := "testMarket" 518 book := getTestOrderBook(t, market) 519 defer book.Finish() 520 521 // submit an iceberg order that sits on the book with a big peak 522 iceberg, confirm := submitIcebergOrder(t, book, 100, 10, 8, true) 523 assert.Equal(t, 0, len(confirm.Trades)) 524 assert.Equal(t, uint64(100), book.getTotalBuyVolume()) 525 526 // amend iceberg such that the size is increased and the reserve is increased 527 amend := iceberg.Clone() 528 amend.Size = 150 529 amend.IcebergOrder.ReservedRemaining = 140 530 err := book.AmendOrder(iceberg, amend) 531 require.NoError(t, err) 532 assert.Equal(t, uint64(150), book.getTotalBuyVolume()) 533 534 // amend iceberg such that the volume is decreased but not enough to eat into the peak 535 amend = iceberg.Clone() 536 amend.Size = 140 537 amend.IcebergOrder.ReservedRemaining = 130 538 err = book.AmendOrder(iceberg, amend) 539 require.NoError(t, err) 540 assert.Equal(t, uint64(140), book.getTotalBuyVolume()) 541 542 // decrease again such that reserved is 0 and peak is reduced 543 amend = iceberg.Clone() 544 amend.Size = 5 545 amend.Remaining = 5 546 amend.IcebergOrder.ReservedRemaining = 0 547 err = book.AmendOrder(iceberg, amend) 548 require.NoError(t, err) 549 assert.Equal(t, uint64(5), book.getTotalBuyVolume()) 550 } 551 552 func TestIcebergWashTradePassiveIceberg(t *testing.T) { 553 market := "testMarket" 554 book := getTestOrderBook(t, market) 555 defer book.Finish() 556 557 // submit an iceberg order that sits on the book 558 _, confirm := submitIcebergOrder(t, book, 100, 10, 8, true) 559 assert.Equal(t, 0, len(confirm.Trades)) 560 assert.Equal(t, uint64(100), book.getTotalBuyVolume()) 561 562 // same party submits and order which trades with themselves 563 o, confirm := submitCrossedWashOrder(t, book, 10) 564 assert.Equal(t, types.OrderStatusStopped, o.Status) 565 assert.Equal(t, 0, len(confirm.Trades)) 566 } 567 568 func TestIcebergWashTradeAggressiveIceberg(t *testing.T) { 569 market := "testMarket" 570 book := getTestOrderBook(t, market) 571 defer book.Finish() 572 573 // party submits an order that sits on the book 574 _, confirm := submitCrossedWashOrder(t, book, 10) 575 assert.Equal(t, 0, len(confirm.Trades)) 576 assert.Equal(t, uint64(10), book.getTotalSellVolume()) 577 578 // same party submit an aggressive iceberg order that trades with themselves 579 iceberg, confirm := submitIcebergOrder(t, book, 100, 10, 8, true) 580 assert.Equal(t, types.OrderStatusStopped, iceberg.Status) 581 assert.Equal(t, 0, len(confirm.Trades)) 582 } 583 584 func TestIcebergWashTradeAggressiveIcebergPartialFill(t *testing.T) { 585 market := "testMarket" 586 book := getTestOrderBook(t, market) 587 defer book.Finish() 588 589 _, confirm := submitCrossedOrder(t, book, 5) 590 assert.Equal(t, 0, len(confirm.Trades)) 591 assert.Equal(t, uint64(5), book.getTotalSellVolume()) 592 593 _, confirm = submitCrossedWashOrder(t, book, 10) 594 assert.Equal(t, 0, len(confirm.Trades)) 595 assert.Equal(t, uint64(15), book.getTotalSellVolume()) 596 597 // submit an iceberg order that partially trades, then causes a wash trade and so 598 // is not put on the book 599 iceberg, confirm := submitIcebergOrder(t, book, 100, 10, 8, true) 600 assert.Equal(t, types.OrderStatusPartiallyFilled, iceberg.Status) 601 assert.Equal(t, 1, len(confirm.Trades)) 602 assert.Equal(t, uint64(10), book.getTotalSellVolume()) 603 } 604 605 func TestRefreshedPeggedIcebergStillPegged(t *testing.T) { 606 market := "testMarket" 607 book := getTestOrderBook(t, market) 608 defer book.Finish() 609 610 // create a pegged iceberg order 611 iceberg, _ := submitPeggedIcebergOrder(t, book, 100, 4, 2) 612 613 // check it is returned as pegged 614 pegged := book.GetActivePeggedOrderIDs() 615 assert.Equal(t, iceberg.ID, pegged[0]) 616 617 // submit an order that will trade a cause a refresh 618 _, confirm := submitCrossedOrder(t, book, 3) 619 assert.Equal(t, 1, len(confirm.Trades)) 620 621 // check it is still returned as pegged 622 pegged = book.GetActivePeggedOrderIDs() 623 assert.Equal(t, iceberg.ID, pegged[0]) 624 }