code.vegaprotocol.io/vega@v0.79.0/core/matching/order_status_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_test
    17  
    18  import (
    19  	"testing"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    24  	"code.vegaprotocol.io/vega/libs/num"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  )
    28  
    29  func TestOrderStatuses(t *testing.T) {
    30  	t.Run("FOK - stopped", testFOKStopped)
    31  	t.Run("FOK - filled", testFOKFilled)
    32  
    33  	t.Run("IOC - stopped", testIOCStopped)
    34  	t.Run("IOC - partially filled", testIOCPartiallyFilled)
    35  	t.Run("IOC - filled", testIOCFilled)
    36  
    37  	t.Run("GTC - active", testGTCActive)
    38  	t.Run("GTC - stopped not filled", testGTCStoppedNotFilled)
    39  	t.Run("GTC - cancelled not filled", testGTCCancelledNotFilled)
    40  	t.Run("GTC - active partially filled", testGTCActivePartiallyFilled)
    41  	t.Run("GTC - cancelled partially filled", testGTCCancelledPartiallyFilled)
    42  	t.Run("GTC - stopped partially filled", testGTCStoppedPartiallyFilled)
    43  	t.Run("GTC - filled", testGTCFilled)
    44  
    45  	t.Run("GTT - active", testGTTActive)
    46  	t.Run("GTT - cancelled not filled", testGTTCancelledNotFilled)
    47  	t.Run("GTT - stopped not filled", testGTTStoppedNotFilled)
    48  	t.Run("GTT - active partially filled", testGTTActivePartiallyFilled)
    49  	t.Run("GTT - cancelled partially filled", testGTTCancelledPartiallyFilled)
    50  	t.Run("GTT - stopped partially filled", testGTTStoppedPartiallyFilled)
    51  	t.Run("GTT - filled", testGTTFilled)
    52  
    53  	// the following test from the specs is not added as it is not possible to test through the order book.
    54  	// and it's not possible for an order to become expired once it's been filled as the order is removed
    55  	// from the book, and the book is setting up orders.
    56  	// |      GTT      |   Yes   |   Yes   |         No        |         No        |      Filled      |
    57  }
    58  
    59  func testFOKStopped(t *testing.T) {
    60  	market := "testMarket"
    61  	partyID := "p1"
    62  	book := getTestOrderBook(t, market)
    63  	defer book.Finish()
    64  	order := types.Order{
    65  		Status:        types.OrderStatusActive,
    66  		MarketID:      market,
    67  		Party:         partyID,
    68  		Side:          types.SideSell,
    69  		Price:         num.NewUint(100),
    70  		OriginalPrice: num.NewUint(100),
    71  		Size:          1,
    72  		Remaining:     1,
    73  		TimeInForce:   types.OrderTimeInForceFOK,
    74  		Type:          types.OrderTypeLimit,
    75  	}
    76  	confirm, err := book.ob.SubmitOrder(&order)
    77  	assert.NoError(t, err)
    78  	assert.Equal(t, 0, len(confirm.Trades))
    79  	assert.Equal(t, types.OrderStatusStopped, order.Status)
    80  }
    81  
    82  func testFOKFilled(t *testing.T) {
    83  	market := "testMarket"
    84  	partyID1 := "p1"
    85  	partyID2 := "p2"
    86  
    87  	book := getTestOrderBook(t, market)
    88  	defer book.Finish()
    89  
    90  	// place a first order to sit in the book
    91  	order1 := types.Order{
    92  		ID:            "V0000000032-0000000009",
    93  		Status:        types.OrderStatusActive,
    94  		MarketID:      market,
    95  		Party:         partyID1,
    96  		Side:          types.SideSell,
    97  		Price:         num.NewUint(100),
    98  		OriginalPrice: num.NewUint(100),
    99  		Size:          1,
   100  		Remaining:     1,
   101  		TimeInForce:   types.OrderTimeInForceGTC,
   102  		Type:          types.OrderTypeLimit,
   103  	}
   104  	_, err := book.ob.SubmitOrder(&order1)
   105  	assert.NoError(t, err)
   106  
   107  	// now place our fok order to be filled
   108  	order := types.Order{
   109  		ID:            "V0000000032-0000000010",
   110  		Status:        types.OrderStatusActive,
   111  		MarketID:      market,
   112  		Party:         partyID2,
   113  		Side:          types.SideBuy,
   114  		Price:         num.NewUint(100),
   115  		OriginalPrice: num.NewUint(100),
   116  		Size:          1,
   117  		Remaining:     1,
   118  		TimeInForce:   types.OrderTimeInForceFOK,
   119  		Type:          types.OrderTypeLimit,
   120  	}
   121  	confirm, err := book.ob.SubmitOrder(&order)
   122  	assert.NoError(t, err)
   123  	assert.Equal(t, 1, len(confirm.Trades))
   124  	assert.Equal(t, types.OrderStatusFilled, order.Status)
   125  }
   126  
   127  func testIOCStopped(t *testing.T) {
   128  	market := "testMarket"
   129  	partyID := "p1"
   130  	book := getTestOrderBook(t, market)
   131  	defer book.Finish()
   132  	order := types.Order{
   133  		Status:        types.OrderStatusActive,
   134  		MarketID:      market,
   135  		Party:         partyID,
   136  		Side:          types.SideSell,
   137  		Price:         num.NewUint(100),
   138  		OriginalPrice: num.NewUint(100),
   139  		Size:          1,
   140  		Remaining:     1,
   141  		TimeInForce:   types.OrderTimeInForceIOC,
   142  		Type:          types.OrderTypeLimit,
   143  	}
   144  	confirm, err := book.ob.SubmitOrder(&order)
   145  	assert.NoError(t, err)
   146  	assert.Equal(t, 0, len(confirm.Trades))
   147  	assert.Equal(t, types.OrderStatusStopped, order.Status)
   148  }
   149  
   150  func testIOCPartiallyFilled(t *testing.T) {
   151  	market := "testMarket"
   152  	partyID1 := "p1"
   153  	partyID2 := "p2"
   154  
   155  	book := getTestOrderBook(t, market)
   156  	defer book.Finish()
   157  
   158  	// place a first order to sit in the book
   159  	order1 := types.Order{
   160  		ID:            "V0000000032-0000000009",
   161  		Status:        types.OrderStatusActive,
   162  		MarketID:      market,
   163  		Party:         partyID1,
   164  		Side:          types.SideSell,
   165  		Price:         num.NewUint(100),
   166  		OriginalPrice: num.NewUint(100),
   167  		Size:          1,
   168  		Remaining:     1,
   169  		TimeInForce:   types.OrderTimeInForceGTC,
   170  		Type:          types.OrderTypeLimit,
   171  	}
   172  	_, err := book.ob.SubmitOrder(&order1)
   173  	assert.NoError(t, err)
   174  
   175  	// now place our IOC order to be filled
   176  	order := types.Order{
   177  		ID:            "V0000000032-0000000010",
   178  		Status:        types.OrderStatusActive,
   179  		MarketID:      market,
   180  		Party:         partyID2,
   181  		Side:          types.SideBuy,
   182  		Price:         num.NewUint(100),
   183  		OriginalPrice: num.NewUint(100),
   184  		Size:          2,
   185  		Remaining:     2,
   186  		TimeInForce:   types.OrderTimeInForceIOC,
   187  		Type:          types.OrderTypeLimit,
   188  	}
   189  	confirm, err := book.ob.SubmitOrder(&order)
   190  	assert.NoError(t, err)
   191  	assert.Equal(t, 1, len(confirm.Trades))
   192  	assert.Equal(t, types.OrderStatusPartiallyFilled, order.Status)
   193  }
   194  
   195  func testIOCFilled(t *testing.T) {
   196  	market := "testMarket"
   197  	partyID1 := "p1"
   198  	partyID2 := "p2"
   199  
   200  	book := getTestOrderBook(t, market)
   201  	defer book.Finish()
   202  
   203  	// place a first order to sit in the book
   204  	order1 := types.Order{
   205  		ID:            "V0000000032-0000000009",
   206  		Status:        types.OrderStatusActive,
   207  		MarketID:      market,
   208  		Party:         partyID1,
   209  		Side:          types.SideSell,
   210  		Price:         num.NewUint(100),
   211  		OriginalPrice: num.NewUint(100),
   212  		Size:          1,
   213  		Remaining:     1,
   214  		TimeInForce:   types.OrderTimeInForceGTC,
   215  		Type:          types.OrderTypeLimit,
   216  	}
   217  	_, err := book.ob.SubmitOrder(&order1)
   218  	assert.NoError(t, err)
   219  
   220  	// now place our fok order to be filled
   221  	order := types.Order{
   222  		ID:            "V0000000032-0000000010",
   223  		Status:        types.OrderStatusActive,
   224  		MarketID:      market,
   225  		Party:         partyID2,
   226  		Side:          types.SideBuy,
   227  		Price:         num.NewUint(100),
   228  		OriginalPrice: num.NewUint(100),
   229  		Size:          1,
   230  		Remaining:     1,
   231  		TimeInForce:   types.OrderTimeInForceIOC,
   232  		Type:          types.OrderTypeLimit,
   233  	}
   234  	confirm, err := book.ob.SubmitOrder(&order)
   235  	assert.NoError(t, err)
   236  	assert.Equal(t, 1, len(confirm.Trades))
   237  	assert.Equal(t, types.OrderStatusFilled, order.Status)
   238  }
   239  
   240  func testGTCActive(t *testing.T) {
   241  	market := "testMarket"
   242  	partyID1 := "p1"
   243  	orderID := "v0000000000000-0000001"
   244  
   245  	book := getTestOrderBook(t, market)
   246  	defer book.Finish()
   247  
   248  	order1 := types.Order{
   249  		Status:        types.OrderStatusActive,
   250  		ID:            orderID,
   251  		MarketID:      market,
   252  		Party:         partyID1,
   253  		Side:          types.SideSell,
   254  		Price:         num.NewUint(100),
   255  		OriginalPrice: num.NewUint(100),
   256  		Size:          10,
   257  		Remaining:     10,
   258  		TimeInForce:   types.OrderTimeInForceGTC,
   259  		Type:          types.OrderTypeLimit,
   260  	}
   261  	_, err := book.ob.SubmitOrder(&order1)
   262  	assert.NoError(t, err)
   263  	assert.Equal(t, types.OrderStatusActive, order1.Status)
   264  }
   265  
   266  func testGTCStoppedNotFilled(t *testing.T) {
   267  	market := "testMarket"
   268  	partyID1 := "p1"
   269  	orderID := vgcrypto.RandomHash()
   270  
   271  	book := getTestOrderBook(t, market)
   272  	defer book.Finish()
   273  
   274  	order1 := types.Order{
   275  		Status:        types.OrderStatusActive,
   276  		ID:            orderID,
   277  		MarketID:      market,
   278  		Party:         partyID1,
   279  		Side:          types.SideSell,
   280  		Price:         num.NewUint(100),
   281  		OriginalPrice: num.NewUint(100),
   282  		Size:          10,
   283  		Remaining:     10,
   284  		TimeInForce:   types.OrderTimeInForceGTC,
   285  		Type:          types.OrderTypeLimit,
   286  	}
   287  	_, err := book.ob.SubmitOrder(&order1)
   288  	assert.NoError(t, err)
   289  
   290  	// then stop the order
   291  	rmOrders, err := book.ob.RemoveDistressedOrders([]events.MarketPosition{marketPositionFake{partyID1}})
   292  	assert.NoError(t, err)
   293  	assert.Len(t, rmOrders, 1)
   294  	assert.Equal(t, types.OrderStatusStopped, rmOrders[0].Status)
   295  }
   296  
   297  func testGTCCancelledNotFilled(t *testing.T) {
   298  	market := "testMarket"
   299  	partyID1 := "p1"
   300  	orderID := vgcrypto.RandomHash()
   301  
   302  	book := getTestOrderBook(t, market)
   303  	defer book.Finish()
   304  
   305  	order1 := types.Order{
   306  		Status:        types.OrderStatusActive,
   307  		ID:            orderID,
   308  		MarketID:      market,
   309  		Party:         partyID1,
   310  		Side:          types.SideSell,
   311  		Price:         num.NewUint(100),
   312  		OriginalPrice: num.NewUint(100),
   313  		Size:          10,
   314  		Remaining:     10,
   315  		TimeInForce:   types.OrderTimeInForceGTC,
   316  		Type:          types.OrderTypeLimit,
   317  	}
   318  	_, err := book.ob.SubmitOrder(&order1)
   319  	assert.NoError(t, err)
   320  
   321  	// then stop the order
   322  	confirm, err := book.ob.CancelOrder(&order1)
   323  	assert.NoError(t, err)
   324  	assert.Equal(t, types.OrderStatusCancelled, confirm.Order.Status)
   325  }
   326  
   327  func testGTCActivePartiallyFilled(t *testing.T) {
   328  	market := "testMarket"
   329  	partyID1 := "p1"
   330  	partyID2 := "p2"
   331  	orderID := vgcrypto.RandomHash()
   332  
   333  	book := getTestOrderBook(t, market)
   334  	defer book.Finish()
   335  
   336  	// place a first order to sit in the book, be partially filled, and stopped
   337  	order1 := types.Order{
   338  		Status:        types.OrderStatusActive,
   339  		ID:            orderID,
   340  		MarketID:      market,
   341  		Party:         partyID1,
   342  		Side:          types.SideSell,
   343  		Price:         num.NewUint(100),
   344  		OriginalPrice: num.NewUint(100),
   345  		Size:          10,
   346  		Remaining:     10,
   347  		TimeInForce:   types.OrderTimeInForceGTC,
   348  		Type:          types.OrderTypeLimit,
   349  	}
   350  	_, err := book.ob.SubmitOrder(&order1)
   351  	assert.NoError(t, err)
   352  
   353  	// now place our order which will consume some of the first order
   354  	order := types.Order{
   355  		ID:            vgcrypto.RandomHash(),
   356  		Status:        types.OrderStatusActive,
   357  		MarketID:      market,
   358  		Party:         partyID2,
   359  		Side:          types.SideBuy,
   360  		Price:         num.NewUint(100),
   361  		OriginalPrice: num.NewUint(100),
   362  		Size:          1,
   363  		Remaining:     1,
   364  		TimeInForce:   types.OrderTimeInForceGTC,
   365  		Type:          types.OrderTypeLimit,
   366  	}
   367  	confirm, err := book.ob.SubmitOrder(&order)
   368  	assert.NoError(t, err)
   369  	assert.Len(t, confirm.PassiveOrdersAffected, 1)
   370  	assert.Equal(t, types.OrderStatusActive, confirm.PassiveOrdersAffected[0].Status)
   371  }
   372  
   373  func testGTCCancelledPartiallyFilled(t *testing.T) {
   374  	market := "testMarket"
   375  	partyID1 := "p1"
   376  	partyID2 := "p2"
   377  	orderID := vgcrypto.RandomHash()
   378  
   379  	book := getTestOrderBook(t, market)
   380  	defer book.Finish()
   381  
   382  	// place a first order to sit in the book, be partially filled, and stopped
   383  	order1 := types.Order{
   384  		Status:        types.OrderStatusActive,
   385  		ID:            orderID,
   386  		MarketID:      market,
   387  		Party:         partyID1,
   388  		Side:          types.SideSell,
   389  		Price:         num.NewUint(100),
   390  		OriginalPrice: num.NewUint(100),
   391  		Size:          10,
   392  		Remaining:     10,
   393  		TimeInForce:   types.OrderTimeInForceGTC,
   394  		Type:          types.OrderTypeLimit,
   395  	}
   396  	_, err := book.ob.SubmitOrder(&order1)
   397  	assert.NoError(t, err)
   398  
   399  	// now place our order which will consume some of the first order
   400  	order := types.Order{
   401  		Status:        types.OrderStatusActive,
   402  		MarketID:      market,
   403  		Party:         partyID2,
   404  		Side:          types.SideBuy,
   405  		Price:         num.NewUint(100),
   406  		OriginalPrice: num.NewUint(100),
   407  		Size:          1,
   408  		Remaining:     1,
   409  		TimeInForce:   types.OrderTimeInForceGTC,
   410  		Type:          types.OrderTypeLimit,
   411  	}
   412  	_, err = book.ob.SubmitOrder(&order)
   413  	assert.NoError(t, err)
   414  
   415  	// then stop the order
   416  	confirm, err := book.ob.CancelOrder(&order1)
   417  	assert.NoError(t, err)
   418  	assert.NoError(t, err)
   419  	assert.Equal(t, types.OrderStatusCancelled, confirm.Order.Status)
   420  }
   421  
   422  func testGTCStoppedPartiallyFilled(t *testing.T) {
   423  	market := "testMarket"
   424  	partyID1 := "p1"
   425  	partyID2 := "p2"
   426  	orderID := vgcrypto.RandomHash()
   427  
   428  	book := getTestOrderBook(t, market)
   429  	defer book.Finish()
   430  
   431  	// place a first order to sit in the book, be partially filled, and stopped
   432  	order1 := types.Order{
   433  		Status:        types.OrderStatusActive,
   434  		ID:            orderID,
   435  		MarketID:      market,
   436  		Party:         partyID1,
   437  		Side:          types.SideSell,
   438  		Price:         num.NewUint(100),
   439  		OriginalPrice: num.NewUint(100),
   440  		Size:          10,
   441  		Remaining:     10,
   442  		TimeInForce:   types.OrderTimeInForceGTC,
   443  		Type:          types.OrderTypeLimit,
   444  	}
   445  	_, err := book.ob.SubmitOrder(&order1)
   446  	assert.NoError(t, err)
   447  
   448  	// now place our order which will consume some of the first order
   449  	order := types.Order{
   450  		Status:        types.OrderStatusActive,
   451  		MarketID:      market,
   452  		Party:         partyID2,
   453  		Side:          types.SideBuy,
   454  		Price:         num.NewUint(100),
   455  		OriginalPrice: num.NewUint(100),
   456  		Size:          1,
   457  		Remaining:     1,
   458  		TimeInForce:   types.OrderTimeInForceGTC,
   459  		Type:          types.OrderTypeLimit,
   460  	}
   461  	_, err = book.ob.SubmitOrder(&order)
   462  	assert.NoError(t, err)
   463  
   464  	// then stop the order
   465  	rmOrders, err := book.ob.RemoveDistressedOrders([]events.MarketPosition{marketPositionFake{partyID1}})
   466  	assert.NoError(t, err)
   467  	assert.Len(t, rmOrders, 1)
   468  	assert.Equal(t, types.OrderStatusStopped, rmOrders[0].Status)
   469  }
   470  
   471  func testGTCFilled(t *testing.T) {
   472  	market := "testMarket"
   473  	partyID1 := "p1"
   474  	partyID2 := "p2"
   475  
   476  	book := getTestOrderBook(t, market)
   477  	defer book.Finish()
   478  
   479  	// place a first order to sit in the book
   480  	order1 := types.Order{
   481  		ID:            vgcrypto.RandomHash(),
   482  		Status:        types.OrderStatusActive,
   483  		MarketID:      market,
   484  		Party:         partyID1,
   485  		Side:          types.SideSell,
   486  		Price:         num.NewUint(100),
   487  		OriginalPrice: num.NewUint(100),
   488  		Size:          1,
   489  		Remaining:     1,
   490  		TimeInForce:   types.OrderTimeInForceGTC,
   491  		Type:          types.OrderTypeLimit,
   492  	}
   493  	_, err := book.ob.SubmitOrder(&order1)
   494  	assert.NoError(t, err)
   495  
   496  	// now place our GTC order to be filled
   497  	order := types.Order{
   498  		ID:            vgcrypto.RandomHash(),
   499  		Status:        types.OrderStatusActive,
   500  		MarketID:      market,
   501  		Party:         partyID2,
   502  		Side:          types.SideBuy,
   503  		Price:         num.NewUint(100),
   504  		OriginalPrice: num.NewUint(100),
   505  		Size:          1,
   506  		Remaining:     1,
   507  		TimeInForce:   types.OrderTimeInForceGTC,
   508  		Type:          types.OrderTypeLimit,
   509  	}
   510  	confirm, err := book.ob.SubmitOrder(&order)
   511  	assert.NoError(t, err)
   512  	assert.Equal(t, 1, len(confirm.Trades))
   513  	assert.Equal(t, types.OrderStatusFilled, order.Status)
   514  }
   515  
   516  func testGTTActive(t *testing.T) {
   517  	market := "testMarket"
   518  	partyID1 := "p1"
   519  	orderID := vgcrypto.RandomHash()
   520  
   521  	book := getTestOrderBook(t, market)
   522  	defer book.Finish()
   523  
   524  	order1 := types.Order{
   525  		Status:        types.OrderStatusActive,
   526  		ID:            orderID,
   527  		MarketID:      market,
   528  		Party:         partyID1,
   529  		Side:          types.SideSell,
   530  		Price:         num.NewUint(100),
   531  		OriginalPrice: num.NewUint(100),
   532  		Size:          10,
   533  		Remaining:     10,
   534  		TimeInForce:   types.OrderTimeInForceGTT,
   535  		Type:          types.OrderTypeLimit,
   536  		ExpiresAt:     10,
   537  	}
   538  	_, err := book.ob.SubmitOrder(&order1)
   539  	assert.NoError(t, err)
   540  	assert.Equal(t, types.OrderStatusActive, order1.Status)
   541  }
   542  
   543  func testGTTStoppedNotFilled(t *testing.T) {
   544  	market := "testMarket"
   545  	partyID1 := "p1"
   546  	orderID := vgcrypto.RandomHash()
   547  
   548  	book := getTestOrderBook(t, market)
   549  	defer book.Finish()
   550  
   551  	order1 := types.Order{
   552  		Status:        types.OrderStatusActive,
   553  		ID:            orderID,
   554  		MarketID:      market,
   555  		Party:         partyID1,
   556  		Side:          types.SideSell,
   557  		Price:         num.NewUint(100),
   558  		OriginalPrice: num.NewUint(100),
   559  		Size:          10,
   560  		Remaining:     10,
   561  		TimeInForce:   types.OrderTimeInForceGTT,
   562  		Type:          types.OrderTypeLimit,
   563  		ExpiresAt:     10,
   564  	}
   565  	_, err := book.ob.SubmitOrder(&order1)
   566  	assert.NoError(t, err)
   567  
   568  	// then stop the order
   569  	rmOrders, err := book.ob.RemoveDistressedOrders([]events.MarketPosition{marketPositionFake{partyID1}})
   570  	assert.NoError(t, err)
   571  	assert.Len(t, rmOrders, 1)
   572  	assert.Equal(t, types.OrderStatusStopped, rmOrders[0].Status)
   573  }
   574  
   575  func testGTTCancelledNotFilled(t *testing.T) {
   576  	market := "testMarket"
   577  	partyID1 := "p1"
   578  	orderID := vgcrypto.RandomHash()
   579  
   580  	book := getTestOrderBook(t, market)
   581  	defer book.Finish()
   582  
   583  	order1 := types.Order{
   584  		Status:        types.OrderStatusActive,
   585  		ID:            orderID,
   586  		MarketID:      market,
   587  		Party:         partyID1,
   588  		Side:          types.SideSell,
   589  		Price:         num.NewUint(100),
   590  		OriginalPrice: num.NewUint(100),
   591  		Size:          10,
   592  		Remaining:     10,
   593  		TimeInForce:   types.OrderTimeInForceGTT,
   594  		Type:          types.OrderTypeLimit,
   595  		ExpiresAt:     10,
   596  	}
   597  	_, err := book.ob.SubmitOrder(&order1)
   598  	assert.NoError(t, err)
   599  
   600  	// then stop the order
   601  	confirm, err := book.ob.CancelOrder(&order1)
   602  	assert.NoError(t, err)
   603  	assert.Equal(t, types.OrderStatusCancelled, confirm.Order.Status)
   604  }
   605  
   606  func testGTTActivePartiallyFilled(t *testing.T) {
   607  	market := "testMarket"
   608  	partyID1 := "p1"
   609  	partyID2 := "p2"
   610  	orderID := vgcrypto.RandomHash()
   611  
   612  	book := getTestOrderBook(t, market)
   613  	defer book.Finish()
   614  
   615  	// place a first order to sit in the book, be partially filled
   616  	order1 := types.Order{
   617  		Status:        types.OrderStatusActive,
   618  		ID:            orderID,
   619  		MarketID:      market,
   620  		Party:         partyID1,
   621  		Side:          types.SideSell,
   622  		Price:         num.NewUint(100),
   623  		OriginalPrice: num.NewUint(100),
   624  		Size:          10,
   625  		Remaining:     10,
   626  		TimeInForce:   types.OrderTimeInForceGTT,
   627  		Type:          types.OrderTypeLimit,
   628  		ExpiresAt:     10,
   629  	}
   630  	_, err := book.ob.SubmitOrder(&order1)
   631  	assert.NoError(t, err)
   632  
   633  	// now place our order which will consume some of the first order
   634  	order := types.Order{
   635  		ID:            vgcrypto.RandomHash(),
   636  		Status:        types.OrderStatusActive,
   637  		MarketID:      market,
   638  		Party:         partyID2,
   639  		Side:          types.SideBuy,
   640  		Price:         num.NewUint(100),
   641  		OriginalPrice: num.NewUint(100),
   642  		Size:          1,
   643  		Remaining:     1,
   644  		TimeInForce:   types.OrderTimeInForceGTT,
   645  		Type:          types.OrderTypeLimit,
   646  		ExpiresAt:     10,
   647  	}
   648  	confirm, err := book.ob.SubmitOrder(&order)
   649  	assert.NoError(t, err)
   650  	assert.Len(t, confirm.PassiveOrdersAffected, 1)
   651  	assert.Equal(t, types.OrderStatusActive, confirm.PassiveOrdersAffected[0].Status)
   652  }
   653  
   654  func testGTTCancelledPartiallyFilled(t *testing.T) {
   655  	market := "testMarket"
   656  	partyID1 := "p1"
   657  	partyID2 := "p2"
   658  	orderID := vgcrypto.RandomHash()
   659  
   660  	book := getTestOrderBook(t, market)
   661  	defer book.Finish()
   662  
   663  	// place a first order to sit in the book, be partially filled, and cancelled
   664  	order1 := types.Order{
   665  		Status:        types.OrderStatusActive,
   666  		ID:            orderID,
   667  		MarketID:      market,
   668  		Party:         partyID1,
   669  		Side:          types.SideSell,
   670  		Price:         num.NewUint(100),
   671  		OriginalPrice: num.NewUint(100),
   672  		Size:          10,
   673  		Remaining:     10,
   674  		TimeInForce:   types.OrderTimeInForceGTT,
   675  		Type:          types.OrderTypeLimit,
   676  		ExpiresAt:     10,
   677  	}
   678  	_, err := book.ob.SubmitOrder(&order1)
   679  	assert.NoError(t, err)
   680  
   681  	// now place our order which will consume some of the first order
   682  	order := types.Order{
   683  		ID:            vgcrypto.RandomHash(),
   684  		Status:        types.OrderStatusActive,
   685  		MarketID:      market,
   686  		Party:         partyID2,
   687  		Side:          types.SideBuy,
   688  		Price:         num.NewUint(100),
   689  		OriginalPrice: num.NewUint(100),
   690  		Size:          1,
   691  		Remaining:     1,
   692  		TimeInForce:   types.OrderTimeInForceGTT,
   693  		Type:          types.OrderTypeLimit,
   694  		ExpiresAt:     10,
   695  	}
   696  	_, err = book.ob.SubmitOrder(&order)
   697  	assert.NoError(t, err)
   698  
   699  	// then stop the order
   700  	confirm, err := book.ob.CancelOrder(&order1)
   701  	assert.NoError(t, err)
   702  	assert.NoError(t, err)
   703  	assert.Equal(t, types.OrderStatusCancelled, confirm.Order.Status)
   704  }
   705  
   706  func testGTTStoppedPartiallyFilled(t *testing.T) {
   707  	market := "testMarket"
   708  	partyID1 := "p1"
   709  	partyID2 := "p2"
   710  	orderID := vgcrypto.RandomHash()
   711  
   712  	book := getTestOrderBook(t, market)
   713  	defer book.Finish()
   714  
   715  	// place a first order to sit in the book, be partially filled, and stopped
   716  	order1 := types.Order{
   717  		Status:        types.OrderStatusActive,
   718  		ID:            orderID,
   719  		MarketID:      market,
   720  		Party:         partyID1,
   721  		Side:          types.SideSell,
   722  		Price:         num.NewUint(100),
   723  		OriginalPrice: num.NewUint(100),
   724  		Size:          10,
   725  		Remaining:     10,
   726  		TimeInForce:   types.OrderTimeInForceGTT,
   727  		Type:          types.OrderTypeLimit,
   728  		ExpiresAt:     10,
   729  	}
   730  	_, err := book.ob.SubmitOrder(&order1)
   731  	assert.NoError(t, err)
   732  
   733  	// now place our order which will consume some of the first order
   734  	order := types.Order{
   735  		ID:            vgcrypto.RandomHash(),
   736  		Status:        types.OrderStatusActive,
   737  		MarketID:      market,
   738  		Party:         partyID2,
   739  		Side:          types.SideBuy,
   740  		Price:         num.NewUint(100),
   741  		OriginalPrice: num.NewUint(100),
   742  		Size:          1,
   743  		Remaining:     1,
   744  		TimeInForce:   types.OrderTimeInForceGTT,
   745  		Type:          types.OrderTypeLimit,
   746  		ExpiresAt:     10,
   747  	}
   748  	_, err = book.ob.SubmitOrder(&order)
   749  	assert.NoError(t, err)
   750  
   751  	// then stop the order
   752  	rmOrders, err := book.ob.RemoveDistressedOrders([]events.MarketPosition{marketPositionFake{partyID1}})
   753  	assert.NoError(t, err)
   754  	assert.Len(t, rmOrders, 1)
   755  	assert.Equal(t, types.OrderStatusStopped, rmOrders[0].Status)
   756  }
   757  
   758  func testGTTFilled(t *testing.T) {
   759  	market := "testMarket"
   760  	partyID1 := "p1"
   761  	partyID2 := "p2"
   762  
   763  	book := getTestOrderBook(t, market)
   764  	defer book.Finish()
   765  
   766  	// place a first order to sit in the book
   767  	order1 := types.Order{
   768  		ID:            vgcrypto.RandomHash(),
   769  		Status:        types.OrderStatusActive,
   770  		MarketID:      market,
   771  		Party:         partyID1,
   772  		Side:          types.SideSell,
   773  		Price:         num.NewUint(100),
   774  		OriginalPrice: num.NewUint(100),
   775  		Size:          1,
   776  		Remaining:     1,
   777  		TimeInForce:   types.OrderTimeInForceGTT,
   778  		Type:          types.OrderTypeLimit,
   779  		ExpiresAt:     10,
   780  	}
   781  	_, err := book.ob.SubmitOrder(&order1)
   782  	assert.NoError(t, err)
   783  
   784  	// now place our GTT order to be filled
   785  	order := types.Order{
   786  		ID:            vgcrypto.RandomHash(),
   787  		Status:        types.OrderStatusActive,
   788  		MarketID:      market,
   789  		Party:         partyID2,
   790  		Side:          types.SideBuy,
   791  		Price:         num.NewUint(100),
   792  		OriginalPrice: num.NewUint(100),
   793  		Size:          1,
   794  		Remaining:     1,
   795  		TimeInForce:   types.OrderTimeInForceGTT,
   796  		Type:          types.OrderTypeLimit,
   797  		ExpiresAt:     10,
   798  	}
   799  	confirm, err := book.ob.SubmitOrder(&order)
   800  	assert.NoError(t, err)
   801  	assert.Equal(t, 1, len(confirm.Trades))
   802  	assert.Equal(t, types.OrderStatusFilled, order.Status)
   803  }
   804  
   805  type marketPositionFake struct {
   806  	party string
   807  }
   808  
   809  func (m marketPositionFake) AverageEntryPrice() *num.Uint { return num.UintZero() }
   810  func (m marketPositionFake) Party() string                { return m.party }
   811  func (m marketPositionFake) Size() int64                  { return 0 }
   812  func (m marketPositionFake) Buy() int64                   { return 0 }
   813  func (m marketPositionFake) Sell() int64                  { return 0 }
   814  func (m marketPositionFake) Price() *num.Uint             { return num.UintZero() }
   815  func (m marketPositionFake) BuySumProduct() *num.Uint     { return num.UintZero() }
   816  func (m marketPositionFake) SellSumProduct() *num.Uint    { return num.UintZero() }
   817  func (m marketPositionFake) VWBuy() *num.Uint             { return num.UintZero() }
   818  func (m marketPositionFake) VWSell() *num.Uint            { return num.UintZero() }