code.vegaprotocol.io/vega@v0.79.0/core/execution/future/order_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 future_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/events"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	vegacontext "code.vegaprotocol.io/vega/libs/context"
    26  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    27  	"code.vegaprotocol.io/vega/libs/num"
    28  
    29  	"github.com/golang/mock/gomock"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestReduceOnly(t *testing.T) {
    35  	lpparty := "lp-party-1"
    36  	lpparty2 := "lp-party-2"
    37  	lpparty3 := "lp-party-3"
    38  
    39  	p1 := "p1"
    40  	p2 := "p2"
    41  
    42  	party1 := "party1"
    43  
    44  	now := time.Unix(10, 0)
    45  	auctionEnd := now.Add(10001 * time.Second)
    46  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
    47  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
    48  		Duration: 10000,
    49  	})
    50  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
    51  	tm.StartOpeningAuction().
    52  		// the liquidity provider
    53  		WithAccountAndAmount(lpparty, 500000000000).
    54  		WithAccountAndAmount(lpparty2, 500000000000).
    55  		WithAccountAndAmount(lpparty3, 500000000000).
    56  		WithAccountAndAmount(p1, 500000000000).
    57  		WithAccountAndAmount(p2, 500000000000)
    58  	addAccountWithAmount(tm, "lpprov", 10000000)
    59  
    60  	lp := &types.LiquidityProvisionSubmission{
    61  		MarketID:         tm.market.GetID(),
    62  		CommitmentAmount: num.NewUint(55000),
    63  		Fee:              num.DecimalFromFloat(0.01),
    64  	}
    65  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
    66  	tm.EndOpeningAuction(t, auctionEnd, false)
    67  
    68  	addAccountWithAmount(tm, party1, 10000000000)
    69  
    70  	volumeOrder := &types.Order{
    71  		Status:      types.OrderStatusActive,
    72  		Type:        types.OrderTypeLimit,
    73  		TimeInForce: types.OrderTimeInForceGTC,
    74  		ID:          "someid",
    75  		Side:        types.SideBuy,
    76  		Party:       lpparty,
    77  		MarketID:    tm.market.GetID(),
    78  		Size:        100,
    79  		Price:       num.NewUint(900),
    80  		Remaining:   100,
    81  		CreatedAt:   now.UnixNano(),
    82  		Reference:   "party1-buy-order",
    83  	}
    84  	confirmation, err := tm.market.SubmitOrder(context.TODO(), volumeOrder)
    85  	assert.NotNil(t, confirmation)
    86  	assert.NoError(t, err)
    87  	volumeOrder.Price = num.NewUint(1100)
    88  	volumeOrder.Side = types.SideSell
    89  
    90  	confirmation, err = tm.market.SubmitOrder(context.TODO(), volumeOrder)
    91  	assert.NotNil(t, confirmation)
    92  	assert.NoError(t, err)
    93  
    94  	orderBuy := &types.Order{
    95  		Status:      types.OrderStatusActive,
    96  		Type:        types.OrderTypeMarket,
    97  		TimeInForce: types.OrderTimeInForceIOC,
    98  		ID:          "someid",
    99  		Side:        types.SideBuy,
   100  		Party:       party1,
   101  		MarketID:    tm.market.GetID(),
   102  		Size:        5,
   103  		Price:       num.UintZero(),
   104  		Remaining:   5,
   105  		CreatedAt:   now.UnixNano(),
   106  		Reference:   "party1-buy-order",
   107  		ReduceOnly:  true,
   108  	}
   109  
   110  	// Submit the original order, it will return an error
   111  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   112  	assert.Nil(t, confirmation)
   113  	assert.EqualError(t, err, "OrderError: reduce only order would not reduce position")
   114  
   115  	orderBuy.TimeInForce = types.OrderTimeInForceFOK
   116  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   117  	assert.Nil(t, confirmation)
   118  	assert.EqualError(t, err, "OrderError: reduce only order would not reduce position")
   119  
   120  	// now open a position
   121  	orderBuy.ReduceOnly = false
   122  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   123  	assert.NotNil(t, confirmation)
   124  	assert.NoError(t, err)
   125  
   126  	// now try to reduce the position fully with an FOK bigger than the position
   127  	orderBuy.TimeInForce = types.OrderTimeInForceFOK
   128  	orderBuy.Side = types.SideSell
   129  	orderBuy.ReduceOnly = true
   130  	orderBuy.Size = 10
   131  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   132  	assert.Nil(t, confirmation)
   133  	assert.EqualError(t, err, "OrderError: reduce only order would not reduce position")
   134  
   135  	// now try to reduce the position a little with FOK
   136  	orderBuy.TimeInForce = types.OrderTimeInForceFOK
   137  	orderBuy.ReduceOnly = true
   138  	orderBuy.Size = 2
   139  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   140  	assert.NotNil(t, confirmation)
   141  	assert.NoError(t, err)
   142  
   143  	// now fully clear with FOK
   144  	orderBuy.TimeInForce = types.OrderTimeInForceFOK
   145  	orderBuy.ReduceOnly = true
   146  	orderBuy.Size = 3
   147  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   148  	assert.NotNil(t, confirmation)
   149  	assert.NoError(t, err)
   150  
   151  	// now fully do it again just to make sure we are done with it
   152  	orderBuy.TimeInForce = types.OrderTimeInForceFOK
   153  	orderBuy.ReduceOnly = true
   154  	orderBuy.Size = 1
   155  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   156  	assert.Nil(t, confirmation)
   157  	assert.EqualError(t, err, "OrderError: reduce only order would not reduce position")
   158  
   159  	// Now try again with IOC and the inverse situation
   160  	// we start by selling
   161  	orderSell := orderBuy
   162  	orderSell.TimeInForce = types.OrderTimeInForceIOC
   163  	orderSell.Side = types.SideSell
   164  	orderSell.Size = 5
   165  	orderSell.ReduceOnly = false
   166  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   167  	assert.NotNil(t, confirmation)
   168  	assert.NoError(t, err)
   169  
   170  	// now try to reduce it a little
   171  	// we should have a position of 2 after
   172  	orderSell.Side = types.SideBuy
   173  	orderSell.Size = 3
   174  	orderSell.ReduceOnly = true
   175  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   176  	assert.NotNil(t, confirmation)
   177  	assert.NoError(t, err)
   178  
   179  	// now try to reduce which would flip the position
   180  	// this will trade just enough to get to 0
   181  	// we should have a position of 0 after
   182  	orderSell.Side = types.SideBuy
   183  	orderSell.Size = 5
   184  	orderSell.ReduceOnly = true
   185  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   186  	assert.NotNil(t, confirmation)
   187  	assert.NoError(t, err)
   188  	assert.Equal(t, int(confirmation.Order.Remaining), 3)
   189  }
   190  
   191  func TestPostOnly(t *testing.T) {
   192  	lpparty := "lp-party-1"
   193  	lpparty2 := "lp-party-2"
   194  	lpparty3 := "lp-party-3"
   195  
   196  	p1 := "p1"
   197  	p2 := "p2"
   198  
   199  	party1 := "party1"
   200  
   201  	now := time.Unix(10, 0)
   202  	auctionEnd := now.Add(10001 * time.Second)
   203  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   204  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
   205  		Duration: 10000,
   206  	})
   207  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
   208  	tm.StartOpeningAuction().
   209  		// the liquidity provider
   210  		WithAccountAndAmount(lpparty, 500000000000).
   211  		WithAccountAndAmount(lpparty2, 500000000000).
   212  		WithAccountAndAmount(lpparty3, 500000000000).
   213  		WithAccountAndAmount(p1, 500000000000).
   214  		WithAccountAndAmount(p2, 500000000000)
   215  	addAccountWithAmount(tm, "lpprov", 10000000)
   216  
   217  	lp := &types.LiquidityProvisionSubmission{
   218  		MarketID:         tm.market.GetID(),
   219  		CommitmentAmount: num.NewUint(55000),
   220  		Fee:              num.DecimalFromFloat(0.01),
   221  	}
   222  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
   223  	tm.EndOpeningAuction(t, auctionEnd, false)
   224  
   225  	addAccountWithAmount(tm, party1, 10000000000)
   226  
   227  	orderBuy := &types.Order{
   228  		Status:      types.OrderStatusActive,
   229  		Type:        types.OrderTypeLimit,
   230  		TimeInForce: types.OrderTimeInForceGTC,
   231  		ID:          "someid",
   232  		Side:        types.SideBuy,
   233  		Party:       party1,
   234  		MarketID:    tm.market.GetID(),
   235  		Size:        1,
   236  		Price:       num.NewUint(1100),
   237  		Remaining:   100,
   238  		CreatedAt:   now.UnixNano(),
   239  		Reference:   "party1-buy-order",
   240  		PostOnly:    true,
   241  	}
   242  
   243  	// Submit the original order, this would trade, so expect an error
   244  	confirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   245  	assert.Nil(t, confirmation)
   246  	assert.EqualError(t, err, "OrderError: post only order would trade")
   247  
   248  	// Submit the original order this would not trade, so we expect a success
   249  	orderBuy.Price = num.NewUint(100)
   250  	confirmation, err = tm.market.SubmitOrder(context.TODO(), orderBuy)
   251  	assert.NotNil(t, confirmation)
   252  	assert.NoError(t, err)
   253  }
   254  
   255  func TestAmendMarginCheckFails(t *testing.T) {
   256  	lpparty := "lp-party-1"
   257  	lpparty2 := "lp-party-2"
   258  	lpparty3 := "lp-party-3"
   259  
   260  	p1 := "p1"
   261  	p2 := "p2"
   262  
   263  	party1 := "party1"
   264  
   265  	now := time.Unix(10, 0)
   266  	auctionEnd := now.Add(10001 * time.Second)
   267  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   268  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
   269  		Duration: 10000,
   270  	})
   271  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
   272  	tm.StartOpeningAuction().
   273  		// the liquidity provider
   274  		WithAccountAndAmount(lpparty, 500000000000).
   275  		WithAccountAndAmount(lpparty2, 500000000000).
   276  		WithAccountAndAmount(lpparty3, 500000000000).
   277  		WithAccountAndAmount(p1, 500000000000).
   278  		WithAccountAndAmount(p2, 500000000000)
   279  	addAccountWithAmount(tm, "lpprov", 10000000)
   280  
   281  	lp := &types.LiquidityProvisionSubmission{
   282  		MarketID:         tm.market.GetID(),
   283  		CommitmentAmount: num.NewUint(55000),
   284  		Fee:              num.DecimalFromFloat(0.01),
   285  	}
   286  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
   287  	tm.EndOpeningAuction(t, auctionEnd, false)
   288  
   289  	addAccountWithAmount(tm, party1, 18001)
   290  
   291  	orderBuy := &types.Order{
   292  		Status:      types.OrderStatusActive,
   293  		Type:        types.OrderTypeLimit,
   294  		TimeInForce: types.OrderTimeInForceGTC,
   295  		ID:          "someid",
   296  		Side:        types.SideBuy,
   297  		Party:       party1,
   298  		MarketID:    tm.market.GetID(),
   299  		Size:        100,
   300  		Price:       num.NewUint(100),
   301  		Remaining:   100,
   302  		CreatedAt:   now.UnixNano(),
   303  		Reference:   "party1-buy-order",
   304  	}
   305  
   306  	// Submit the original order
   307  	confirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   308  	assert.NotNil(t, confirmation)
   309  	assert.NoError(t, err)
   310  
   311  	orderID := confirmation.Order.ID
   312  
   313  	// Amend the price to force a cancel+resubmit to the order book
   314  
   315  	amend := &types.OrderAmendment{
   316  		OrderID:   orderID,
   317  		MarketID:  confirmation.Order.MarketID,
   318  		SizeDelta: 100000,
   319  	}
   320  
   321  	tm.events = nil
   322  	amended, err := tm.market.AmendOrder(context.TODO(), amend, confirmation.Order.Party, vgcrypto.RandomHash())
   323  	assert.Nil(t, amended)
   324  	assert.EqualError(t, err, "margin check failed")
   325  	// ensure no events for the update order were sent
   326  	assert.Len(t, tm.events, 2)
   327  	// first event was to update the positions
   328  	assert.Equal(t, int64(100100), tm.events[0].(*events.PositionState).PotentialBuys())
   329  	// second to restore to the initial size as margin check failed
   330  	assert.Equal(t, int64(100), tm.events[1].(*events.PositionState).PotentialBuys())
   331  
   332  	// now we just cancel it and see if all is fine.
   333  	tm.events = nil
   334  	cancelled, err := tm.market.CancelOrder(context.TODO(), confirmation.Order.Party, orderID, vgcrypto.RandomHash())
   335  	assert.NotNil(t, cancelled)
   336  	assert.NoError(t, err)
   337  	assert.Equal(t, cancelled.Order.Status, types.OrderStatusCancelled)
   338  
   339  	found := false
   340  	for _, v := range tm.events {
   341  		if co, ok := v.(*events.CancelledOrders); ok {
   342  			for _, oid := range co.OrderIDs() {
   343  				if oid == orderID {
   344  					found = true
   345  					break
   346  				}
   347  			}
   348  			if found {
   349  				break
   350  			}
   351  		}
   352  	}
   353  	assert.True(t, found)
   354  }
   355  
   356  func TestOrderBufferOutputCount(t *testing.T) {
   357  	party1 := "party1"
   358  	now := time.Unix(10, 0)
   359  	tm := getTestMarket(t, now, nil, nil)
   360  
   361  	addAccount(t, tm, party1)
   362  
   363  	orderBuy := &types.Order{
   364  		Type:        types.OrderTypeLimit,
   365  		TimeInForce: types.OrderTimeInForceGTC,
   366  		Status:      types.OrderStatusActive,
   367  		ID:          "someid",
   368  		Side:        types.SideBuy,
   369  		Party:       party1,
   370  		MarketID:    tm.market.GetID(),
   371  		Size:        100,
   372  		Price:       num.NewUint(100),
   373  		Remaining:   100,
   374  		CreatedAt:   now.UnixNano(),
   375  		ExpiresAt:   0,
   376  		Reference:   "party1-buy-order",
   377  	}
   378  	orderAmend := *orderBuy
   379  
   380  	// Create an order (generates one order message)
   381  	confirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   382  	assert.NotNil(t, confirmation)
   383  	assert.NoError(t, err)
   384  
   385  	// Create a new order (generates one order message)
   386  	orderAmend.ID = "amendingorder"
   387  	orderAmend.Reference = "amendingorderreference"
   388  	confirmation, err = tm.market.SubmitOrder(context.TODO(), &orderAmend)
   389  	assert.NotNil(t, confirmation)
   390  	assert.NoError(t, err)
   391  
   392  	amend := &types.OrderAmendment{
   393  		MarketID: tm.market.GetID(),
   394  		OrderID:  orderAmend.ID,
   395  	}
   396  
   397  	one := num.NewUint(1)
   398  	// Amend price down (generates one order message)
   399  	amend.Price = num.UintZero().Sub(orderBuy.Price, one)
   400  	amendConf, err := tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   401  	assert.NotNil(t, amendConf)
   402  	assert.NoError(t, err)
   403  
   404  	// Amend price up (generates one order message)
   405  	amend.Price.AddSum(one, one) // we subtracted one, add 1 to get == to orderBuy.Price, + 1 again
   406  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   407  	assert.NotNil(t, amendConf)
   408  	assert.NoError(t, err)
   409  
   410  	// Amend size down (generates one order message)
   411  	amend.Price = nil
   412  	amend.SizeDelta = -1
   413  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   414  	assert.NotNil(t, amendConf)
   415  	assert.NoError(t, err)
   416  
   417  	// Amend size up (generates one order message)
   418  	amend.SizeDelta = +1
   419  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   420  	assert.NotNil(t, amendConf)
   421  	assert.NoError(t, err)
   422  
   423  	// Amend TIME_IN_FORCE -> GTT (generates one order message)
   424  	amend.SizeDelta = 0
   425  	amend.TimeInForce = types.OrderTimeInForceGTT
   426  	exp := now.UnixNano() + 100000000000
   427  	amend.ExpiresAt = &exp
   428  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   429  	assert.NotNil(t, amendConf)
   430  	assert.NoError(t, err)
   431  
   432  	// Amend TIME_IN_FORCE -> GTC (generates one order message)
   433  	amend.TimeInForce = types.OrderTimeInForceGTC
   434  	amend.ExpiresAt = nil
   435  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   436  	assert.NotNil(t, amendConf)
   437  	assert.NoError(t, err)
   438  
   439  	// Amend ExpiresAt (generates two order messages)
   440  	amend.TimeInForce = types.OrderTimeInForceGTT
   441  	exp = now.UnixNano() + 100000000000
   442  	amend.ExpiresAt = &exp
   443  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   444  	assert.NotNil(t, amendConf)
   445  	assert.NoError(t, err)
   446  
   447  	exp = now.UnixNano() + 200000000000
   448  	amend.ExpiresAt = &exp
   449  	amendConf, err = tm.market.AmendOrder(context.TODO(), amend, party1, vgcrypto.RandomHash())
   450  	assert.NotNil(t, amendConf)
   451  	assert.NoError(t, err)
   452  }
   453  
   454  func TestAmendCancelResubmit(t *testing.T) {
   455  	party1 := "party1"
   456  	now := time.Unix(10, 0)
   457  	tm := getTestMarket(t, now, nil, nil)
   458  
   459  	addAccount(t, tm, party1)
   460  
   461  	orderBuy := &types.Order{
   462  		Status:      types.OrderStatusActive,
   463  		Type:        types.OrderTypeLimit,
   464  		TimeInForce: types.OrderTimeInForceGTC,
   465  		ID:          "someid",
   466  		Side:        types.SideBuy,
   467  		Party:       party1,
   468  		MarketID:    tm.market.GetID(),
   469  		Size:        100,
   470  		Price:       num.NewUint(100),
   471  		Remaining:   100,
   472  		CreatedAt:   now.UnixNano(),
   473  		Reference:   "party1-buy-order",
   474  	}
   475  	// Submit the original order
   476  	confirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   477  	assert.NotNil(t, confirmation)
   478  	assert.NoError(t, err)
   479  
   480  	orderID := confirmation.Order.ID
   481  
   482  	// Amend the price to force a cancel+resubmit to the order book
   483  
   484  	amend := &types.OrderAmendment{
   485  		OrderID:  orderID,
   486  		MarketID: confirmation.Order.MarketID,
   487  		Price:    num.NewUint(101),
   488  	}
   489  	amended, err := tm.market.AmendOrder(context.TODO(), amend, confirmation.Order.Party, vgcrypto.RandomHash())
   490  	assert.NotNil(t, amended)
   491  	assert.NoError(t, err)
   492  
   493  	amend = &types.OrderAmendment{
   494  		OrderID:   orderID,
   495  		MarketID:  confirmation.Order.MarketID,
   496  		Price:     num.NewUint(101),
   497  		SizeDelta: 1,
   498  	}
   499  	amended, err = tm.market.AmendOrder(context.TODO(), amend, confirmation.Order.Party, vgcrypto.RandomHash())
   500  	assert.NotNil(t, amended)
   501  	assert.NoError(t, err)
   502  }
   503  
   504  func TestCancelWithWrongPartyID(t *testing.T) {
   505  	party1 := "party1"
   506  	party2 := "party2"
   507  	now := time.Unix(10, 0)
   508  	tm := getTestMarket(t, now, nil, nil)
   509  
   510  	addAccount(t, tm, party1)
   511  	addAccount(t, tm, party2)
   512  
   513  	orderBuy := &types.Order{
   514  		Status:      types.OrderStatusActive,
   515  		Type:        types.OrderTypeLimit,
   516  		TimeInForce: types.OrderTimeInForceGTC,
   517  		ID:          "someid",
   518  		Side:        types.SideBuy,
   519  		Party:       party1,
   520  		MarketID:    tm.market.GetID(),
   521  		Size:        100,
   522  		Price:       num.NewUint(100),
   523  		Remaining:   100,
   524  		CreatedAt:   now.UnixNano(),
   525  		Reference:   "party1-buy-order",
   526  	}
   527  	// Submit the original order
   528  	confirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   529  	assert.NotNil(t, confirmation)
   530  	assert.NoError(t, err)
   531  
   532  	// Now attempt to cancel it with the wrong partyID
   533  	cancelOrder := &types.OrderCancellation{
   534  		OrderID:  confirmation.Order.ID,
   535  		MarketID: confirmation.Order.MarketID,
   536  	}
   537  	cancelconf, err := tm.market.CancelOrder(context.TODO(), party2, cancelOrder.OrderID, vgcrypto.RandomHash())
   538  	assert.Nil(t, cancelconf)
   539  	assert.Error(t, err, types.ErrInvalidPartyID)
   540  }
   541  
   542  func TestMarkPriceUpdateAfterPartialFill(t *testing.T) {
   543  	party1 := "party1"
   544  	party2 := "party2"
   545  	auxParty := "auxParty"
   546  	auxParty2 := "auxParty2"
   547  	now := time.Unix(10, 0)
   548  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
   549  		Duration: 1,
   550  	}, true, 0.95)
   551  
   552  	addAccount(t, tm, party1)
   553  	addAccount(t, tm, party2)
   554  	addAccount(t, tm, auxParty)
   555  	addAccount(t, tm, auxParty2)
   556  	addAccountWithAmount(tm, "lpprov", 10000000)
   557  
   558  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
   559  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
   560  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
   561  	require.NotNil(t, conf)
   562  	require.NoError(t, err)
   563  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   564  
   565  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 10000)
   566  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
   567  	require.NotNil(t, conf)
   568  	require.NoError(t, err)
   569  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   570  
   571  	auxOrders := []*types.Order{
   572  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
   573  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
   574  	}
   575  	for _, o := range auxOrders {
   576  		conf, err := tm.market.SubmitOrder(context.Background(), o)
   577  		require.NoError(t, err)
   578  		require.NotNil(t, conf)
   579  	}
   580  	lp := &types.LiquidityProvisionSubmission{
   581  		MarketID:         tm.market.GetID(),
   582  		CommitmentAmount: num.NewUint(25000),
   583  		Fee:              num.DecimalFromFloat(0.01),
   584  	}
   585  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
   586  	// leave opening auction
   587  	now = now.Add(2 * time.Second)
   588  	tm.now = now
   589  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
   590  
   591  	orderBuy := &types.Order{
   592  		Status:      types.OrderStatusActive,
   593  		TimeInForce: types.OrderTimeInForceGTC,
   594  		ID:          "someid",
   595  		Side:        types.SideBuy,
   596  		Party:       party1,
   597  		MarketID:    tm.market.GetID(),
   598  		Size:        100,
   599  		Price:       num.NewUint(10),
   600  		Remaining:   100,
   601  		CreatedAt:   now.UnixNano(),
   602  		Reference:   "party1-buy-order",
   603  		Type:        types.OrderTypeLimit,
   604  	}
   605  	// Submit the original order
   606  	buyConfirmation, err := tm.market.SubmitOrder(context.TODO(), orderBuy)
   607  	assert.NotNil(t, buyConfirmation)
   608  	assert.NoError(t, err)
   609  
   610  	orderSell := &types.Order{
   611  		Status:      types.OrderStatusActive,
   612  		TimeInForce: types.OrderTimeInForceIOC,
   613  		ID:          "someid",
   614  		Side:        types.SideSell,
   615  		Party:       party2,
   616  		MarketID:    tm.market.GetID(),
   617  		Size:        50,
   618  		Price:       num.NewUint(10),
   619  		Remaining:   50,
   620  		CreatedAt:   now.UnixNano(),
   621  		Reference:   "party2-sell-order",
   622  		Type:        types.OrderTypeMarket,
   623  	}
   624  	// Submit an opposite order to partially fill
   625  	sellConfirmation, err := tm.market.SubmitOrder(context.TODO(), orderSell)
   626  	assert.NotNil(t, sellConfirmation)
   627  	assert.NoError(t, err)
   628  
   629  	// Validate that the last traded price has been updated
   630  	assert.True(t, tm.market.GetMarketData().LastTradedPrice.EQ(num.NewUint(10)))
   631  }
   632  
   633  func TestExpireCancelGTCOrder(t *testing.T) {
   634  	party1 := "party1"
   635  	now := time.Unix(10, 0)
   636  	tm := getTestMarket(t, now, nil, nil)
   637  
   638  	addAccount(t, tm, party1)
   639  
   640  	orderBuy := &types.Order{
   641  		CreatedAt:   int64(now.Second()),
   642  		Status:      types.OrderStatusActive,
   643  		TimeInForce: types.OrderTimeInForceGTC,
   644  		ID:          "someid",
   645  		Side:        types.SideBuy,
   646  		Party:       party1,
   647  		MarketID:    tm.market.GetID(),
   648  		Size:        100,
   649  		Price:       num.NewUint(10),
   650  		Remaining:   100,
   651  		Reference:   "party1-buy-order",
   652  		Type:        types.OrderTypeLimit,
   653  	}
   654  	// Submit the original order
   655  	buyConfirmation, err := tm.market.SubmitOrder(context.Background(), orderBuy)
   656  	assert.NotNil(t, buyConfirmation)
   657  	assert.NoError(t, err)
   658  
   659  	tm.now = time.Unix(10, 100)
   660  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), time.Unix(10, 100))
   661  	exp := int64(10000000010)
   662  	amend := &types.OrderAmendment{
   663  		OrderID:     buyConfirmation.Order.ID,
   664  		MarketID:    tm.market.GetID(),
   665  		ExpiresAt:   &exp,
   666  		TimeInForce: types.OrderTimeInForceGTT,
   667  	}
   668  
   669  	amended, err := tm.market.AmendOrder(context.Background(), amend, party1, vgcrypto.RandomHash())
   670  	assert.NotNil(t, amended)
   671  	assert.NoError(t, err)
   672  
   673  	// Validate that the mark price has been updated
   674  	assert.EqualValues(t, amended.Order.TimeInForce, types.OrderTimeInForceGTT)
   675  	assert.EqualValues(t, amended.Order.Status, types.OrderStatusExpired)
   676  	assert.EqualValues(t, amended.Order.CreatedAt, 10000000000)
   677  	assert.EqualValues(t, amended.Order.ExpiresAt, exp)
   678  	assert.EqualValues(t, 10000000100, amended.Order.UpdatedAt)
   679  }
   680  
   681  func TestAmendPartialFillCancelReplace(t *testing.T) {
   682  	party1 := "party1"
   683  	party2 := "party2"
   684  	auxParty := "auxParty"
   685  	auxParty2 := "auxParty2"
   686  	now := time.Unix(10, 0)
   687  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
   688  		Duration: 1,
   689  	})
   690  
   691  	addAccount(t, tm, party1)
   692  	addAccount(t, tm, party2)
   693  	addAccount(t, tm, auxParty)
   694  	addAccount(t, tm, auxParty2)
   695  	addAccountWithAmount(tm, "lpprov", 10000000)
   696  
   697  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
   698  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
   699  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
   700  	require.NotNil(t, conf)
   701  	require.NoError(t, err)
   702  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   703  
   704  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 30)
   705  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
   706  	require.NotNil(t, conf)
   707  	require.NoError(t, err)
   708  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   709  
   710  	auxOrders := []*types.Order{
   711  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 5),
   712  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 5),
   713  	}
   714  	for _, o := range auxOrders {
   715  		conf, err := tm.market.SubmitOrder(context.Background(), o)
   716  		require.NoError(t, err)
   717  		require.NotNil(t, conf)
   718  	}
   719  
   720  	md0 := tm.market.GetMarketData()
   721  	require.NotNil(t, md0)
   722  
   723  	lp := &types.LiquidityProvisionSubmission{
   724  		MarketID:         tm.market.GetID(),
   725  		CommitmentAmount: num.NewUint(25000),
   726  		Fee:              num.DecimalFromFloat(0.01),
   727  	}
   728  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
   729  	// leave opening auction
   730  	now = now.Add(2 * time.Second)
   731  	tm.now = now
   732  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
   733  
   734  	orderBuy := &types.Order{
   735  		Status:      types.OrderStatusActive,
   736  		TimeInForce: types.OrderTimeInForceGTC,
   737  		Side:        types.SideBuy,
   738  		Party:       party1,
   739  		MarketID:    tm.market.GetID(),
   740  		Size:        20,
   741  		Price:       num.NewUint(5),
   742  		Remaining:   20,
   743  		Reference:   "party1-buy-order",
   744  		Type:        types.OrderTypeLimit,
   745  	}
   746  	// Place an order
   747  	buyConfirmation, err := tm.market.SubmitOrder(context.Background(), orderBuy)
   748  	assert.NotNil(t, buyConfirmation)
   749  	assert.Zero(t, len(buyConfirmation.Trades))
   750  	assert.NoError(t, err)
   751  
   752  	marketOrderSell := &types.Order{
   753  		Status:      types.OrderStatusActive,
   754  		TimeInForce: types.OrderTimeInForceIOC,
   755  		Side:        types.SideSell,
   756  		Party:       party2,
   757  		MarketID:    tm.market.GetID(),
   758  		Size:        10,
   759  		Price:       num.UintZero(),
   760  		Remaining:   10,
   761  		Reference:   "party2-sell-order",
   762  		Type:        types.OrderTypeMarket,
   763  	}
   764  	// Partially fill the original order
   765  	sellConfirmation, err := tm.market.SubmitOrder(context.Background(), marketOrderSell)
   766  	assert.NotNil(t, sellConfirmation)
   767  	assert.NoError(t, err)
   768  
   769  	amend := &types.OrderAmendment{
   770  		OrderID:  buyConfirmation.Order.ID,
   771  		MarketID: tm.market.GetID(),
   772  		Price:    num.NewUint(20),
   773  	}
   774  	amended, err := tm.market.AmendOrder(context.Background(), amend, party1, vgcrypto.RandomHash())
   775  	assert.NotNil(t, amended)
   776  	assert.NoError(t, err)
   777  
   778  	// Check the values are correct
   779  	assert.True(t, amended.Order.Price.EQ(amend.Price))
   780  	assert.EqualValues(t, amended.Order.Remaining, orderBuy.Size-marketOrderSell.Size)
   781  	assert.EqualValues(t, amended.Order.Size, orderBuy.Size)
   782  }
   783  
   784  func TestAmendWrongPartyID(t *testing.T) {
   785  	party1 := "party1"
   786  	party2 := "party2"
   787  	now := time.Unix(10, 0)
   788  	tm := getTestMarket(t, now, nil, nil)
   789  
   790  	addAccount(t, tm, party1)
   791  	addAccount(t, tm, party2)
   792  
   793  	orderBuy := &types.Order{
   794  		Status:      types.OrderStatusActive,
   795  		Type:        types.OrderTypeLimit,
   796  		TimeInForce: types.OrderTimeInForceGTC,
   797  		Side:        types.SideBuy,
   798  		Party:       party1,
   799  		MarketID:    tm.market.GetID(),
   800  		Size:        100,
   801  		Price:       num.NewUint(100),
   802  		Remaining:   100,
   803  		CreatedAt:   now.UnixNano(),
   804  		Reference:   "party1-buy-order",
   805  	}
   806  	// Submit the original order
   807  	confirmation, err := tm.market.SubmitOrder(context.Background(), orderBuy)
   808  	assert.NotNil(t, confirmation)
   809  	assert.NoError(t, err)
   810  
   811  	// Send an amend but use the wrong partyID
   812  	amend := &types.OrderAmendment{
   813  		OrderID:  confirmation.Order.ID,
   814  		MarketID: confirmation.Order.MarketID,
   815  		Price:    num.NewUint(101),
   816  	}
   817  	amended, err := tm.market.AmendOrder(context.Background(), amend, party2, vgcrypto.RandomHash())
   818  	assert.Nil(t, amended)
   819  	assert.Error(t, err, types.ErrInvalidPartyID)
   820  }
   821  
   822  func TestPartialFilledWashTrade(t *testing.T) {
   823  	party1 := "party1"
   824  	party2 := "party2"
   825  	auxParty := "auxParty"
   826  	auxParty2 := "auxParty2"
   827  	now := time.Unix(10, 0)
   828  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
   829  		Duration: 1,
   830  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
   831  	}, true, 1.05)
   832  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   833  
   834  	addAccount(t, tm, party1)
   835  	addAccount(t, tm, party2)
   836  	addAccount(t, tm, auxParty)
   837  	addAccount(t, tm, auxParty2)
   838  	addAccountWithAmount(tm, "lpprov", 10000000)
   839  
   840  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
   841  
   842  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
   843  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
   844  	require.NotNil(t, conf)
   845  	require.NoError(t, err)
   846  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   847  
   848  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 10000)
   849  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
   850  	require.NotNil(t, conf)
   851  	require.NoError(t, err)
   852  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
   853  
   854  	auxOrders := []*types.Order{
   855  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 55),
   856  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 55),
   857  	}
   858  	for _, o := range auxOrders {
   859  		conf, err := tm.market.SubmitOrder(ctx, o)
   860  		require.NoError(t, err)
   861  		require.NotNil(t, conf)
   862  	}
   863  	lp := &types.LiquidityProvisionSubmission{
   864  		MarketID:         tm.market.GetID(),
   865  		CommitmentAmount: num.NewUint(25000),
   866  		Fee:              num.DecimalFromFloat(0.01),
   867  	}
   868  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
   869  	// leave opening auction
   870  	now = now.Add(2 * time.Second)
   871  	tm.now = now
   872  	tm.market.OnTick(ctx, now)
   873  
   874  	orderSell1 := &types.Order{
   875  		Status:      types.OrderStatusActive,
   876  		Type:        types.OrderTypeLimit,
   877  		TimeInForce: types.OrderTimeInForceGTC,
   878  		Side:        types.SideSell,
   879  		Party:       party1,
   880  		MarketID:    tm.market.GetID(),
   881  		Size:        15,
   882  		Price:       num.NewUint(55),
   883  		Remaining:   15,
   884  		CreatedAt:   now.UnixNano(),
   885  		Reference:   "party1-sell-order",
   886  	}
   887  	confirmation, err := tm.market.SubmitOrder(context.Background(), orderSell1)
   888  	assert.NotNil(t, confirmation)
   889  	assert.NoError(t, err)
   890  
   891  	orderSell2 := &types.Order{
   892  		Status:      types.OrderStatusActive,
   893  		Type:        types.OrderTypeLimit,
   894  		TimeInForce: types.OrderTimeInForceGTC,
   895  		Side:        types.SideSell,
   896  		Party:       party2,
   897  		MarketID:    tm.market.GetID(),
   898  		Size:        15,
   899  		Price:       num.NewUint(53),
   900  		Remaining:   15,
   901  		CreatedAt:   now.UnixNano(),
   902  		Reference:   "party2-sell-order",
   903  	}
   904  	confirmation, err = tm.market.SubmitOrder(context.Background(), orderSell2)
   905  	assert.NotNil(t, confirmation)
   906  	assert.NoError(t, err)
   907  
   908  	// This order should partially fill and then be rejected
   909  	orderBuy1 := &types.Order{
   910  		Status:      types.OrderStatusActive,
   911  		Type:        types.OrderTypeLimit,
   912  		TimeInForce: types.OrderTimeInForceGTC,
   913  		Side:        types.SideBuy,
   914  		Party:       party1,
   915  		MarketID:    tm.market.GetID(),
   916  		Size:        30,
   917  		Price:       num.NewUint(60),
   918  		Remaining:   30,
   919  		CreatedAt:   now.UnixNano(),
   920  		Reference:   "party1-buy-order",
   921  	}
   922  
   923  	md := tm.market.GetMarketData()
   924  	require.NotNil(t, md)
   925  
   926  	confirmation, err = tm.market.SubmitOrder(context.Background(), orderBuy1)
   927  	assert.NotNil(t, confirmation)
   928  	assert.NoError(t, err)
   929  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusPartiallyFilled)
   930  	assert.Equal(t, confirmation.Order.Remaining, uint64(15))
   931  }
   932  
   933  func getAmend(market string, orderID string, sizeDelta int64, price uint64, tif types.OrderTimeInForce, expiresAt int64) *types.OrderAmendment {
   934  	amend := &types.OrderAmendment{
   935  		OrderID:     orderID,
   936  		MarketID:    market,
   937  		SizeDelta:   sizeDelta,
   938  		TimeInForce: tif,
   939  	}
   940  
   941  	if price > 0 {
   942  		amend.Price = num.NewUint(price)
   943  	}
   944  
   945  	if expiresAt > 0 {
   946  		amend.ExpiresAt = &expiresAt
   947  	}
   948  
   949  	return amend
   950  }
   951  
   952  func amendOrder(t *testing.T, tm *testMarket, party string, orderID string, sizeDelta int64, price uint64,
   953  	tif types.OrderTimeInForce, expiresAt int64, pass bool,
   954  ) {
   955  	t.Helper()
   956  	amend := getAmend(tm.market.GetID(), orderID, sizeDelta, price, tif, expiresAt)
   957  
   958  	amended, err := tm.market.AmendOrder(context.Background(), amend, party, vgcrypto.RandomHash())
   959  	if pass {
   960  		assert.NotNil(t, amended)
   961  		assert.NoError(t, err)
   962  	}
   963  }
   964  
   965  //nolint:unparam
   966  func getOrder(t *testing.T, tm *testMarket, now *time.Time, orderType types.OrderType, tif types.OrderTimeInForce,
   967  	expiresAt int64, side types.Side, party string, size uint64, price uint64,
   968  ) types.Order {
   969  	t.Helper()
   970  	order := types.Order{
   971  		Status:      types.OrderStatusActive,
   972  		Type:        orderType,
   973  		TimeInForce: tif,
   974  		Side:        side,
   975  		Party:       party,
   976  		MarketID:    tm.market.GetID(),
   977  		Size:        size,
   978  		Price:       num.NewUint(price),
   979  		Remaining:   size,
   980  		CreatedAt:   now.UnixNano(),
   981  		Reference:   "",
   982  	}
   983  
   984  	if expiresAt > 0 {
   985  		order.ExpiresAt = expiresAt
   986  	}
   987  	return order
   988  }
   989  
   990  func sendOrder(t *testing.T, tm *testMarket, now *time.Time, orderType types.OrderType, tif types.OrderTimeInForce, expiresAt int64, side types.Side, party string,
   991  	size uint64, price uint64,
   992  ) string {
   993  	t.Helper()
   994  	order := &types.Order{
   995  		Status:      types.OrderStatusActive,
   996  		Type:        orderType,
   997  		TimeInForce: tif,
   998  		Side:        side,
   999  		Party:       party,
  1000  		MarketID:    tm.market.GetID(),
  1001  		Size:        size,
  1002  		Price:       num.NewUint(price),
  1003  		Remaining:   size,
  1004  		CreatedAt:   now.UnixNano(),
  1005  		Reference:   "",
  1006  	}
  1007  
  1008  	if expiresAt > 0 {
  1009  		order.ExpiresAt = expiresAt
  1010  	}
  1011  
  1012  	confirmation, err := tm.market.SubmitOrder(context.Background(), order)
  1013  	require.NotNil(t, confirmation)
  1014  	assert.NoError(t, err)
  1015  	return confirmation.Order.ID
  1016  }
  1017  
  1018  func TestAmendToFill(t *testing.T) {
  1019  	now := time.Unix(10, 0)
  1020  	tm := getTestMarket(t, now, nil, nil)
  1021  
  1022  	addAccount(t, tm, "party1")
  1023  	addAccount(t, tm, "party2")
  1024  
  1025  	// test_AmendMarketOrderFail
  1026  	_ = sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 100)      // 1 - a8
  1027  	_ = sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 110)      // 1 - a8
  1028  	_ = sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 120)      // 1 - a8
  1029  	orderID := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party2", 40, 50) // 1 - a8
  1030  	amendOrder(t, tm, "party2", orderID, 0, 500, types.OrderTimeInForceUnspecified, 0, true)
  1031  }
  1032  
  1033  func TestAmendToLosePriorityThenCancel(t *testing.T) {
  1034  	now := time.Unix(10, 0)
  1035  	tm := getTestMarket(t, now, nil, nil)
  1036  
  1037  	addAccount(t, tm, "party1")
  1038  	addAccount(t, tm, "party2")
  1039  
  1040  	// Create 2 orders at the same level
  1041  	order1 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1042  	_ = sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1043  
  1044  	// Amend the first order to make it lose time priority
  1045  	amendOrder(t, tm, "party1", order1, 1, 0, types.OrderTimeInForceUnspecified, 0, true)
  1046  
  1047  	// Check we can cancel it
  1048  	cancelconf, _ := tm.market.CancelOrder(context.TODO(), "party1", order1, vgcrypto.RandomHash())
  1049  	assert.NotNil(t, cancelconf)
  1050  	assert.Equal(t, types.OrderStatusCancelled, cancelconf.Order.Status)
  1051  }
  1052  
  1053  func TestUnableToAmendGFAGFN(t *testing.T) {
  1054  	now := time.Unix(10, 0)
  1055  	closeSec := int64(10000000000)
  1056  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{Duration: 1})
  1057  	mainParty := "party1"
  1058  	auxParty := "party2"
  1059  	auxParty2 := "party22"
  1060  	addAccount(t, tm, mainParty)
  1061  	addAccount(t, tm, auxParty)
  1062  	addAccount(t, tm, auxParty2)
  1063  	addAccountWithAmount(tm, "lpprov", 10000000)
  1064  
  1065  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
  1066  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  1067  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  1068  	require.NotNil(t, conf)
  1069  	require.NoError(t, err)
  1070  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1071  
  1072  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 10000)
  1073  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  1074  	require.NotNil(t, conf)
  1075  	require.NoError(t, err)
  1076  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1077  
  1078  	auxOrders := []*types.Order{
  1079  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1080  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1081  	}
  1082  	for _, o := range auxOrders {
  1083  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  1084  		require.NoError(t, err)
  1085  		require.NotNil(t, conf)
  1086  	}
  1087  	lp := &types.LiquidityProvisionSubmission{
  1088  		MarketID:         tm.market.GetID(),
  1089  		CommitmentAmount: num.NewUint(25000),
  1090  		Fee:              num.DecimalFromFloat(0.01),
  1091  	}
  1092  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1093  	// leave opening auction
  1094  	now = now.Add(2 * time.Second)
  1095  	tm.now = now
  1096  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  1097  
  1098  	// test_AmendMarketOrderFail
  1099  	orderID := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, mainParty, 10, 100)
  1100  	amendOrder(t, tm, mainParty, orderID, 0, 0, types.OrderTimeInForceGFA, 0, false)
  1101  	amendOrder(t, tm, mainParty, orderID, 0, 0, types.OrderTimeInForceGFN, 0, false)
  1102  
  1103  	orderID2 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGFN, 0, types.SideSell, mainParty, 10, 100)
  1104  	amendOrder(t, tm, mainParty, orderID2, 0, 0, types.OrderTimeInForceGTC, 0, false)
  1105  	amendOrder(t, tm, mainParty, orderID2, 0, 0, types.OrderTimeInForceGFA, 0, false)
  1106  
  1107  	// EnterAuction should actually trigger an auction here...
  1108  	tm.mas.StartPriceAuction(now, &types.AuctionDuration{
  1109  		Duration: closeSec / 10, // some time in the future, before closing
  1110  	})
  1111  	tm.market.EnterAuction(context.Background())
  1112  	orderID3 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGFA, 0, types.SideSell, "party1", 10, 100)
  1113  	amendOrder(t, tm, "party1", orderID3, 0, 0, types.OrderTimeInForceGTC, 0, false)
  1114  	amendOrder(t, tm, "party1", orderID3, 0, 0, types.OrderTimeInForceGFN, 0, false)
  1115  }
  1116  
  1117  func TestMarketPeggedOrders(t *testing.T) {
  1118  	t.Run("pegged orders must be LIMIT orders ", testPeggedOrderTypes)
  1119  	t.Run("pegged orders must be either GTT or GTC ", testPeggedOrderTIFs)
  1120  	t.Run("pegged orders buy side validation", testPeggedOrderBuys)
  1121  	t.Run("pegged orders sell side validation", testPeggedOrderSells)
  1122  	t.Run("pegged orders are parked when price below 0", testPeggedOrderParkWhenPriceBelowZero)
  1123  	t.Run("pegged orders are parked when price reprices below 0", testPeggedOrderParkWhenPriceRepricesBelowZero)
  1124  	t.Run("pegged order when there is no market prices", testPeggedOrderAddWithNoMarketPrice)
  1125  	t.Run("pegged order add to order book", testPeggedOrderAdd)
  1126  	t.Run("pegged order test when placing a pegged order forces a reprice", testPeggedOrderWithReprice)
  1127  	t.Run("pegged order entry during an auction", testPeggedOrderParkWhenInAuction)
  1128  	t.Run("Pegged orders unpark order after leaving auction", testPeggedOrderUnparkAfterLeavingAuction)
  1129  	t.Run("pegged order repricing", testPeggedOrderRepricing)
  1130  	t.Run("pegged order check that a filled pegged order is handled correctly", testPeggedOrderFilledOrder)
  1131  	t.Run("parked orders during normal trading are unparked when possible", testParkedOrdersAreUnparkedWhenPossible)
  1132  	t.Run("pegged orders are handled correctly when moving into auction", testPeggedOrdersEnteringAuction)
  1133  	t.Run("pegged orders are handled correctly when moving out of auction", testPeggedOrdersLeavingAuction)
  1134  	t.Run("pegged orders amend to move reference", testPeggedOrderAmendToMoveReference)
  1135  	t.Run("pegged orders are removed when expired", testPeggedOrderExpiring)
  1136  	t.Run("pegged orders unpark order due to reference becoming valid", testPeggedOrderUnpark)
  1137  	t.Run("pegged order cancel a parked order", testPeggedOrderCancelParked)
  1138  	t.Run("pegged order reprice when no limit orders", testPeggedOrderRepriceCrashWhenNoLimitOrders)
  1139  	t.Run("pegged orders cancelall", testPeggedOrderParkCancelAll)
  1140  	t.Run("pegged orders expiring 2", testPeggedOrderExpiring2)
  1141  	t.Run("pegged orders test for events produced", testPeggedOrderOutputMessages)
  1142  }
  1143  
  1144  func testPeggedOrderRepriceCrashWhenNoLimitOrders(t *testing.T) {
  1145  	now := time.Unix(10, 0)
  1146  	tm := getTestMarket(t, now, nil, nil)
  1147  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1148  
  1149  	addAccount(t, tm, "party1")
  1150  	addAccount(t, tm, "party2")
  1151  
  1152  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party2", 5, 9000)
  1153  
  1154  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party2", 10, 0)
  1155  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  1156  	_, err := tm.market.SubmitOrder(ctx, &order)
  1157  	require.NoError(t, err)
  1158  
  1159  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 5, 9000)
  1160  }
  1161  
  1162  func testPeggedOrderUnpark(t *testing.T) {
  1163  	now := time.Unix(10, 0)
  1164  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1165  		Duration: 1,
  1166  	})
  1167  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1168  
  1169  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1170  	addAccount(t, tm, "party1")
  1171  	addAccount(t, tm, "party2")
  1172  	addAccount(t, tm, auxParty)
  1173  	addAccount(t, tm, auxParty2)
  1174  	addAccountWithAmount(tm, "lpprov", 10000000)
  1175  
  1176  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  1177  	auxOrders := []*types.Order{
  1178  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  1179  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  1180  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1181  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1182  	}
  1183  	for _, o := range auxOrders {
  1184  		conf, err := tm.market.SubmitOrder(ctx, o)
  1185  		require.NoError(t, err)
  1186  		require.NotNil(t, conf)
  1187  	}
  1188  
  1189  	// Create a single buy order to give this party a valid position
  1190  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 5, 11)
  1191  
  1192  	// Add a pegged order which will park due to missing reference price
  1193  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1194  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  1195  	_, err := tm.market.SubmitOrder(ctx, &order)
  1196  	require.NoError(t, err)
  1197  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1198  	lp := &types.LiquidityProvisionSubmission{
  1199  		MarketID:         tm.market.GetID(),
  1200  		CommitmentAmount: num.NewUint(5000),
  1201  		Fee:              num.DecimalFromFloat(0.01),
  1202  	}
  1203  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1204  
  1205  	// leave opening auction
  1206  	now = now.Add(2 * time.Second)
  1207  	tm.now = now
  1208  	tm.market.OnTick(ctx, now)
  1209  	// Send a new order to set the BEST_ASK price and force the parked order to unpark
  1210  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party2", 5, 15)
  1211  
  1212  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1213  }
  1214  
  1215  func testPeggedOrderAmendToMoveReference(t *testing.T) {
  1216  	now := time.Unix(10, 0)
  1217  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1218  		Duration: 1,
  1219  	})
  1220  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1221  
  1222  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1223  	addAccount(t, tm, "party1")
  1224  	addAccount(t, tm, auxParty)
  1225  	addAccount(t, tm, auxParty2)
  1226  
  1227  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  1228  	auxOrders := []*types.Order{
  1229  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  1230  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  1231  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1232  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1233  	}
  1234  	for _, o := range auxOrders {
  1235  		conf, err := tm.market.SubmitOrder(ctx, o)
  1236  		require.NoError(t, err)
  1237  		require.NotNil(t, conf)
  1238  	}
  1239  	// leave opening auction
  1240  	now = now.Add(2 * time.Second)
  1241  	tm.now = now
  1242  	tm.market.OnTick(ctx, now)
  1243  
  1244  	// Place 2 orders to create valid reference prices
  1245  	bestBidOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  1246  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 110)
  1247  
  1248  	// Place a valid pegged order which will be added to the order book
  1249  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 100)
  1250  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  1251  	_, err := tm.market.SubmitOrder(ctx, &order)
  1252  	require.NoError(t, err)
  1253  
  1254  	// Amend best bid price
  1255  	amendOrder(t, tm, "party1", bestBidOrder, 0, 88, types.OrderTimeInForceUnspecified, 0, true)
  1256  	amendOrder(t, tm, "party1", bestBidOrder, 0, 86, types.OrderTimeInForceUnspecified, 0, true)
  1257  }
  1258  
  1259  func testPeggedOrderFilledOrder(t *testing.T) {
  1260  	now := time.Unix(10, 0)
  1261  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1262  		Duration: 1,
  1263  	})
  1264  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1265  
  1266  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1267  	addAccount(t, tm, "party1")
  1268  	addAccount(t, tm, "party2")
  1269  	addAccount(t, tm, auxParty)
  1270  	addAccount(t, tm, auxParty2)
  1271  	addAccountWithAmount(tm, "lpprov", 10000000)
  1272  
  1273  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  1274  	auxOrders := []*types.Order{
  1275  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 80),
  1276  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 120),
  1277  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1278  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1279  	}
  1280  	for _, o := range auxOrders {
  1281  		conf, err := tm.market.SubmitOrder(ctx, o)
  1282  		require.NoError(t, err)
  1283  		require.NotNil(t, conf)
  1284  	}
  1285  	lp := &types.LiquidityProvisionSubmission{
  1286  		MarketID:         tm.market.GetID(),
  1287  		CommitmentAmount: num.NewUint(5000),
  1288  		Fee:              num.DecimalFromFloat(0.01),
  1289  	}
  1290  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1291  	// leave opening auction
  1292  	now = now.Add(2 * time.Second)
  1293  	tm.now = now
  1294  	tm.market.OnTick(ctx, now)
  1295  
  1296  	// Place 2 orders to create valid reference prices
  1297  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  1298  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 110)
  1299  
  1300  	// Place a valid pegged order which will be added to the order book
  1301  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 100)
  1302  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1)
  1303  	_, err := tm.market.SubmitOrder(ctx, &order)
  1304  	require.NoError(t, err)
  1305  
  1306  	// Place a valid pegged order which will be added to the order book
  1307  	order = getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 100)
  1308  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 2)
  1309  	_, err = tm.market.SubmitOrder(ctx, &order)
  1310  	require.NoError(t, err)
  1311  
  1312  	// Place a sell MARKET order to fill the buy orders
  1313  	sendOrder(t, tm, &now, types.OrderTypeMarket, types.OrderTimeInForceIOC, 0, types.SideSell, "party2", 2, 0)
  1314  
  1315  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1316  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1317  }
  1318  
  1319  func testParkedOrdersAreUnparkedWhenPossible(t *testing.T) {
  1320  	now := time.Unix(10, 0)
  1321  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1322  		Duration: 1,
  1323  	})
  1324  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1325  
  1326  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1327  	addAccount(t, tm, "party1")
  1328  	addAccount(t, tm, "party2")
  1329  	addAccount(t, tm, auxParty)
  1330  	addAccount(t, tm, auxParty2)
  1331  	addAccountWithAmount(tm, "lpprov", 10000000)
  1332  
  1333  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  1334  	auxOrders := []*types.Order{
  1335  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  1336  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  1337  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1338  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1339  	}
  1340  	for _, o := range auxOrders {
  1341  		conf, err := tm.market.SubmitOrder(ctx, o)
  1342  		require.NoError(t, err)
  1343  		require.NotNil(t, conf)
  1344  	}
  1345  
  1346  	// Place 2 orders to create valid reference prices
  1347  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 5)
  1348  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1349  
  1350  	// Place a valid pegged order which will be parked because it cannot be repriced
  1351  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 1)
  1352  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  1353  	_, err := tm.market.SubmitOrder(ctx, &order)
  1354  	require.NoError(t, err)
  1355  
  1356  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1357  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1358  
  1359  	// Send a higher buy price order to move the BEST BID price up
  1360  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 50)
  1361  
  1362  	lp := &types.LiquidityProvisionSubmission{
  1363  		MarketID:         tm.market.GetID(),
  1364  		CommitmentAmount: num.NewUint(5000),
  1365  		Fee:              num.DecimalFromFloat(0.01),
  1366  	}
  1367  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1368  	// leave opening auction
  1369  	now = now.Add(2 * time.Second)
  1370  	tm.now = now
  1371  	tm.market.OnTick(ctx, now)
  1372  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1373  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1374  }
  1375  
  1376  func testPeggedOrdersLeavingAuction(t *testing.T) {
  1377  	now := time.Unix(10, 0)
  1378  	auctionClose := now.Add(101 * time.Second)
  1379  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1380  		Duration: 100,
  1381  	})
  1382  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1383  
  1384  	addAccount(t, tm, "party1")
  1385  	addAccount(t, tm, "party2")
  1386  	addAccount(t, tm, "party3")
  1387  	addAccountWithAmount(tm, "lpprov", 10000000)
  1388  
  1389  	// Move into auction
  1390  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, 100*time.Second)
  1391  
  1392  	// Place 2 orders to create valid reference prices
  1393  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  1394  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1395  	// place 2 more orders that will result in a mark price being set
  1396  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party2", 1, 95)
  1397  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party3", 1, 95)
  1398  
  1399  	// Pegged order must be a LIMIT order
  1400  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1401  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 10)
  1402  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1403  	require.NoError(t, err)
  1404  	assert.NotNil(t, confirmation)
  1405  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusParked)
  1406  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1407  	// During an auction all pegged orders are parked so we don't add them to the list
  1408  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1409  
  1410  	lp := &types.LiquidityProvisionSubmission{
  1411  		MarketID:         tm.market.GetID(),
  1412  		CommitmentAmount: num.NewUint(5000),
  1413  		Fee:              num.DecimalFromFloat(0.01),
  1414  	}
  1415  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1416  	// Update the time to force the auction to end
  1417  	tm.now = auctionClose
  1418  	tm.market.OnTick(ctx, auctionClose)
  1419  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1420  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1421  }
  1422  
  1423  func testPeggedOrdersEnteringAuction(t *testing.T) {
  1424  	now := time.Unix(10, 0)
  1425  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1426  		Duration: 100,
  1427  	})
  1428  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1429  
  1430  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1431  	addAccount(t, tm, "party1")
  1432  	addAccount(t, tm, "party2")
  1433  	addAccount(t, tm, "party3")
  1434  	addAccount(t, tm, auxParty)
  1435  	addAccount(t, tm, auxParty2)
  1436  
  1437  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, 100*time.Second)
  1438  	// Place 2 orders to create valid reference prices
  1439  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  1440  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 100)
  1441  	// place 2 more orders that will result in a mark price being set
  1442  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party2", 1, 95)
  1443  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party3", 1, 95)
  1444  
  1445  	// Pegged order must be a LIMIT order
  1446  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1447  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 10)
  1448  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1449  	require.NoError(t, err)
  1450  	assert.NotNil(t, confirmation)
  1451  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusParked)
  1452  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1453  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1454  
  1455  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1456  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1457  }
  1458  
  1459  func testPeggedOrderAddWithNoMarketPrice(t *testing.T) {
  1460  	now := time.Unix(10, 0)
  1461  	tm := getTestMarket(t, now, nil, nil)
  1462  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1463  
  1464  	addAccount(t, tm, "party1")
  1465  
  1466  	// Place a valid pegged order which will be parked
  1467  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1468  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1469  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1470  	assert.NotNil(t, confirmation)
  1471  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusParked)
  1472  	assert.NoError(t, err)
  1473  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  1474  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  1475  }
  1476  
  1477  func testPeggedOrderAdd(t *testing.T) {
  1478  	now := time.Unix(10, 0)
  1479  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1480  		Duration: 1,
  1481  	})
  1482  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1483  
  1484  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1485  	addAccount(t, tm, "party1")
  1486  	addAccount(t, tm, auxParty)
  1487  	addAccount(t, tm, auxParty2)
  1488  	addAccountWithAmount(tm, "lpprov", 10000000)
  1489  
  1490  	auxOrders := []*types.Order{
  1491  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  1492  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  1493  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1494  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1495  	}
  1496  	for _, o := range auxOrders {
  1497  		conf, err := tm.market.SubmitOrder(ctx, o)
  1498  		require.NoError(t, err)
  1499  		require.NotNil(t, conf)
  1500  	}
  1501  	lp := &types.LiquidityProvisionSubmission{
  1502  		MarketID:         tm.market.GetID(),
  1503  		CommitmentAmount: num.NewUint(25000),
  1504  		Fee:              num.DecimalFromFloat(0.01),
  1505  	}
  1506  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1507  	// leave auction
  1508  	now = now.Add(2 * time.Second)
  1509  	tm.now = now
  1510  	tm.market.OnTick(ctx, now)
  1511  
  1512  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1513  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1514  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1515  	assert.NotNil(t, confirmation)
  1516  	assert.Equal(t, types.OrderStatusActive, confirmation.Order.Status)
  1517  	require.NoError(t, err)
  1518  
  1519  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 100)
  1520  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 102)
  1521  
  1522  	// Place a valid pegged order which will be added to the order book
  1523  	order = getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1524  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1525  	confirmation, err = tm.market.SubmitOrder(ctx, &order)
  1526  	require.NoError(t, err)
  1527  
  1528  	assert.NotNil(t, confirmation)
  1529  	assert.Equal(t, types.OrderStatusActive, confirmation.Order.Status)
  1530  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1531  	assert.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1532  
  1533  	assert.True(t, order.Price.EQ(num.NewUint(500047)), order.Price.String())
  1534  }
  1535  
  1536  func testPeggedOrderWithReprice(t *testing.T) {
  1537  	now := time.Unix(10, 0)
  1538  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  1539  		Duration: 1,
  1540  	})
  1541  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1542  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  1543  
  1544  	auxParty, auxParty2 := "auxParty", "auxParty2"
  1545  	addAccount(t, tm, "party1")
  1546  	addAccount(t, tm, auxParty)
  1547  	addAccount(t, tm, auxParty2)
  1548  	addAccountWithAmount(tm, "lpprov", 10000000)
  1549  
  1550  	auxOrders := []*types.Order{
  1551  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  1552  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  1553  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1554  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1555  	}
  1556  	for _, o := range auxOrders {
  1557  		conf, err := tm.market.SubmitOrder(ctx, o)
  1558  		require.NoError(t, err)
  1559  		require.NotNil(t, conf)
  1560  	}
  1561  	lp := &types.LiquidityProvisionSubmission{
  1562  		MarketID:         tm.market.GetID(),
  1563  		CommitmentAmount: num.NewUint(25000),
  1564  		Fee:              num.DecimalFromFloat(0.01),
  1565  	}
  1566  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  1567  	// leave auction
  1568  	now = now.Add(2 * time.Second)
  1569  	tm.now = now
  1570  	tm.market.OnTick(ctx, now)
  1571  
  1572  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1573  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1574  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1575  	assert.NotNil(t, confirmation)
  1576  	assert.Equal(t, types.OrderStatusActive, confirmation.Order.Status)
  1577  	require.NoError(t, err)
  1578  
  1579  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  1580  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 110)
  1581  
  1582  	md := tm.market.GetMarketData()
  1583  	assert.True(t, md.StaticMidPrice.EQ(num.NewUint(500045)), md.StaticMidPrice.String())
  1584  	// MidPrice > StaticMidPrice as LP volume range pushes LP orders in front of best bid / ask
  1585  	assert.True(t, md.MidPrice.EQ(num.NewUint(750021)), md.MidPrice.String())
  1586  	// Place a valid pegged order which will be added to the order book
  1587  	// This order will cause the MID price to move and thus a reprice multiple times until it settles
  1588  	order = getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1589  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1590  	_, err = tm.market.SubmitOrder(ctx, &order)
  1591  	require.NoError(t, err)
  1592  
  1593  	// Check to make sure the existing pegged order is repriced correctly
  1594  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1595  	assert.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1596  }
  1597  
  1598  func testPeggedOrderParkWhenInAuction(t *testing.T) {
  1599  	now := time.Unix(10, 0)
  1600  	tm := getTestMarket(t, now, nil, nil)
  1601  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1602  
  1603  	addAccount(t, tm, "party1")
  1604  
  1605  	// Move into auction
  1606  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 100})
  1607  	tm.market.EnterAuction(ctx)
  1608  
  1609  	// Pegged order must be a LIMIT order
  1610  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1611  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1612  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1613  	assert.NotNil(t, confirmation)
  1614  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusParked)
  1615  	assert.NoError(t, err)
  1616  }
  1617  
  1618  func testPeggedOrderUnparkAfterLeavingAuction(t *testing.T) {
  1619  	now := time.Unix(10, 0)
  1620  	closeSec := int64(10000000000)
  1621  	closingAt := time.Unix(closeSec, 0)
  1622  	tm := getTestMarket(t, now, nil, nil)
  1623  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1624  
  1625  	addAccount(t, tm, "party1")
  1626  
  1627  	// Move into auction
  1628  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 100})
  1629  	tm.market.EnterAuction(ctx)
  1630  
  1631  	// Pegged order must be a LIMIT order
  1632  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1633  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  1634  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1635  	assert.NotNil(t, confirmation)
  1636  	assert.Equal(t, confirmation.Order.Status, types.OrderStatusParked)
  1637  	assert.NoError(t, err)
  1638  
  1639  	buy := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 90)
  1640  	confirmation, err = tm.market.SubmitOrder(context.Background(), &buy)
  1641  	require.NotNil(t, confirmation)
  1642  	assert.NoError(t, err)
  1643  
  1644  	require.NotNil(t, buy)
  1645  	sell := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 110)
  1646  	confirmation, err = tm.market.SubmitOrder(context.Background(), &sell)
  1647  	require.NotNil(t, confirmation)
  1648  	assert.NoError(t, err)
  1649  
  1650  	tm.market.LeaveAuctionWithIDGen(ctx, closingAt, newTestIDGenerator())
  1651  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1652  }
  1653  
  1654  func testPeggedOrderTypes(t *testing.T) {
  1655  	now := time.Unix(10, 0)
  1656  	tm := getTestMarket(t, now, nil, nil)
  1657  
  1658  	addAccount(t, tm, "party1")
  1659  
  1660  	// Pegged order must be a LIMIT order
  1661  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1662  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1663  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  1664  	assert.NotNil(t, confirmation)
  1665  	assert.NoError(t, err)
  1666  
  1667  	// Not MARKET
  1668  	order.Type = types.OrderTypeMarket
  1669  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1670  	assert.Nil(t, confirmation)
  1671  	assert.Error(t, err)
  1672  }
  1673  
  1674  func testPeggedOrderCancelParked(t *testing.T) {
  1675  	now := time.Unix(10, 0)
  1676  	tm := getTestMarket(t, now, nil, nil)
  1677  
  1678  	addAccount(t, tm, "party1")
  1679  
  1680  	// Pegged order will be parked as no reference prices
  1681  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1682  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1683  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  1684  	require.NotNil(t, confirmation)
  1685  	assert.NoError(t, err)
  1686  }
  1687  
  1688  func testPeggedOrderTIFs(t *testing.T) {
  1689  	now := time.Unix(10, 0)
  1690  	tm := getTestMarket(t, now, nil, nil)
  1691  
  1692  	addAccount(t, tm, "party1")
  1693  
  1694  	// Pegged order must be a LIMIT order
  1695  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1696  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1697  
  1698  	// Only allowed GTC
  1699  	order.Type = types.OrderTypeLimit
  1700  	order.TimeInForce = types.OrderTimeInForceGTC
  1701  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  1702  	assert.NotNil(t, confirmation)
  1703  	assert.NoError(t, err)
  1704  
  1705  	// and GTT
  1706  	order.TimeInForce = types.OrderTimeInForceGTT
  1707  	order.ExpiresAt = now.UnixNano() + 1000000000
  1708  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1709  	assert.NotNil(t, confirmation)
  1710  	assert.NoError(t, err)
  1711  
  1712  	// but not IOC
  1713  	order.ExpiresAt = 0
  1714  	order.TimeInForce = types.OrderTimeInForceIOC
  1715  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1716  	assert.Nil(t, confirmation)
  1717  	assert.Error(t, err)
  1718  
  1719  	// or FOK
  1720  	order.TimeInForce = types.OrderTimeInForceFOK
  1721  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1722  	assert.Nil(t, confirmation)
  1723  	assert.Error(t, err)
  1724  }
  1725  
  1726  func testPeggedOrderBuys(t *testing.T) {
  1727  	now := time.Unix(10, 0)
  1728  	tm := getTestMarket(t, now, nil, nil)
  1729  
  1730  	addAccount(t, tm, "party1")
  1731  
  1732  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 100)
  1733  
  1734  	// BEST BID peg must be >= 0
  1735  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  1736  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  1737  	assert.NotNil(t, confirmation)
  1738  	assert.NoError(t, err)
  1739  
  1740  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 0)
  1741  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1742  	assert.NotNil(t, confirmation)
  1743  	assert.NoError(t, err)
  1744  
  1745  	// MID peg must be > 0
  1746  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 0)
  1747  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1748  	assert.Nil(t, confirmation)
  1749  	assert.Error(t, err)
  1750  
  1751  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1752  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1753  	assert.NotNil(t, confirmation)
  1754  	assert.NoError(t, err)
  1755  
  1756  	// BEST ASK peg not allowed
  1757  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 3)
  1758  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1759  	assert.Nil(t, confirmation)
  1760  	assert.Error(t, err)
  1761  
  1762  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 3)
  1763  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1764  	assert.Nil(t, confirmation)
  1765  	assert.Error(t, err)
  1766  
  1767  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 0)
  1768  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1769  	assert.Nil(t, confirmation)
  1770  	assert.Error(t, err)
  1771  }
  1772  
  1773  func testPeggedOrderSells(t *testing.T) {
  1774  	now := time.Unix(10, 0)
  1775  	tm := getTestMarket(t, now, nil, nil)
  1776  
  1777  	addAccount(t, tm, "party1")
  1778  
  1779  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 100)
  1780  
  1781  	// BEST BID peg not allowed
  1782  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  1783  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  1784  	assert.Nil(t, confirmation)
  1785  	assert.Error(t, err)
  1786  
  1787  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  1788  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1789  	assert.Nil(t, confirmation)
  1790  	assert.Error(t, err)
  1791  
  1792  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 0)
  1793  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1794  	assert.Nil(t, confirmation)
  1795  	assert.Error(t, err)
  1796  
  1797  	// MID peg must be > 0
  1798  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 0)
  1799  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1800  	assert.Nil(t, confirmation)
  1801  	assert.Error(t, err)
  1802  
  1803  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 3)
  1804  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1805  	assert.NotNil(t, confirmation)
  1806  	assert.NoError(t, err)
  1807  
  1808  	// BEST ASK peg must be >= 0
  1809  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 3)
  1810  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1811  	assert.NotNil(t, confirmation)
  1812  	assert.NoError(t, err)
  1813  
  1814  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 0)
  1815  	confirmation, err = tm.market.SubmitOrder(context.Background(), &order)
  1816  	assert.NotNil(t, confirmation)
  1817  	assert.NoError(t, err)
  1818  }
  1819  
  1820  func testPeggedOrderParkWhenPriceBelowZero(t *testing.T) {
  1821  	now := time.Unix(10, 0)
  1822  	tm := getTestMarket(t, now, nil, nil)
  1823  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1824  
  1825  	for _, acc := range []string{"buyer", "seller", "pegged"} {
  1826  		addAccount(t, tm, acc)
  1827  	}
  1828  
  1829  	buy := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "buyer", 10, 4)
  1830  	_, err := tm.market.SubmitOrder(ctx, &buy)
  1831  	require.NoError(t, err)
  1832  
  1833  	sell := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "seller", 10, 8)
  1834  	_, err = tm.market.SubmitOrder(ctx, &sell)
  1835  	require.NoError(t, err)
  1836  
  1837  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "pegged", 10, 4)
  1838  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 10)
  1839  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1840  	require.NoError(t, err)
  1841  	assert.Equal(t,
  1842  		types.OrderStatusParked.String(),
  1843  		confirmation.Order.Status.String(), "When pegged price below zero (MIDPRICE - OFFSET) <= 0")
  1844  }
  1845  
  1846  func testPeggedOrderParkWhenPriceRepricesBelowZero(t *testing.T) {
  1847  	now := time.Unix(10, 0)
  1848  	tm := getTestMarket(t, now, nil, nil)
  1849  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1850  
  1851  	for _, acc := range []string{"buyer", "seller", "pegged"} {
  1852  		addAccount(t, tm, acc)
  1853  	}
  1854  
  1855  	buy := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "buyer", 10, 4)
  1856  	_, err := tm.market.SubmitOrder(ctx, &buy)
  1857  	require.NoError(t, err)
  1858  
  1859  	sell := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "seller", 10, 8)
  1860  	_, err = tm.market.SubmitOrder(ctx, &sell)
  1861  	require.NoError(t, err)
  1862  
  1863  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "pegged", 10, 4)
  1864  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 5)
  1865  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1866  	require.NoError(t, err)
  1867  
  1868  	amendOrder(t, tm, "buyer", buy.ID, 0, 1, types.OrderTimeInForceUnspecified, 0, true)
  1869  
  1870  	assert.Equal(t, types.OrderStatusParked.String(), confirmation.Order.Status.String())
  1871  }
  1872  
  1873  /*func TestPeggedOrderCrash(t *testing.T) {
  1874  	now := time.Unix(10, 0)
  1875  	closeSec := int64(10000000000)
  1876  	closingAt := time.Unix(closeSec, 0)
  1877  	tm := getTestMarket(t, now, closingAt, nil, nil)
  1878  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1879  
  1880  	for _, acc := range []string{"user1", "user2", "user3", "user4", "user5", "user6", "user7"} {
  1881  		addAccount(tm, acc)
  1882  	}
  1883  
  1884  	// Set up the best bid/ask values
  1885  	sendOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_BUY, "user1", 5, 10500)
  1886  	sendOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_SELL, "user2", 20, 11000)
  1887  
  1888  	// Pegged order buy 35 MID -500
  1889  	order := getOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_BUY, "user3", 35, 0)
  1890  	order.PeggedOrder = getPeggedOrder(types.PeggedReference_PEGGED_REFERENCE_MID,500)
  1891  	_, err := tm.market.SubmitOrder(ctx, &order)
  1892  	require.NoError(t, err)
  1893  
  1894  	// Pegged order buy 16 BEST_BID -2000
  1895  	order2 := getOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_BUY, "user4", 16, 0)
  1896  	order2.PeggedOrder = getPeggedOrder(types.PeggedReference_PEGGED_REFERENCE_BEST_BID,2000)
  1897  	_, err = tm.market.SubmitOrder(ctx, &order2)
  1898  	require.NoError(t, err)
  1899  
  1900  	// Pegged order sell 19 BEST_ASK 3000
  1901  	order3 := getOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_SELL, "user5", 19, 0)
  1902  	order3.PeggedOrder = getPeggedOrder(types.PeggedReference_PEGGED_REFERENCE_BEST_ASK,3000)
  1903  	_, err = tm.market.SubmitOrder(ctx, &order3)
  1904  	require.NoError(t, err)
  1905  
  1906  	// Buy 25 @ 10000
  1907  	sendOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_BUY, "user6", 25, 10000)
  1908  
  1909  	// Sell 25 @ 10250
  1910  	sendOrder(t, tm, &now, types.Order_TYPE_LIMIT, types.Order_TIME_IN_FORCE_GTC, 0, types.Side_SIDE_SELL, "user7", 25, 10250)
  1911  }*/
  1912  
  1913  func testPeggedOrderParkCancelAll(t *testing.T) {
  1914  	now := time.Unix(10, 0)
  1915  	tm := getTestMarket(t, now, nil, nil)
  1916  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1917  
  1918  	addAccount(t, tm, "user")
  1919  
  1920  	// Send one normal order
  1921  	limitOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user", 10, 100)
  1922  	require.NotEmpty(t, limitOrder)
  1923  
  1924  	// Send one pegged order that is live
  1925  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user", 10, 0)
  1926  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 5)
  1927  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1928  	require.NoError(t, err)
  1929  	assert.NotNil(t, confirmation)
  1930  
  1931  	// Send one pegged order that is parked
  1932  	order2 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user", 10, 0)
  1933  	order2.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 5)
  1934  	confirmation2, err := tm.market.SubmitOrder(ctx, &order2)
  1935  	require.NoError(t, err)
  1936  	assert.NotNil(t, confirmation2)
  1937  
  1938  	cancelConf, err := tm.market.CancelAllOrders(ctx, "user")
  1939  	require.NoError(t, err)
  1940  	require.NotNil(t, cancelConf)
  1941  	assert.Equal(t, 3, len(cancelConf))
  1942  }
  1943  
  1944  func testPeggedOrderExpiring2(t *testing.T) {
  1945  	now := time.Unix(10, 0)
  1946  	expire := now.Add(time.Second * 100)
  1947  	afterexpire := now.Add(time.Second * 200)
  1948  	tm := getTestMarket(t, now, nil, nil)
  1949  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1950  
  1951  	addAccount(t, tm, "user")
  1952  
  1953  	// Send one normal expiring order
  1954  	limitOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTT, expire.UnixNano(), types.SideBuy, "user", 10, 100)
  1955  	require.NotEmpty(t, limitOrder)
  1956  
  1957  	// Amend the expiry time
  1958  	amendOrder(t, tm, "user", limitOrder, 0, 0, types.OrderTimeInForceUnspecified, now.UnixNano(), true)
  1959  
  1960  	// Send one pegged order that will be parked
  1961  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTT, expire.UnixNano(), types.SideBuy, "user", 10, 0)
  1962  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 5)
  1963  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  1964  	require.NoError(t, err)
  1965  	assert.NotNil(t, confirmation)
  1966  
  1967  	// Send one pegged order that will also be parked (after additing liquidity monitoring to market all orders will be parked unless both best_bid and best_offer exist)
  1968  	order2 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTT, expire.UnixNano(), types.SideBuy, "user", 10, 0)
  1969  	order2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 5)
  1970  	confirmation, err = tm.market.SubmitOrder(ctx, &order2)
  1971  	require.NoError(t, err)
  1972  	assert.NotNil(t, confirmation)
  1973  	tm.now = tm.now.Add(time.Second)
  1974  	tm.market.OnTick(ctx, tm.now)
  1975  
  1976  	// the limit order has expired so the order pegged to it has to be parked!
  1977  	assert.Equal(t, 2, tm.market.GetParkedOrderCount())
  1978  	assert.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1979  
  1980  	// Move the time forward
  1981  	tm.events = nil
  1982  	tm.market.OnTick(ctx, afterexpire)
  1983  	t.Run("3 orders expired", func(t *testing.T) {
  1984  		// First collect all the orders events
  1985  		orders := []string{}
  1986  		for _, e := range tm.events {
  1987  			switch evt := e.(type) {
  1988  			case *events.ExpiredOrders:
  1989  				orders = append(orders, evt.OrderIDs()...)
  1990  			}
  1991  		}
  1992  		require.Len(t, orders, 2)
  1993  		// Check that we have no pegged orders
  1994  		assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  1995  		assert.Equal(t, 0, tm.market.GetPeggedOrderCount())
  1996  	})
  1997  }
  1998  
  1999  func testPeggedOrderOutputMessages(t *testing.T) {
  2000  	now := time.Unix(10, 0)
  2001  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2002  		Duration: 1,
  2003  	})
  2004  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2005  
  2006  	addAccount(t, tm, "user1")
  2007  	addAccount(t, tm, "user2")
  2008  	addAccount(t, tm, "user3")
  2009  	addAccount(t, tm, "user4")
  2010  	addAccount(t, tm, "user5")
  2011  	addAccount(t, tm, "user6")
  2012  	auxParty := "auxParty"
  2013  	auxParty2 := "auxParty2"
  2014  	addAccount(t, tm, auxParty)
  2015  	addAccount(t, tm, auxParty2)
  2016  	addAccountWithAmount(tm, "lpprov", 10000000)
  2017  
  2018  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2019  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  2020  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  2021  	require.NotNil(t, conf)
  2022  	require.NoError(t, err)
  2023  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2024  
  2025  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  2026  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  2027  	require.NotNil(t, conf)
  2028  	require.NoError(t, err)
  2029  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2030  
  2031  	auxOrders := []*types.Order{
  2032  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  2033  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  2034  	}
  2035  	for _, o := range auxOrders {
  2036  		conf, err := tm.market.SubmitOrder(ctx, o)
  2037  		require.NoError(t, err)
  2038  		require.NotNil(t, conf)
  2039  	}
  2040  	lp := &types.LiquidityProvisionSubmission{
  2041  		MarketID:         tm.market.GetID(),
  2042  		CommitmentAmount: num.NewUint(5000),
  2043  		Fee:              num.DecimalFromFloat(0.01),
  2044  	}
  2045  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2046  	// leave opening auction
  2047  	now = now.Add(2 * time.Second)
  2048  	tm.now = now
  2049  	tm.market.OnTick(ctx, now)
  2050  
  2051  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "user1", 10, 0)
  2052  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  2053  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  2054  	require.NoError(t, err)
  2055  	assert.NotNil(t, confirmation)
  2056  	assert.Equal(t, 7, int(tm.orderEventCount))
  2057  
  2058  	order2 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "user2", 10, 0)
  2059  	order2.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 15)
  2060  	confirmation2, err := tm.market.SubmitOrder(ctx, &order2)
  2061  	require.NoError(t, err)
  2062  	assert.NotNil(t, confirmation2)
  2063  	assert.Equal(t, 8, int(tm.orderEventCount))
  2064  
  2065  	order3 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user3", 10, 0)
  2066  	order3.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  2067  	confirmation3, err := tm.market.SubmitOrder(ctx, &order3)
  2068  	require.NoError(t, err)
  2069  	assert.NotNil(t, confirmation3)
  2070  	assert.Equal(t, 9, int(tm.orderEventCount))
  2071  
  2072  	order4 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user4", 10, 0)
  2073  	order4.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 10)
  2074  	confirmation4, err := tm.market.SubmitOrder(ctx, &order4)
  2075  	require.NoError(t, err)
  2076  	assert.NotNil(t, confirmation4)
  2077  	assert.Equal(t, 10, int(tm.orderEventCount))
  2078  
  2079  	limitOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "user5", 1000, 120)
  2080  	require.NotEmpty(t, limitOrder)
  2081  	// force reference price  checks result in more events
  2082  	// assert.Equal(t, int(28), int(tm.orderEventCount))
  2083  	assert.Equal(t, 14, int(tm.orderEventCount))
  2084  
  2085  	limitOrder2 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "user6", 1000, 80)
  2086  	require.NotEmpty(t, limitOrder2)
  2087  	// assert.Equal(t, int(35), int(tm.orderEventCount))
  2088  	assert.Equal(t, 17, int(tm.orderEventCount))
  2089  }
  2090  
  2091  func testPeggedOrderRepricing(t *testing.T) {
  2092  	// Create the market
  2093  	now := time.Unix(10, 0)
  2094  
  2095  	var (
  2096  		buyPrice  uint64 = 90
  2097  		sellPrice uint64 = 110
  2098  		midPrice         = (sellPrice + buyPrice) / 2
  2099  	)
  2100  
  2101  	tests := []struct {
  2102  		reference      types.PeggedReference
  2103  		side           types.Side
  2104  		offset         uint64
  2105  		expectedPrice  *num.Uint
  2106  		expectingError string
  2107  	}{
  2108  		{
  2109  			reference:     types.PeggedReferenceBestBid,
  2110  			side:          types.SideBuy,
  2111  			offset:        3,
  2112  			expectedPrice: num.NewUint(buyPrice - 3),
  2113  		},
  2114  		{
  2115  			reference:      types.PeggedReferenceBestAsk,
  2116  			side:           types.SideBuy,
  2117  			offset:         0,
  2118  			expectedPrice:  num.UintZero(),
  2119  			expectingError: "offset must be greater than zero",
  2120  		},
  2121  		{
  2122  			reference:     types.PeggedReferenceMid,
  2123  			side:          types.SideBuy,
  2124  			offset:        5,
  2125  			expectedPrice: num.NewUint(midPrice - 5),
  2126  		},
  2127  		{
  2128  			reference:     types.PeggedReferenceMid,
  2129  			side:          types.SideSell,
  2130  			offset:        5,
  2131  			expectedPrice: num.NewUint(midPrice + 5),
  2132  		},
  2133  		{
  2134  			reference:     types.PeggedReferenceBestAsk,
  2135  			side:          types.SideSell,
  2136  			offset:        5,
  2137  			expectedPrice: num.NewUint(sellPrice + 5),
  2138  		},
  2139  	}
  2140  
  2141  	for _, test := range tests {
  2142  		t.Run("", func(t *testing.T) {
  2143  			// Create market
  2144  			tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2145  				Duration: 1,
  2146  			})
  2147  			ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2148  			tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2149  
  2150  			auxParty, auxParty2 := "auxParty", "auxParty2"
  2151  			addAccount(t, tm, "party1")
  2152  			addAccount(t, tm, auxParty)
  2153  			addAccount(t, tm, auxParty2)
  2154  			addAccountWithAmount(tm, "lpprov", 10000000)
  2155  
  2156  			auxOrders := []*types.Order{
  2157  				getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 80),
  2158  				getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 120),
  2159  				getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  2160  				getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  2161  			}
  2162  			for _, o := range auxOrders {
  2163  				conf, err := tm.market.SubmitOrder(ctx, o)
  2164  				require.NoError(t, err)
  2165  				require.NotNil(t, conf)
  2166  			}
  2167  			lp := &types.LiquidityProvisionSubmission{
  2168  				MarketID:         tm.market.GetID(),
  2169  				CommitmentAmount: num.NewUint(25000),
  2170  				Fee:              num.DecimalFromFloat(0.01),
  2171  			}
  2172  			require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2173  			// leave auction
  2174  			now := now.Add(2 * time.Second)
  2175  			tm.now = now
  2176  			tm.market.OnTick(ctx, now)
  2177  
  2178  			// Create buy and sell orders
  2179  			sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, buyPrice)
  2180  			sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, sellPrice)
  2181  
  2182  			// Create pegged order
  2183  			order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, test.side, "party1", 10, 0)
  2184  			order.PeggedOrder = newPeggedOrder(test.reference, test.offset)
  2185  			conf, err := tm.market.SubmitOrder(context.Background(), &order)
  2186  			if msg := test.expectingError; msg != "" {
  2187  				require.Error(t, err, msg)
  2188  			} else {
  2189  				require.NoError(t, err)
  2190  				assert.True(t, test.expectedPrice.EQ(conf.Order.Price), conf.Order.Price)
  2191  			}
  2192  		})
  2193  	}
  2194  }
  2195  
  2196  func testPeggedOrderExpiring(t *testing.T) {
  2197  	// Create the market
  2198  	now := time.Unix(10, 0)
  2199  
  2200  	tm := getTestMarket(t, now, nil, nil)
  2201  	addAccount(t, tm, "party")
  2202  
  2203  	// Create buy and sell orders
  2204  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party", 1, 100)
  2205  	sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party", 1, 200)
  2206  
  2207  	// let's create N orders with different expiration time
  2208  	expirations := []struct {
  2209  		party      string
  2210  		expiration time.Time
  2211  	}{
  2212  		{"party-10", now.Add(10 * time.Minute)},
  2213  		{"party-20", now.Add(20 * time.Minute)},
  2214  		{"party-30", now.Add(30 * time.Minute)},
  2215  	}
  2216  	for _, test := range expirations {
  2217  		addAccount(t, tm, test.party)
  2218  
  2219  		order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTT, 0, types.SideBuy, test.party, 10, 150)
  2220  		order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  2221  		order.ExpiresAt = test.expiration.UnixNano()
  2222  		_, err := tm.market.SubmitOrder(context.Background(), &order)
  2223  		require.NoError(t, err)
  2224  	}
  2225  	assert.Equal(t, len(expirations), tm.market.GetPeggedOrderCount())
  2226  
  2227  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2228  	tm.events = nil
  2229  	tm.market.OnTick(ctx, now.Add(25*time.Minute))
  2230  	t.Run("2 orders expired", func(t *testing.T) {
  2231  		// First collect all the orders events
  2232  		orders := []string{}
  2233  		for _, e := range tm.events {
  2234  			switch evt := e.(type) {
  2235  			case *events.ExpiredOrders:
  2236  				orders = append(orders, evt.OrderIDs()...)
  2237  			}
  2238  		}
  2239  
  2240  		assert.Equal(t, 2, len(orders))
  2241  		assert.Equal(t, 1, tm.market.GetPeggedOrderCount(), "1 order should still be in the market")
  2242  	})
  2243  }
  2244  
  2245  func TestPeggedOrdersAmends(t *testing.T) {
  2246  	t.Run("pegged orders amend an order that is parked but becomes live ", testPeggedOrderAmendParkedToLive)
  2247  	t.Run("pegged orders amend an order that is parked and remains parked", testPeggedOrderAmendParkedStayParked)
  2248  	t.Run("pegged orders amend an order that is live but becomes parked", testPeggedOrderAmendForcesPark)
  2249  	t.Run("pegged orders amend an order while in auction", testPeggedOrderAmendDuringAuction)
  2250  	t.Run("pegged orders amend an orders pegged reference", testPeggedOrderAmendReference)
  2251  	t.Run("pegged orders amend an orders pegged reference during an auction", testPeggedOrderAmendReferenceInAuction)
  2252  	t.Run("pegged orders amend multiple fields at once", testPeggedOrderAmendMultiple)
  2253  	t.Run("pegged orders amend multiple fields at once in an auction", testPeggedOrderAmendMultipleInAuction)
  2254  	t.Run("pegged orders delete an order that has lost time priority", testPeggedOrderCanDeleteAfterLostPriority)
  2255  	t.Run("pegged orders validate mid price values", testPeggedOrderMidPriceCalc)
  2256  }
  2257  
  2258  // We had a case where things crashed when the orders on the same price level were not sorted
  2259  // in createdAt order. Test this by creating a pegged order and repricing to make it lose it's time order.
  2260  func testPeggedOrderCanDeleteAfterLostPriority(t *testing.T) {
  2261  	now := time.Unix(10, 0)
  2262  	tm := getTestMarket(t, now, nil, nil)
  2263  
  2264  	addAccount(t, tm, "party1")
  2265  
  2266  	// Place trades so we have a valid BEST_BID
  2267  	buyOrder1 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 100)
  2268  	require.NotNil(t, buyOrder1)
  2269  
  2270  	// Place the pegged order
  2271  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2272  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  2273  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  2274  	require.NotNil(t, confirmation)
  2275  	assert.NoError(t, err)
  2276  
  2277  	// Place a normal limit order behind the pegged order
  2278  	buyOrder2 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  2279  	require.NotNil(t, buyOrder2)
  2280  
  2281  	// Amend first order to move pegged
  2282  	amendOrder(t, tm, "party1", buyOrder1, 0, 101, types.OrderTimeInForceUnspecified, 0, true)
  2283  	// Amend again to make the pegged order reprice behind the second limit order
  2284  	amendOrder(t, tm, "party1", buyOrder1, 0, 100, types.OrderTimeInForceUnspecified, 0, true)
  2285  
  2286  	// Try to delete the pegged order
  2287  	cancelconf, _ := tm.market.CancelOrder(context.TODO(), "party1", order.ID, vgcrypto.RandomHash())
  2288  	assert.NotNil(t, cancelconf)
  2289  	assert.Equal(t, types.OrderStatusCancelled, cancelconf.Order.Status)
  2290  }
  2291  
  2292  // If we amend an order that is parked and not in auction we need to see if the amendment has caused the
  2293  // order to be unparkable. If so we will have to put it back on the live book.
  2294  func testPeggedOrderAmendParkedToLive(t *testing.T) {
  2295  	now := time.Unix(10, 0)
  2296  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2297  		Duration: 1,
  2298  	})
  2299  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2300  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2301  
  2302  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2303  	addAccount(t, tm, "party1")
  2304  	addAccount(t, tm, auxParty)
  2305  	addAccount(t, tm, auxParty2)
  2306  	addAccountWithAmount(tm, "lpprov", 10000000)
  2307  
  2308  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2309  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2310  	require.NotNil(t, buyOrder)
  2311  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2312  	require.NotNil(t, sellOrder)
  2313  	auxOrders := []*types.Order{
  2314  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 10),
  2315  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 10),
  2316  	}
  2317  	for _, o := range auxOrders {
  2318  		conf, err := tm.market.SubmitOrder(ctx, o)
  2319  		assert.NoError(t, err)
  2320  		assert.NotNil(t, conf)
  2321  	}
  2322  
  2323  	// Place the pegged order which will be parked
  2324  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2325  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 20)
  2326  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  2327  	require.NotNil(t, confirmation)
  2328  	assert.NoError(t, err)
  2329  
  2330  	// Amend offset so we can reprice
  2331  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2332  	off := num.NewUint(5)
  2333  	amend.PeggedOffset = off
  2334  	amended, err := tm.market.AmendOrder(ctx, amend, "party1", vgcrypto.RandomHash())
  2335  	require.NotNil(t, amended)
  2336  	assert.Equal(t, off, amended.Order.PeggedOrder.Offset)
  2337  	assert.NoError(t, err)
  2338  
  2339  	// Check we should have no parked orders
  2340  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2341  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2342  	lp := &types.LiquidityProvisionSubmission{
  2343  		MarketID:         tm.market.GetID(),
  2344  		CommitmentAmount: num.NewUint(5000),
  2345  		Fee:              num.DecimalFromFloat(0.01),
  2346  	}
  2347  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2348  	// leave opening auction
  2349  	now = now.Add(2 * time.Second)
  2350  	tm.now = now
  2351  	tm.market.OnTick(ctx, now)
  2352  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2353  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2354  }
  2355  
  2356  // Amend a parked order but the order remains parked.
  2357  func testPeggedOrderAmendParkedStayParked(t *testing.T) {
  2358  	now := time.Unix(10, 0)
  2359  	tm := getTestMarket(t, now, nil, nil)
  2360  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2361  
  2362  	addAccount(t, tm, "party1")
  2363  
  2364  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2365  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2366  	require.NotNil(t, buyOrder)
  2367  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2368  	require.NotNil(t, sellOrder)
  2369  
  2370  	// Place the pegged order which will be parked
  2371  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2372  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 20)
  2373  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  2374  	require.NotNil(t, confirmation)
  2375  	assert.NoError(t, err)
  2376  
  2377  	// Amend offset so we can reprice
  2378  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2379  	off := num.NewUint(15)
  2380  	amend.PeggedOffset = off
  2381  	amended, err := tm.market.AmendOrder(ctx, amend, "party1", vgcrypto.RandomHash())
  2382  	require.NotNil(t, amended)
  2383  	assert.Equal(t, off, amended.Order.PeggedOrder.Offset)
  2384  	assert.NoError(t, err)
  2385  
  2386  	// Check we should have no parked orders
  2387  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2388  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2389  }
  2390  
  2391  // Take a valid live order and force it to be parked by amending it.
  2392  func testPeggedOrderAmendForcesPark(t *testing.T) {
  2393  	now := time.Unix(10, 0)
  2394  	tm := getTestMarket(t, now, nil, nil)
  2395  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2396  
  2397  	addAccount(t, tm, "party1")
  2398  
  2399  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2400  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2401  	require.NotNil(t, buyOrder)
  2402  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2403  	require.NotNil(t, sellOrder)
  2404  
  2405  	// Place the pegged order
  2406  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2407  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2408  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  2409  	require.NotNil(t, confirmation)
  2410  	assert.NoError(t, err)
  2411  
  2412  	// Amend offset so we cannot reprice
  2413  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2414  	amend.PeggedOffset = num.NewUint(15)
  2415  	amended, err := tm.market.AmendOrder(ctx, amend, "party1", vgcrypto.RandomHash())
  2416  	require.NotNil(t, amended)
  2417  	assert.NoError(t, err)
  2418  
  2419  	// Order should be parked
  2420  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2421  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2422  	assert.Equal(t, types.OrderStatusParked, amended.Order.Status)
  2423  }
  2424  
  2425  func testPeggedOrderAmendDuringAuction(t *testing.T) {
  2426  	now := time.Unix(10, 0)
  2427  	closeSec := int64(10000000000)
  2428  	tm := getTestMarket(t, now, nil, nil)
  2429  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2430  
  2431  	addAccount(t, tm, "party1")
  2432  
  2433  	tm.mas.StartPriceAuction(now, &types.AuctionDuration{
  2434  		Duration: closeSec / 10, // some time in the future, before closing
  2435  	})
  2436  	tm.market.EnterAuction(ctx)
  2437  
  2438  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2439  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2440  	require.NotNil(t, buyOrder)
  2441  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2442  	require.NotNil(t, sellOrder)
  2443  
  2444  	// Place the pegged order which will park it
  2445  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2446  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2447  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  2448  	require.NotNil(t, confirmation)
  2449  	assert.NoError(t, err)
  2450  
  2451  	// Amend offset so we cannot reprice
  2452  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2453  	amend.PeggedOffset = num.NewUint(5)
  2454  	amended, err := tm.market.AmendOrder(context.Background(), amend, "party1", vgcrypto.RandomHash())
  2455  	require.NotNil(t, amended)
  2456  	assert.NoError(t, err)
  2457  
  2458  	assert.Equal(t, types.OrderStatusParked, amended.Order.Status)
  2459  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2460  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2461  }
  2462  
  2463  func testPeggedOrderAmendReference(t *testing.T) {
  2464  	now := time.Unix(10, 0)
  2465  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2466  		Duration: 1,
  2467  	})
  2468  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2469  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2470  
  2471  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2472  	addAccount(t, tm, "party1")
  2473  	addAccount(t, tm, auxParty)
  2474  	addAccount(t, tm, auxParty2)
  2475  	addAccountWithAmount(tm, "lpprov", 10000000)
  2476  
  2477  	auxOrders := []*types.Order{
  2478  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 10),
  2479  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 10),
  2480  	}
  2481  	for _, o := range auxOrders {
  2482  		conf, err := tm.market.SubmitOrder(ctx, o)
  2483  		require.NoError(t, err)
  2484  		require.NotNil(t, conf)
  2485  	}
  2486  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2487  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2488  	require.NotNil(t, buyOrder)
  2489  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2490  	require.NotNil(t, sellOrder)
  2491  	lp := &types.LiquidityProvisionSubmission{
  2492  		MarketID:         tm.market.GetID(),
  2493  		CommitmentAmount: num.NewUint(5000),
  2494  		Fee:              num.DecimalFromFloat(0.01),
  2495  	}
  2496  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2497  	// leave opening auction
  2498  	now = now.Add(2 * time.Second)
  2499  	tm.now = now
  2500  	tm.market.OnTick(ctx, now)
  2501  
  2502  	// Place the pegged order which will park it
  2503  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2504  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2505  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  2506  	require.NotNil(t, confirmation)
  2507  	assert.NoError(t, err)
  2508  
  2509  	// Amend offset so we cannot reprice
  2510  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2511  	amend.PeggedReference = types.PeggedReferenceMid
  2512  	amended, err := tm.market.AmendOrder(context.Background(), amend, "party1", vgcrypto.RandomHash())
  2513  	require.NotNil(t, amended)
  2514  	assert.NoError(t, err)
  2515  
  2516  	assert.Equal(t, types.OrderStatusActive, amended.Order.Status)
  2517  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2518  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2519  	assert.Equal(t, types.PeggedReferenceMid, amended.Order.PeggedOrder.Reference)
  2520  }
  2521  
  2522  func testPeggedOrderAmendReferenceInAuction(t *testing.T) {
  2523  	now := time.Unix(10, 0)
  2524  	closeSec := int64(10000000000)
  2525  	tm := getTestMarket(t, now, nil, nil)
  2526  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2527  
  2528  	addAccount(t, tm, "party1")
  2529  
  2530  	tm.mas.StartPriceAuction(now, &types.AuctionDuration{
  2531  		Duration: closeSec / 10, // some time in the future, before closing
  2532  	})
  2533  	tm.market.EnterAuction(ctx)
  2534  
  2535  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2536  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2537  	require.NotNil(t, buyOrder)
  2538  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2539  	require.NotNil(t, sellOrder)
  2540  
  2541  	// Place the pegged order which will park it
  2542  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2543  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2544  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  2545  	require.NotNil(t, confirmation)
  2546  	assert.NoError(t, err)
  2547  
  2548  	// Amend offset so we cannot reprice
  2549  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2550  	amend.PeggedReference = types.PeggedReferenceMid
  2551  	amended, err := tm.market.AmendOrder(context.Background(), amend, "party1", vgcrypto.RandomHash())
  2552  	require.NotNil(t, amended)
  2553  	assert.NoError(t, err)
  2554  
  2555  	assert.Equal(t, types.OrderStatusParked, amended.Order.Status)
  2556  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2557  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2558  	assert.Equal(t, types.PeggedReferenceMid, amended.Order.PeggedOrder.Reference)
  2559  }
  2560  
  2561  func testPeggedOrderAmendMultipleInAuction(t *testing.T) {
  2562  	now := time.Unix(10, 0)
  2563  	closeSec := int64(10000000000)
  2564  	tm := getTestMarket(t, now, nil, nil)
  2565  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2566  
  2567  	addAccount(t, tm, "party1")
  2568  
  2569  	tm.mas.StartPriceAuction(now, &types.AuctionDuration{
  2570  		Duration: closeSec / 10, // some time in the future, before closing
  2571  	})
  2572  	tm.market.EnterAuction(ctx)
  2573  
  2574  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2575  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2576  	require.NotNil(t, buyOrder)
  2577  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2578  	require.NotNil(t, sellOrder)
  2579  
  2580  	// Place the pegged order which will park it
  2581  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2582  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2583  	confirmation, err := tm.market.SubmitOrder(ctx, &order)
  2584  	require.NotNil(t, confirmation)
  2585  	assert.NoError(t, err)
  2586  
  2587  	// Amend offset so we cannot reprice
  2588  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2589  	amend.PeggedReference = types.PeggedReferenceMid
  2590  	amend.TimeInForce = types.OrderTimeInForceGTT
  2591  	exp := int64(20000000000)
  2592  	amend.ExpiresAt = &exp
  2593  	amended, err := tm.market.AmendOrder(ctx, amend, "party1", vgcrypto.RandomHash())
  2594  	require.NotNil(t, amended)
  2595  	assert.NoError(t, err)
  2596  
  2597  	assert.Equal(t, types.OrderStatusParked, amended.Order.Status)
  2598  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2599  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2600  	assert.Equal(t, types.PeggedReferenceMid, amended.Order.PeggedOrder.Reference)
  2601  	assert.Equal(t, types.OrderTimeInForceGTT, amended.Order.TimeInForce)
  2602  }
  2603  
  2604  func testPeggedOrderAmendMultiple(t *testing.T) {
  2605  	now := time.Unix(10, 0)
  2606  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2607  		Duration: 1,
  2608  	})
  2609  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2610  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2611  
  2612  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2613  	addAccount(t, tm, "party1")
  2614  	addAccount(t, tm, auxParty)
  2615  	addAccount(t, tm, auxParty2)
  2616  	addAccountWithAmount(tm, "lpprov", 10000000)
  2617  
  2618  	auxOrders := []*types.Order{
  2619  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 10),
  2620  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 10),
  2621  	}
  2622  	for _, o := range auxOrders {
  2623  		conf, err := tm.market.SubmitOrder(ctx, o)
  2624  		require.NoError(t, err)
  2625  		require.NotNil(t, conf)
  2626  	}
  2627  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2628  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 9)
  2629  	require.NotNil(t, buyOrder)
  2630  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 11)
  2631  	require.NotNil(t, sellOrder)
  2632  	lp := &types.LiquidityProvisionSubmission{
  2633  		MarketID:         tm.market.GetID(),
  2634  		CommitmentAmount: num.NewUint(5000),
  2635  		Fee:              num.DecimalFromFloat(0.01),
  2636  	}
  2637  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2638  
  2639  	// leave opening auction
  2640  	now = now.Add(2 * time.Second)
  2641  	tm.now = now
  2642  	tm.market.OnTick(ctx, now)
  2643  
  2644  	// Place the pegged order which will park it
  2645  	order := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2646  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 3)
  2647  	confirmation, err := tm.market.SubmitOrder(context.Background(), &order)
  2648  	require.NotNil(t, confirmation)
  2649  	assert.NoError(t, err)
  2650  
  2651  	// Amend offset so we cannot reprice
  2652  	amend := getAmend(tm.market.GetID(), confirmation.Order.ID, 0, 0, types.OrderTimeInForceUnspecified, 0)
  2653  	amend.PeggedReference = types.PeggedReferenceMid
  2654  	amend.TimeInForce = types.OrderTimeInForceGTT
  2655  	exp := int64(20000000000)
  2656  	amend.ExpiresAt = &exp
  2657  	amended, err := tm.market.AmendOrder(context.Background(), amend, "party1", vgcrypto.RandomHash())
  2658  	require.NotNil(t, amended)
  2659  	assert.NoError(t, err)
  2660  
  2661  	assert.Equal(t, types.OrderStatusActive, amended.Order.Status)
  2662  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2663  	assert.Equal(t, 1, tm.market.GetPeggedOrderCount())
  2664  	assert.Equal(t, types.PeggedReferenceMid, amended.Order.PeggedOrder.Reference)
  2665  	assert.Equal(t, types.OrderTimeInForceGTT, amended.Order.TimeInForce)
  2666  }
  2667  
  2668  func testPeggedOrderMidPriceCalc(t *testing.T) {
  2669  	now := time.Unix(10, 0)
  2670  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2671  		Duration: 1,
  2672  	})
  2673  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2674  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2675  
  2676  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2677  	addAccount(t, tm, "party1")
  2678  	addAccount(t, tm, auxParty)
  2679  	addAccount(t, tm, auxParty2)
  2680  	addAccountWithAmount(tm, "lpprov", 10000000)
  2681  
  2682  	// Place 2 trades so we have a valid BEST_BID+MID+BEST_ASK price
  2683  	buyOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 90)
  2684  	require.NotNil(t, buyOrder)
  2685  	sellOrder := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 1, 110)
  2686  	require.NotNil(t, sellOrder)
  2687  	auxOrders := []*types.Order{
  2688  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  2689  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  2690  	}
  2691  	for _, o := range auxOrders {
  2692  		conf, err := tm.market.SubmitOrder(ctx, o)
  2693  		require.NoError(t, err)
  2694  		require.NotNil(t, conf)
  2695  	}
  2696  	lp := &types.LiquidityProvisionSubmission{
  2697  		MarketID:         tm.market.GetID(),
  2698  		CommitmentAmount: num.NewUint(5000),
  2699  		Fee:              num.DecimalFromFloat(0.01),
  2700  	}
  2701  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2702  	now = now.Add(2 * time.Second)
  2703  	tm.now = now
  2704  	tm.market.OnTick(ctx, now)
  2705  
  2706  	// Place the pegged orders
  2707  	order1 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 10, 10)
  2708  	order1.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 20)
  2709  	confirmation1, err := tm.market.SubmitOrder(context.Background(), &order1)
  2710  	require.NotNil(t, confirmation1)
  2711  	assert.NoError(t, err)
  2712  	assert.True(t, confirmation1.Order.Price.EQ(num.NewUint(80)))
  2713  
  2714  	order2 := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, "party1", 10, 10)
  2715  	order2.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 20)
  2716  	confirmation2, err := tm.market.SubmitOrder(context.Background(), &order2)
  2717  	require.NotNil(t, confirmation2)
  2718  	assert.NoError(t, err)
  2719  	assert.True(t, confirmation2.Order.Price.EQ(num.NewUint(120)))
  2720  
  2721  	// Make the mid price wonky (needs rounding)
  2722  	buyOrder2 := sendOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, "party1", 1, 91)
  2723  	require.NotNil(t, buyOrder2)
  2724  
  2725  	// Check the pegged orders have reprices properly
  2726  	assert.True(t, confirmation1.Order.Price.EQ(num.NewUint(81)))  // Buy price gets rounded up
  2727  	assert.True(t, confirmation2.Order.Price.EQ(num.NewUint(120))) // Sell price gets rounded down
  2728  }
  2729  
  2730  func TestPeggedOrderUnparkAfterLeavingAuctionWithNoFunds2772(t *testing.T) {
  2731  	now := time.Unix(10, 0)
  2732  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2733  		Duration: 1,
  2734  	})
  2735  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2736  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2737  
  2738  	auxParty1, auxParty2, lp, party1 := "auxParty", "auxParty2", "lp", "party1"
  2739  	addAccount(t, tm, auxParty1)
  2740  	addAccount(t, tm, auxParty2)
  2741  	addAccountWithAmount(tm, lp, 10000000)
  2742  	addAccount(t, tm, party1)
  2743  
  2744  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2745  	peggedOffset := uint64(10)
  2746  	buyPeggedOrder := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, party1, peggedOffset, 0)
  2747  	buyPeggedOrder.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  2748  	confirmationPeggedBuy, err := tm.market.SubmitOrder(ctx, &buyPeggedOrder)
  2749  	assert.NotNil(t, confirmationPeggedBuy)
  2750  	assert.Equal(t, confirmationPeggedBuy.Order.Status, types.OrderStatusParked)
  2751  	assert.NoError(t, err)
  2752  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2753  
  2754  	sellPeggedOrder := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, party1, peggedOffset, 0)
  2755  	sellPeggedOrder.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  2756  	confirmationPeggedSell, err := tm.market.SubmitOrder(ctx, &sellPeggedOrder)
  2757  	assert.NotNil(t, confirmationPeggedSell)
  2758  	assert.Equal(t, confirmationPeggedSell.Order.Status, types.OrderStatusParked)
  2759  	assert.NoError(t, err)
  2760  	assert.Equal(t, 2, tm.market.GetParkedOrderCount())
  2761  
  2762  	bestBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 1)
  2763  	auxOrders := []*types.Order{
  2764  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty1, 1, 10000),
  2765  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 2000),
  2766  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideSell, auxParty1, 1, 2000),
  2767  	}
  2768  	bestBidConf, err := tm.market.SubmitOrder(ctx, bestBid)
  2769  	require.NoError(t, err)
  2770  	require.NotNil(t, bestBidConf)
  2771  	for _, o := range auxOrders {
  2772  		conf, err := tm.market.SubmitOrder(ctx, o)
  2773  		require.NoError(t, err)
  2774  		require.NotNil(t, conf)
  2775  	}
  2776  	lps := &types.LiquidityProvisionSubmission{
  2777  		MarketID:         tm.market.GetID(),
  2778  		CommitmentAmount: num.NewUint(5000),
  2779  		Fee:              num.DecimalFromFloat(0.01),
  2780  	}
  2781  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp, vgcrypto.RandomHash()))
  2782  
  2783  	// leave opening auction
  2784  	now = now.Add(2 * time.Second)
  2785  	tm.now = now
  2786  	tm.market.OnTick(ctx, now)
  2787  
  2788  	md := tm.market.GetMarketData()
  2789  	require.NotNil(t, md)
  2790  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  2791  
  2792  	// 1 pegged order should get deployed, the other one should remain parked
  2793  	// as its offset is such that the price would be negative with current best bid
  2794  	assert.Equal(t, confirmationPeggedBuy.Order.Status, types.OrderStatusParked)
  2795  	assert.Equal(t, confirmationPeggedSell.Order.Status, types.OrderStatusActive)
  2796  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2797  
  2798  	amend := &types.OrderAmendment{
  2799  		OrderID:  bestBidConf.Order.ID,
  2800  		MarketID: bestBidConf.Order.MarketID,
  2801  		Price:    num.NewUint(peggedOffset + 1),
  2802  	}
  2803  
  2804  	tm.events = nil
  2805  	amended, err := tm.market.AmendOrder(ctx, amend, bestBidConf.Order.Party, vgcrypto.RandomHash())
  2806  	require.NoError(t, err)
  2807  	assert.Equal(t, amended.Order.Status, types.OrderStatusActive)
  2808  
  2809  	// now both orders should get unparked
  2810  	assert.Equal(t, confirmationPeggedBuy.Order.Status, types.OrderStatusActive)
  2811  	assert.Equal(t, confirmationPeggedSell.Order.Status, types.OrderStatusActive)
  2812  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2813  }
  2814  
  2815  func TestPeggedOrderCancelledWhenPartyCannotAffordTheMarginOnceDeployed(t *testing.T) {
  2816  	now := time.Unix(10, 0)
  2817  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2818  		Duration: 1,
  2819  	})
  2820  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2821  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2822  
  2823  	auxParty1, auxParty2, lp, party1 := "auxParty", "auxParty2", "lp", "party1"
  2824  	addAccount(t, tm, auxParty1)
  2825  	addAccount(t, tm, auxParty2)
  2826  	addAccountWithAmount(tm, lp, 10000000)
  2827  	addAccountWithAmount(tm, party1, 1)
  2828  
  2829  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2830  	peggedOffset := uint64(10)
  2831  	buyPeggedOrder := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideBuy, party1, peggedOffset, 0)
  2832  	buyPeggedOrder.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1)
  2833  	confirmationPeggedBuy, err := tm.market.SubmitOrder(ctx, &buyPeggedOrder)
  2834  	assert.NotNil(t, confirmationPeggedBuy)
  2835  	assert.Equal(t, confirmationPeggedBuy.Order.Status, types.OrderStatusParked)
  2836  	assert.NoError(t, err)
  2837  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  2838  
  2839  	sellPeggedOrder := getOrder(t, tm, &now, types.OrderTypeLimit, types.OrderTimeInForceGTC, 0, types.SideSell, party1, peggedOffset, 0)
  2840  	sellPeggedOrder.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 1)
  2841  	confirmationPeggedSell, err := tm.market.SubmitOrder(ctx, &sellPeggedOrder)
  2842  	assert.NotNil(t, confirmationPeggedSell)
  2843  	assert.Equal(t, confirmationPeggedSell.Order.Status, types.OrderStatusParked)
  2844  	assert.NoError(t, err)
  2845  	assert.Equal(t, 2, tm.market.GetParkedOrderCount())
  2846  
  2847  	bestBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 10)
  2848  	matchingPrice := uint64(2000)
  2849  	auxOrders := []*types.Order{
  2850  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty1, 1, 10000),
  2851  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, matchingPrice),
  2852  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideSell, auxParty1, 1, matchingPrice),
  2853  	}
  2854  	bestBidConf, err := tm.market.SubmitOrder(ctx, bestBid)
  2855  	require.NoError(t, err)
  2856  	require.NotNil(t, bestBidConf)
  2857  	for _, o := range auxOrders {
  2858  		conf, err := tm.market.SubmitOrder(ctx, o)
  2859  		require.NoError(t, err)
  2860  		require.NotNil(t, conf)
  2861  	}
  2862  	lps := &types.LiquidityProvisionSubmission{
  2863  		MarketID:         tm.market.GetID(),
  2864  		CommitmentAmount: num.NewUint(5000),
  2865  		Fee:              num.DecimalFromFloat(0.01),
  2866  	}
  2867  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp, vgcrypto.RandomHash()))
  2868  
  2869  	// leave opening auction
  2870  	now = now.Add(2 * time.Second)
  2871  	tm.now = now
  2872  	tm.market.OnTick(ctx, now)
  2873  
  2874  	md := tm.market.GetMarketData()
  2875  	require.NotNil(t, md)
  2876  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  2877  	require.Equal(t, num.NewUint(matchingPrice), md.MarkPrice)
  2878  
  2879  	assert.Equal(t, confirmationPeggedBuy.Order.Status, types.OrderStatusCancelled)
  2880  	assert.Equal(t, confirmationPeggedSell.Order.Status, types.OrderStatusCancelled)
  2881  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  2882  }
  2883  
  2884  // test for issue 787,
  2885  // segv when an GTT order is cancelled, then expires.
  2886  func TestOrderBookSimple_CancelGTTOrderThenRunExpiration(t *testing.T) {
  2887  	now := time.Unix(5, 0)
  2888  	tm := getTestMarket(t, now, nil, nil)
  2889  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2890  	defer tm.ctrl.Finish()
  2891  
  2892  	addAccount(t, tm, "aaa")
  2893  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2894  
  2895  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order01", types.SideBuy, "aaa", 10, 100)
  2896  	o1.ExpiresAt = now.Add(5 * time.Second).UnixNano()
  2897  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  2898  	require.NoError(t, err)
  2899  	require.NotNil(t, o1conf)
  2900  
  2901  	cncl, err := tm.market.CancelOrder(ctx, o1.Party, o1.ID, vgcrypto.RandomHash())
  2902  	require.NoError(t, err)
  2903  	require.NotNil(t, cncl)
  2904  	assert.Equal(t, 0, tm.market.GetPeggedExpiryOrderCount())
  2905  
  2906  	tm.market.OnTick(ctx, now.Add(10*time.Second))
  2907  	t.Run("no orders expired", func(t *testing.T) {
  2908  		// First collect all the orders events
  2909  		orders := []*types.Order{}
  2910  		for _, e := range tm.events {
  2911  			switch evt := e.(type) {
  2912  			case *events.Order:
  2913  				if evt.Order().Status == types.OrderStatusExpired {
  2914  					orders = append(orders, mustOrderFromProto(evt.Order()))
  2915  				}
  2916  			}
  2917  		}
  2918  		require.Len(t, orders, 0)
  2919  	})
  2920  	assert.Equal(t, 0, tm.market.GetPeggedExpiryOrderCount())
  2921  }
  2922  
  2923  func TestGTTExpiredNotFilled(t *testing.T) {
  2924  	now := time.Unix(5, 0)
  2925  	tm := getTestMarket(t, now, nil, nil)
  2926  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2927  	defer tm.ctrl.Finish()
  2928  
  2929  	addAccount(t, tm, "aaa")
  2930  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2931  
  2932  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order01", types.SideSell, "aaa", 10, 100)
  2933  	o1.ExpiresAt = now.Add(5 * time.Second).UnixNano()
  2934  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  2935  	require.NoError(t, err)
  2936  	require.NotNil(t, o1conf)
  2937  
  2938  	// then remove expired, set 1 sec after order exp time.
  2939  	tm.events = nil
  2940  	tm.market.OnTick(ctx, now.Add(10*time.Second))
  2941  	t.Run("1 order expired", func(t *testing.T) {
  2942  		// First collect all the orders events
  2943  		orders := []string{}
  2944  		for _, e := range tm.events {
  2945  			switch evt := e.(type) {
  2946  			case *events.ExpiredOrders:
  2947  				orders = append(orders, evt.OrderIDs()...)
  2948  			}
  2949  		}
  2950  		assert.Len(t, orders, 1)
  2951  	})
  2952  }
  2953  
  2954  func TestGTTExpiredPartiallyFilled(t *testing.T) {
  2955  	now := time.Unix(5, 0)
  2956  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  2957  		Duration: 1,
  2958  	})
  2959  	defer tm.ctrl.Finish()
  2960  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2961  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2962  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  2963  
  2964  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2965  	addAccount(t, tm, auxParty)
  2966  	addAccount(t, tm, auxParty2)
  2967  	addAccountWithAmount(tm, "lpprov", 10000000)
  2968  
  2969  	auxOrders := []*types.Order{
  2970  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000),
  2971  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1),
  2972  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  2973  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  2974  	}
  2975  	for _, o := range auxOrders {
  2976  		conf, err := tm.market.SubmitOrder(ctx, o)
  2977  		require.NoError(t, err)
  2978  		require.NotNil(t, conf)
  2979  	}
  2980  	lp := &types.LiquidityProvisionSubmission{
  2981  		MarketID:         tm.market.GetID(),
  2982  		CommitmentAmount: num.NewUint(5000),
  2983  		Fee:              num.DecimalFromFloat(0.01),
  2984  	}
  2985  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2986  	// leave auction
  2987  	tm.now = tm.now.Add(2 * time.Second)
  2988  	tm.market.OnTick(ctx, tm.now)
  2989  	addAccount(t, tm, "aaa")
  2990  	addAccount(t, tm, "bbb")
  2991  
  2992  	// We probably don't need these orders anymore, but they don't do any harm
  2993  	// place expiring order
  2994  	o1 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order01", types.SideSell, "aaa", 10, 100)
  2995  	o1.ExpiresAt = tm.now.Add(5 * time.Second).UnixNano()
  2996  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  2997  	require.NoError(t, err)
  2998  	require.NotNil(t, o1conf)
  2999  
  3000  	// add matching order
  3001  	o2 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order02", types.SideBuy, "bbb", 1, 100)
  3002  	o2.ExpiresAt = now.Add(5 * time.Second).UnixNano()
  3003  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  3004  	require.NoError(t, err)
  3005  	require.NotNil(t, o2conf)
  3006  
  3007  	// then remove expired, set 1 sec after order exp time.
  3008  	tm.events = nil
  3009  	tm.market.OnTick(ctx, tm.now.Add(10*time.Second))
  3010  	t.Run("1 order expired - the other matched", func(t *testing.T) {
  3011  		// First collect all the orders events
  3012  		orders := []string{}
  3013  		for _, e := range tm.events {
  3014  			switch evt := e.(type) {
  3015  			case *events.ExpiredOrders:
  3016  				orders = append(orders, evt.OrderIDs()...)
  3017  			}
  3018  		}
  3019  		assert.Len(t, orders, 1)
  3020  	})
  3021  }
  3022  
  3023  func TestOrderBook_RemoveExpiredOrders(t *testing.T) {
  3024  	now := time.Unix(5, 0)
  3025  	tm := getTestMarket(t, now, nil, nil)
  3026  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3027  	defer tm.ctrl.Finish()
  3028  
  3029  	addAccount(t, tm, "aaa")
  3030  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3031  
  3032  	someTimeLater := now.Add(100 * time.Second)
  3033  
  3034  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order01", types.SideSell, "aaa", 1, 1)
  3035  	o1.ExpiresAt = someTimeLater.UnixNano()
  3036  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  3037  	require.NoError(t, err)
  3038  	require.NotNil(t, o1conf)
  3039  
  3040  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order02", types.SideSell, "aaa", 99, 3298)
  3041  	o2.ExpiresAt = someTimeLater.UnixNano() + 1
  3042  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  3043  	require.NoError(t, err)
  3044  	require.NotNil(t, o2conf)
  3045  
  3046  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order03", types.SideSell, "aaa", 19, 771)
  3047  	o3.ExpiresAt = someTimeLater.UnixNano()
  3048  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  3049  	require.NoError(t, err)
  3050  	require.NotNil(t, o3conf)
  3051  
  3052  	o4 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order04", types.SideSell, "aaa", 7, 1000)
  3053  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  3054  	require.NoError(t, err)
  3055  	require.NotNil(t, o4conf)
  3056  
  3057  	o5 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order05", types.SideSell, "aaa", 99999, 199)
  3058  	o5.ExpiresAt = someTimeLater.UnixNano()
  3059  	o5conf, err := tm.market.SubmitOrder(ctx, o5)
  3060  	require.NoError(t, err)
  3061  	require.NotNil(t, o5conf)
  3062  
  3063  	o6 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order06", types.SideSell, "aaa", 100, 100)
  3064  	o6conf, err := tm.market.SubmitOrder(ctx, o6)
  3065  	require.NoError(t, err)
  3066  	require.NotNil(t, o6conf)
  3067  
  3068  	o7 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order07", types.SideSell, "aaa", 9999, 41)
  3069  	o7.ExpiresAt = someTimeLater.UnixNano() + 9999
  3070  	o7conf, err := tm.market.SubmitOrder(ctx, o7)
  3071  	require.NoError(t, err)
  3072  	require.NotNil(t, o7conf)
  3073  
  3074  	o8 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order08", types.SideSell, "aaa", 1, 1)
  3075  	o8.ExpiresAt = someTimeLater.UnixNano() - 9999
  3076  	o8conf, err := tm.market.SubmitOrder(ctx, o8)
  3077  	require.NoError(t, err)
  3078  	require.NotNil(t, o8conf)
  3079  
  3080  	o9 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order09", types.SideSell, "aaa", 12, 65)
  3081  	o9conf, err := tm.market.SubmitOrder(ctx, o9)
  3082  	require.NoError(t, err)
  3083  	require.NotNil(t, o9conf)
  3084  
  3085  	o10 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order10", types.SideSell, "aaa", 1, 1)
  3086  	o10.ExpiresAt = someTimeLater.UnixNano() - 1
  3087  	o10conf, err := tm.market.SubmitOrder(ctx, o10)
  3088  	require.NoError(t, err)
  3089  	require.NotNil(t, o10conf)
  3090  
  3091  	tm.events = nil
  3092  	tm.market.OnTick(ctx, someTimeLater)
  3093  	t.Run("5 orders expired", func(t *testing.T) {
  3094  		// First collect all the orders events
  3095  		orders := []string{}
  3096  		for _, e := range tm.events {
  3097  			switch evt := e.(type) {
  3098  			case *events.ExpiredOrders:
  3099  				orders = append(orders, evt.OrderIDs()...)
  3100  			}
  3101  		}
  3102  		require.Len(t, orders, 5)
  3103  	})
  3104  }
  3105  
  3106  func TestMissingLP(t *testing.T) {
  3107  	party1 := "party1"
  3108  	party2 := "party2"
  3109  	party3 := "party3"
  3110  	auxParty, auxParty2 := "auxParty", "auxParty2"
  3111  	now := time.Unix(10, 0)
  3112  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  3113  		Duration: 1,
  3114  	})
  3115  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3116  
  3117  	addAccount(t, tm, party1)
  3118  	addAccount(t, tm, party2)
  3119  	addAccount(t, tm, party3)
  3120  	addAccount(t, tm, auxParty)
  3121  	addAccount(t, tm, auxParty2)
  3122  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3123  
  3124  	// ensure auction durations are 1 second
  3125  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  3126  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, vgcrypto.RandomHash(), types.SideBuy, auxParty, 1, 800000)
  3127  	conf, err := tm.market.SubmitOrder(ctx, alwaysOnBid)
  3128  	require.NotNil(t, conf)
  3129  	require.NoError(t, err)
  3130  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3131  
  3132  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, vgcrypto.RandomHash(), types.SideSell, auxParty, 1, 8200000)
  3133  	conf, err = tm.market.SubmitOrder(ctx, alwaysOnAsk)
  3134  	require.NotNil(t, conf)
  3135  	require.NoError(t, err)
  3136  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3137  	// create orders so we can leave opening auction
  3138  	auxOrders := []*types.Order{
  3139  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, vgcrypto.RandomHash(), types.SideBuy, auxParty, 1, 3500000),
  3140  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, vgcrypto.RandomHash(), types.SideSell, auxParty2, 1, 3500000),
  3141  	}
  3142  	for _, o := range auxOrders {
  3143  		conf, err := tm.market.SubmitOrder(ctx, o)
  3144  		require.NotNil(t, conf)
  3145  		require.NoError(t, err)
  3146  	}
  3147  	now = now.Add(time.Second * 2) // opening auction is 1 second, move time ahead by 2 seconds so we leave auction
  3148  	tm.now = now
  3149  	tm.market.OnTick(ctx, now)
  3150  
  3151  	// Here we are in auction
  3152  	assert.False(t, tm.mas.InAuction())
  3153  
  3154  	// Send LP order
  3155  	lps := &types.LiquidityProvisionSubmission{
  3156  		MarketID:         tm.market.GetID(),
  3157  		CommitmentAmount: num.NewUint(10000),
  3158  		Fee:              num.DecimalFromFloat(0.01),
  3159  	}
  3160  
  3161  	tm.market.SubmitLiquidityProvision(ctx, lps, party1, vgcrypto.RandomHash())
  3162  
  3163  	assert.EqualValues(t, 2, tm.market.GetOrdersOnBookCount())
  3164  
  3165  	// Send in a limit order to move the BEST_BID and MID price
  3166  	newBestBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, vgcrypto.RandomHash(), types.SideBuy, auxParty, 1, 810000)
  3167  	conf, err = tm.market.SubmitOrder(ctx, newBestBid)
  3168  	require.NotNil(t, conf)
  3169  	require.NoError(t, err)
  3170  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3171  
  3172  	// Check we have 3 orders in total
  3173  	assert.EqualValues(t, 3, tm.market.GetOrdersOnBookCount())
  3174  	now = now.Add(time.Second * 2) // opening auction is 1 second, move time ahead by 2 seconds so we leave auction
  3175  	tm.now = now
  3176  	tm.market.OnTick(ctx, now)
  3177  }