code.vegaprotocol.io/vega@v0.79.0/core/matching/orderbook_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  	"encoding/hex"
    20  	"fmt"
    21  	"math/rand"
    22  	"testing"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/core/matching"
    26  	"code.vegaprotocol.io/vega/core/types"
    27  	"code.vegaprotocol.io/vega/libs/crypto"
    28  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    29  	"code.vegaprotocol.io/vega/libs/num"
    30  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    31  	"code.vegaprotocol.io/vega/logging"
    32  	"code.vegaprotocol.io/vega/protos/vega"
    33  
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  // launch aggressiveOrder orders from both sides to fully clear the order book.
    39  type aggressiveOrderScenario struct {
    40  	aggressiveOrder               *types.Order
    41  	expectedPassiveOrdersAffected []types.Order
    42  	expectedTrades                []types.Trade
    43  }
    44  
    45  func peggedOrderCounterForTest(int64) {}
    46  
    47  type tstOB struct {
    48  	ob  *matching.CachedOrderBook
    49  	log *logging.Logger
    50  }
    51  
    52  func (t *tstOB) Finish() {
    53  	t.log.Sync()
    54  }
    55  
    56  func getCurrentUtcTimestampNano() int64 {
    57  	return time.Now().UnixNano()
    58  }
    59  
    60  func getTestOrderBook(t *testing.T, market string) *tstOB {
    61  	t.Helper()
    62  	tob := tstOB{
    63  		log: logging.NewTestLogger(),
    64  	}
    65  	tob.ob = matching.NewCachedOrderBook(tob.log, matching.NewDefaultConfig(), market, false, peggedOrderCounterForTest)
    66  	tob.ob.LogRemovedOrdersDebug = true
    67  	return &tob
    68  }
    69  
    70  func TestOrderBook_GetClosePNL(t *testing.T) {
    71  	t.Run("Get Buy-side close PNL values", getClosePNLBuy)
    72  	t.Run("Get Sell-side close PNL values", getClosePNLSell)
    73  	t.Run("Get Incomplete close-out-pnl (check error) - Buy", getClosePNLIncompleteBuy)
    74  	t.Run("Get Incomplete close-out-pnl (check error) - Sell", getClosePNLIncompleteSell)
    75  	t.Run("Get Best bid price and volume", testBestBidPriceAndVolume)
    76  	t.Run("Get Best offer price and volume", testBestOfferPriceAndVolume)
    77  }
    78  
    79  func TestOrderBook_CancelBulk(t *testing.T) {
    80  	t.Run("Cancel all order for a party", cancelAllOrderForAParty)
    81  	t.Run("Get all order for a party", getAllOrderForAParty)
    82  	t.Run("Party with no order cancel nothing", partyWithNoOrderCancelNothing)
    83  }
    84  
    85  func TestGetVolumeAtPrice(t *testing.T) {
    86  	market := "testMarket"
    87  	book := getTestOrderBook(t, market)
    88  	defer book.Finish()
    89  
    90  	buyPrices := []uint64{
    91  		90,
    92  		85,
    93  		80,
    94  		75,
    95  		70,
    96  		65,
    97  		50,
    98  	}
    99  	sellPrices := []uint64{
   100  		100,
   101  		105,
   102  		110,
   103  		120,
   104  		125,
   105  		130,
   106  		150,
   107  	}
   108  	// populate a book with buy orders ranging between 50 and 90
   109  	// sell orders starting at 100, up to 150. All orders have a size of 2
   110  	orders := getTestOrders(t, market, 2, buyPrices, sellPrices)
   111  	for _, o := range orders {
   112  		_, err := book.ob.SubmitOrder(o)
   113  		assert.NoError(t, err)
   114  	}
   115  	t.Run("Getting volume at price with a single price level returns the volume for that price level", func(t *testing.T) {
   116  		// check the buy side
   117  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[0]), types.SideBuy)
   118  		require.Equal(t, uint64(2), v)
   119  		// check the sell side
   120  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[0]), types.SideSell)
   121  		require.Equal(t, uint64(2), v)
   122  	})
   123  	t.Run("Getting volume at price containing all price levels returns the total volume on that side of the book", func(t *testing.T) {
   124  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[len(buyPrices)-1]), types.SideBuy)
   125  		exp := uint64(len(buyPrices) * 2)
   126  		require.Equal(t, exp, v)
   127  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[len(sellPrices)-1]), types.SideSell)
   128  		exp = uint64(len(sellPrices) * 2)
   129  		require.Equal(t, exp, v)
   130  	})
   131  	t.Run("Getting volume at a price that is out of range returns zero volume", func(t *testing.T) {
   132  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[0]+1), types.SideBuy)
   133  		require.Equal(t, uint64(0), v)
   134  		// check the sell side
   135  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[0]-1), types.SideSell)
   136  		require.Equal(t, uint64(0), v)
   137  	})
   138  	t.Run("Getting volume at price allowing for more than all price levels returns the total volume on that side of the book", func(t *testing.T) {
   139  		// lowest buy order -1
   140  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[len(buyPrices)-1]-1), types.SideBuy)
   141  		exp := uint64(len(buyPrices) * 2)
   142  		require.Equal(t, exp, v)
   143  		// highest sell order on the book +1
   144  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[len(sellPrices)-1]+1), types.SideSell)
   145  		exp = uint64(len(sellPrices) * 2)
   146  		require.Equal(t, exp, v)
   147  	})
   148  	t.Run("Getting volume at a price that is somewhere in the middle returns the correct volume", func(t *testing.T) {
   149  		idx := len(buyPrices) / 2
   150  		// remember: includes 0 idx
   151  		exp := uint64(idx*2 + 2)
   152  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[idx]), types.SideBuy)
   153  		require.Equal(t, exp, v)
   154  		idx = len(sellPrices) / 2
   155  		exp = uint64(idx*2 + 2)
   156  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[idx]), types.SideSell)
   157  		require.Equal(t, exp, v)
   158  	})
   159  }
   160  
   161  func TestGetVolumeAtPriceIceberg(t *testing.T) {
   162  	market := "testMarket"
   163  	book := getTestOrderBook(t, market)
   164  	defer book.Finish()
   165  
   166  	buyPrices := []uint64{
   167  		90,
   168  		85,
   169  		80,
   170  		75,
   171  		70,
   172  		65,
   173  		50,
   174  	}
   175  	sellPrices := []uint64{
   176  		100,
   177  		105,
   178  		110,
   179  		120,
   180  		125,
   181  		130,
   182  		150,
   183  	}
   184  	// populate a book with buy orders ranging between 50 and 90
   185  	// sell orders starting at 100, up to 150. All orders are iceberg orders with a visible size of 2, hidden size of 2.
   186  	orders := getTestOrders(t, market, 4, buyPrices, sellPrices)
   187  	for _, o := range orders {
   188  		// make this an iceberg order
   189  		o.IcebergOrder = &types.IcebergOrder{
   190  			PeakSize:           2,
   191  			MinimumVisibleSize: 2,
   192  		}
   193  		_, err := book.ob.SubmitOrder(o)
   194  		assert.NoError(t, err)
   195  	}
   196  	t.Run("Getting volume at price with a single price level returns the volume for that price level", func(t *testing.T) {
   197  		// check the buy side
   198  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[0]), types.SideBuy)
   199  		require.Equal(t, uint64(4), v)
   200  		// check the sell side
   201  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[0]), types.SideSell)
   202  		require.Equal(t, uint64(4), v)
   203  	})
   204  	t.Run("Getting volume at price containing all price levels returns the total volume on that side of the book", func(t *testing.T) {
   205  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[len(buyPrices)-1]), types.SideBuy)
   206  		exp := uint64(len(buyPrices) * 4)
   207  		require.Equal(t, exp, v)
   208  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[len(sellPrices)-1]), types.SideSell)
   209  		exp = uint64(len(sellPrices) * 4)
   210  		require.Equal(t, exp, v)
   211  	})
   212  	t.Run("Getting volume at a price that is out of range returns zero volume", func(t *testing.T) {
   213  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[0]+1), types.SideBuy)
   214  		require.Equal(t, uint64(0), v)
   215  		// check the sell side
   216  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[0]-1), types.SideSell)
   217  		require.Equal(t, uint64(0), v)
   218  	})
   219  	t.Run("Getting volume at price allowing for more than all price levels returns the total volume on that side of the book", func(t *testing.T) {
   220  		// lowest buy order -1
   221  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[len(buyPrices)-1]-1), types.SideBuy)
   222  		exp := uint64(len(buyPrices) * 4)
   223  		require.Equal(t, exp, v)
   224  		// highest sell order on the book +1
   225  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[len(sellPrices)-1]+1), types.SideSell)
   226  		exp = uint64(len(sellPrices) * 4)
   227  		require.Equal(t, exp, v)
   228  	})
   229  	t.Run("Getting volume at a price that is somewhere in the middle returns the correct volume", func(t *testing.T) {
   230  		idx := len(buyPrices) / 2
   231  		// remember: includes 0 idx
   232  		exp := uint64(idx*4 + 4)
   233  		v := book.ob.GetVolumeAtPrice(num.NewUint(buyPrices[idx]), types.SideBuy)
   234  		require.Equal(t, exp, v)
   235  		idx = len(sellPrices) / 2
   236  		exp = uint64(idx*4 + 4)
   237  		v = book.ob.GetVolumeAtPrice(num.NewUint(sellPrices[idx]), types.SideSell)
   238  		require.Equal(t, exp, v)
   239  	})
   240  }
   241  
   242  func TestHash(t *testing.T) {
   243  	market := "testMarket"
   244  	book := getTestOrderBook(t, market)
   245  	defer book.Finish()
   246  
   247  	orders := []*types.Order{
   248  		{
   249  			ID:            "1111111111111111111111",
   250  			Status:        types.OrderStatusActive,
   251  			Type:          types.OrderTypeLimit,
   252  			MarketID:      market,
   253  			Party:         "A",
   254  			Side:          types.SideBuy,
   255  			Price:         num.NewUint(10),
   256  			OriginalPrice: num.NewUint(10),
   257  			Size:          1,
   258  			Remaining:     1,
   259  			TimeInForce:   types.OrderTimeInForceGTC,
   260  		},
   261  		{
   262  			ID:            "2222222222222222222222",
   263  			Status:        types.OrderStatusActive,
   264  			Type:          types.OrderTypeLimit,
   265  			MarketID:      market,
   266  			Party:         "A",
   267  			Side:          types.SideBuy,
   268  			Price:         num.NewUint(30),
   269  			OriginalPrice: num.NewUint(30),
   270  			Size:          5,
   271  			Remaining:     5,
   272  			TimeInForce:   types.OrderTimeInForceGTC,
   273  		},
   274  		{
   275  			ID:            "3333333333333333333333",
   276  			Status:        types.OrderStatusActive,
   277  			Type:          types.OrderTypeLimit,
   278  			MarketID:      market,
   279  			Party:         "B",
   280  			Side:          types.SideSell,
   281  			Price:         num.NewUint(200),
   282  			OriginalPrice: num.NewUint(200),
   283  			Size:          1,
   284  			Remaining:     1,
   285  			TimeInForce:   types.OrderTimeInForceGTC,
   286  		},
   287  		{
   288  			ID:            "4444444444444444444444",
   289  			Status:        types.OrderStatusActive,
   290  			Type:          types.OrderTypeLimit,
   291  			MarketID:      market,
   292  			Party:         "A",
   293  			Side:          types.SideSell,
   294  			Price:         num.NewUint(400),
   295  			OriginalPrice: num.NewUint(400),
   296  			Size:          10,
   297  			Remaining:     10,
   298  			TimeInForce:   types.OrderTimeInForceGTC,
   299  		},
   300  	}
   301  
   302  	for _, o := range orders {
   303  		_, err := book.ob.SubmitOrder(o)
   304  		assert.NoError(t, err)
   305  	}
   306  
   307  	hash := book.ob.Hash()
   308  	require.Equal(t,
   309  		"fc0073b33273253dd021d4fdd330e00c32c8b484c8bb484abac92acfb9d575bf",
   310  		hex.EncodeToString(hash),
   311  		"It should match against the known hash",
   312  	)
   313  	// compute the hash 100 times for determinism verification
   314  	for i := 0; i < 100; i++ {
   315  		got := book.ob.Hash()
   316  		require.Equal(t, hash, got)
   317  	}
   318  }
   319  
   320  func cancelAllOrderForAParty(t *testing.T) {
   321  	market := "testMarket"
   322  	book := getTestOrderBook(t, market)
   323  	defer book.Finish()
   324  	orderID1 := vgcrypto.RandomHash()
   325  	orderID2 := vgcrypto.RandomHash()
   326  	orderID3 := vgcrypto.RandomHash()
   327  	orderID4 := vgcrypto.RandomHash()
   328  
   329  	orders := []*types.Order{
   330  		{
   331  			ID:            orderID1,
   332  			Status:        types.OrderStatusActive,
   333  			Type:          types.OrderTypeLimit,
   334  			MarketID:      market,
   335  			Party:         "A",
   336  			Side:          types.SideBuy,
   337  			Price:         num.NewUint(100),
   338  			OriginalPrice: num.NewUint(100),
   339  			Size:          1,
   340  			Remaining:     1,
   341  			TimeInForce:   types.OrderTimeInForceGTC,
   342  		},
   343  		{
   344  			ID:            orderID2,
   345  			Status:        types.OrderStatusActive,
   346  			Type:          types.OrderTypeLimit,
   347  			MarketID:      market,
   348  			Party:         "A",
   349  			Side:          types.SideBuy,
   350  			Price:         num.NewUint(300),
   351  			OriginalPrice: num.NewUint(300),
   352  			Size:          5,
   353  			Remaining:     5,
   354  			TimeInForce:   types.OrderTimeInForceGTC,
   355  		},
   356  		{
   357  			ID:            orderID3,
   358  			Status:        types.OrderStatusActive,
   359  			Type:          types.OrderTypeLimit,
   360  			MarketID:      market,
   361  			Party:         "B",
   362  			Side:          types.SideBuy,
   363  			Price:         num.NewUint(200),
   364  			OriginalPrice: num.NewUint(200),
   365  			Size:          1,
   366  			Remaining:     1,
   367  			TimeInForce:   types.OrderTimeInForceGTC,
   368  		},
   369  		{
   370  			ID:            orderID4,
   371  			Status:        types.OrderStatusActive,
   372  			Type:          types.OrderTypeLimit,
   373  			MarketID:      market,
   374  			Party:         "A",
   375  			Side:          types.SideBuy,
   376  			Price:         num.NewUint(300),
   377  			OriginalPrice: num.NewUint(300),
   378  			Size:          10,
   379  			Remaining:     10,
   380  			TimeInForce:   types.OrderTimeInForceGTC,
   381  		},
   382  	}
   383  	for _, o := range orders {
   384  		confirm, err := book.ob.SubmitOrder(o)
   385  		assert.NoError(t, err)
   386  		assert.Equal(t, 0, len(confirm.Trades))
   387  	}
   388  	confs, err := book.ob.CancelAllOrders("A")
   389  	assert.NoError(t, err)
   390  	assert.Len(t, confs, 3)
   391  	expectedIDs := map[string]struct{}{
   392  		orderID1: {},
   393  		orderID2: {},
   394  		orderID4: {},
   395  	}
   396  	for _, conf := range confs {
   397  		if _, ok := expectedIDs[conf.Order.ID]; ok {
   398  			delete(expectedIDs, conf.Order.ID)
   399  		} else {
   400  			t.Fatalf("unexpected order has been cancelled %v", conf.Order)
   401  		}
   402  	}
   403  }
   404  
   405  func getAllOrderForAParty(t *testing.T) {
   406  	market := "testMarket"
   407  	book := getTestOrderBook(t, market)
   408  	defer book.Finish()
   409  
   410  	orderID1 := vgcrypto.RandomHash()
   411  	orderID2 := vgcrypto.RandomHash()
   412  	orderID3 := vgcrypto.RandomHash()
   413  	orderID4 := vgcrypto.RandomHash()
   414  
   415  	orders := []*types.Order{
   416  		{
   417  			ID:            orderID1,
   418  			Status:        types.OrderStatusActive,
   419  			Type:          types.OrderTypeLimit,
   420  			MarketID:      market,
   421  			Party:         "A",
   422  			Side:          types.SideBuy,
   423  			Price:         num.NewUint(100),
   424  			OriginalPrice: num.NewUint(100),
   425  			Size:          1,
   426  			Remaining:     1,
   427  			TimeInForce:   types.OrderTimeInForceGTC,
   428  		},
   429  		{
   430  			ID:            orderID2,
   431  			Status:        types.OrderStatusActive,
   432  			Type:          types.OrderTypeLimit,
   433  			MarketID:      market,
   434  			Party:         "A",
   435  			Side:          types.SideBuy,
   436  			Price:         num.NewUint(300),
   437  			OriginalPrice: num.NewUint(300),
   438  			Size:          5,
   439  			Remaining:     5,
   440  			TimeInForce:   types.OrderTimeInForceGTC,
   441  		},
   442  		{
   443  			ID:            orderID3,
   444  			Status:        types.OrderStatusActive,
   445  			Type:          types.OrderTypeLimit,
   446  			MarketID:      market,
   447  			Party:         "B",
   448  			Side:          types.SideBuy,
   449  			Price:         num.NewUint(200),
   450  			OriginalPrice: num.NewUint(200),
   451  			Size:          1,
   452  			Remaining:     1,
   453  			TimeInForce:   types.OrderTimeInForceGTC,
   454  		},
   455  		{
   456  			ID:            orderID4,
   457  			Status:        types.OrderStatusActive,
   458  			Type:          types.OrderTypeLimit,
   459  			MarketID:      market,
   460  			Party:         "A",
   461  			Side:          types.SideBuy,
   462  			Price:         num.NewUint(300),
   463  			OriginalPrice: num.NewUint(300),
   464  			Size:          10,
   465  			Remaining:     10,
   466  			TimeInForce:   types.OrderTimeInForceGTC,
   467  		},
   468  	}
   469  	for _, o := range orders {
   470  		confirm, err := book.ob.SubmitOrder(o)
   471  		assert.NoError(t, err)
   472  		assert.Equal(t, 0, len(confirm.Trades))
   473  	}
   474  	ordersLs := book.ob.GetOrdersPerParty("A")
   475  	assert.Len(t, ordersLs, 3)
   476  	expectedIDs := map[string]struct{}{
   477  		orderID1: {},
   478  		orderID2: {},
   479  		orderID4: {},
   480  	}
   481  	for _, o := range ordersLs {
   482  		if _, ok := expectedIDs[o.ID]; ok {
   483  			delete(expectedIDs, o.ID)
   484  		} else {
   485  			t.Fatalf("unexpected order has been cancelled %v", o)
   486  		}
   487  	}
   488  }
   489  
   490  func partyWithNoOrderCancelNothing(t *testing.T) {
   491  	market := "testMarket"
   492  	book := getTestOrderBook(t, market)
   493  	defer book.Finish()
   494  	orders := []*types.Order{
   495  		{
   496  			ID:            vgcrypto.RandomHash(),
   497  			Status:        types.OrderStatusActive,
   498  			Type:          types.OrderTypeLimit,
   499  			MarketID:      market,
   500  			Party:         "A",
   501  			Side:          types.SideBuy,
   502  			Price:         num.NewUint(100),
   503  			OriginalPrice: num.NewUint(100),
   504  			Size:          1,
   505  			Remaining:     1,
   506  			TimeInForce:   types.OrderTimeInForceGTC,
   507  		},
   508  		{
   509  			ID:            vgcrypto.RandomHash(),
   510  			Status:        types.OrderStatusActive,
   511  			Type:          types.OrderTypeLimit,
   512  			MarketID:      market,
   513  			Party:         "A",
   514  			Side:          types.SideBuy,
   515  			Price:         num.NewUint(300),
   516  			OriginalPrice: num.NewUint(300),
   517  			Size:          5,
   518  			Remaining:     5,
   519  			TimeInForce:   types.OrderTimeInForceGTC,
   520  		},
   521  		{
   522  			ID:            vgcrypto.RandomHash(),
   523  			Status:        types.OrderStatusActive,
   524  			Type:          types.OrderTypeLimit,
   525  			MarketID:      market,
   526  			Party:         "B",
   527  			Side:          types.SideBuy,
   528  			Price:         num.NewUint(200),
   529  			OriginalPrice: num.NewUint(200),
   530  			Size:          1,
   531  			Remaining:     1,
   532  			TimeInForce:   types.OrderTimeInForceGTC,
   533  		},
   534  		{
   535  			ID:            vgcrypto.RandomHash(),
   536  			Status:        types.OrderStatusActive,
   537  			Type:          types.OrderTypeLimit,
   538  			MarketID:      market,
   539  			Party:         "A",
   540  			Side:          types.SideBuy,
   541  			Price:         num.NewUint(300),
   542  			OriginalPrice: num.NewUint(300),
   543  			Size:          10,
   544  			Remaining:     10,
   545  			TimeInForce:   types.OrderTimeInForceGTC,
   546  		},
   547  	}
   548  	for _, o := range orders {
   549  		confirm, err := book.ob.SubmitOrder(o)
   550  		assert.NoError(t, err)
   551  		assert.Equal(t, 0, len(confirm.Trades))
   552  	}
   553  	ordersLs := book.ob.GetOrdersPerParty("X")
   554  	assert.Len(t, ordersLs, 0)
   555  }
   556  
   557  func testBestBidPriceAndVolume(t *testing.T) {
   558  	market := "testMarket"
   559  	book := getTestOrderBook(t, market)
   560  	defer book.Finish()
   561  	// 3 orders of size 1, 3 different prices
   562  	orders := []*types.Order{
   563  		{
   564  			ID:            vgcrypto.RandomHash(),
   565  			Status:        types.OrderStatusActive,
   566  			Type:          types.OrderTypeLimit,
   567  			MarketID:      market,
   568  			Party:         "A",
   569  			Side:          types.SideBuy,
   570  			Price:         num.NewUint(100),
   571  			OriginalPrice: num.NewUint(100),
   572  			Size:          1,
   573  			Remaining:     1,
   574  			TimeInForce:   types.OrderTimeInForceGTC,
   575  		},
   576  		{
   577  			ID:            vgcrypto.RandomHash(),
   578  			Status:        types.OrderStatusActive,
   579  			Type:          types.OrderTypeLimit,
   580  			MarketID:      market,
   581  			Party:         "B",
   582  			Side:          types.SideBuy,
   583  			Price:         num.NewUint(300),
   584  			OriginalPrice: num.NewUint(300),
   585  			Size:          5,
   586  			Remaining:     5,
   587  			TimeInForce:   types.OrderTimeInForceGTC,
   588  		},
   589  		{
   590  			ID:            vgcrypto.RandomHash(),
   591  			Status:        types.OrderStatusActive,
   592  			Type:          types.OrderTypeLimit,
   593  			MarketID:      market,
   594  			Party:         "B",
   595  			Side:          types.SideBuy,
   596  			Price:         num.NewUint(200),
   597  			OriginalPrice: num.NewUint(200),
   598  			Size:          1,
   599  			Remaining:     1,
   600  			TimeInForce:   types.OrderTimeInForceGTC,
   601  		},
   602  		{
   603  			ID:            vgcrypto.RandomHash(),
   604  			Status:        types.OrderStatusActive,
   605  			Type:          types.OrderTypeLimit,
   606  			MarketID:      market,
   607  			Party:         "d",
   608  			Side:          types.SideBuy,
   609  			Price:         num.NewUint(300),
   610  			OriginalPrice: num.NewUint(300),
   611  			Size:          10,
   612  			Remaining:     10,
   613  			TimeInForce:   types.OrderTimeInForceGTC,
   614  		},
   615  	}
   616  	for _, o := range orders {
   617  		trades, getErr := book.ob.GetTrades(o)
   618  		assert.NoError(t, getErr)
   619  		confirm, err := book.ob.SubmitOrder(o)
   620  		assert.NoError(t, err)
   621  		assert.Equal(t, 0, len(confirm.Trades))
   622  		assert.Equal(t, len(confirm.Trades), len(trades))
   623  	}
   624  
   625  	price, volume, err := book.ob.BestBidPriceAndVolume()
   626  	assert.NoError(t, err)
   627  	assert.Equal(t, uint64(300), price.Uint64())
   628  	assert.Equal(t, uint64(15), volume)
   629  }
   630  
   631  func testBestOfferPriceAndVolume(t *testing.T) {
   632  	market := "testMarket"
   633  	book := getTestOrderBook(t, market)
   634  	defer book.Finish()
   635  	// 3 orders of size 1, 3 different prices
   636  	orders := []*types.Order{
   637  		{
   638  			ID:            vgcrypto.RandomHash(),
   639  			Status:        types.OrderStatusActive,
   640  			Type:          types.OrderTypeLimit,
   641  			MarketID:      market,
   642  			Party:         "A",
   643  			Side:          types.SideSell,
   644  			Price:         num.NewUint(100),
   645  			OriginalPrice: num.NewUint(100),
   646  			Size:          1,
   647  			Remaining:     1,
   648  			TimeInForce:   types.OrderTimeInForceGTC,
   649  		},
   650  		{
   651  			ID:            vgcrypto.RandomHash(),
   652  			Status:        types.OrderStatusActive,
   653  			Type:          types.OrderTypeLimit,
   654  			MarketID:      market,
   655  			Party:         "B",
   656  			Side:          types.SideSell,
   657  			Price:         num.NewUint(10),
   658  			OriginalPrice: num.NewUint(10),
   659  			Size:          5,
   660  			Remaining:     5,
   661  			TimeInForce:   types.OrderTimeInForceGTC,
   662  		},
   663  		{
   664  			ID:            vgcrypto.RandomHash(),
   665  			Status:        types.OrderStatusActive,
   666  			Type:          types.OrderTypeLimit,
   667  			MarketID:      market,
   668  			Party:         "B",
   669  			Side:          types.SideSell,
   670  			Price:         num.NewUint(200),
   671  			OriginalPrice: num.NewUint(200),
   672  			Size:          1,
   673  			Remaining:     1,
   674  			TimeInForce:   types.OrderTimeInForceGTC,
   675  		},
   676  		{
   677  			ID:            vgcrypto.RandomHash(),
   678  			Status:        types.OrderStatusActive,
   679  			Type:          types.OrderTypeLimit,
   680  			MarketID:      market,
   681  			Party:         "d",
   682  			Side:          types.SideSell,
   683  			Price:         num.NewUint(10),
   684  			OriginalPrice: num.NewUint(10),
   685  			Size:          10,
   686  			Remaining:     10,
   687  			TimeInForce:   types.OrderTimeInForceGTC,
   688  		},
   689  	}
   690  	for _, o := range orders {
   691  		trades, getErr := book.ob.GetTrades(o)
   692  		assert.NoError(t, getErr)
   693  		confirm, err := book.ob.SubmitOrder(o)
   694  		assert.NoError(t, err)
   695  		assert.Equal(t, 0, len(confirm.Trades))
   696  		assert.Equal(t, len(trades), len(confirm.Trades))
   697  	}
   698  
   699  	price, volume, err := book.ob.BestOfferPriceAndVolume()
   700  	assert.NoError(t, err)
   701  	assert.Equal(t, uint64(10), price.Uint64())
   702  	assert.Equal(t, uint64(15), volume)
   703  }
   704  
   705  func getClosePNLIncompleteBuy(t *testing.T) {
   706  	market := "testMarket"
   707  	book := getTestOrderBook(t, market)
   708  	defer book.Finish()
   709  	// 3 orders of size 1, 3 different prices
   710  	orders := []*types.Order{
   711  		{
   712  			ID:            vgcrypto.RandomHash(),
   713  			Status:        types.OrderStatusActive,
   714  			Type:          types.OrderTypeLimit,
   715  			MarketID:      market,
   716  			Party:         "A",
   717  			Side:          types.SideBuy,
   718  			Price:         num.NewUint(100),
   719  			OriginalPrice: num.NewUint(100),
   720  			Size:          1,
   721  			Remaining:     1,
   722  			TimeInForce:   types.OrderTimeInForceGTC,
   723  			CreatedAt:     0,
   724  		},
   725  		{
   726  			ID:            vgcrypto.RandomHash(),
   727  			Status:        types.OrderStatusActive,
   728  			Type:          types.OrderTypeLimit,
   729  			MarketID:      market,
   730  			Party:         "B",
   731  			Side:          types.SideBuy,
   732  			Price:         num.NewUint(110),
   733  			OriginalPrice: num.NewUint(110),
   734  			Size:          1,
   735  			Remaining:     1,
   736  			TimeInForce:   types.OrderTimeInForceGTC,
   737  			CreatedAt:     0,
   738  		},
   739  	}
   740  	for _, o := range orders {
   741  		trades, getErr := book.ob.GetTrades(o)
   742  		assert.NoError(t, getErr)
   743  		confirm, err := book.ob.SubmitOrder(o)
   744  		assert.NoError(t, err)
   745  		assert.Equal(t, 0, len(confirm.Trades))
   746  		assert.Equal(t, len(trades), len(confirm.Trades))
   747  	}
   748  	// volume + expected price
   749  	callExp := map[uint64]uint64{
   750  		2: 210 / 2,
   751  		1: 110,
   752  	}
   753  	// this calculates the actual volume
   754  	for vol, exp := range callExp {
   755  		price, err := book.ob.GetFillPrice(vol, types.SideBuy)
   756  		assert.Equal(t, exp, price.Uint64())
   757  		assert.NoError(t, err)
   758  	}
   759  	price, err := book.ob.GetFillPrice(3, types.SideBuy)
   760  	assert.Equal(t, callExp[2], price.Uint64())
   761  	assert.Equal(t, matching.ErrNotEnoughOrders, err)
   762  }
   763  
   764  func getClosePNLIncompleteSell(t *testing.T) {
   765  	market := "testMarket"
   766  	book := getTestOrderBook(t, market)
   767  	defer book.Finish()
   768  	// 3 orders of size 1, 3 different prices
   769  	orders := []*types.Order{
   770  		{
   771  			ID:            vgcrypto.RandomHash(),
   772  			Status:        types.OrderStatusActive,
   773  			Type:          types.OrderTypeLimit,
   774  			MarketID:      market,
   775  			Party:         "A",
   776  			Side:          types.SideSell,
   777  			Price:         num.NewUint(100),
   778  			OriginalPrice: num.NewUint(100),
   779  			Size:          1,
   780  			Remaining:     1,
   781  			TimeInForce:   types.OrderTimeInForceGTC,
   782  			CreatedAt:     0,
   783  		},
   784  		{
   785  			ID:            vgcrypto.RandomHash(),
   786  			Status:        types.OrderStatusActive,
   787  			Type:          types.OrderTypeLimit,
   788  			MarketID:      market,
   789  			Party:         "B",
   790  			Side:          types.SideSell,
   791  			Price:         num.NewUint(110),
   792  			OriginalPrice: num.NewUint(110),
   793  			Size:          1,
   794  			Remaining:     1,
   795  			TimeInForce:   types.OrderTimeInForceGTC,
   796  			CreatedAt:     0,
   797  		},
   798  	}
   799  	for _, o := range orders {
   800  		trades, getErr := book.ob.GetTrades(o)
   801  		assert.NoError(t, getErr)
   802  		confirm, err := book.ob.SubmitOrder(o)
   803  		assert.NoError(t, err)
   804  		assert.Equal(t, 0, len(confirm.Trades))
   805  		assert.Equal(t, len(trades), len(confirm.Trades))
   806  	}
   807  	// volume + expected price
   808  	callExp := map[uint64]uint64{
   809  		2: 210 / 2,
   810  		1: 100,
   811  	}
   812  	// this calculates the actual volume
   813  	for vol, exp := range callExp {
   814  		price, err := book.ob.GetFillPrice(vol, types.SideSell)
   815  		assert.Equal(t, exp, price.Uint64())
   816  		assert.NoError(t, err)
   817  	}
   818  	price, err := book.ob.GetFillPrice(3, types.SideSell)
   819  	assert.Equal(t, callExp[2], price.Uint64())
   820  	assert.Equal(t, matching.ErrNotEnoughOrders, err)
   821  }
   822  
   823  func getClosePNLBuy(t *testing.T) {
   824  	market := "testMarket"
   825  	book := getTestOrderBook(t, market)
   826  	defer book.Finish()
   827  	// 3 orders of size 1, 3 different prices
   828  	orders := []*types.Order{
   829  		{
   830  			ID:            vgcrypto.RandomHash(),
   831  			Status:        types.OrderStatusActive,
   832  			Type:          types.OrderTypeLimit,
   833  			MarketID:      market,
   834  			Party:         "A",
   835  			Side:          types.SideBuy,
   836  			Price:         num.NewUint(100),
   837  			OriginalPrice: num.NewUint(100),
   838  			Size:          1,
   839  			Remaining:     1,
   840  			TimeInForce:   types.OrderTimeInForceGTC,
   841  			CreatedAt:     0,
   842  		},
   843  		{
   844  			ID:            vgcrypto.RandomHash(),
   845  			Status:        types.OrderStatusActive,
   846  			Type:          types.OrderTypeLimit,
   847  			MarketID:      market,
   848  			Party:         "B",
   849  			Side:          types.SideBuy,
   850  			Price:         num.NewUint(110),
   851  			OriginalPrice: num.NewUint(110),
   852  			Size:          1,
   853  			Remaining:     1,
   854  			TimeInForce:   types.OrderTimeInForceGTC,
   855  			CreatedAt:     0,
   856  		},
   857  		{
   858  			ID:            vgcrypto.RandomHash(),
   859  			Status:        types.OrderStatusActive,
   860  			Type:          types.OrderTypeLimit,
   861  			MarketID:      market,
   862  			Party:         "C",
   863  			Side:          types.SideBuy,
   864  			Price:         num.NewUint(120),
   865  			OriginalPrice: num.NewUint(120),
   866  			Size:          1,
   867  			Remaining:     1,
   868  			TimeInForce:   types.OrderTimeInForceGTC,
   869  			CreatedAt:     0,
   870  		},
   871  	}
   872  	for _, o := range orders {
   873  		trades, getErr := book.ob.GetTrades(o)
   874  		assert.NoError(t, getErr)
   875  		confirm, err := book.ob.SubmitOrder(o)
   876  		assert.NoError(t, err)
   877  		assert.Equal(t, 0, len(confirm.Trades))
   878  		assert.Equal(t, len(trades), len(confirm.Trades))
   879  	}
   880  	// volume + expected price
   881  	callExp := map[uint64]uint64{
   882  		3: 330 / 3,
   883  		2: 230 / 2,
   884  		1: 120,
   885  	}
   886  	// this calculates the actual volume
   887  	for vol, exp := range callExp {
   888  		price, err := book.ob.GetFillPrice(vol, types.SideBuy)
   889  		assert.Equal(t, exp, price.Uint64())
   890  		assert.NoError(t, err)
   891  	}
   892  }
   893  
   894  func getClosePNLSell(t *testing.T) {
   895  	market := "testMarket"
   896  	book := getTestOrderBook(t, market)
   897  	defer book.Finish()
   898  	// 3 orders of size 1, 3 different prices
   899  	orders := []*types.Order{
   900  		{
   901  			ID:            vgcrypto.RandomHash(),
   902  			Status:        types.OrderStatusActive,
   903  			Type:          types.OrderTypeLimit,
   904  			MarketID:      market,
   905  			Party:         "A",
   906  			Side:          types.SideSell,
   907  			Price:         num.NewUint(100),
   908  			OriginalPrice: num.NewUint(100),
   909  			Size:          1,
   910  			Remaining:     1,
   911  			TimeInForce:   types.OrderTimeInForceGTC,
   912  			CreatedAt:     0,
   913  		},
   914  		{
   915  			ID:            vgcrypto.RandomHash(),
   916  			Status:        types.OrderStatusActive,
   917  			Type:          types.OrderTypeLimit,
   918  			MarketID:      market,
   919  			Party:         "B",
   920  			Side:          types.SideSell,
   921  			Price:         num.NewUint(110),
   922  			OriginalPrice: num.NewUint(110),
   923  			Size:          1,
   924  			Remaining:     1,
   925  			TimeInForce:   types.OrderTimeInForceGTC,
   926  			CreatedAt:     0,
   927  		},
   928  		{
   929  			ID:            vgcrypto.RandomHash(),
   930  			Status:        types.OrderStatusActive,
   931  			Type:          types.OrderTypeLimit,
   932  			MarketID:      market,
   933  			Party:         "C",
   934  			Side:          types.SideSell,
   935  			Price:         num.NewUint(120),
   936  			OriginalPrice: num.NewUint(120),
   937  			Size:          1,
   938  			Remaining:     1,
   939  			TimeInForce:   types.OrderTimeInForceGTC,
   940  			CreatedAt:     0,
   941  		},
   942  	}
   943  	for _, o := range orders {
   944  		trades, getErr := book.ob.GetTrades(o)
   945  		assert.NoError(t, getErr)
   946  		confirm, err := book.ob.SubmitOrder(o)
   947  		assert.NoError(t, err)
   948  		assert.Equal(t, 0, len(confirm.Trades))
   949  		assert.Equal(t, len(trades), len(confirm.Trades))
   950  	}
   951  	// volume + expected price
   952  	callExp := map[uint64]uint64{
   953  		3: 330 / 3,
   954  		2: 210 / 2,
   955  		1: 100,
   956  	}
   957  	// this calculates the actual volume
   958  	for vol, exp := range callExp {
   959  		price, err := book.ob.GetFillPrice(vol, types.SideSell)
   960  		assert.NoError(t, err)
   961  		assert.Equal(t, exp, price.Uint64())
   962  	}
   963  }
   964  
   965  func TestOrderBook_CancelReturnsTheOrderFromTheBook(t *testing.T) {
   966  	market := "cancel-returns-order"
   967  	party := "p1"
   968  
   969  	book := getTestOrderBook(t, market)
   970  	defer book.Finish()
   971  	currentTimestamp := getCurrentUtcTimestampNano()
   972  
   973  	orderID := vgcrypto.RandomHash()
   974  	order1 := types.Order{
   975  		Status:        types.OrderStatusActive,
   976  		Type:          types.OrderTypeLimit,
   977  		MarketID:      market,
   978  		Party:         party,
   979  		Side:          types.SideSell,
   980  		Price:         num.NewUint(1),
   981  		OriginalPrice: num.NewUint(1),
   982  		Size:          100,
   983  		Remaining:     100,
   984  		TimeInForce:   types.OrderTimeInForceGTC,
   985  		CreatedAt:     currentTimestamp,
   986  		ID:            orderID,
   987  	}
   988  	order2 := types.Order{
   989  		Status:        types.OrderStatusActive,
   990  		Type:          types.OrderTypeLimit,
   991  		MarketID:      market,
   992  		Party:         party,
   993  		Side:          types.SideSell,
   994  		Price:         num.NewUint(1),
   995  		OriginalPrice: num.NewUint(1),
   996  		Size:          100,
   997  		Remaining:     1, // use a wrong remaining here to get the order from the book
   998  		TimeInForce:   types.OrderTimeInForceGTC,
   999  		CreatedAt:     currentTimestamp,
  1000  		ID:            orderID,
  1001  	}
  1002  
  1003  	trades, getErr := book.ob.GetTrades(&order1)
  1004  	assert.NoError(t, getErr)
  1005  	confirm, err := book.ob.SubmitOrder(&order1)
  1006  	assert.Equal(t, err, nil)
  1007  	assert.Equal(t, len(trades), len(confirm.Trades))
  1008  
  1009  	o, err := book.ob.CancelOrder(&order2)
  1010  	assert.Equal(t, err, nil)
  1011  	assert.Equal(t, o.Order.Remaining, order1.Remaining)
  1012  }
  1013  
  1014  func TestOrderBook_RemoveExpiredOrders(t *testing.T) {
  1015  	market := "expiringOrderBookTest"
  1016  	party := "clay-davis"
  1017  
  1018  	book := getTestOrderBook(t, market)
  1019  	defer book.Finish()
  1020  	currentTimestamp := getCurrentUtcTimestampNano()
  1021  	someTimeLater := currentTimestamp + (1000 * 1000)
  1022  
  1023  	order1 := &types.Order{
  1024  		Status:        types.OrderStatusActive,
  1025  		Type:          types.OrderTypeLimit,
  1026  		MarketID:      market,
  1027  		Party:         party,
  1028  		Side:          types.SideSell,
  1029  		Price:         num.NewUint(1),
  1030  		OriginalPrice: num.NewUint(1),
  1031  		Size:          1,
  1032  		Remaining:     1,
  1033  		TimeInForce:   types.OrderTimeInForceGTT,
  1034  		CreatedAt:     currentTimestamp,
  1035  		ExpiresAt:     someTimeLater,
  1036  		ID:            "1",
  1037  	}
  1038  	trades, getErr := book.ob.GetTrades(order1)
  1039  	assert.NoError(t, getErr)
  1040  	confirm, err := book.ob.SubmitOrder(order1)
  1041  	assert.Equal(t, err, nil)
  1042  	assert.Equal(t, len(trades), len(confirm.Trades))
  1043  
  1044  	order2 := &types.Order{
  1045  		Status:        types.OrderStatusActive,
  1046  		Type:          types.OrderTypeLimit,
  1047  		MarketID:      market,
  1048  		Party:         party,
  1049  		Side:          types.SideSell,
  1050  		Price:         num.NewUint(3298),
  1051  		OriginalPrice: num.NewUint(3298),
  1052  		Size:          99,
  1053  		Remaining:     99,
  1054  		TimeInForce:   types.OrderTimeInForceGTT,
  1055  		CreatedAt:     currentTimestamp,
  1056  		ExpiresAt:     someTimeLater + 1,
  1057  		ID:            "2",
  1058  	}
  1059  	trades, getErr = book.ob.GetTrades(order2)
  1060  	assert.NoError(t, getErr)
  1061  	confirm, err = book.ob.SubmitOrder(order2)
  1062  	assert.Equal(t, err, nil)
  1063  	assert.Equal(t, len(trades), len(confirm.Trades))
  1064  
  1065  	order3 := &types.Order{
  1066  		Status:        types.OrderStatusActive,
  1067  		Type:          types.OrderTypeLimit,
  1068  		MarketID:      market,
  1069  		Party:         party,
  1070  		Side:          types.SideSell,
  1071  		Price:         num.NewUint(771),
  1072  		OriginalPrice: num.NewUint(771),
  1073  		Size:          19,
  1074  		Remaining:     19,
  1075  		TimeInForce:   types.OrderTimeInForceGTT,
  1076  		CreatedAt:     currentTimestamp,
  1077  		ExpiresAt:     someTimeLater,
  1078  		ID:            "3",
  1079  	}
  1080  	trades, getErr = book.ob.GetTrades(order3)
  1081  	assert.NoError(t, getErr)
  1082  	confirm, err = book.ob.SubmitOrder(order3)
  1083  	assert.Equal(t, err, nil)
  1084  	assert.Equal(t, len(trades), len(confirm.Trades))
  1085  
  1086  	order4 := &types.Order{
  1087  		Status:        types.OrderStatusActive,
  1088  		Type:          types.OrderTypeLimit,
  1089  		MarketID:      market,
  1090  		Party:         party,
  1091  		Side:          types.SideSell,
  1092  		Price:         num.NewUint(1000),
  1093  		OriginalPrice: num.NewUint(1000),
  1094  		Size:          7,
  1095  		Remaining:     7,
  1096  		TimeInForce:   types.OrderTimeInForceGTC,
  1097  		CreatedAt:     currentTimestamp,
  1098  		ID:            "4",
  1099  	}
  1100  	trades, getErr = book.ob.GetTrades(order4)
  1101  	assert.NoError(t, getErr)
  1102  	confirm, err = book.ob.SubmitOrder(order4)
  1103  	assert.Equal(t, err, nil)
  1104  	assert.Equal(t, len(trades), len(confirm.Trades))
  1105  
  1106  	order5 := &types.Order{
  1107  		Status:        types.OrderStatusActive,
  1108  		Type:          types.OrderTypeLimit,
  1109  		MarketID:      market,
  1110  		Party:         party,
  1111  		Side:          types.SideSell,
  1112  		Price:         num.NewUint(199),
  1113  		OriginalPrice: num.NewUint(199),
  1114  		Size:          99999,
  1115  		Remaining:     99999,
  1116  		TimeInForce:   types.OrderTimeInForceGTT,
  1117  		CreatedAt:     currentTimestamp,
  1118  		ExpiresAt:     someTimeLater,
  1119  		ID:            "5",
  1120  	}
  1121  
  1122  	trades, getErr = book.ob.GetTrades(order5)
  1123  	assert.NoError(t, getErr)
  1124  	confirm, err = book.ob.SubmitOrder(order5)
  1125  	assert.Equal(t, err, nil)
  1126  	assert.Equal(t, len(trades), len(confirm.Trades))
  1127  
  1128  	order6 := &types.Order{
  1129  		Status:        types.OrderStatusActive,
  1130  		Type:          types.OrderTypeLimit,
  1131  		MarketID:      market,
  1132  		Party:         party,
  1133  		Side:          types.SideSell,
  1134  		Price:         num.NewUint(100),
  1135  		OriginalPrice: num.NewUint(100),
  1136  		Size:          100,
  1137  		Remaining:     100,
  1138  		TimeInForce:   types.OrderTimeInForceGTC,
  1139  		CreatedAt:     currentTimestamp,
  1140  		ID:            "6",
  1141  	}
  1142  	trades, getErr = book.ob.GetTrades(order6)
  1143  	assert.NoError(t, getErr)
  1144  	confirm, err = book.ob.SubmitOrder(order6)
  1145  	assert.Equal(t, err, nil)
  1146  	assert.Equal(t, len(trades), len(confirm.Trades))
  1147  
  1148  	order7 := &types.Order{
  1149  		Status:        types.OrderStatusActive,
  1150  		Type:          types.OrderTypeLimit,
  1151  		MarketID:      market,
  1152  		Party:         party,
  1153  		Side:          types.SideSell,
  1154  		Price:         num.NewUint(41),
  1155  		OriginalPrice: num.NewUint(41),
  1156  		Size:          9999,
  1157  		Remaining:     9999,
  1158  		TimeInForce:   types.OrderTimeInForceGTT,
  1159  		CreatedAt:     currentTimestamp,
  1160  		ExpiresAt:     someTimeLater + 9999,
  1161  		ID:            "7",
  1162  	}
  1163  	trades, getErr = book.ob.GetTrades(order7)
  1164  	assert.NoError(t, getErr)
  1165  	confirm, err = book.ob.SubmitOrder(order7)
  1166  	assert.Equal(t, err, nil)
  1167  	assert.Equal(t, len(trades), len(confirm.Trades))
  1168  
  1169  	order8 := &types.Order{
  1170  		Status:        types.OrderStatusActive,
  1171  		Type:          types.OrderTypeLimit,
  1172  		MarketID:      market,
  1173  		Party:         party,
  1174  		Side:          types.SideSell,
  1175  		Price:         num.NewUint(1),
  1176  		OriginalPrice: num.NewUint(1),
  1177  		Size:          1,
  1178  		Remaining:     1,
  1179  		TimeInForce:   types.OrderTimeInForceGTT,
  1180  		CreatedAt:     currentTimestamp,
  1181  		ExpiresAt:     someTimeLater - 9999,
  1182  		ID:            "8",
  1183  	}
  1184  	trades, getErr = book.ob.GetTrades(order8)
  1185  	assert.NoError(t, getErr)
  1186  	confirm, err = book.ob.SubmitOrder(order8)
  1187  	assert.Equal(t, err, nil)
  1188  	assert.Equal(t, len(trades), len(confirm.Trades))
  1189  
  1190  	order9 := &types.Order{
  1191  		Status:        types.OrderStatusActive,
  1192  		Type:          types.OrderTypeLimit,
  1193  		MarketID:      market,
  1194  		Party:         party,
  1195  		Side:          types.SideSell,
  1196  		Price:         num.NewUint(65),
  1197  		OriginalPrice: num.NewUint(65),
  1198  		Size:          12,
  1199  		Remaining:     12,
  1200  		TimeInForce:   types.OrderTimeInForceGTC,
  1201  		CreatedAt:     currentTimestamp,
  1202  		ID:            "9",
  1203  	}
  1204  	trades, getErr = book.ob.GetTrades(order9)
  1205  	assert.NoError(t, getErr)
  1206  	confirm, err = book.ob.SubmitOrder(order9)
  1207  	assert.Equal(t, err, nil)
  1208  	assert.Equal(t, len(trades), len(confirm.Trades))
  1209  
  1210  	order10 := &types.Order{
  1211  		Status:        types.OrderStatusActive,
  1212  		Type:          types.OrderTypeLimit,
  1213  		MarketID:      market,
  1214  		Party:         party,
  1215  		Side:          types.SideSell,
  1216  		Price:         num.NewUint(1),
  1217  		OriginalPrice: num.NewUint(1),
  1218  		Size:          1,
  1219  		Remaining:     1,
  1220  		TimeInForce:   types.OrderTimeInForceGTT,
  1221  		CreatedAt:     currentTimestamp,
  1222  		ExpiresAt:     someTimeLater - 1,
  1223  		ID:            "10",
  1224  	}
  1225  	trades, getErr = book.ob.GetTrades(order10)
  1226  	assert.NoError(t, getErr)
  1227  	confirm, err = book.ob.SubmitOrder(order10)
  1228  	assert.Equal(t, err, nil)
  1229  	assert.Equal(t, len(trades), len(confirm.Trades))
  1230  }
  1231  
  1232  // test for order validation.
  1233  func TestOrderBook_SubmitOrder2WithValidation(t *testing.T) {
  1234  	market := vgrand.RandomStr(5)
  1235  	book := getTestOrderBook(t, market)
  1236  	defer book.Finish()
  1237  	timeStampOrder := types.Order{
  1238  		Status:    types.OrderStatusActive,
  1239  		Type:      types.OrderTypeLimit,
  1240  		ID:        "timestamporderID",
  1241  		MarketID:  market,
  1242  		Party:     "A",
  1243  		CreatedAt: 10,
  1244  		Side:      types.SideBuy,
  1245  		Size:      1,
  1246  		Remaining: 1,
  1247  	}
  1248  	trades, getErr := book.ob.GetTrades(&timeStampOrder)
  1249  	assert.NoError(t, getErr)
  1250  	confirm, err := book.ob.SubmitOrder(&timeStampOrder)
  1251  	assert.NoError(t, err)
  1252  	assert.Equal(t, len(trades), len(confirm.Trades))
  1253  	// cancel order again, just so we set the timestamp as expected
  1254  	book.ob.CancelOrder(&timeStampOrder)
  1255  
  1256  	invalidRemainingSizeOrdertypes := &types.Order{
  1257  		Status:        types.OrderStatusActive,
  1258  		Type:          types.OrderTypeLimit,
  1259  		MarketID:      market,
  1260  		Party:         "A",
  1261  		Side:          types.SideSell,
  1262  		Price:         num.NewUint(100),
  1263  		OriginalPrice: num.NewUint(100),
  1264  		Size:          100,
  1265  		Remaining:     300,
  1266  		TimeInForce:   types.OrderTimeInForceGTC,
  1267  		CreatedAt:     10,
  1268  		ID:            "id-number-one",
  1269  	}
  1270  	trades, getErr = book.ob.GetTrades(invalidRemainingSizeOrdertypes)
  1271  	_, err = book.ob.SubmitOrder(invalidRemainingSizeOrdertypes)
  1272  	assert.Equal(t, err, getErr)
  1273  	assert.Equal(t, types.OrderErrorInvalidRemainingSize, err)
  1274  	assert.Equal(t, 0, len(trades))
  1275  }
  1276  
  1277  func TestOrderBook_DeleteOrder(t *testing.T) {
  1278  	market := vgrand.RandomStr(5)
  1279  	book := getTestOrderBook(t, market)
  1280  	defer book.Finish()
  1281  
  1282  	newOrder := &types.Order{
  1283  		Status:        types.OrderStatusActive,
  1284  		Type:          types.OrderTypeLimit,
  1285  		MarketID:      market,
  1286  		Party:         "A",
  1287  		Side:          types.SideSell,
  1288  		Price:         num.NewUint(101),
  1289  		OriginalPrice: num.NewUint(101),
  1290  		Size:          100,
  1291  		Remaining:     100,
  1292  		TimeInForce:   types.OrderTimeInForceGTC,
  1293  		CreatedAt:     0,
  1294  	}
  1295  
  1296  	trades, err := book.ob.GetTrades(newOrder)
  1297  	assert.NoError(t, err)
  1298  	assert.Equal(t, 0, len(trades))
  1299  	book.ob.SubmitOrder(newOrder)
  1300  
  1301  	_, err = book.ob.DeleteOrder(newOrder)
  1302  	require.NoError(t, err)
  1303  
  1304  	book.ob.PrintState("AFTER REMOVE ORDER")
  1305  }
  1306  
  1307  func TestOrderBook_RemoveOrder(t *testing.T) {
  1308  	market := vgrand.RandomStr(5)
  1309  	book := getTestOrderBook(t, market)
  1310  	defer book.Finish()
  1311  
  1312  	newOrder := &types.Order{
  1313  		Status:        types.OrderStatusActive,
  1314  		Type:          types.OrderTypeLimit,
  1315  		MarketID:      market,
  1316  		Party:         "A",
  1317  		Side:          types.SideSell,
  1318  		Price:         num.NewUint(101),
  1319  		OriginalPrice: num.NewUint(101),
  1320  		Size:          100,
  1321  		Remaining:     100,
  1322  		TimeInForce:   types.OrderTimeInForceGTC,
  1323  		CreatedAt:     0,
  1324  	}
  1325  
  1326  	trades, err := book.ob.GetTrades(newOrder)
  1327  	assert.NoError(t, err)
  1328  	assert.Equal(t, 0, len(trades))
  1329  	book.ob.SubmitOrder(newOrder)
  1330  
  1331  	// First time we remove the order it should succeed
  1332  	_, err = book.ob.RemoveOrder(newOrder.ID)
  1333  	assert.Error(t, err, vega.ErrInvalidOrderID)
  1334  
  1335  	// Second time we try to remove the order it should fail
  1336  	_, err = book.ob.RemoveOrder(newOrder.ID)
  1337  	assert.Error(t, err)
  1338  }
  1339  
  1340  func TestOrderBook_SubmitOrderInvalidMarket(t *testing.T) {
  1341  	market := vgrand.RandomStr(5)
  1342  	book := getTestOrderBook(t, market)
  1343  	defer book.Finish()
  1344  
  1345  	newOrder := &types.Order{
  1346  		Status:        types.OrderStatusActive,
  1347  		Type:          types.OrderTypeLimit,
  1348  		MarketID:      "invalid",
  1349  		Party:         "A",
  1350  		Side:          types.SideSell,
  1351  		Price:         num.NewUint(101),
  1352  		OriginalPrice: num.NewUint(101),
  1353  		Size:          100,
  1354  		Remaining:     100,
  1355  		TimeInForce:   types.OrderTimeInForceGTC,
  1356  		CreatedAt:     0,
  1357  		ID:            vgcrypto.RandomHash(),
  1358  	}
  1359  
  1360  	trades, getErr := book.ob.GetTrades(newOrder)
  1361  	assert.Error(t, getErr)
  1362  	assert.Equal(t, 0, len(trades))
  1363  	_, err := book.ob.SubmitOrder(newOrder)
  1364  	require.Error(t, err)
  1365  	assert.ErrorIs(t, err, types.OrderErrorInvalidMarketID)
  1366  	assert.ErrorIs(t, err, getErr)
  1367  }
  1368  
  1369  func TestOrderBook_CancelSellOrder(t *testing.T) {
  1370  	market := vgrand.RandomStr(5)
  1371  	book := getTestOrderBook(t, market)
  1372  	defer book.Finish()
  1373  
  1374  	// Arrange
  1375  	id := vgcrypto.RandomHash()
  1376  	newOrder := &types.Order{
  1377  		Status:        types.OrderStatusActive,
  1378  		Type:          types.OrderTypeLimit,
  1379  		MarketID:      market,
  1380  		Party:         "A",
  1381  		Side:          types.SideSell,
  1382  		Price:         num.NewUint(101),
  1383  		OriginalPrice: num.NewUint(101),
  1384  		Size:          100,
  1385  		Remaining:     100,
  1386  		TimeInForce:   types.OrderTimeInForceGTC,
  1387  		CreatedAt:     0,
  1388  		ID:            id,
  1389  	}
  1390  
  1391  	trades, getErr := book.ob.GetTrades(newOrder)
  1392  	assert.NoError(t, getErr)
  1393  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1394  	assert.NoError(t, err)
  1395  	orderAdded := confirmation.Order
  1396  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1397  
  1398  	// Act
  1399  	res, err := book.ob.CancelOrder(orderAdded)
  1400  
  1401  	// Assert
  1402  	assert.NoError(t, err)
  1403  	assert.Equal(t, id, res.Order.ID)
  1404  	assert.Equal(t, types.OrderStatusCancelled, res.Order.Status)
  1405  
  1406  	book.ob.PrintState("AFTER CANCEL ORDER")
  1407  }
  1408  
  1409  func TestOrderBook_CancelBuyOrder(t *testing.T) {
  1410  	market := vgrand.RandomStr(5)
  1411  	book := getTestOrderBook(t, market)
  1412  	defer book.Finish()
  1413  
  1414  	logger := logging.NewTestLogger()
  1415  	defer logger.Sync()
  1416  	logger.Debug("BEGIN CANCELLING VALID ORDER")
  1417  
  1418  	// Arrange
  1419  	id := vgcrypto.RandomHash()
  1420  	newOrder := &types.Order{
  1421  		Status:        types.OrderStatusActive,
  1422  		Type:          types.OrderTypeLimit,
  1423  		MarketID:      market,
  1424  		Party:         "A",
  1425  		Side:          types.SideBuy,
  1426  		Price:         num.NewUint(101),
  1427  		OriginalPrice: num.NewUint(101),
  1428  		Size:          100,
  1429  		Remaining:     100,
  1430  		TimeInForce:   types.OrderTimeInForceGTC,
  1431  		CreatedAt:     0,
  1432  		ID:            id,
  1433  	}
  1434  
  1435  	trades, getErr := book.ob.GetTrades(newOrder)
  1436  	assert.NoError(t, getErr)
  1437  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1438  	assert.NoError(t, err)
  1439  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1440  	orderAdded := confirmation.Order
  1441  
  1442  	// Act
  1443  	res, err := book.ob.CancelOrder(orderAdded)
  1444  
  1445  	// Assert
  1446  	assert.NoError(t, err)
  1447  	assert.Equal(t, id, res.Order.ID)
  1448  	assert.Equal(t, types.OrderStatusCancelled, res.Order.Status)
  1449  
  1450  	book.ob.PrintState("AFTER CANCEL ORDER")
  1451  }
  1452  
  1453  func TestOrderBook_CancelOrderByID(t *testing.T) {
  1454  	market := vgrand.RandomStr(5)
  1455  	book := getTestOrderBook(t, market)
  1456  	defer book.Finish()
  1457  
  1458  	logger := logging.NewTestLogger()
  1459  	defer logger.Sync()
  1460  	logger.Debug("BEGIN CANCELLING VALID ORDER BY ID")
  1461  
  1462  	id := vgcrypto.RandomHash()
  1463  	newOrder := &types.Order{
  1464  		Status:        types.OrderStatusActive,
  1465  		Type:          types.OrderTypeLimit,
  1466  		MarketID:      market,
  1467  		Party:         "A",
  1468  		Side:          types.SideBuy,
  1469  		Price:         num.NewUint(101),
  1470  		OriginalPrice: num.NewUint(101),
  1471  		Size:          100,
  1472  		Remaining:     100,
  1473  		TimeInForce:   types.OrderTimeInForceGTC,
  1474  		CreatedAt:     0,
  1475  		ID:            id,
  1476  	}
  1477  
  1478  	trades, getErr := book.ob.GetTrades(newOrder)
  1479  	assert.NoError(t, getErr)
  1480  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1481  	assert.NotNil(t, confirmation, "submit order should succeed")
  1482  	assert.NoError(t, err, "submit order should succeed")
  1483  	orderAdded := confirmation.Order
  1484  	assert.NotNil(t, orderAdded, "submitted order is expected to be valid")
  1485  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1486  
  1487  	orderFound, err := book.ob.GetOrderByID(orderAdded.ID)
  1488  	assert.NotNil(t, orderFound, "order lookup should work for the order just submitted")
  1489  	assert.NoError(t, err, "order lookup should not fail")
  1490  
  1491  	res, err := book.ob.CancelOrder(orderFound)
  1492  	assert.NotNil(t, res, "cancelling should work for a valid order that was just found")
  1493  	assert.NoError(t, err, "order cancel should not fail")
  1494  
  1495  	orderFound, err = book.ob.GetOrderByID(orderAdded.ID)
  1496  	assert.Error(t, err, "order lookup for an already cancelled order should fail")
  1497  	assert.Nil(t, orderFound, "order lookup for an already cancelled order should not be possible")
  1498  
  1499  	book.ob.PrintState("AFTER CANCEL ORDER BY ID")
  1500  }
  1501  
  1502  func TestOrderBook_CancelOrderMarketMismatch(t *testing.T) {
  1503  	logger := logging.NewTestLogger()
  1504  	defer logger.Sync()
  1505  	logger.Debug("BEGIN CANCELLING MARKET MISMATCH ORDER")
  1506  
  1507  	market := vgrand.RandomStr(5)
  1508  	book := getTestOrderBook(t, market)
  1509  	defer book.Finish()
  1510  	newOrder := &types.Order{
  1511  		Status:    types.OrderStatusActive,
  1512  		Type:      types.OrderTypeLimit,
  1513  		MarketID:  market,
  1514  		ID:        vgcrypto.RandomHash(),
  1515  		Party:     "A",
  1516  		Size:      100,
  1517  		Remaining: 100,
  1518  	}
  1519  
  1520  	trades, getErr := book.ob.GetTrades(newOrder)
  1521  	assert.NoError(t, getErr)
  1522  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1523  	assert.NoError(t, err)
  1524  	orderAdded := confirmation.Order
  1525  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1526  
  1527  	orderAdded.MarketID = "invalid" // Bad market, malformed?
  1528  
  1529  	assert.Panics(t, func() { _, err = book.ob.CancelOrder(orderAdded) })
  1530  }
  1531  
  1532  func TestOrderBook_CancelOrderInvalidID(t *testing.T) {
  1533  	logger := logging.NewTestLogger()
  1534  	defer logger.Sync()
  1535  	logger.Debug("BEGIN CANCELLING INVALID ORDER")
  1536  
  1537  	market := vgrand.RandomStr(5)
  1538  	book := getTestOrderBook(t, market)
  1539  	defer book.Finish()
  1540  	newOrder := &types.Order{
  1541  		Status:    types.OrderStatusActive,
  1542  		Type:      types.OrderTypeLimit,
  1543  		MarketID:  market,
  1544  		ID:        "id",
  1545  		Party:     "A",
  1546  		Size:      100,
  1547  		Remaining: 100,
  1548  	}
  1549  
  1550  	trades, getErr := book.ob.GetTrades(newOrder)
  1551  	assert.NoError(t, getErr)
  1552  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1553  	assert.NoError(t, err)
  1554  	orderAdded := confirmation.Order
  1555  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1556  
  1557  	_, err = book.ob.CancelOrder(orderAdded)
  1558  	if err != nil {
  1559  		logger.Debug("error cancelling order", logging.Error(err))
  1560  	}
  1561  
  1562  	assert.Equal(t, types.OrderErrorInvalidOrderID, err)
  1563  }
  1564  
  1565  func expectTrade(t *testing.T, expectedTrade, trade *types.Trade) {
  1566  	t.Helper()
  1567  	// run asserts for protocol trade data
  1568  	assert.Equal(t, expectedTrade.Type, trade.Type, "invalid trade type")
  1569  	assert.Equal(t, int(expectedTrade.Price.Uint64()), int(trade.Price.Uint64()), "invalid trade price")
  1570  	assert.Equal(t, int(expectedTrade.Size), int(trade.Size), "invalid trade size")
  1571  	assert.Equal(t, expectedTrade.Buyer, trade.Buyer, "invalid trade buyer")
  1572  	assert.Equal(t, expectedTrade.Seller, trade.Seller, "invalid trade seller")
  1573  	assert.Equal(t, expectedTrade.Aggressor, trade.Aggressor, "invalid trade aggressor")
  1574  }
  1575  
  1576  func expectOrder(t *testing.T, expectedOrder, order *types.Order) {
  1577  	t.Helper()
  1578  	// run asserts for order
  1579  	assert.Equal(t, expectedOrder.MarketID, order.MarketID, "invalid order market id")
  1580  	assert.Equal(t, expectedOrder.Party, order.Party, "invalid order party id")
  1581  	assert.Equal(t, expectedOrder.Side, order.Side, "invalid order side")
  1582  	assert.Equal(t, int(expectedOrder.Price.Uint64()), int(order.Price.Uint64()), "invalid order price")
  1583  	assert.Equal(t, int(expectedOrder.Size), int(order.Size), "invalid order size")
  1584  	assert.Equal(t, int(expectedOrder.Remaining), int(order.Remaining), "invalid order remaining")
  1585  	assert.Equal(t, expectedOrder.TimeInForce, order.TimeInForce, "invalid order tif")
  1586  	assert.Equal(t, expectedOrder.CreatedAt, order.CreatedAt, "invalid order created at")
  1587  }
  1588  
  1589  func TestOrderBook_AmendOrder(t *testing.T) {
  1590  	market := vgrand.RandomStr(5)
  1591  	book := getTestOrderBook(t, market)
  1592  	defer book.Finish()
  1593  
  1594  	newOrder := &types.Order{
  1595  		Status:        types.OrderStatusActive,
  1596  		Type:          types.OrderTypeLimit,
  1597  		MarketID:      market,
  1598  		ID:            "123456",
  1599  		Party:         "A",
  1600  		Side:          types.SideBuy,
  1601  		Price:         num.NewUint(100),
  1602  		OriginalPrice: num.NewUint(100),
  1603  		Size:          200,
  1604  		Remaining:     200,
  1605  		TimeInForce:   types.OrderTimeInForceGTC,
  1606  	}
  1607  
  1608  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1609  	if err != nil {
  1610  		t.Log(err)
  1611  	}
  1612  
  1613  	assert.Equal(t, nil, err)
  1614  	assert.NotNil(t, confirmation)
  1615  	assert.Equal(t, "123456", confirmation.Order.ID)
  1616  	assert.Equal(t, 0, len(confirmation.Trades))
  1617  
  1618  	editedOrder := &types.Order{
  1619  		Status:        types.OrderStatusActive,
  1620  		Type:          types.OrderTypeLimit,
  1621  		MarketID:      market,
  1622  		ID:            "123456",
  1623  		Party:         "A",
  1624  		Side:          types.SideBuy,
  1625  		Price:         num.NewUint(100),
  1626  		OriginalPrice: num.NewUint(100),
  1627  		Size:          200,
  1628  		Remaining:     200,
  1629  		TimeInForce:   types.OrderTimeInForceGTC,
  1630  	}
  1631  
  1632  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1633  	if err != nil {
  1634  		t.Log(err)
  1635  	}
  1636  
  1637  	assert.Nil(t, err)
  1638  }
  1639  
  1640  func TestOrderBook_AmendOrderInvalidRemaining(t *testing.T) {
  1641  	market := vgrand.RandomStr(5)
  1642  	book := getTestOrderBook(t, market)
  1643  	defer book.Finish()
  1644  
  1645  	newOrder := &types.Order{
  1646  		Status:        types.OrderStatusActive,
  1647  		Type:          types.OrderTypeLimit,
  1648  		MarketID:      market,
  1649  		ID:            "123456",
  1650  		Party:         "A",
  1651  		Side:          types.SideBuy,
  1652  		Price:         num.NewUint(100),
  1653  		OriginalPrice: num.NewUint(100),
  1654  		Size:          200,
  1655  		Remaining:     200,
  1656  		TimeInForce:   types.OrderTimeInForceGTC,
  1657  	}
  1658  
  1659  	trades, getErr := book.ob.GetTrades(newOrder)
  1660  	assert.NoError(t, getErr)
  1661  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1662  
  1663  	assert.Equal(t, nil, err)
  1664  	assert.NotNil(t, confirmation)
  1665  	assert.Equal(t, "123456", confirmation.Order.ID)
  1666  	assert.Equal(t, 0, len(confirmation.Trades))
  1667  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1668  
  1669  	editedOrder := &types.Order{
  1670  		Status:        types.OrderStatusActive,
  1671  		Type:          types.OrderTypeLimit,
  1672  		MarketID:      market,
  1673  		Party:         "A",
  1674  		ID:            "123456",
  1675  		Side:          types.SideSell,
  1676  		Price:         num.NewUint(100),
  1677  		OriginalPrice: num.NewUint(100),
  1678  		Size:          100,
  1679  		Remaining:     200,
  1680  		TimeInForce:   types.OrderTimeInForceGTC,
  1681  	}
  1682  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1683  	if err != types.OrderErrorInvalidRemainingSize {
  1684  		t.Log(err)
  1685  	}
  1686  
  1687  	assert.Equal(t, types.OrderErrorInvalidRemainingSize, err)
  1688  }
  1689  
  1690  func TestOrderBook_AmendOrderInvalidAmend(t *testing.T) {
  1691  	market := vgrand.RandomStr(5)
  1692  	book := getTestOrderBook(t, market)
  1693  	defer book.Finish()
  1694  
  1695  	newOrder := &types.Order{
  1696  		Status:        types.OrderStatusActive,
  1697  		Type:          types.OrderTypeLimit,
  1698  		MarketID:      market,
  1699  		ID:            "123456",
  1700  		Side:          types.SideBuy,
  1701  		Price:         num.NewUint(100),
  1702  		OriginalPrice: num.NewUint(100),
  1703  		Size:          200,
  1704  		Remaining:     200,
  1705  		TimeInForce:   types.OrderTimeInForceGTC,
  1706  	}
  1707  
  1708  	trades, getErr := book.ob.GetTrades(newOrder)
  1709  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1710  	assert.Equal(t, err, getErr)
  1711  	assert.Equal(t, 0, len(trades))
  1712  
  1713  	fmt.Printf("confirmation : %+v", confirmation)
  1714  
  1715  	editedOrder := &types.Order{
  1716  		Status:        types.OrderStatusActive,
  1717  		Type:          types.OrderTypeLimit,
  1718  		MarketID:      market,
  1719  		ID:            "123456",
  1720  		Party:         "A",
  1721  		Side:          types.SideSell,
  1722  		Price:         num.NewUint(100),
  1723  		OriginalPrice: num.NewUint(100),
  1724  		Size:          200,
  1725  		Remaining:     200,
  1726  		TimeInForce:   types.OrderTimeInForceGTC,
  1727  	}
  1728  
  1729  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1730  	assert.Equal(t, types.OrderErrorNotFound, err)
  1731  }
  1732  
  1733  func TestOrderBook_AmendOrderInvalidAmend1(t *testing.T) {
  1734  	logger := logging.NewTestLogger()
  1735  	defer logger.Sync()
  1736  	logger.Debug("BEGIN AMENDING ORDER")
  1737  
  1738  	market := vgrand.RandomStr(5)
  1739  	book := getTestOrderBook(t, market)
  1740  	defer book.Finish()
  1741  	newOrder := &types.Order{
  1742  		Status:        types.OrderStatusActive,
  1743  		Type:          types.OrderTypeLimit,
  1744  		MarketID:      market,
  1745  		ID:            "123456",
  1746  		Side:          types.SideBuy,
  1747  		Price:         num.NewUint(100),
  1748  		OriginalPrice: num.NewUint(100),
  1749  		Party:         "A",
  1750  		Size:          200,
  1751  		Remaining:     200,
  1752  		TimeInForce:   types.OrderTimeInForceGTC,
  1753  	}
  1754  
  1755  	trades, getErr := book.ob.GetTrades(newOrder)
  1756  	assert.NoError(t, getErr)
  1757  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1758  
  1759  	assert.Equal(t, nil, err)
  1760  	assert.NotNil(t, confirmation)
  1761  	assert.Equal(t, "123456", confirmation.Order.ID)
  1762  	assert.Equal(t, 0, len(confirmation.Trades))
  1763  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1764  
  1765  	editedOrder := &types.Order{
  1766  		Status:        types.OrderStatusActive,
  1767  		Type:          types.OrderTypeLimit,
  1768  		MarketID:      market,
  1769  		ID:            "123456",
  1770  		Side:          types.SideBuy,
  1771  		Price:         num.NewUint(100),
  1772  		OriginalPrice: num.NewUint(100),
  1773  		Party:         "B",
  1774  		Size:          200,
  1775  		Remaining:     200,
  1776  		TimeInForce:   types.OrderTimeInForceGTC,
  1777  	}
  1778  
  1779  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1780  	if err != types.OrderErrorAmendFailure {
  1781  		t.Log(err)
  1782  	}
  1783  
  1784  	assert.Equal(t, types.OrderErrorAmendFailure, err)
  1785  }
  1786  
  1787  func TestOrderBook_AmendOrderInvalidAmendOutOfSequence(t *testing.T) {
  1788  	market := vgrand.RandomStr(5)
  1789  	book := getTestOrderBook(t, market)
  1790  	defer book.Finish()
  1791  
  1792  	logger := logging.NewTestLogger()
  1793  	defer logger.Sync()
  1794  	logger.Debug("BEGIN AMENDING OUT OF SEQUENCE ORDER")
  1795  
  1796  	newOrder := &types.Order{
  1797  		Status:        types.OrderStatusActive,
  1798  		Type:          types.OrderTypeLimit,
  1799  		MarketID:      market,
  1800  		ID:            "123456",
  1801  		Side:          types.SideBuy,
  1802  		Price:         num.NewUint(100),
  1803  		OriginalPrice: num.NewUint(100),
  1804  		Party:         "A",
  1805  		Size:          200,
  1806  		Remaining:     200,
  1807  		TimeInForce:   types.OrderTimeInForceGTC,
  1808  		CreatedAt:     10,
  1809  	}
  1810  
  1811  	trades, getErr := book.ob.GetTrades(newOrder)
  1812  	assert.NoError(t, getErr)
  1813  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1814  
  1815  	assert.Equal(t, nil, err)
  1816  	assert.NotNil(t, confirmation)
  1817  	assert.Equal(t, "123456", confirmation.Order.ID)
  1818  	assert.Equal(t, 0, len(confirmation.Trades))
  1819  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1820  
  1821  	editedOrder := &types.Order{
  1822  		Status:        types.OrderStatusActive,
  1823  		Type:          types.OrderTypeLimit,
  1824  		MarketID:      market,
  1825  		ID:            "123456",
  1826  		Side:          types.SideBuy,
  1827  		Price:         num.NewUint(100),
  1828  		OriginalPrice: num.NewUint(100),
  1829  		Party:         "A",
  1830  		Size:          200,
  1831  		Remaining:     200,
  1832  		TimeInForce:   types.OrderTimeInForceGTC,
  1833  		CreatedAt:     5,
  1834  	}
  1835  
  1836  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1837  	if err != types.OrderErrorOutOfSequence {
  1838  		t.Log(err)
  1839  	}
  1840  
  1841  	assert.Equal(t, types.OrderErrorOutOfSequence, err)
  1842  }
  1843  
  1844  func TestOrderBook_AmendOrderInvalidAmendSize(t *testing.T) {
  1845  	market := vgrand.RandomStr(5)
  1846  	book := getTestOrderBook(t, market)
  1847  	defer book.Finish()
  1848  
  1849  	logger := logging.NewTestLogger()
  1850  	defer logger.Sync()
  1851  	logger.Debug("BEGIN AMEND ORDER INVALID SIZE")
  1852  
  1853  	newOrder := &types.Order{
  1854  		Status:        types.OrderStatusActive,
  1855  		Type:          types.OrderTypeLimit,
  1856  		MarketID:      market,
  1857  		ID:            "123456",
  1858  		Side:          types.SideBuy,
  1859  		Price:         num.NewUint(100),
  1860  		OriginalPrice: num.NewUint(100),
  1861  		Party:         "A",
  1862  		Size:          200,
  1863  		Remaining:     200,
  1864  		TimeInForce:   types.OrderTimeInForceGTC,
  1865  		CreatedAt:     10,
  1866  	}
  1867  
  1868  	trades, getErr := book.ob.GetTrades(newOrder)
  1869  	assert.NoError(t, getErr)
  1870  	confirmation, err := book.ob.SubmitOrder(newOrder)
  1871  
  1872  	assert.Equal(t, nil, err)
  1873  	assert.NotNil(t, confirmation)
  1874  	assert.Equal(t, "123456", confirmation.Order.ID)
  1875  	assert.Equal(t, 0, len(confirmation.Trades))
  1876  	assert.Equal(t, len(trades), len(confirmation.Trades))
  1877  
  1878  	editedOrder := &types.Order{
  1879  		Status:        types.OrderStatusActive,
  1880  		Type:          types.OrderTypeLimit,
  1881  		MarketID:      market,
  1882  		ID:            "123456",
  1883  		Side:          types.SideBuy,
  1884  		Price:         num.NewUint(100),
  1885  		OriginalPrice: num.NewUint(100),
  1886  		Party:         "B",
  1887  		Size:          300,
  1888  		Remaining:     300,
  1889  		TimeInForce:   types.OrderTimeInForceGTC,
  1890  		CreatedAt:     10,
  1891  	}
  1892  
  1893  	err = book.ob.AmendOrder(newOrder, editedOrder)
  1894  	if err != types.OrderErrorAmendFailure {
  1895  		t.Log(err)
  1896  	}
  1897  
  1898  	assert.Equal(t, types.OrderErrorAmendFailure, err)
  1899  }
  1900  
  1901  // ProRata mode OFF which is a default config for vega ME.
  1902  func TestOrderBook_SubmitOrderProRataModeOff(t *testing.T) {
  1903  	market := vgrand.RandomStr(5)
  1904  	book := getTestOrderBook(t, market)
  1905  	defer book.Finish()
  1906  
  1907  	// logger := logging.NewTestLogger()
  1908  	// defer logger.Sync()
  1909  	// logger.Debug("BEGIN PRO-RATA MODE OFF")
  1910  
  1911  	const numberOfTimestamps = 2
  1912  	m := make(map[int64][]*types.Order, numberOfTimestamps)
  1913  
  1914  	// sell and buy side orders at timestamp 0
  1915  	m[0] = []*types.Order{
  1916  		// Side Sell
  1917  		{
  1918  			ID:            "V0000000032-0000000009",
  1919  			Status:        types.OrderStatusActive,
  1920  			Type:          types.OrderTypeLimit,
  1921  			MarketID:      market,
  1922  			Party:         "A",
  1923  			Side:          types.SideSell,
  1924  			Price:         num.NewUint(101),
  1925  			OriginalPrice: num.NewUint(101),
  1926  			Size:          100,
  1927  			Remaining:     100,
  1928  			TimeInForce:   types.OrderTimeInForceGTC,
  1929  			CreatedAt:     0,
  1930  		},
  1931  		{
  1932  			ID:            "V0000000032-0000000010",
  1933  			Status:        types.OrderStatusActive,
  1934  			Type:          types.OrderTypeLimit,
  1935  			MarketID:      market,
  1936  			Party:         "B",
  1937  			Side:          types.SideSell,
  1938  			Price:         num.NewUint(101),
  1939  			OriginalPrice: num.NewUint(101),
  1940  			Size:          100,
  1941  			Remaining:     100,
  1942  			TimeInForce:   types.OrderTimeInForceGTC,
  1943  			CreatedAt:     0,
  1944  		},
  1945  		// Side Buy
  1946  		{
  1947  			ID:            "V0000000032-0000000011",
  1948  			Status:        types.OrderStatusActive,
  1949  			Type:          types.OrderTypeLimit,
  1950  			MarketID:      market,
  1951  			Party:         "C",
  1952  			Side:          types.SideBuy,
  1953  			Price:         num.NewUint(98),
  1954  			OriginalPrice: num.NewUint(98),
  1955  			Size:          100,
  1956  			Remaining:     100,
  1957  			TimeInForce:   types.OrderTimeInForceGTC,
  1958  			CreatedAt:     0,
  1959  		},
  1960  		{
  1961  			ID:            "V0000000032-0000000012",
  1962  			Status:        types.OrderStatusActive,
  1963  			Type:          types.OrderTypeLimit,
  1964  			MarketID:      market,
  1965  			Party:         "D",
  1966  			Side:          types.SideBuy,
  1967  			Price:         num.NewUint(98),
  1968  			OriginalPrice: num.NewUint(98),
  1969  			Size:          100,
  1970  			Remaining:     100,
  1971  			TimeInForce:   types.OrderTimeInForceGTC,
  1972  			CreatedAt:     0,
  1973  		},
  1974  	}
  1975  
  1976  	// sell and buy orders at timestamp 1
  1977  	m[1] = []*types.Order{
  1978  		// Side Sell
  1979  		{
  1980  			ID:            "V0000000032-0000000013",
  1981  			Status:        types.OrderStatusActive,
  1982  			Type:          types.OrderTypeLimit,
  1983  			MarketID:      market,
  1984  			Party:         "E",
  1985  			Side:          types.SideSell,
  1986  			Price:         num.NewUint(101),
  1987  			OriginalPrice: num.NewUint(101),
  1988  			Size:          100,
  1989  			Remaining:     100,
  1990  			TimeInForce:   types.OrderTimeInForceGTC,
  1991  			CreatedAt:     1,
  1992  		},
  1993  		// Side Buy
  1994  		{
  1995  			ID:            "V0000000032-0000000014",
  1996  			Status:        types.OrderStatusActive,
  1997  			Type:          types.OrderTypeLimit,
  1998  			MarketID:      market,
  1999  			Party:         "F",
  2000  			Side:          types.SideBuy,
  2001  			Price:         num.NewUint(99),
  2002  			OriginalPrice: num.NewUint(99),
  2003  			Size:          100,
  2004  			Remaining:     100,
  2005  			TimeInForce:   types.OrderTimeInForceGTC,
  2006  			CreatedAt:     1,
  2007  		},
  2008  	}
  2009  
  2010  	timestamps := []int64{0, 1}
  2011  	for _, timestamp := range timestamps {
  2012  		for _, o := range m[timestamp] {
  2013  			trades, getErr := book.ob.GetTrades(o)
  2014  			assert.NoError(t, getErr)
  2015  			confirmation, err := book.ob.SubmitOrder(o)
  2016  			// this should not return any errors
  2017  			assert.Equal(t, nil, err)
  2018  			// this should not generate any trades
  2019  			assert.Equal(t, 0, len(confirmation.Trades))
  2020  			assert.Equal(t, len(trades), len(confirmation.Trades))
  2021  		}
  2022  	}
  2023  
  2024  	scenario := []aggressiveOrderScenario{
  2025  		{
  2026  			// same price level, remaining on the passive
  2027  			aggressiveOrder: &types.Order{
  2028  				ID:            "V0000000032-0000000015",
  2029  				Status:        types.OrderStatusActive,
  2030  				Type:          types.OrderTypeLimit,
  2031  				MarketID:      market,
  2032  				Party:         "M",
  2033  				Side:          types.SideBuy,
  2034  				Price:         num.NewUint(101),
  2035  				OriginalPrice: num.NewUint(101),
  2036  				Size:          100,
  2037  				Remaining:     100,
  2038  				TimeInForce:   types.OrderTimeInForceGTC,
  2039  				CreatedAt:     3,
  2040  			},
  2041  			expectedTrades: []types.Trade{
  2042  				{
  2043  					Type:      types.TradeTypeDefault,
  2044  					MarketID:  market,
  2045  					Price:     num.NewUint(101),
  2046  					Size:      100,
  2047  					Buyer:     "M",
  2048  					Seller:    "A",
  2049  					Aggressor: types.SideBuy,
  2050  				},
  2051  			},
  2052  			expectedPassiveOrdersAffected: []types.Order{
  2053  				{
  2054  					Status:        types.OrderStatusActive,
  2055  					Type:          types.OrderTypeLimit,
  2056  					MarketID:      market,
  2057  					Party:         "A",
  2058  					Side:          types.SideSell,
  2059  					Price:         num.NewUint(101),
  2060  					OriginalPrice: num.NewUint(101),
  2061  					Size:          100,
  2062  					Remaining:     0,
  2063  					TimeInForce:   types.OrderTimeInForceGTC,
  2064  					CreatedAt:     0,
  2065  				},
  2066  			},
  2067  		},
  2068  		{
  2069  			// same price level, remaining on the passive
  2070  			aggressiveOrder: &types.Order{
  2071  				Status:        types.OrderStatusActive,
  2072  				Type:          types.OrderTypeLimit,
  2073  				MarketID:      market,
  2074  				Party:         "N",
  2075  				Side:          types.SideBuy,
  2076  				Price:         num.NewUint(102),
  2077  				OriginalPrice: num.NewUint(102),
  2078  				Size:          200,
  2079  				Remaining:     200,
  2080  				TimeInForce:   types.OrderTimeInForceGTC,
  2081  				CreatedAt:     4,
  2082  			},
  2083  			expectedTrades: []types.Trade{
  2084  				{
  2085  					Type:      types.TradeTypeDefault,
  2086  					MarketID:  market,
  2087  					Price:     num.NewUint(101),
  2088  					Size:      100,
  2089  					Buyer:     "N",
  2090  					Seller:    "B",
  2091  					Aggressor: types.SideBuy,
  2092  				},
  2093  				{
  2094  					Type:      types.TradeTypeDefault,
  2095  					MarketID:  market,
  2096  					Price:     num.NewUint(101),
  2097  					Size:      100,
  2098  					Buyer:     "N",
  2099  					Seller:    "E",
  2100  					Aggressor: types.SideBuy,
  2101  				},
  2102  			},
  2103  			expectedPassiveOrdersAffected: []types.Order{
  2104  				{
  2105  					Status:        types.OrderStatusActive,
  2106  					Type:          types.OrderTypeLimit,
  2107  					MarketID:      market,
  2108  					Party:         "B",
  2109  					Side:          types.SideSell,
  2110  					Price:         num.NewUint(101),
  2111  					OriginalPrice: num.NewUint(101),
  2112  					Size:          100,
  2113  					Remaining:     0,
  2114  					TimeInForce:   types.OrderTimeInForceGTC,
  2115  					CreatedAt:     0,
  2116  				},
  2117  				{
  2118  					Status:        types.OrderStatusActive,
  2119  					Type:          types.OrderTypeLimit,
  2120  					MarketID:      market,
  2121  					Party:         "E",
  2122  					Side:          types.SideSell,
  2123  					Price:         num.NewUint(101),
  2124  					OriginalPrice: num.NewUint(101),
  2125  					Size:          100,
  2126  					Remaining:     0,
  2127  					TimeInForce:   types.OrderTimeInForceGTC,
  2128  					CreatedAt:     1,
  2129  				},
  2130  			},
  2131  		},
  2132  		{
  2133  			// same price level, NO PRORATA
  2134  			aggressiveOrder: &types.Order{
  2135  				Status:        types.OrderStatusActive,
  2136  				Type:          types.OrderTypeLimit,
  2137  				MarketID:      market,
  2138  				Party:         "O",
  2139  				Side:          types.SideSell,
  2140  				Price:         num.NewUint(97),
  2141  				OriginalPrice: num.NewUint(97),
  2142  				Size:          250,
  2143  				Remaining:     250,
  2144  				TimeInForce:   types.OrderTimeInForceGTC,
  2145  				CreatedAt:     5,
  2146  			},
  2147  			expectedTrades: []types.Trade{
  2148  				{
  2149  					Type:      types.TradeTypeDefault,
  2150  					MarketID:  market,
  2151  					Price:     num.NewUint(99),
  2152  					Size:      100,
  2153  					Buyer:     "F",
  2154  					Seller:    "O",
  2155  					Aggressor: types.SideSell,
  2156  				},
  2157  				{
  2158  					Type:      types.TradeTypeDefault,
  2159  					MarketID:  market,
  2160  					Price:     num.NewUint(98),
  2161  					Size:      100,
  2162  					Buyer:     "C",
  2163  					Seller:    "O",
  2164  					Aggressor: types.SideSell,
  2165  				},
  2166  				{
  2167  					Type:      types.TradeTypeDefault,
  2168  					MarketID:  market,
  2169  					Price:     num.NewUint(98),
  2170  					Size:      50,
  2171  					Buyer:     "D",
  2172  					Seller:    "O",
  2173  					Aggressor: types.SideSell,
  2174  				},
  2175  			},
  2176  			expectedPassiveOrdersAffected: []types.Order{
  2177  				{
  2178  					Status:        types.OrderStatusActive,
  2179  					Type:          types.OrderTypeLimit,
  2180  					MarketID:      market,
  2181  					Party:         "F",
  2182  					Side:          types.SideBuy,
  2183  					Price:         num.NewUint(99),
  2184  					OriginalPrice: num.NewUint(99),
  2185  					Size:          100,
  2186  					Remaining:     0,
  2187  					TimeInForce:   types.OrderTimeInForceGTC,
  2188  					CreatedAt:     1,
  2189  				},
  2190  				{
  2191  					Status:        types.OrderStatusActive,
  2192  					Type:          types.OrderTypeLimit,
  2193  					MarketID:      market,
  2194  					Party:         "C",
  2195  					Side:          types.SideBuy,
  2196  					Price:         num.NewUint(98),
  2197  					OriginalPrice: num.NewUint(98),
  2198  					Size:          100,
  2199  					Remaining:     0,
  2200  					TimeInForce:   types.OrderTimeInForceGTC,
  2201  					CreatedAt:     0,
  2202  				},
  2203  				{
  2204  					Status:        types.OrderStatusActive,
  2205  					Type:          types.OrderTypeLimit,
  2206  					MarketID:      market,
  2207  					Party:         "D",
  2208  					Side:          types.SideBuy,
  2209  					Price:         num.NewUint(98),
  2210  					OriginalPrice: num.NewUint(98),
  2211  					Size:          100,
  2212  					Remaining:     50,
  2213  					TimeInForce:   types.OrderTimeInForceGTC,
  2214  					CreatedAt:     0,
  2215  				},
  2216  			},
  2217  		},
  2218  		{
  2219  			// same price level, NO PRORATA
  2220  			aggressiveOrder: &types.Order{
  2221  				Status:        types.OrderStatusActive,
  2222  				Type:          types.OrderTypeLimit,
  2223  				MarketID:      market,
  2224  				Party:         "X",
  2225  				Side:          types.SideSell,
  2226  				Price:         num.NewUint(98),
  2227  				OriginalPrice: num.NewUint(98),
  2228  				Size:          50,
  2229  				Remaining:     50,
  2230  				TimeInForce:   types.OrderTimeInForceGTC,
  2231  				CreatedAt:     6,
  2232  			},
  2233  			expectedTrades: []types.Trade{
  2234  				{
  2235  					Type:      types.TradeTypeDefault,
  2236  					MarketID:  market,
  2237  					Price:     num.NewUint(98),
  2238  					Size:      50,
  2239  					Buyer:     "D",
  2240  					Seller:    "X",
  2241  					Aggressor: types.SideSell,
  2242  				},
  2243  			},
  2244  			expectedPassiveOrdersAffected: []types.Order{
  2245  				{
  2246  					Status:        types.OrderStatusActive,
  2247  					Type:          types.OrderTypeLimit,
  2248  					MarketID:      market,
  2249  					Party:         "D",
  2250  					Side:          types.SideBuy,
  2251  					Price:         num.NewUint(98),
  2252  					OriginalPrice: num.NewUint(98),
  2253  					Size:          100,
  2254  					Remaining:     0,
  2255  					TimeInForce:   types.OrderTimeInForceGTC,
  2256  					CreatedAt:     0,
  2257  				},
  2258  			},
  2259  		},
  2260  	}
  2261  
  2262  	for i, s := range scenario {
  2263  		fmt.Println()
  2264  		fmt.Println()
  2265  		fmt.Printf("SCENARIO %d / %d ------------------------------------------------------------------", i+1, len(scenario))
  2266  		fmt.Println()
  2267  		fmt.Println("aggressor: ", s.aggressiveOrder)
  2268  		fmt.Println("expectedPassiveOrdersAffected: ", s.expectedPassiveOrdersAffected)
  2269  		fmt.Println("expectedTrades: ", s.expectedTrades)
  2270  		fmt.Println()
  2271  
  2272  		trades, getErr := book.ob.GetTrades(s.aggressiveOrder)
  2273  		assert.NoError(t, getErr)
  2274  		confirmationtypes, err := book.ob.SubmitOrder(s.aggressiveOrder)
  2275  
  2276  		// this should not return any errors
  2277  		assert.Equal(t, nil, err)
  2278  
  2279  		// this should not generate any trades
  2280  		assert.Equal(t, len(s.expectedTrades), len(confirmationtypes.Trades))
  2281  		assert.Equal(t, len(confirmationtypes.Trades), len(trades))
  2282  
  2283  		fmt.Println("CONFIRMATION types:")
  2284  		fmt.Println("-> Aggressive:", confirmationtypes.Order)
  2285  		fmt.Println("-> Trades :", confirmationtypes.Trades)
  2286  		fmt.Println("-> PassiveOrdersAffected:", confirmationtypes.PassiveOrdersAffected)
  2287  		fmt.Printf("Scenario: %d / %d \n", i+1, len(scenario))
  2288  
  2289  		// trades should match expected trades
  2290  		for i, exp := range s.expectedTrades {
  2291  			expectTrade(t, &exp, confirmationtypes.Trades[i])
  2292  			expectTrade(t, &exp, trades[i])
  2293  		}
  2294  
  2295  		// orders affected should match expected values
  2296  		for i, exp := range s.expectedPassiveOrdersAffected {
  2297  			expectOrder(t, &exp, confirmationtypes.PassiveOrdersAffected[i])
  2298  		}
  2299  	}
  2300  }
  2301  
  2302  // Validate that an IOC order that is not fully filled
  2303  // is not added to the order book.ob.
  2304  func TestOrderBook_PartialFillIOCOrder(t *testing.T) {
  2305  	market := vgrand.RandomStr(5)
  2306  	book := getTestOrderBook(t, market)
  2307  	defer book.Finish()
  2308  
  2309  	logger := logging.NewTestLogger()
  2310  	defer logger.Sync()
  2311  	logger.Debug("BEGIN PARTIAL FILL IOC ORDER")
  2312  
  2313  	orderID := vgcrypto.RandomHash()
  2314  	newOrder := &types.Order{
  2315  		ID:            orderID,
  2316  		Status:        types.OrderStatusActive,
  2317  		Type:          types.OrderTypeLimit,
  2318  		MarketID:      market,
  2319  		Side:          types.SideSell,
  2320  		Price:         num.NewUint(100),
  2321  		OriginalPrice: num.NewUint(100),
  2322  		Party:         "A",
  2323  		Size:          100,
  2324  		Remaining:     100,
  2325  		TimeInForce:   types.OrderTimeInForceGTC,
  2326  		CreatedAt:     10,
  2327  	}
  2328  
  2329  	trades, getErr := book.ob.GetTrades(newOrder)
  2330  	assert.NoError(t, getErr)
  2331  	confirmation, err := book.ob.SubmitOrder(newOrder)
  2332  
  2333  	assert.Equal(t, nil, err)
  2334  	assert.NotNil(t, confirmation)
  2335  	assert.Equal(t, orderID, confirmation.Order.ID)
  2336  	assert.Equal(t, 0, len(confirmation.Trades))
  2337  	assert.Equal(t, len(trades), len(confirmation.Trades))
  2338  
  2339  	iocOrderID := vgcrypto.RandomHash()
  2340  	iocOrder := &types.Order{
  2341  		Status:        types.OrderStatusActive,
  2342  		Type:          types.OrderTypeLimit,
  2343  		MarketID:      market,
  2344  		ID:            iocOrderID,
  2345  		Side:          types.SideBuy,
  2346  		Price:         num.NewUint(100),
  2347  		OriginalPrice: num.NewUint(100),
  2348  		Party:         "B",
  2349  		Size:          20,
  2350  		Remaining:     20,
  2351  		TimeInForce:   types.OrderTimeInForceIOC,
  2352  		CreatedAt:     10,
  2353  	}
  2354  	trades, getErr = book.ob.GetTrades(iocOrder)
  2355  	assert.NoError(t, getErr)
  2356  	confirmation, err = book.ob.SubmitOrder(iocOrder)
  2357  
  2358  	assert.Equal(t, nil, err)
  2359  	assert.NotNil(t, confirmation)
  2360  	assert.Equal(t, iocOrderID, confirmation.Order.ID)
  2361  	assert.Equal(t, 1, len(confirmation.Trades))
  2362  	assert.Equal(t, len(trades), len(confirmation.Trades))
  2363  
  2364  	// Check to see if the order still exists (it should not)
  2365  	nonorder, err := book.ob.GetOrderByID(iocOrderID)
  2366  	assert.Equal(t, matching.ErrOrderDoesNotExist, err)
  2367  	assert.Nil(t, nonorder)
  2368  }
  2369  
  2370  func makeOrder(t *testing.T, orderbook *tstOB, market string, id string, side types.Side, price uint64, partyid string, size uint64) *types.Order {
  2371  	t.Helper()
  2372  	order := getOrder(t, market, id, side, price, partyid, size)
  2373  	_, err := orderbook.ob.SubmitOrder(order)
  2374  	assert.Equal(t, err, nil)
  2375  	return order
  2376  }
  2377  
  2378  func getOrder(t *testing.T, market string, id string, side types.Side, price uint64, partyid string, size uint64) *types.Order {
  2379  	t.Helper()
  2380  	order := &types.Order{
  2381  		Status:        types.OrderStatusActive,
  2382  		Type:          types.OrderTypeLimit,
  2383  		MarketID:      market,
  2384  		ID:            id,
  2385  		Side:          side,
  2386  		Price:         num.NewUint(price),
  2387  		OriginalPrice: num.NewUint(price),
  2388  		Party:         partyid,
  2389  		Size:          size,
  2390  		Remaining:     size,
  2391  		TimeInForce:   types.OrderTimeInForceGTC,
  2392  		CreatedAt:     10,
  2393  	}
  2394  	return order
  2395  }
  2396  
  2397  /*****************************************************************************/
  2398  /*                             GFN/GFA TESTING                               */
  2399  /*****************************************************************************/
  2400  
  2401  func TestOrderBook_GFNMarketNoExpiry(t *testing.T) {
  2402  	market := vgrand.RandomStr(5)
  2403  	book := getTestOrderBook(t, market)
  2404  	defer book.Finish()
  2405  
  2406  	logger := logging.NewTestLogger()
  2407  	defer logger.Sync()
  2408  
  2409  	// Enter a GFN market order with no expiration time
  2410  	buyOrder := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2411  	buyOrder.TimeInForce = types.OrderTimeInForceGFN
  2412  	buyOrder.Type = types.OrderTypeMarket
  2413  	buyOrder.ExpiresAt = 0
  2414  	buyOrderConf, err := book.ob.SubmitOrder(buyOrder)
  2415  	assert.NoError(t, err)
  2416  	assert.NotNil(t, buyOrderConf)
  2417  
  2418  	// Enter a GFN market order with no expiration time
  2419  	sellOrder := getOrder(t, market, "SellOrder01", types.SideSell, 100, "party01", 10)
  2420  	sellOrder.TimeInForce = types.OrderTimeInForceGFN
  2421  	sellOrder.Type = types.OrderTypeMarket
  2422  	sellOrder.ExpiresAt = 0
  2423  	sellOrderConf, err := book.ob.SubmitOrder(sellOrder)
  2424  	assert.NoError(t, err)
  2425  	assert.NotNil(t, sellOrderConf)
  2426  }
  2427  
  2428  func TestOrderBook_GFNMarketWithExpiry(t *testing.T) {
  2429  	market := vgrand.RandomStr(5)
  2430  	book := getTestOrderBook(t, market)
  2431  	defer book.Finish()
  2432  
  2433  	logger := logging.NewTestLogger()
  2434  	defer logger.Sync()
  2435  
  2436  	// Enter a GFN market order with an expiration time (which is invalid)
  2437  	buyOrder := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2438  	buyOrder.TimeInForce = types.OrderTimeInForceGFN
  2439  	buyOrder.Type = types.OrderTypeMarket
  2440  	buyOrder.ExpiresAt = 100
  2441  	buyOrderConf, err := book.ob.SubmitOrder(buyOrder)
  2442  	assert.Error(t, err, types.ErrInvalidExpirationDatetime)
  2443  	assert.Nil(t, buyOrderConf)
  2444  
  2445  	// Enter a GFN market order with an expiration time (which is invalid)
  2446  	sellOrder := getOrder(t, market, "SellOrder01", types.SideSell, 100, "party01", 10)
  2447  	sellOrder.TimeInForce = types.OrderTimeInForceGFN
  2448  	sellOrder.Type = types.OrderTypeMarket
  2449  	sellOrder.ExpiresAt = 100
  2450  	sellOrderConf, err := book.ob.SubmitOrder(sellOrder)
  2451  	assert.Error(t, err, types.ErrInvalidExpirationDatetime)
  2452  	assert.Nil(t, sellOrderConf)
  2453  }
  2454  
  2455  func TestOrderBook_GFNLimitInstantMatch(t *testing.T) {
  2456  	market := vgrand.RandomStr(5)
  2457  	book := getTestOrderBook(t, market)
  2458  	defer book.Finish()
  2459  
  2460  	logger := logging.NewTestLogger()
  2461  	defer logger.Sync()
  2462  
  2463  	// Normal limit buy order to match against
  2464  	buyOrder := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2465  	buyOrderConf, err := book.ob.SubmitOrder(buyOrder)
  2466  	assert.NoError(t, err)
  2467  	assert.NotNil(t, buyOrderConf)
  2468  
  2469  	// Enter a GFN market order with an expiration time (which is invalid)
  2470  	sellOrder := getOrder(t, market, "SellOrder01", types.SideSell, 100, "party02", 10)
  2471  	sellOrder.TimeInForce = types.OrderTimeInForceGFN
  2472  	sellOrder.Type = types.OrderTypeLimit
  2473  	sellOrderConf, err := book.ob.SubmitOrder(sellOrder)
  2474  	assert.NoError(t, err)
  2475  	assert.NotNil(t, sellOrderConf)
  2476  }
  2477  
  2478  // AUCTION TESTING.
  2479  func TestOrderBook_AuctionGFNAreRejected(t *testing.T) {
  2480  	market := vgrand.RandomStr(5)
  2481  	book := getTestOrderBook(t, market)
  2482  	defer book.Finish()
  2483  
  2484  	logger := logging.NewTestLogger()
  2485  	defer logger.Sync()
  2486  
  2487  	// Switch to auction mode
  2488  	book.ob.EnterAuction()
  2489  	assert.True(t, book.ob.InAuction())
  2490  
  2491  	// Try to add an order of type GFN which should be rejected
  2492  	order := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2493  	order.TimeInForce = types.OrderTimeInForceGFN
  2494  	orderConf, err := book.ob.SubmitOrder(order)
  2495  	assert.Equal(t, err, types.OrderErrorInvalidTimeInForce)
  2496  	assert.Nil(t, orderConf)
  2497  }
  2498  
  2499  func TestOrderBook_ContinuousGFAAreRejected(t *testing.T) {
  2500  	market := vgrand.RandomStr(5)
  2501  	book := getTestOrderBook(t, market)
  2502  	defer book.Finish()
  2503  
  2504  	logger := logging.NewTestLogger()
  2505  	defer logger.Sync()
  2506  
  2507  	// We start in continuous mode
  2508  	assert.False(t, book.ob.InAuction())
  2509  
  2510  	// Try to add an order of type GFA which should be rejected
  2511  	order := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2512  	order.TimeInForce = types.OrderTimeInForceGFA
  2513  	orderConf, err := book.ob.SubmitOrder(order)
  2514  	assert.Equal(t, err, types.OrderErrorInvalidTimeInForce)
  2515  	assert.Nil(t, orderConf)
  2516  }
  2517  
  2518  func TestOrderBook_GFNOrdersCancelledInAuction(t *testing.T) {
  2519  	market := vgrand.RandomStr(5)
  2520  	book := getTestOrderBook(t, market)
  2521  	defer book.Finish()
  2522  
  2523  	logger := logging.NewTestLogger()
  2524  	defer logger.Sync()
  2525  
  2526  	// We start in continuous mode
  2527  	assert.False(t, book.ob.InAuction())
  2528  
  2529  	// Add a GFN order
  2530  	order := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2531  	order.TimeInForce = types.OrderTimeInForceGFN
  2532  	orderConf, err := book.ob.SubmitOrder(order)
  2533  	assert.NoError(t, err)
  2534  	assert.NotNil(t, orderConf)
  2535  
  2536  	// Switch to auction and makes sure the order is cancelled
  2537  	orders := book.ob.EnterAuction()
  2538  	assert.Equal(t, len(orders), 1)
  2539  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(1))
  2540  }
  2541  
  2542  func TestOrderBook_GFAOrdersCancelledInContinuous(t *testing.T) {
  2543  	market := vgrand.RandomStr(5)
  2544  	book := getTestOrderBook(t, market)
  2545  	defer book.Finish()
  2546  
  2547  	logger := logging.NewTestLogger()
  2548  	defer logger.Sync()
  2549  
  2550  	// Flip straight to auction mode
  2551  	_ = book.ob.EnterAuction()
  2552  	assert.True(t, book.ob.InAuction())
  2553  
  2554  	// Add a GFA order
  2555  	order := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2556  	order.TimeInForce = types.OrderTimeInForceGFA
  2557  	orderConf, err := book.ob.SubmitOrder(order)
  2558  	assert.NoError(t, err)
  2559  	assert.NotNil(t, orderConf)
  2560  
  2561  	// Switch to continuous mode and makes sure the order is cancelled
  2562  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2563  	assert.NoError(t, err)
  2564  	assert.Equal(t, len(uncrossedOrders), 0)
  2565  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(1))
  2566  	assert.Equal(t, len(cancels), 1)
  2567  }
  2568  
  2569  func TestOrderBook_IndicativePriceAndVolumeState(t *testing.T) {
  2570  	market := vgrand.RandomStr(5)
  2571  	book := getTestOrderBook(t, market)
  2572  	defer book.Finish()
  2573  
  2574  	logger := logging.NewTestLogger()
  2575  	defer logger.Sync()
  2576  
  2577  	// We start in continuous trading mode
  2578  	assert.False(t, book.ob.InAuction())
  2579  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(0))
  2580  
  2581  	// Get indicative auction price and volume which should be zero as we are out of auction
  2582  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2583  	assert.Equal(t, price.Uint64(), uint64(0))
  2584  	assert.Equal(t, volume, uint64(0))
  2585  	assert.Equal(t, side, types.SideUnspecified)
  2586  	price = book.ob.GetIndicativePrice()
  2587  	assert.Equal(t, price.Uint64(), uint64(0))
  2588  
  2589  	// Switch to auction mode
  2590  	book.ob.EnterAuction()
  2591  	assert.True(t, book.ob.InAuction())
  2592  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(0))
  2593  
  2594  	// Get indicative auction price and volume
  2595  	price, volume, side = book.ob.GetIndicativePriceAndVolume()
  2596  	assert.Equal(t, price.Uint64(), uint64(0))
  2597  	assert.Equal(t, volume, uint64(0))
  2598  	assert.Equal(t, side, types.SideUnspecified)
  2599  	price = book.ob.GetIndicativePrice()
  2600  	assert.Equal(t, price.Uint64(), uint64(0))
  2601  
  2602  	// Leave auction and uncross the book
  2603  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2604  	assert.Nil(t, err)
  2605  	assert.False(t, book.ob.InAuction())
  2606  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(0))
  2607  	assert.Equal(t, len(uncrossedOrders), 0)
  2608  	assert.Equal(t, len(cancels), 0)
  2609  }
  2610  
  2611  func TestOrderBook_IndicativePriceAndVolumeEmpty(t *testing.T) {
  2612  	market := vgrand.RandomStr(5)
  2613  	book := getTestOrderBook(t, market)
  2614  	defer book.Finish()
  2615  
  2616  	logger := logging.NewTestLogger()
  2617  	defer logger.Sync()
  2618  
  2619  	// Switch to auction mode
  2620  	book.ob.EnterAuction()
  2621  	assert.True(t, book.ob.InAuction())
  2622  
  2623  	// No trades!
  2624  
  2625  	// Get indicative auction price and volume
  2626  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2627  	assert.Equal(t, price.Uint64(), uint64(0))
  2628  	assert.Equal(t, volume, uint64(0))
  2629  	assert.Equal(t, side, types.SideUnspecified)
  2630  	price = book.ob.GetIndicativePrice()
  2631  	assert.Equal(t, price.Uint64(), uint64(0))
  2632  
  2633  	// Leave auction and uncross the book
  2634  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2635  	assert.False(t, book.ob.InAuction())
  2636  	assert.Nil(t, err)
  2637  	assert.Equal(t, len(uncrossedOrders), 0)
  2638  	assert.Equal(t, len(cancels), 0)
  2639  }
  2640  
  2641  func TestOrderBook_IndicativePriceAndVolumeOnlyBuySide(t *testing.T) {
  2642  	market := vgrand.RandomStr(5)
  2643  	book := getTestOrderBook(t, market)
  2644  	defer book.Finish()
  2645  
  2646  	logger := logging.NewTestLogger()
  2647  	defer logger.Sync()
  2648  
  2649  	// Switch to auction mode
  2650  	book.ob.EnterAuction()
  2651  
  2652  	// Trades on just one side of the book
  2653  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 100, "party01", 10)
  2654  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 99, "party01", 10)
  2655  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 98, "party01", 10)
  2656  
  2657  	// Get indicative auction price and volume
  2658  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2659  	assert.Equal(t, price.Uint64(), uint64(0))
  2660  	assert.Equal(t, volume, uint64(0))
  2661  	assert.Equal(t, side, types.SideUnspecified)
  2662  	price = book.ob.GetIndicativePrice()
  2663  	assert.Equal(t, price.Uint64(), uint64(0))
  2664  
  2665  	// Leave auction and uncross the book
  2666  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2667  	assert.Nil(t, err)
  2668  	assert.Equal(t, len(uncrossedOrders), 0)
  2669  	assert.Equal(t, len(cancels), 0)
  2670  
  2671  	// All of the orders should remain on the book
  2672  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(3))
  2673  }
  2674  
  2675  func TestOrderBook_IndicativePriceAndVolumeOnlySellSide(t *testing.T) {
  2676  	market := vgrand.RandomStr(5)
  2677  	book := getTestOrderBook(t, market)
  2678  	defer book.Finish()
  2679  
  2680  	logger := logging.NewTestLogger()
  2681  	defer logger.Sync()
  2682  
  2683  	// Switch to auction mode
  2684  	book.ob.EnterAuction()
  2685  
  2686  	// Trades on just one side of the book
  2687  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 100, "party01", 10)
  2688  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 99, "party01", 10)
  2689  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 98, "party01", 10)
  2690  
  2691  	// Get indicative auction price and volume
  2692  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2693  	assert.Equal(t, price.Uint64(), uint64(0))
  2694  	assert.Equal(t, volume, uint64(0))
  2695  	assert.Equal(t, side, types.SideUnspecified)
  2696  	price = book.ob.GetIndicativePrice()
  2697  	assert.Equal(t, price.Uint64(), uint64(0))
  2698  
  2699  	// Leave auction and uncross the book
  2700  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2701  	assert.Nil(t, err)
  2702  	assert.Equal(t, len(uncrossedOrders), 0)
  2703  	assert.Equal(t, len(cancels), 0)
  2704  
  2705  	// All of the orders should remain on the book
  2706  	assert.Equal(t, book.ob.GetTotalNumberOfOrders(), int64(3))
  2707  }
  2708  
  2709  func TestOrderBook_IndicativePriceAndVolume1(t *testing.T) {
  2710  	market := vgrand.RandomStr(5)
  2711  	book := getTestOrderBook(t, market)
  2712  	defer book.Finish()
  2713  
  2714  	logger := logging.NewTestLogger()
  2715  	defer logger.Sync()
  2716  
  2717  	// Switch to auction mode
  2718  	book.ob.EnterAuction()
  2719  
  2720  	// Populate buy side
  2721  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 101, "party01", 20)
  2722  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 100, "party01", 10)
  2723  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 99, "party01", 20)
  2724  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 98, "party01", 10)
  2725  
  2726  	// Populate sell side
  2727  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 100, "party02", 10)
  2728  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 101, "party02", 15)
  2729  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 102, "party02", 5)
  2730  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 103, "party02", 10)
  2731  
  2732  	// Get indicative auction price and volume
  2733  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2734  	assert.Equal(t, price.Uint64(), uint64(101))
  2735  	assert.Equal(t, volume, uint64(20))
  2736  	assert.Equal(t, side, types.SideBuy)
  2737  	price = book.ob.GetIndicativePrice()
  2738  	assert.Equal(t, price.Uint64(), uint64(101))
  2739  
  2740  	// Get indicative trades
  2741  	trades, err := book.ob.GetIndicativeTrades()
  2742  	assert.NoError(t, err)
  2743  	for _, x := range trades {
  2744  		assert.Equal(t, price, x.Price)
  2745  	}
  2746  
  2747  	// Leave auction and uncross the book
  2748  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2749  	assert.Nil(t, err)
  2750  	assert.Equal(t, len(uncrossedOrders), 1)
  2751  	assert.Equal(t, len(cancels), 0)
  2752  	for _, o := range uncrossedOrders {
  2753  		for _, x := range o.Trades {
  2754  			assert.Equal(t, price, x.Price)
  2755  		}
  2756  	}
  2757  }
  2758  
  2759  func TestOrderBook_IndicativePriceAndVolume2(t *testing.T) {
  2760  	market := vgrand.RandomStr(5)
  2761  	book := getTestOrderBook(t, market)
  2762  	defer book.Finish()
  2763  
  2764  	logger := logging.NewTestLogger()
  2765  	defer logger.Sync()
  2766  
  2767  	// Switch to auction mode
  2768  	book.ob.EnterAuction()
  2769  
  2770  	// Populate buy side
  2771  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 101, "party01", 30)
  2772  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 100, "party01", 10)
  2773  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 99, "party01", 20)
  2774  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 98, "party01", 10)
  2775  	makeOrder(t, book, market, "BuyOrder05", types.SideBuy, 97, "party01", 5)
  2776  
  2777  	// Populate sell side
  2778  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 100, "party02", 30)
  2779  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 101, "party02", 15)
  2780  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 102, "party02", 5)
  2781  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 103, "party02", 10)
  2782  
  2783  	// Get indicative auction price and volume
  2784  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2785  	assert.Equal(t, uint64(100), price.Uint64())
  2786  	assert.Equal(t, uint64(30), volume)
  2787  	assert.Equal(t, types.SideBuy, side)
  2788  	price = book.ob.GetIndicativePrice()
  2789  	assert.Equal(t, uint64(100), price.Uint64())
  2790  
  2791  	// Get indicative trades
  2792  	trades, err := book.ob.GetIndicativeTrades()
  2793  	assert.NoError(t, err)
  2794  	for _, x := range trades {
  2795  		assert.Equal(t, price, x.Price)
  2796  	}
  2797  
  2798  	// Leave auction and uncross the book
  2799  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2800  	assert.Nil(t, err)
  2801  	assert.Equal(t, 1, len(uncrossedOrders))
  2802  	assert.Equal(t, 0, len(cancels))
  2803  
  2804  	for _, o := range uncrossedOrders {
  2805  		for _, x := range o.Trades {
  2806  			assert.Equal(t, price, x.Price)
  2807  		}
  2808  	}
  2809  }
  2810  
  2811  func TestOrderBook_IndicativePriceAndVolume3(t *testing.T) {
  2812  	market := vgrand.RandomStr(5)
  2813  	book := getTestOrderBook(t, market)
  2814  	defer book.Finish()
  2815  
  2816  	logger := logging.NewTestLogger()
  2817  	defer logger.Sync()
  2818  
  2819  	// Switch to auction mode
  2820  	book.ob.EnterAuction()
  2821  
  2822  	// Populate buy side
  2823  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 104, "party01", 10)
  2824  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 103, "party01", 20)
  2825  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 102, "party01", 15)
  2826  
  2827  	// Populate sell side
  2828  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 98, "party02", 10)
  2829  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 97, "party02", 20)
  2830  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 96, "party02", 15)
  2831  
  2832  	// Get indicative auction price and volume
  2833  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2834  	assert.Equal(t, 100, int(price.Uint64()))
  2835  	assert.Equal(t, 45, int(volume))
  2836  	assert.Equal(t, types.SideBuy, side)
  2837  	price = book.ob.GetIndicativePrice()
  2838  	assert.Equal(t, 100, int(price.Uint64()))
  2839  
  2840  	// Get indicative trades
  2841  	trades, err := book.ob.GetIndicativeTrades()
  2842  	assert.NoError(t, err)
  2843  	for _, x := range trades {
  2844  		assert.Equal(t, price, x.Price)
  2845  	}
  2846  
  2847  	// Leave auction and uncross the book
  2848  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2849  	assert.Nil(t, err)
  2850  	assert.Equal(t, 3, len(uncrossedOrders))
  2851  	assert.Equal(t, 0, len(cancels))
  2852  
  2853  	for _, o := range uncrossedOrders {
  2854  		for _, x := range o.Trades {
  2855  			assert.Equal(t, price, x.Price)
  2856  		}
  2857  	}
  2858  }
  2859  
  2860  func TestOrderBook_IndicativePriceAndVolume4(t *testing.T) {
  2861  	market := vgrand.RandomStr(5)
  2862  	book := getTestOrderBook(t, market)
  2863  	defer book.Finish()
  2864  
  2865  	logger := logging.NewTestLogger()
  2866  	defer logger.Sync()
  2867  
  2868  	// Switch to auction mode
  2869  	book.ob.EnterAuction()
  2870  
  2871  	// Populate buy side
  2872  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 99, "party01", 10)
  2873  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 98, "party01", 25)
  2874  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 97, "party01", 5)
  2875  
  2876  	// Populate sell side
  2877  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 102, "party02", 30)
  2878  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 101, "party02", 15)
  2879  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 100, "party02", 5)
  2880  
  2881  	// Get indicative auction price and volume
  2882  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2883  	assert.Equal(t, uint64(0), price.Uint64())
  2884  	assert.Equal(t, uint64(0), volume)
  2885  	assert.Equal(t, types.SideUnspecified, side)
  2886  	price = book.ob.GetIndicativePrice()
  2887  	assert.Equal(t, uint64(0), price.Uint64())
  2888  
  2889  	// Get indicative trades
  2890  	trades, err := book.ob.GetIndicativeTrades()
  2891  	assert.NoError(t, err)
  2892  	for _, x := range trades {
  2893  		assert.Equal(t, price, x.Price)
  2894  	}
  2895  
  2896  	// Leave auction and uncross the book
  2897  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2898  	assert.Nil(t, err)
  2899  	assert.Equal(t, len(uncrossedOrders), 0)
  2900  	assert.Equal(t, len(cancels), 0)
  2901  
  2902  	for _, o := range uncrossedOrders {
  2903  		for _, x := range o.Trades {
  2904  			assert.Equal(t, price, x.Price)
  2905  		}
  2906  	}
  2907  }
  2908  
  2909  func TestOrderBook_IndicativePriceAndVolume5(t *testing.T) {
  2910  	market := vgrand.RandomStr(5)
  2911  	book := getTestOrderBook(t, market)
  2912  	defer book.Finish()
  2913  
  2914  	logger := logging.NewTestLogger()
  2915  	defer logger.Sync()
  2916  
  2917  	// Switch to auction mode
  2918  	book.ob.EnterAuction()
  2919  
  2920  	// Populate buy side
  2921  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 103, "party01", 10)
  2922  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 102, "party01", 9)
  2923  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 101, "party01", 8)
  2924  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 100, "party01", 7)
  2925  	makeOrder(t, book, market, "BuyOrder05", types.SideBuy, 99, "party01", 6)
  2926  	makeOrder(t, book, market, "BuyOrder06", types.SideBuy, 98, "party01", 5)
  2927  	makeOrder(t, book, market, "BuyOrder07", types.SideBuy, 97, "party01", 4)
  2928  	makeOrder(t, book, market, "BuyOrder08", types.SideBuy, 96, "party01", 3)
  2929  	makeOrder(t, book, market, "BuyOrder09", types.SideBuy, 95, "party01", 2)
  2930  	makeOrder(t, book, market, "BuyOrder10", types.SideBuy, 94, "party01", 1)
  2931  
  2932  	// Populate sell side
  2933  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 105, "party02", 1)
  2934  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 104, "party02", 2)
  2935  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 103, "party02", 3)
  2936  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 102, "party02", 4)
  2937  	makeOrder(t, book, market, "SellOrder05", types.SideSell, 101, "party02", 5)
  2938  	makeOrder(t, book, market, "SellOrder06", types.SideSell, 100, "party02", 6)
  2939  	makeOrder(t, book, market, "SellOrder07", types.SideSell, 99, "party02", 7)
  2940  	makeOrder(t, book, market, "SellOrder08", types.SideSell, 98, "party02", 8)
  2941  	makeOrder(t, book, market, "SellOrder09", types.SideSell, 97, "party02", 9)
  2942  	makeOrder(t, book, market, "SellOrder10", types.SideSell, 96, "party02", 10)
  2943  
  2944  	// Get indicative auction price and volume
  2945  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2946  	assert.Equal(t, uint64(99), price.Uint64())
  2947  	assert.Equal(t, uint64(34), volume)
  2948  	assert.Equal(t, types.SideBuy, side)
  2949  	price = book.ob.GetIndicativePrice()
  2950  	assert.Equal(t, uint64(99), price.Uint64())
  2951  
  2952  	// Get indicative trades
  2953  	trades, err := book.ob.GetIndicativeTrades()
  2954  	assert.NoError(t, err)
  2955  	for _, x := range trades {
  2956  		assert.Equal(t, price, x.Price)
  2957  	}
  2958  
  2959  	// Leave auction and uncross the book
  2960  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  2961  	assert.Nil(t, err)
  2962  	assert.Equal(t, 4, len(uncrossedOrders))
  2963  	assert.Equal(t, 0, len(cancels))
  2964  
  2965  	for _, o := range uncrossedOrders {
  2966  		for _, x := range o.Trades {
  2967  			assert.Equal(t, price, x.Price)
  2968  		}
  2969  	}
  2970  }
  2971  
  2972  // Set up an auction so that the sell side is processed when we uncross.
  2973  func TestOrderBook_IndicativePriceAndVolume6(t *testing.T) {
  2974  	market := vgrand.RandomStr(5)
  2975  	book := getTestOrderBook(t, market)
  2976  	defer book.Finish()
  2977  
  2978  	logger := logging.NewTestLogger()
  2979  	defer logger.Sync()
  2980  
  2981  	// Switch to auction mode
  2982  	book.ob.EnterAuction()
  2983  
  2984  	// Populate buy side
  2985  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 103, "party01", 10)
  2986  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 102, "party01", 9)
  2987  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 101, "party01", 8)
  2988  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 100, "party01", 7)
  2989  
  2990  	// Populate sell side
  2991  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 99, "party02", 1)
  2992  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 98, "party02", 2)
  2993  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 97, "party02", 3)
  2994  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 96, "party02", 4)
  2995  
  2996  	// Get indicative auction price and volume
  2997  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  2998  	assert.Equal(t, 101, int(price.Uint64()))
  2999  	assert.Equal(t, 10, int(volume))
  3000  	assert.Equal(t, types.SideBuy, side)
  3001  	price = book.ob.GetIndicativePrice()
  3002  	assert.Equal(t, 101, int(price.Uint64()))
  3003  
  3004  	// Get indicative trades
  3005  	trades, err := book.ob.GetIndicativeTrades()
  3006  	assert.NoError(t, err)
  3007  	for _, x := range trades {
  3008  		assert.Equal(t, price, x.Price)
  3009  	}
  3010  
  3011  	// Leave auction and uncross the book
  3012  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3013  	assert.Nil(t, err)
  3014  	assert.Equal(t, len(uncrossedOrders), 1)
  3015  	assert.Equal(t, len(cancels), 0)
  3016  
  3017  	for _, o := range uncrossedOrders {
  3018  		for _, x := range o.Trades {
  3019  			assert.Equal(t, price, x.Price)
  3020  		}
  3021  	}
  3022  }
  3023  
  3024  // Check that multiple orders per price level work.
  3025  func TestOrderBook_IndicativePriceAndVolume7(t *testing.T) {
  3026  	market := vgrand.RandomStr(5)
  3027  	book := getTestOrderBook(t, market)
  3028  	defer book.Finish()
  3029  
  3030  	logger := logging.NewTestLogger()
  3031  	defer logger.Sync()
  3032  
  3033  	// Switch to auction mode
  3034  	book.ob.EnterAuction()
  3035  
  3036  	// Populate buy side
  3037  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 103, "party01", 10)
  3038  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 103, "party01", 1)
  3039  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 102, "party01", 9)
  3040  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 102, "party01", 1)
  3041  	makeOrder(t, book, market, "BuyOrder05", types.SideBuy, 101, "party01", 8)
  3042  	makeOrder(t, book, market, "BuyOrder06", types.SideBuy, 101, "party01", 1)
  3043  	makeOrder(t, book, market, "BuyOrder07", types.SideBuy, 100, "party01", 7)
  3044  	makeOrder(t, book, market, "BuyOrder08", types.SideBuy, 100, "party01", 1)
  3045  
  3046  	// Populate sell side
  3047  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 99, "party02", 10)
  3048  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 98, "party02", 10)
  3049  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 97, "party02", 10)
  3050  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 96, "party02", 7)
  3051  
  3052  	// Get indicative auction price and volume
  3053  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3054  	assert.Equal(t, uint64(99), price.Uint64())
  3055  	assert.Equal(t, uint64(37), volume)
  3056  	assert.Equal(t, types.SideSell, side)
  3057  	price = book.ob.GetIndicativePrice()
  3058  	assert.Equal(t, uint64(99), price.Uint64())
  3059  
  3060  	// Get indicative trades
  3061  	trades, err := book.ob.GetIndicativeTrades()
  3062  	assert.NoError(t, err)
  3063  	for _, x := range trades {
  3064  		assert.Equal(t, price, x.Price)
  3065  	}
  3066  
  3067  	// Leave auction and uncross the book
  3068  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3069  	assert.Nil(t, err)
  3070  	assert.Equal(t, 4, len(uncrossedOrders))
  3071  	assert.Equal(t, 0, len(cancels))
  3072  
  3073  	for _, o := range uncrossedOrders {
  3074  		for _, x := range o.Trades {
  3075  			assert.Equal(t, price, x.Price)
  3076  		}
  3077  	}
  3078  }
  3079  
  3080  func TestOrderBook_IndicativePriceAndVolume8(t *testing.T) {
  3081  	market := vgrand.RandomStr(5)
  3082  	book := getTestOrderBook(t, market)
  3083  	defer book.Finish()
  3084  
  3085  	logger := logging.NewTestLogger()
  3086  	defer logger.Sync()
  3087  
  3088  	// Switch to auction mode
  3089  	book.ob.EnterAuction()
  3090  
  3091  	// Populate buy side
  3092  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 103, "party01", 10)
  3093  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 103, "party01", 1)
  3094  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 102, "party01", 9)
  3095  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 102, "party01", 1)
  3096  	makeOrder(t, book, market, "BuyOrder05", types.SideBuy, 101, "party01", 8)
  3097  	makeOrder(t, book, market, "BuyOrder06", types.SideBuy, 101, "party01", 1)
  3098  	makeOrder(t, book, market, "BuyOrder07", types.SideBuy, 100, "party01", 7)
  3099  	makeOrder(t, book, market, "BuyOrder08", types.SideBuy, 100, "party01", 1)
  3100  
  3101  	// Populate sell side
  3102  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 99, "party02", 10)
  3103  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 98, "party02", 10)
  3104  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 97, "party02", 10)
  3105  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 96, "party02", 9)
  3106  
  3107  	// Get indicative auction price and volume
  3108  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3109  	assert.Equal(t, 99, int(price.Uint64()))
  3110  	assert.Equal(t, 38, int(volume))
  3111  	assert.Equal(t, types.SideBuy, side)
  3112  	price = book.ob.GetIndicativePrice()
  3113  	assert.Equal(t, 99, int(price.Uint64()))
  3114  
  3115  	// Get indicative trades
  3116  	trades, err := book.ob.GetIndicativeTrades()
  3117  	assert.NoError(t, err)
  3118  	for _, x := range trades {
  3119  		assert.Equal(t, price, x.Price)
  3120  	}
  3121  
  3122  	// Leave auction and uncross the book
  3123  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3124  	assert.Nil(t, err)
  3125  	assert.Equal(t, 8, len(uncrossedOrders))
  3126  	assert.Equal(t, 0, len(cancels))
  3127  
  3128  	for _, o := range uncrossedOrders {
  3129  		for _, x := range o.Trades {
  3130  			assert.Equal(t, price, x.Price)
  3131  		}
  3132  	}
  3133  }
  3134  
  3135  func TestOrderBook_IndicativePriceAndVolume9(t *testing.T) {
  3136  	market := vgrand.RandomStr(5)
  3137  	book := getTestOrderBook(t, market)
  3138  	defer book.Finish()
  3139  
  3140  	logger := logging.NewTestLogger()
  3141  	defer logger.Sync()
  3142  
  3143  	// Switch to auction mode
  3144  	book.ob.EnterAuction()
  3145  
  3146  	// Populate buy side
  3147  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 110, "party01", 1)
  3148  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 110, "party02", 1)
  3149  
  3150  	makeOrder(t, book, market, "BuyOrder01-2", types.SideBuy, 111, "party01", 1)
  3151  	makeOrder(t, book, market, "SellOrder01-2", types.SideSell, 111, "party02", 1)
  3152  
  3153  	makeOrder(t, book, market, "BuyOrder01-3", types.SideBuy, 133, "party01", 2)
  3154  	makeOrder(t, book, market, "SellOrder01-3", types.SideSell, 133, "party02", 2)
  3155  
  3156  	makeOrder(t, book, market, "BuyOrder01-4", types.SideBuy, 303, "party01", 10)
  3157  	makeOrder(t, book, market, "SellOrder01-4", types.SideSell, 303, "party02", 10)
  3158  
  3159  	// Get indicative auction price and volume
  3160  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3161  	assert.Equal(t, 303, int(price.Uint64()))
  3162  	assert.Equal(t, 10, int(volume))
  3163  	assert.Equal(t, types.SideBuy, side)
  3164  	price = book.ob.GetIndicativePrice()
  3165  	assert.Equal(t, 303, int(price.Uint64()))
  3166  
  3167  	// Get indicative trades
  3168  	trades, err := book.ob.GetIndicativeTrades()
  3169  	assert.NoError(t, err)
  3170  	for _, x := range trades {
  3171  		assert.Equal(t, price, x.Price)
  3172  	}
  3173  
  3174  	// Leave auction and uncross the book
  3175  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3176  	assert.Nil(t, err)
  3177  	assert.Equal(t, 1, len(uncrossedOrders))
  3178  	assert.Equal(t, 0, len(cancels))
  3179  
  3180  	for _, o := range uncrossedOrders {
  3181  		for _, x := range o.Trades {
  3182  			assert.Equal(t, price, x.Price)
  3183  		}
  3184  	}
  3185  }
  3186  
  3187  // check behaviour consistent in the presence of wash trades.
  3188  func TestOrderBook_IndicativePriceAndVolume10(t *testing.T) {
  3189  	market := vgrand.RandomStr(5)
  3190  	book := getTestOrderBook(t, market)
  3191  	defer book.Finish()
  3192  
  3193  	logger := logging.NewTestLogger()
  3194  	defer logger.Sync()
  3195  
  3196  	// Switch to auction mode
  3197  	book.ob.EnterAuction()
  3198  
  3199  	// Populate buy side
  3200  	makeOrder(t, book, market, "BuyOrder01", types.SideBuy, 103, "party01", 10)
  3201  	makeOrder(t, book, market, "BuyOrder02", types.SideBuy, 102, "party01", 9)
  3202  	makeOrder(t, book, market, "BuyOrder03", types.SideBuy, 101, "party01", 8)
  3203  	makeOrder(t, book, market, "BuyOrder04", types.SideBuy, 100, "party01", 7)
  3204  
  3205  	// Populate sell side
  3206  	makeOrder(t, book, market, "SellOrder01", types.SideSell, 99, "party02", 1)
  3207  	makeOrder(t, book, market, "SellOrder02", types.SideSell, 98, "party01", 1)
  3208  	makeOrder(t, book, market, "SellOrder03", types.SideSell, 98, "party02", 1)
  3209  	makeOrder(t, book, market, "SellOrder04", types.SideSell, 97, "party02", 3)
  3210  	makeOrder(t, book, market, "SellOrder05", types.SideSell, 96, "party02", 4)
  3211  
  3212  	// Get indicative auction price and volume
  3213  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3214  	assert.Equal(t, 101, int(price.Uint64()))
  3215  	assert.Equal(t, 10, int(volume))
  3216  	assert.Equal(t, types.SideBuy, side)
  3217  	price = book.ob.GetIndicativePrice()
  3218  	assert.Equal(t, 101, int(price.Uint64()))
  3219  
  3220  	// Get indicative trades
  3221  	trades, err := book.ob.GetIndicativeTrades()
  3222  	assert.NoError(t, err)
  3223  	for _, x := range trades {
  3224  		assert.Equal(t, price, x.Price)
  3225  	}
  3226  
  3227  	// Leave auction and uncross the book
  3228  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3229  	assert.Nil(t, err)
  3230  	assert.Equal(t, len(uncrossedOrders), 1)
  3231  	assert.Equal(t, len(cancels), 0)
  3232  
  3233  	nTrades := 0
  3234  	for _, o := range uncrossedOrders {
  3235  		for _, x := range o.Trades {
  3236  			nTrades++
  3237  			assert.Equal(t, price, x.Price)
  3238  		}
  3239  	}
  3240  	assert.Equal(t, len(trades), nTrades)
  3241  }
  3242  
  3243  func TestOrderBook_UncrossTest1(t *testing.T) {
  3244  	market := vgrand.RandomStr(5)
  3245  	book := getTestOrderBook(t, market)
  3246  	defer book.Finish()
  3247  
  3248  	logger := logging.NewTestLogger()
  3249  	defer logger.Sync()
  3250  
  3251  	// Switch to auction mode
  3252  	book.ob.EnterAuction()
  3253  
  3254  	bo1 := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 5)
  3255  	bo1.TimeInForce = types.OrderTimeInForceGFA
  3256  	book.ob.SubmitOrder(bo1)
  3257  
  3258  	so1 := getOrder(t, market, "SellOrder01", types.SideSell, 100, "party02", 5)
  3259  	so1.TimeInForce = types.OrderTimeInForceGFA
  3260  	book.ob.SubmitOrder(so1)
  3261  
  3262  	bo2 := getOrder(t, market, "BuyOrder02", types.SideBuy, 100, "party01", 5)
  3263  	bo2.TimeInForce = types.OrderTimeInForceGFA
  3264  	book.ob.SubmitOrder(bo2)
  3265  
  3266  	so2 := getOrder(t, market, "SellOrder02", types.SideSell, 101, "party02", 5)
  3267  	so2.TimeInForce = types.OrderTimeInForceGFA
  3268  	book.ob.SubmitOrder(so2)
  3269  
  3270  	// Get indicative auction price and volume
  3271  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3272  	assert.Equal(t, price.Uint64(), uint64(100))
  3273  	assert.Equal(t, volume, uint64(5))
  3274  	assert.Equal(t, side, types.SideSell)
  3275  	price = book.ob.GetIndicativePrice()
  3276  	assert.Equal(t, price.Uint64(), uint64(100))
  3277  
  3278  	// Get indicative trades
  3279  	trades, err := book.ob.GetIndicativeTrades()
  3280  	assert.NoError(t, err)
  3281  	for _, x := range trades {
  3282  		assert.Equal(t, price, x.Price)
  3283  	}
  3284  
  3285  	// Leave auction and uncross the book
  3286  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3287  	assert.Nil(t, err)
  3288  	assert.Equal(t, len(uncrossedOrders), 1)
  3289  	assert.Equal(t, len(cancels), 2)
  3290  
  3291  	for _, o := range uncrossedOrders {
  3292  		for _, x := range o.Trades {
  3293  			assert.Equal(t, price, x.Price)
  3294  		}
  3295  	}
  3296  }
  3297  
  3298  // this is a test for issue 2060 to ensure we process FOK orders properly.
  3299  func TestOrderBook_NetworkOrderSuccess(t *testing.T) {
  3300  	market := vgrand.RandomStr(5)
  3301  	book := getTestOrderBook(t, market)
  3302  	defer book.Finish()
  3303  
  3304  	orders := []*types.Order{
  3305  		{
  3306  			Status:        types.OrderStatusActive,
  3307  			Type:          types.OrderTypeLimit,
  3308  			MarketID:      market,
  3309  			ID:            "123456",
  3310  			Side:          types.SideBuy,
  3311  			Price:         num.NewUint(100),
  3312  			OriginalPrice: num.NewUint(100),
  3313  			Party:         "A",
  3314  			Size:          100,
  3315  			Remaining:     100,
  3316  			TimeInForce:   types.OrderTimeInForceGTC,
  3317  			CreatedAt:     10,
  3318  		},
  3319  		{
  3320  			Status:        types.OrderStatusActive,
  3321  			Type:          types.OrderTypeLimit,
  3322  			MarketID:      market,
  3323  			ID:            "234561",
  3324  			Side:          types.SideBuy,
  3325  			Price:         num.NewUint(1),
  3326  			OriginalPrice: num.NewUint(1),
  3327  			Party:         "B",
  3328  			Size:          100,
  3329  			Remaining:     100,
  3330  			TimeInForce:   types.OrderTimeInForceGTC,
  3331  			CreatedAt:     11,
  3332  		},
  3333  	}
  3334  
  3335  	// now we add the trades to the book
  3336  	for _, o := range orders {
  3337  		cnfm, err := book.ob.SubmitOrder(o)
  3338  		assert.NoError(t, err)
  3339  		assert.Len(t, cnfm.Trades, 0)
  3340  	}
  3341  
  3342  	// no price for network order
  3343  	// we want to consume the whole book
  3344  	netorder := &types.Order{
  3345  		Status:      types.OrderStatusActive,
  3346  		Type:        types.OrderTypeNetwork,
  3347  		MarketID:    market,
  3348  		ID:          "345612",
  3349  		Side:        types.SideSell,
  3350  		Party:       "C",
  3351  		Size:        200,
  3352  		Remaining:   200,
  3353  		TimeInForce: types.OrderTimeInForceFOK,
  3354  		CreatedAt:   12,
  3355  	}
  3356  
  3357  	cnfm, err := book.ob.SubmitOrder(netorder)
  3358  	assert.NoError(t, err)
  3359  	assert.Equal(t, types.OrderStatusFilled, netorder.Status)
  3360  	assert.Equal(t, 50, int(netorder.Price.Uint64()))
  3361  	assert.Equal(t, 0, int(netorder.Remaining))
  3362  	_ = cnfm
  3363  }
  3364  
  3365  func TestOrderBook_GetTradesInLineWithSubmitOrderDuringAuction(t *testing.T) {
  3366  	market := vgrand.RandomStr(5)
  3367  	book := getTestOrderBook(t, market)
  3368  
  3369  	orders := book.ob.EnterAuction()
  3370  	assert.Equal(t, 0, len(orders))
  3371  	order1Id := vgcrypto.RandomHash()
  3372  	order2Id := vgcrypto.RandomHash()
  3373  
  3374  	order1 := &types.Order{
  3375  		Status:        types.OrderStatusActive,
  3376  		Type:          types.OrderTypeLimit,
  3377  		MarketID:      market,
  3378  		ID:            order1Id,
  3379  		Side:          types.SideSell,
  3380  		Price:         num.NewUint(100),
  3381  		OriginalPrice: num.NewUint(100),
  3382  		Party:         "A",
  3383  		Size:          100,
  3384  		Remaining:     100,
  3385  		TimeInForce:   types.OrderTimeInForceGTC,
  3386  		CreatedAt:     10,
  3387  	}
  3388  
  3389  	trades, getErr := book.ob.GetTrades(order1)
  3390  	assert.NoError(t, getErr)
  3391  	confirmation, err := book.ob.SubmitOrder(order1)
  3392  
  3393  	assert.Equal(t, nil, err)
  3394  	assert.NotNil(t, confirmation)
  3395  	assert.Equal(t, order1Id, confirmation.Order.ID)
  3396  	assert.Equal(t, 0, len(confirmation.Trades))
  3397  	assert.Equal(t, len(trades), len(confirmation.Trades))
  3398  
  3399  	order2 := &types.Order{
  3400  		Status:        types.OrderStatusActive,
  3401  		Type:          types.OrderTypeLimit,
  3402  		MarketID:      market,
  3403  		ID:            order2Id,
  3404  		Side:          types.SideBuy,
  3405  		Price:         num.NewUint(100),
  3406  		OriginalPrice: num.NewUint(100),
  3407  		Party:         "B",
  3408  		Size:          20,
  3409  		Remaining:     20,
  3410  		TimeInForce:   types.OrderTimeInForceGTC,
  3411  		CreatedAt:     10,
  3412  	}
  3413  	trades, getErr = book.ob.GetTrades(order2)
  3414  	assert.NoError(t, getErr)
  3415  	confirmation, err = book.ob.SubmitOrder(order2)
  3416  
  3417  	assert.Equal(t, nil, err)
  3418  	assert.NotNil(t, confirmation)
  3419  	assert.Equal(t, order2Id, confirmation.Order.ID)
  3420  	assert.Equal(t, 0, len(confirmation.Trades))
  3421  	assert.Equal(t, len(trades), len(confirmation.Trades))
  3422  
  3423  	// Confirm both orders still on the book
  3424  	order, err := book.ob.GetOrderByID(order1Id)
  3425  	assert.NotNil(t, order)
  3426  	assert.Nil(t, err)
  3427  	order, err = book.ob.GetOrderByID(order2Id)
  3428  	assert.NotNil(t, order)
  3429  	assert.Nil(t, err)
  3430  }
  3431  
  3432  func TestOrderBook_AuctionUncrossWashTrades(t *testing.T) {
  3433  	market := vgrand.RandomStr(5)
  3434  	book := getTestOrderBook(t, market)
  3435  	defer book.Finish()
  3436  
  3437  	logger := logging.NewTestLogger()
  3438  	defer logger.Sync()
  3439  
  3440  	// Switch to auction mode
  3441  	book.ob.EnterAuction()
  3442  
  3443  	bo1 := getOrder(t, market, "BuyOrder01", types.SideBuy, 100, "party01", 5)
  3444  	bo1.TimeInForce = types.OrderTimeInForceGFA
  3445  	book.ob.SubmitOrder(bo1)
  3446  
  3447  	so1 := getOrder(t, market, "SellOrder01", types.SideSell, 100, "party01", 5)
  3448  	so1.TimeInForce = types.OrderTimeInForceGFA
  3449  	book.ob.SubmitOrder(so1)
  3450  
  3451  	// Get indicative auction price and volume
  3452  	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3453  	assert.Equal(t, price.Uint64(), uint64(100))
  3454  	assert.Equal(t, volume, uint64(5))
  3455  	assert.Equal(t, side, types.SideBuy)
  3456  
  3457  	// Get indicative trades
  3458  	trades, err := book.ob.GetIndicativeTrades()
  3459  	assert.NoError(t, err)
  3460  	assert.Equal(t, len(trades), 1)
  3461  
  3462  	// Leave auction and uncross the book
  3463  	uncrossedOrders, cancels, err := book.ob.LeaveAuction(time.Now())
  3464  	assert.Nil(t, err)
  3465  	assert.Equal(t, len(uncrossedOrders), 1)
  3466  	assert.Equal(t, len(uncrossedOrders[0].Trades), 1)
  3467  	assert.Equal(t, len(cancels), 0)
  3468  
  3469  	// Assure indicative trade has same (relevant) data as the actual trade
  3470  	// because the trades are generated when calling LeaveAuction, the aggressor will be unspecified.
  3471  	assert.Equal(t, uncrossedOrders[0].Trades[0].Aggressor, types.SideUnspecified)
  3472  	// and thus the aggressor side will not match the value we get from the indicative trades
  3473  	assert.NotEqual(t, uncrossedOrders[0].Trades[0].Aggressor, trades[0].Aggressor)
  3474  	assert.Equal(t, uncrossedOrders[0].Trades[0].Buyer, trades[0].Buyer)
  3475  	assert.Equal(t, uncrossedOrders[0].Trades[0].Seller, trades[0].Seller)
  3476  	assert.Equal(t, uncrossedOrders[0].Trades[0].Size, trades[0].Size)
  3477  	assert.Equal(t, uncrossedOrders[0].Trades[0].Price, trades[0].Price)
  3478  
  3479  	// Assure trade is indeed a wash trade
  3480  	assert.Equal(t, trades[0].Buyer, trades[0].Seller)
  3481  }
  3482  
  3483  func TestOrderBook_AuctionUncrossTamlyn(t *testing.T) {
  3484  	market := vgrand.RandomStr(5)
  3485  	book := getTestOrderBook(t, market)
  3486  	defer book.Finish()
  3487  
  3488  	logger := logging.NewTestLogger()
  3489  	defer logger.Sync()
  3490  
  3491  	// Switch to auction mode
  3492  	book.ob.EnterAuction()
  3493  
  3494  	order1 := getOrder(t, market, "Order1", types.SideBuy, 16, "Tamlyn", 100)
  3495  	order1.TimeInForce = types.OrderTimeInForceGFA
  3496  	conf, err := book.ob.SubmitOrder(order1)
  3497  	require.NoError(t, err)
  3498  	assert.NotNil(t, conf)
  3499  
  3500  	order2 := getOrder(t, market, "Order2", types.SideSell, 20, "Tamlyn", 100)
  3501  	order2.TimeInForce = types.OrderTimeInForceGFA
  3502  	conf, err = book.ob.SubmitOrder(order2)
  3503  	require.NoError(t, err)
  3504  	assert.NotNil(t, conf)
  3505  
  3506  	order3 := getOrder(t, market, "Order3", types.SideSell, 3, "Tamlyn", 100)
  3507  	order3.TimeInForce = types.OrderTimeInForceGFA
  3508  	conf, err = book.ob.SubmitOrder(order3)
  3509  	require.NoError(t, err)
  3510  	assert.NotNil(t, conf)
  3511  
  3512  	order4 := getOrder(t, market, "Order4", types.SideSell, 18, "David", 100)
  3513  	order4.TimeInForce = types.OrderTimeInForceGFA
  3514  	conf, err = book.ob.SubmitOrder(order4)
  3515  	require.NoError(t, err)
  3516  	assert.NotNil(t, conf)
  3517  
  3518  	order5 := getOrder(t, market, "Order5", types.SideBuy, 1000, "Tamlyn", 100)
  3519  	order5.TimeInForce = types.OrderTimeInForceGFA
  3520  	conf, err = book.ob.SubmitOrder(order5)
  3521  	require.NoError(t, err)
  3522  	assert.NotNil(t, conf)
  3523  
  3524  	order6 := getOrder(t, market, "Order6", types.SideBuy, 2000, "David", 100)
  3525  	order6.TimeInForce = types.OrderTimeInForceGFA
  3526  	conf, err = book.ob.SubmitOrder(order6)
  3527  	require.NoError(t, err)
  3528  	assert.NotNil(t, conf)
  3529  
  3530  	order7 := getOrder(t, market, "Order7", types.SideSell, 14, "Tamlyn", 15)
  3531  	order7.TimeInForce = types.OrderTimeInForceGFA
  3532  	conf, err = book.ob.SubmitOrder(order7)
  3533  	require.NoError(t, err)
  3534  	assert.NotNil(t, conf)
  3535  
  3536  	order8 := getOrder(t, market, "Order8", types.SideBuy, 14, "Tamlyn", 2)
  3537  	order8.TimeInForce = types.OrderTimeInForceGFA
  3538  	conf, err = book.ob.SubmitOrder(order8)
  3539  	require.NoError(t, err)
  3540  	assert.NotNil(t, conf)
  3541  
  3542  	order9 := getOrder(t, market, "Order9", types.SideSell, 1, "David", 10)
  3543  	order9.TimeInForce = types.OrderTimeInForceGFA
  3544  	conf, err = book.ob.SubmitOrder(order9)
  3545  	require.NoError(t, err)
  3546  	assert.NotNil(t, conf)
  3547  
  3548  	// Get indicative auction price and volume
  3549  	//	price, volume, side := book.ob.GetIndicativePriceAndVolume()
  3550  	//	assert.Equal(t, price, uint64(100))
  3551  	//	assert.Equal(t, volume, uint64(5))
  3552  	//	assert.Equal(t, side, types.Side_SIDE_BUY)
  3553  
  3554  	// Leave auction and uncross the book
  3555  	//	uncrossedOrders, cancels, err := book.ob.leaveAuction(time.Now())
  3556  	//	assert.Nil(t, err)
  3557  	//	assert.Equal(t, len(uncrossedOrders), 1)
  3558  	//	assert.Equal(t, len(cancels), 0)
  3559  }
  3560  
  3561  // Add some pegged orders to the order book and check they are parked when going into auction.
  3562  func TestOrderBook_PeggedOrders(t *testing.T) {
  3563  	market := vgrand.RandomStr(5)
  3564  	book := getTestOrderBook(t, market)
  3565  	defer book.Finish()
  3566  
  3567  	logger := logging.NewTestLogger()
  3568  	defer logger.Sync()
  3569  
  3570  	require.Equal(t, uint64(0), book.ob.GetPeggedOrdersCount())
  3571  
  3572  	// We need some orders on the book to get a valid bestbis/bestask/mid price
  3573  	makeOrder(t, book, market, "PriceSetterBuy", types.SideBuy, 100, "party01", 1)
  3574  	makeOrder(t, book, market, "PriceSetterSell", types.SideSell, 101, "party01", 1)
  3575  
  3576  	require.Equal(t, uint64(0), book.ob.GetPeggedOrdersCount())
  3577  
  3578  	bestask, err := book.ob.GetBestAskPrice()
  3579  	assert.NoError(t, err)
  3580  	bestbid, err := book.ob.GetBestBidPrice()
  3581  	assert.NoError(t, err)
  3582  	assert.Equal(t, bestask.Uint64(), uint64(101))
  3583  	assert.Equal(t, bestbid.Uint64(), uint64(100))
  3584  
  3585  	orderID := crypto.RandomHash()
  3586  	bp1 := getOrder(t, market, orderID, types.SideBuy, 100, "party01", 5)
  3587  	bp1.PeggedOrder = &types.PeggedOrder{
  3588  		Reference: types.PeggedReferenceMid,
  3589  		Offset:    num.NewUint(3),
  3590  	}
  3591  	book.ob.SubmitOrder(bp1)
  3592  
  3593  	require.Equal(t, uint64(1), book.ob.GetPeggedOrdersCount())
  3594  
  3595  	sp1 := getOrder(t, market, "SellPeg1", types.SideSell, 100, "party01", 5)
  3596  	sp1.PeggedOrder = &types.PeggedOrder{
  3597  		Reference: types.PeggedReferenceMid,
  3598  		Offset:    num.NewUint(3),
  3599  	}
  3600  	book.ob.SubmitOrder(sp1)
  3601  
  3602  	// wash trade, doesn't go through so still expect 1
  3603  	require.Equal(t, uint64(1), book.ob.GetPeggedOrdersCount())
  3604  
  3605  	// Leave auction and uncross the book
  3606  	cancels := book.ob.EnterAuction()
  3607  	assert.Equal(t, len(cancels), 0)
  3608  
  3609  	book.ob.CancelOrder(bp1)
  3610  	require.Equal(t, uint64(0), book.ob.GetPeggedOrdersCount())
  3611  }
  3612  
  3613  func TestOrderBook_BidAndAskPresentAfterAuction(t *testing.T) {
  3614  	market := vgrand.RandomStr(5)
  3615  	book := getTestOrderBook(t, market)
  3616  	defer book.Finish()
  3617  
  3618  	logger := logging.NewTestLogger()
  3619  	defer logger.Sync()
  3620  
  3621  	// Switch to auction mode
  3622  	book.ob.EnterAuction()
  3623  	assert.True(t, book.ob.InAuction())
  3624  
  3625  	require.Equal(t, false, book.ob.BidAndAskPresentAfterAuction())
  3626  	require.Equal(t, false, book.ob.CanUncross())
  3627  
  3628  	matchingPrice := uint64(100)
  3629  	party1 := "party1"
  3630  	party2 := "party2"
  3631  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideBuy, matchingPrice-1, party1, 1)
  3632  
  3633  	require.Equal(t, false, book.ob.BidAndAskPresentAfterAuction())
  3634  	require.Equal(t, false, book.ob.CanUncross())
  3635  
  3636  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideSell, matchingPrice+1, party2, 1)
  3637  
  3638  	require.Equal(t, true, book.ob.BidAndAskPresentAfterAuction())
  3639  	require.Equal(t, false, book.ob.CanUncross())
  3640  
  3641  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideBuy, matchingPrice, party1, 1)
  3642  
  3643  	require.Equal(t, true, book.ob.BidAndAskPresentAfterAuction())
  3644  	require.Equal(t, false, book.ob.CanUncross())
  3645  
  3646  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideSell, matchingPrice, party2, 1)
  3647  
  3648  	require.Equal(t, true, book.ob.BidAndAskPresentAfterAuction())
  3649  	require.Equal(t, true, book.ob.CanUncross())
  3650  
  3651  	_, err := book.ob.CancelAllOrders(party1)
  3652  	require.NoError(t, err)
  3653  	_, err = book.ob.CancelAllOrders(party2)
  3654  	require.NoError(t, err)
  3655  
  3656  	require.Equal(t, int64(0), book.ob.GetTotalNumberOfOrders())
  3657  
  3658  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideBuy, matchingPrice, party1, 1)
  3659  
  3660  	require.Equal(t, false, book.ob.BidAndAskPresentAfterAuction())
  3661  	require.Equal(t, false, book.ob.CanUncross())
  3662  
  3663  	makeOrder(t, book, market, vgcrypto.RandomHash(), types.SideSell, matchingPrice, party2, 1)
  3664  
  3665  	require.Equal(t, false, book.ob.BidAndAskPresentAfterAuction())
  3666  	require.Equal(t, false, book.ob.CanUncross())
  3667  }
  3668  
  3669  func TestOrderBook_AuctionUncrossWashTrades2(t *testing.T) {
  3670  	market := vgrand.RandomStr(5)
  3671  	book := getTestOrderBook(t, market)
  3672  	defer book.Finish()
  3673  
  3674  	logger := logging.NewTestLogger()
  3675  	defer logger.Sync()
  3676  
  3677  	// Switch to auction mode
  3678  	book.ob.EnterAuction()
  3679  
  3680  	tt0_0 := getOrder(t, market, "tt_0_0", types.SideBuy, 90, "tt_0", 1000)
  3681  	_, err := book.ob.SubmitOrder(tt0_0)
  3682  	require.NoError(t, err)
  3683  	tt0_1 := getOrder(t, market, "tt_0_1", types.SideSell, 200, "tt_0", 1000)
  3684  	_, err = book.ob.SubmitOrder(tt0_1)
  3685  	require.NoError(t, err)
  3686  
  3687  	tt1_0 := getOrder(t, market, "tt_1_0", types.SideSell, 110, "tt_1", 50)
  3688  	_, err = book.ob.SubmitOrder(tt1_0)
  3689  	require.NoError(t, err)
  3690  	tt2_0 := getOrder(t, market, "tt_2_0", types.SideBuy, 110, "tt_2", 20)
  3691  	_, err = book.ob.SubmitOrder(tt2_0)
  3692  	require.NoError(t, err)
  3693  	tt3_0 := getOrder(t, market, "tt_3_0", types.SideBuy, 110, "tt_3", 30)
  3694  	_, err = book.ob.SubmitOrder(tt3_0)
  3695  	require.NoError(t, err)
  3696  
  3697  	indicativeTrades, err := book.ob.GetIndicativeTrades()
  3698  	require.NoError(t, err)
  3699  	require.Equal(t, 2, len(indicativeTrades))
  3700  
  3701  	require.Equal(t, tt1_0.Party, indicativeTrades[0].Seller)
  3702  	require.Equal(t, tt2_0.Party, indicativeTrades[0].Buyer)
  3703  	require.Equal(t, tt2_0.Size, indicativeTrades[0].Size)
  3704  	require.Equal(t, tt2_0.Price, indicativeTrades[0].Price)
  3705  
  3706  	require.Equal(t, tt1_0.Party, indicativeTrades[1].Seller)
  3707  	require.Equal(t, tt3_0.Party, indicativeTrades[1].Buyer)
  3708  	require.Equal(t, tt3_0.Size, indicativeTrades[1].Size)
  3709  	require.Equal(t, tt3_0.Price, indicativeTrades[1].Price)
  3710  
  3711  	// Add wash trades
  3712  	tt4_0 := getOrder(t, market, "tt_4_0", types.SideSell, 110, "tt_4", 40)
  3713  	_, err = book.ob.SubmitOrder(tt4_0)
  3714  	require.NoError(t, err)
  3715  	tt4_1 := getOrder(t, market, "tt_4_1", types.SideBuy, 110, "tt_4", 40)
  3716  	_, err = book.ob.SubmitOrder(tt4_1)
  3717  	require.NoError(t, err)
  3718  
  3719  	indicativeTrades, err = book.ob.GetIndicativeTrades()
  3720  	require.NoError(t, err)
  3721  	// Expecting one more indicative trade now
  3722  	require.Equal(t, 3, len(indicativeTrades))
  3723  
  3724  	// The first two should stay as they were
  3725  	require.Equal(t, tt1_0.Party, indicativeTrades[0].Seller)
  3726  	require.Equal(t, tt2_0.Party, indicativeTrades[0].Buyer)
  3727  	require.Equal(t, tt2_0.Size, indicativeTrades[0].Size)
  3728  	require.Equal(t, tt2_0.Price, indicativeTrades[0].Price)
  3729  
  3730  	require.Equal(t, tt1_0.Party, indicativeTrades[1].Seller)
  3731  	require.Equal(t, tt3_0.Party, indicativeTrades[1].Buyer)
  3732  	require.Equal(t, tt3_0.Size, indicativeTrades[1].Size)
  3733  	require.Equal(t, tt3_0.Price, indicativeTrades[1].Price)
  3734  
  3735  	// The third one should be the wash trade
  3736  	require.Equal(t, tt4_0.Party, indicativeTrades[2].Seller)
  3737  	require.Equal(t, tt4_1.Party, indicativeTrades[2].Buyer)
  3738  	require.Equal(t, tt4_0.Size, indicativeTrades[2].Size)
  3739  	require.Equal(t, tt4_0.Price, indicativeTrades[2].Price)
  3740  
  3741  	confs, ordersToCancel, err := book.ob.LeaveAuction(time.Now())
  3742  	require.NoError(t, err)
  3743  	require.Equal(t, 3, len(confs))
  3744  	require.Equal(t, 0, len(ordersToCancel))
  3745  
  3746  	for i, c := range confs {
  3747  		require.Equal(t, 1, len(c.Trades))
  3748  		require.Equal(t, c.Trades[0].Buyer, indicativeTrades[i].Buyer)
  3749  		require.Equal(t, c.Trades[0].Seller, indicativeTrades[i].Seller)
  3750  		require.Equal(t, c.Trades[0].Size, indicativeTrades[i].Size)
  3751  		require.Equal(t, c.Trades[0].Price, indicativeTrades[i].Price)
  3752  	}
  3753  }
  3754  
  3755  // just generates random orders with the given prices. Uses parties provided by accessing
  3756  // parties[i%len(parties)], where i is the current index in the buy/sell prices slice.
  3757  // if parties is empty, []string{"A", "B"} is used.
  3758  func getTestOrders(t *testing.T, market string, fixedSize uint64, buyPrices, sellPrices []uint64) []*types.Order {
  3759  	t.Helper()
  3760  	parties := []string{"A", "B"}
  3761  	orders := make([]*types.Order, 0, len(buyPrices)+len(sellPrices))
  3762  	for i, p := range buyPrices {
  3763  		size := fixedSize
  3764  		if size == 0 {
  3765  			size = uint64(rand.Int63n(10-1) + 1)
  3766  		}
  3767  		orders = append(orders, &types.Order{
  3768  			ID:            vgcrypto.RandomHash(),
  3769  			Status:        types.OrderStatusActive,
  3770  			Type:          types.OrderTypeLimit,
  3771  			MarketID:      market,
  3772  			Party:         parties[i%len(parties)],
  3773  			Side:          types.SideBuy,
  3774  			Price:         num.NewUint(p),
  3775  			OriginalPrice: num.NewUint(p),
  3776  			Size:          size,
  3777  			Remaining:     size,
  3778  			TimeInForce:   types.OrderTimeInForceGTC,
  3779  		})
  3780  	}
  3781  	for i, p := range sellPrices {
  3782  		size := fixedSize
  3783  		if size == 0 {
  3784  			size = uint64(rand.Int63n(10-1) + 1)
  3785  		}
  3786  		orders = append(orders, &types.Order{
  3787  			ID:            vgcrypto.RandomHash(),
  3788  			Status:        types.OrderStatusActive,
  3789  			Type:          types.OrderTypeLimit,
  3790  			MarketID:      market,
  3791  			Party:         parties[i%len(parties)],
  3792  			Side:          types.SideSell,
  3793  			Price:         num.NewUint(p),
  3794  			OriginalPrice: num.NewUint(p),
  3795  			Size:          size,
  3796  			Remaining:     size,
  3797  			TimeInForce:   types.OrderTimeInForceGTC,
  3798  		})
  3799  	}
  3800  	return orders
  3801  }
  3802  
  3803  func TestVwapEmptySide(t *testing.T) {
  3804  	ob := getTestOrderBook(t, "market1")
  3805  	_, err := ob.ob.VWAP(0, types.SideBuy)
  3806  	require.Error(t, err)
  3807  	_, err = ob.ob.VWAP(0, types.SideSell)
  3808  	require.Error(t, err)
  3809  
  3810  	_, err = ob.ob.VWAP(10, types.SideBuy)
  3811  	require.Error(t, err)
  3812  	_, err = ob.ob.VWAP(10, types.SideSell)
  3813  	require.Error(t, err)
  3814  }
  3815  
  3816  func TestVwapZeroVolume(t *testing.T) {
  3817  	ob := getTestOrderBook(t, "market1")
  3818  
  3819  	buyPrices := []uint64{
  3820  		90,
  3821  	}
  3822  	sellPrices := []uint64{
  3823  		100,
  3824  	}
  3825  
  3826  	orders := getTestOrders(t, "market1", 10, buyPrices, sellPrices)
  3827  	for _, o := range orders {
  3828  		_, err := ob.ob.SubmitOrder(o)
  3829  		assert.NoError(t, err)
  3830  	}
  3831  
  3832  	// when the volume passed is 0
  3833  	vwap, err := ob.ob.VWAP(0, types.SideBuy)
  3834  	require.NoError(t, err)
  3835  	require.Equal(t, "90", vwap.String())
  3836  	vwap, err = ob.ob.VWAP(0, types.SideSell)
  3837  	require.NoError(t, err)
  3838  	require.Equal(t, "100", vwap.String())
  3839  }
  3840  
  3841  func TestVwapNotEnoughVolume(t *testing.T) {
  3842  	ob := getTestOrderBook(t, "market1")
  3843  
  3844  	buyPrices := []uint64{
  3845  		90,
  3846  		95,
  3847  		100,
  3848  	}
  3849  	sellPrices := []uint64{
  3850  		200,
  3851  		210,
  3852  		220,
  3853  	}
  3854  
  3855  	orders := getTestOrders(t, "market1", 10, buyPrices, sellPrices)
  3856  	for _, o := range orders {
  3857  		_, err := ob.ob.SubmitOrder(o)
  3858  		assert.NoError(t, err)
  3859  	}
  3860  
  3861  	// there's 30 in the order book
  3862  	_, err := ob.ob.VWAP(40, types.SideBuy)
  3863  	require.Error(t, err)
  3864  	_, err = ob.ob.VWAP(40, types.SideSell)
  3865  	require.Error(t, err)
  3866  }
  3867  
  3868  func TestVWAP(t *testing.T) {
  3869  	ob := getTestOrderBook(t, "market1")
  3870  
  3871  	buyPrices := []uint64{
  3872  		60,
  3873  		70,
  3874  		100,
  3875  	}
  3876  	sellPrices := []uint64{
  3877  		200,
  3878  		210,
  3879  		220,
  3880  	}
  3881  
  3882  	orders := getTestOrders(t, "market1", 10, buyPrices, sellPrices)
  3883  	for _, o := range orders {
  3884  		_, err := ob.ob.SubmitOrder(o)
  3885  		assert.NoError(t, err)
  3886  	}
  3887  
  3888  	// Bid side
  3889  	// =========
  3890  	vwap, err := ob.ob.VWAP(5, types.SideBuy)
  3891  	require.NoError(t, err)
  3892  	require.Equal(t, "100", vwap.String())
  3893  
  3894  	vwap, err = ob.ob.VWAP(10, types.SideBuy)
  3895  	require.NoError(t, err)
  3896  	require.Equal(t, "100", vwap.String())
  3897  
  3898  	// (100 * 10 + 70 * 5)/15
  3899  	vwap, err = ob.ob.VWAP(15, types.SideBuy)
  3900  	require.NoError(t, err)
  3901  	require.Equal(t, "90", vwap.String())
  3902  
  3903  	// (100 + 70)/2
  3904  	vwap, err = ob.ob.VWAP(20, types.SideBuy)
  3905  	require.NoError(t, err)
  3906  	require.Equal(t, "85", vwap.String())
  3907  
  3908  	// (100 * 10 + 70 * 10 + 60 * 5)/25
  3909  	vwap, err = ob.ob.VWAP(25, types.SideBuy)
  3910  	require.NoError(t, err)
  3911  	require.Equal(t, "80", vwap.String())
  3912  
  3913  	// (100 + 70 + 60)/3
  3914  	vwap, err = ob.ob.VWAP(30, types.SideBuy)
  3915  	require.NoError(t, err)
  3916  	require.Equal(t, "76", vwap.String())
  3917  
  3918  	// Ask side
  3919  	// =========
  3920  	vwap, err = ob.ob.VWAP(5, types.SideSell)
  3921  	require.NoError(t, err)
  3922  	require.Equal(t, "200", vwap.String())
  3923  
  3924  	vwap, err = ob.ob.VWAP(10, types.SideSell)
  3925  	require.NoError(t, err)
  3926  	require.Equal(t, "200", vwap.String())
  3927  
  3928  	// (200 * 10 + 210 * 5)/15
  3929  	vwap, err = ob.ob.VWAP(15, types.SideSell)
  3930  	require.NoError(t, err)
  3931  	require.Equal(t, "203", vwap.String())
  3932  
  3933  	// (200 + 210)/2
  3934  	vwap, err = ob.ob.VWAP(20, types.SideSell)
  3935  	require.NoError(t, err)
  3936  	require.Equal(t, "205", vwap.String())
  3937  
  3938  	// (200 * 10 + 210 * 10 + 220 * 5)/25
  3939  	vwap, err = ob.ob.VWAP(25, types.SideSell)
  3940  	require.NoError(t, err)
  3941  	require.Equal(t, "208", vwap.String())
  3942  
  3943  	// (200 + 210 + 220)/3
  3944  	vwap, err = ob.ob.VWAP(30, types.SideSell)
  3945  	require.NoError(t, err)
  3946  	require.Equal(t, "210", vwap.String())
  3947  }