code.vegaprotocol.io/vega@v0.79.0/core/execution/future/market_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  	"errors"
    21  	"fmt"
    22  	"math"
    23  	"reflect"
    24  	"testing"
    25  	"time"
    26  
    27  	bmocks "code.vegaprotocol.io/vega/core/broker/mocks"
    28  	"code.vegaprotocol.io/vega/core/collateral"
    29  	"code.vegaprotocol.io/vega/core/datasource"
    30  	dstypes "code.vegaprotocol.io/vega/core/datasource/common"
    31  	dserrors "code.vegaprotocol.io/vega/core/datasource/errors"
    32  	"code.vegaprotocol.io/vega/core/datasource/external/signedoracle"
    33  	"code.vegaprotocol.io/vega/core/datasource/spec"
    34  	"code.vegaprotocol.io/vega/core/events"
    35  	"code.vegaprotocol.io/vega/core/execution/common"
    36  	"code.vegaprotocol.io/vega/core/execution/common/mocks"
    37  	"code.vegaprotocol.io/vega/core/execution/future"
    38  	"code.vegaprotocol.io/vega/core/fee"
    39  	fmocks "code.vegaprotocol.io/vega/core/fee/mocks"
    40  	"code.vegaprotocol.io/vega/core/idgeneration"
    41  	"code.vegaprotocol.io/vega/core/integration/stubs"
    42  	"code.vegaprotocol.io/vega/core/liquidity/v2"
    43  	"code.vegaprotocol.io/vega/core/matching"
    44  	"code.vegaprotocol.io/vega/core/monitor"
    45  	"code.vegaprotocol.io/vega/core/positions"
    46  	"code.vegaprotocol.io/vega/core/risk"
    47  	"code.vegaprotocol.io/vega/core/settlement"
    48  	"code.vegaprotocol.io/vega/core/types"
    49  	vegacontext "code.vegaprotocol.io/vega/libs/context"
    50  	"code.vegaprotocol.io/vega/libs/crypto"
    51  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    52  	"code.vegaprotocol.io/vega/libs/num"
    53  	"code.vegaprotocol.io/vega/logging"
    54  	proto "code.vegaprotocol.io/vega/protos/vega"
    55  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    56  	datapb "code.vegaprotocol.io/vega/protos/vega/data/v1"
    57  
    58  	"github.com/golang/mock/gomock"
    59  	"github.com/stretchr/testify/assert"
    60  	"github.com/stretchr/testify/require"
    61  )
    62  
    63  var (
    64  	MAXMOVEUP   = num.DecimalFromFloat(1000)
    65  	MINMOVEDOWN = num.DecimalFromFloat(500)
    66  )
    67  
    68  func peggedOrderCounterForTest(int64) {}
    69  
    70  var defaultCollateralAssets = []types.Asset{
    71  	{
    72  		ID: "ETH",
    73  		Details: &types.AssetDetails{
    74  			Symbol:  "ETH",
    75  			Quantum: num.DecimalOne(),
    76  		},
    77  	},
    78  	{
    79  		ID: "VOTE",
    80  		Details: &types.AssetDetails{
    81  			Name:     "VOTE",
    82  			Symbol:   "VOTE",
    83  			Decimals: 5,
    84  			Quantum:  num.DecimalOne(),
    85  			Source: &types.AssetDetailsBuiltinAsset{
    86  				BuiltinAsset: &types.BuiltinAsset{},
    87  			},
    88  		},
    89  	},
    90  }
    91  
    92  var defaultPriceMonitorSettings = &types.PriceMonitoringSettings{
    93  	Parameters: &types.PriceMonitoringParameters{
    94  		Triggers: []*types.PriceMonitoringTrigger{
    95  			{
    96  				Horizon:          600,
    97  				HorizonDec:       num.MustDecimalFromString("600"),
    98  				Probability:      num.DecimalFromFloat(0.99),
    99  				AuctionExtension: 120,
   100  			},
   101  		},
   102  	},
   103  }
   104  
   105  func newTestIDGenerator() common.IDGenerator {
   106  	return idgeneration.New(vgcrypto.RandomHash())
   107  }
   108  
   109  type marketW struct {
   110  	*future.Market
   111  }
   112  
   113  func (m *marketW) SubmitOrder(
   114  	ctx context.Context,
   115  	order *types.Order,
   116  ) (*types.OrderConfirmation, error) {
   117  	conf, err := m.Market.SubmitOrder(ctx, order.IntoSubmission(), order.Party, vgcrypto.RandomHash())
   118  	if err == nil {
   119  		*order = *conf.Order.Clone()
   120  	}
   121  	return conf, err
   122  }
   123  
   124  func (m *marketW) SubmitOrderWithHash(
   125  	ctx context.Context,
   126  	order *types.Order,
   127  	hash string,
   128  ) (*types.OrderConfirmation, error) {
   129  	conf, err := m.Market.SubmitOrder(ctx, order.IntoSubmission(), order.Party, hash)
   130  	if err == nil {
   131  		*order = *conf.Order.Clone()
   132  	}
   133  	return conf, err
   134  }
   135  
   136  type testMarket struct {
   137  	t *testing.T
   138  
   139  	market           *marketW
   140  	log              *logging.Logger
   141  	ctrl             *gomock.Controller
   142  	collateralEngine *collateral.Engine
   143  	broker           *bmocks.MockBroker
   144  	timeService      *mocks.MockTimeService
   145  	now              time.Time
   146  	asset            string
   147  	mas              *monitor.AuctionState
   148  	eventCount       uint64
   149  	orderEventCount  uint64
   150  	events           []events.Event
   151  	orderEvents      []events.Event
   152  	mktCfg           *types.Market
   153  	oracleEngine     *spec.Engine
   154  	stateVar         *stubs.StateVarStub
   155  	builtinOracle    *spec.Builtin
   156  
   157  	// Options
   158  	Assets []types.Asset
   159  }
   160  
   161  func newTestMarket(t *testing.T, now time.Time) *testMarket {
   162  	t.Helper()
   163  	ctrl := gomock.NewController(t)
   164  	tm := &testMarket{
   165  		t:    t,
   166  		ctrl: ctrl,
   167  		log:  logging.NewTestLogger(),
   168  		now:  now,
   169  	}
   170  
   171  	// Setup Mocking Expectations
   172  	tm.broker = bmocks.NewMockBroker(ctrl)
   173  	tm.timeService = mocks.NewMockTimeService(ctrl)
   174  	tm.timeService.EXPECT().GetTimeNow().DoAndReturn(
   175  		func() time.Time {
   176  			return tm.now
   177  		}).AnyTimes()
   178  
   179  	// eventFn records and count events and orderEvents
   180  	eventFn := func(evt events.Event) {
   181  		if evt.Type() == events.OrderEvent {
   182  			tm.orderEventCount++
   183  			tm.orderEvents = append(tm.orderEvents, evt)
   184  		}
   185  		tm.eventCount++
   186  		tm.events = append(tm.events, evt)
   187  	}
   188  	// eventsFn is the same as eventFn above but handles []event
   189  	eventsFn := func(evts []events.Event) {
   190  		for _, evt := range evts {
   191  			eventFn(evt)
   192  		}
   193  	}
   194  
   195  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes().Do(eventFn)
   196  	tm.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes().Do(eventsFn)
   197  	tm.oracleEngine = spec.NewEngine(tm.log, spec.NewDefaultConfig(), tm.timeService, tm.broker)
   198  	tm.builtinOracle = spec.NewBuiltin(tm.oracleEngine, tm.timeService)
   199  	return tm
   200  }
   201  
   202  func (tm *testMarket) Run(ctx context.Context, mktCfg types.Market) *testMarket {
   203  	collateralEngine := collateral.New(tm.log, collateral.NewDefaultConfig(), tm.timeService, tm.broker)
   204  	// create asset with same decimal places as the market asset
   205  	mktAssets, _ := mktCfg.GetAssets()
   206  	cfgAsset := NewAssetStub(mktAssets[0], mktCfg.DecimalPlaces)
   207  	assets := tm.Assets
   208  	if len(assets) == 0 {
   209  		assets = defaultCollateralAssets
   210  	}
   211  	for _, asset := range assets {
   212  		err := collateralEngine.EnableAsset(ctx, asset)
   213  		require.NoError(tm.t, err)
   214  	}
   215  
   216  	var (
   217  		riskConfig       = risk.NewDefaultConfig()
   218  		positionConfig   = positions.NewDefaultConfig()
   219  		settlementConfig = settlement.NewDefaultConfig()
   220  		matchingConfig   = matching.NewDefaultConfig()
   221  		feeConfig        = fee.NewDefaultConfig()
   222  		liquidityConfig  = liquidity.NewDefaultConfig()
   223  	)
   224  	positionConfig.StreamPositionVerbose = true
   225  
   226  	oracleEngine := spec.NewEngine(tm.log, spec.NewDefaultConfig(), tm.timeService, tm.broker)
   227  
   228  	mas := monitor.NewAuctionState(&mktCfg, tm.now)
   229  	monitor.NewAuctionState(&mktCfg, tm.now)
   230  
   231  	statevarEngine := stubs.NewStateVar()
   232  	epochEngine := mocks.NewMockEpochEngine(tm.ctrl)
   233  	epochEngine.EXPECT().NotifyOnEpoch(gomock.Any(), gomock.Any()).Times(1)
   234  
   235  	teams := mocks.NewMockTeams(tm.ctrl)
   236  	bc := mocks.NewMockAccountBalanceChecker(tm.ctrl)
   237  	broker := bmocks.NewMockBroker(tm.ctrl)
   238  	marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
   239  	epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
   240  
   241  	referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl)
   242  	volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl)
   243  	volumeRebate := fmocks.NewMockVolumeRebateService(tm.ctrl)
   244  	referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes()
   245  	referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   246  	referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   247  	volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   248  	volumeRebate.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
   249  	banking := mocks.NewMockBanking(tm.ctrl)
   250  	parties := mocks.NewMockParties(tm.ctrl)
   251  
   252  	mktEngine, err := future.NewMarket(ctx,
   253  		tm.log, riskConfig, positionConfig, settlementConfig, matchingConfig,
   254  		feeConfig, liquidityConfig, collateralEngine, oracleEngine, &mktCfg, tm.timeService, tm.broker, mas, statevarEngine, marketActivityTracker, cfgAsset,
   255  		peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties,
   256  	)
   257  	require.NoError(tm.t, err)
   258  
   259  	settlementAssets, err := mktCfg.GetAssets()
   260  	require.NoError(tm.t, err)
   261  
   262  	_, _, err = collateralEngine.CreateMarketAccounts(ctx, mktEngine.GetID(), settlementAssets[0])
   263  	require.NoError(tm.t, err)
   264  
   265  	tm.market = &marketW{mktEngine}
   266  	tm.market.UpdateRiskFactorsForTest()
   267  	tm.collateralEngine = collateralEngine
   268  	tm.asset = settlementAssets[0]
   269  	tm.mas = mas
   270  	tm.mktCfg = &mktCfg
   271  	tm.stateVar = statevarEngine
   272  
   273  	// Reset event counters
   274  	tm.eventCount = 0
   275  	tm.orderEventCount = 0
   276  
   277  	return tm
   278  }
   279  
   280  func (tm *testMarket) EndOpeningAuction(t *testing.T, auctionEnd time.Time, setMarkPrice bool) {
   281  	t.Helper()
   282  	var (
   283  		party0 = "clearing-auction-party0"
   284  		party1 = "clearing-auction-party1"
   285  		party2 = "lpprov-party"
   286  	)
   287  
   288  	// parties used for clearing opening auction
   289  	tm.WithAccountAndAmount(party0, 1000000).
   290  		WithAccountAndAmount(party1, 1000000).
   291  		WithAccountAndAmount(party2, 90000000000) // LP needs a lot of balance
   292  
   293  	auctionOrders := []*types.Order{
   294  		// Limit Orders
   295  		{
   296  			Type:        types.OrderTypeLimit,
   297  			Size:        5,
   298  			Remaining:   5,
   299  			Price:       num.NewUint(1000),
   300  			Side:        types.SideBuy,
   301  			Party:       party0,
   302  			TimeInForce: types.OrderTimeInForceGTC,
   303  		},
   304  		{
   305  			Type:        types.OrderTypeLimit,
   306  			Size:        5,
   307  			Remaining:   5,
   308  			Price:       num.NewUint(1000),
   309  			Side:        types.SideSell,
   310  			Party:       party1,
   311  			TimeInForce: types.OrderTimeInForceGTC,
   312  		},
   313  		{
   314  			Type:        types.OrderTypeLimit,
   315  			Size:        1,
   316  			Remaining:   1,
   317  			Price:       num.NewUint(900),
   318  			Side:        types.SideBuy,
   319  			Party:       party0,
   320  			TimeInForce: types.OrderTimeInForceGTC,
   321  		},
   322  		{
   323  			Type:        types.OrderTypeLimit,
   324  			Size:        1,
   325  			Remaining:   1,
   326  			Price:       num.NewUint(1100),
   327  			Side:        types.SideSell,
   328  			Party:       party1,
   329  			TimeInForce: types.OrderTimeInForceGTC,
   330  		},
   331  	}
   332  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   333  	// submit the auctions orders & LP
   334  	tm.WithSubmittedOrders(t, auctionOrders...)
   335  	// update the time to get out of auction
   336  	if setMarkPrice {
   337  		// now set the markprice
   338  		mpOrders := []*types.Order{
   339  			{
   340  				Type:        types.OrderTypeLimit,
   341  				Size:        1,
   342  				Remaining:   1,
   343  				Price:       num.NewUint(900),
   344  				Side:        types.SideSell,
   345  				Party:       party1,
   346  				TimeInForce: types.OrderTimeInForceGTC,
   347  			},
   348  			{
   349  				Type:        types.OrderTypeLimit,
   350  				Size:        1,
   351  				Remaining:   1,
   352  				Price:       num.NewUint(2500),
   353  				Side:        types.SideBuy,
   354  				Party:       party0,
   355  				TimeInForce: types.OrderTimeInForceGTC,
   356  			},
   357  		}
   358  		// submit the auctions orders
   359  		tm.WithSubmittedOrders(t, mpOrders...)
   360  	}
   361  
   362  	tm.now = auctionEnd
   363  	tm.market.OnTick(ctx, auctionEnd)
   364  
   365  	assert.Equal(t,
   366  		tm.market.GetMarketData().MarketTradingMode,
   367  		types.MarketTradingModeContinuous,
   368  	)
   369  }
   370  
   371  func (tm *testMarket) EndOpeningAuction2(t *testing.T, auctionEnd time.Time, setMarkPrice bool) {
   372  	t.Helper()
   373  	var (
   374  		party0 = "clearing-auction-party0"
   375  		party1 = "clearing-auction-party1"
   376  	)
   377  
   378  	// parties used for clearing opening auction
   379  	tm.WithAccountAndAmount(party0, 1000000).
   380  		WithAccountAndAmount(party1, 1000000)
   381  
   382  	auctionOrders := []*types.Order{
   383  		// Limit Orders
   384  		{
   385  			Type:        types.OrderTypeLimit,
   386  			Size:        5,
   387  			Remaining:   5,
   388  			Price:       num.NewUint(1000),
   389  			Side:        types.SideBuy,
   390  			Party:       party0,
   391  			TimeInForce: types.OrderTimeInForceGTC,
   392  		},
   393  		{
   394  			Type:        types.OrderTypeLimit,
   395  			Size:        5,
   396  			Remaining:   5,
   397  			Price:       num.NewUint(1000),
   398  			Side:        types.SideSell,
   399  			Party:       party1,
   400  			TimeInForce: types.OrderTimeInForceGTC,
   401  		},
   402  		{
   403  			Type:        types.OrderTypeLimit,
   404  			Size:        1,
   405  			Remaining:   1,
   406  			Price:       num.NewUint(900),
   407  			Side:        types.SideBuy,
   408  			Party:       party0,
   409  			TimeInForce: types.OrderTimeInForceGTC,
   410  		},
   411  		{
   412  			Type:        types.OrderTypeLimit,
   413  			Size:        1,
   414  			Remaining:   1,
   415  			Price:       num.NewUint(1200),
   416  			Side:        types.SideSell,
   417  			Party:       party1,
   418  			TimeInForce: types.OrderTimeInForceGTC,
   419  		},
   420  	}
   421  
   422  	// submit the auctions orders
   423  	tm.WithSubmittedOrders(t, auctionOrders...)
   424  
   425  	// update the time to get out of auction
   426  	tm.market.OnTick(context.Background(), auctionEnd)
   427  
   428  	assert.Equal(t,
   429  		tm.market.GetMarketData().MarketTradingMode,
   430  		types.MarketTradingModeContinuous,
   431  	)
   432  
   433  	if setMarkPrice {
   434  		// now set the markprice
   435  		mpOrders := []*types.Order{
   436  			{
   437  				Type:        types.OrderTypeLimit,
   438  				Size:        1,
   439  				Remaining:   1,
   440  				Price:       num.NewUint(900),
   441  				Side:        types.SideSell,
   442  				Party:       party1,
   443  				TimeInForce: types.OrderTimeInForceGTC,
   444  			},
   445  			{
   446  				Type:        types.OrderTypeLimit,
   447  				Size:        1,
   448  				Remaining:   1,
   449  				Price:       num.NewUint(1200),
   450  				Side:        types.SideBuy,
   451  				Party:       party0,
   452  				TimeInForce: types.OrderTimeInForceGTC,
   453  			},
   454  		}
   455  		// submit the auctions orders
   456  		tm.WithSubmittedOrders(t, mpOrders...)
   457  	}
   458  }
   459  
   460  func mustOrderFromProto(o *vegapb.Order) *types.Order {
   461  	order, _ := types.OrderFromProto(o)
   462  	return order
   463  }
   464  
   465  func (tm *testMarket) lastOrderUpdate(id string) *types.Order {
   466  	var order *types.Order
   467  	cancel := false
   468  	for _, e := range tm.events {
   469  		switch evt := e.(type) {
   470  		case *events.Order:
   471  			ord := evt.Order()
   472  			if ord.Id == id {
   473  				order = mustOrderFromProto(ord)
   474  			}
   475  		case *events.CancelledOrders:
   476  			cancel = true
   477  		}
   478  	}
   479  	if cancel {
   480  		order.Status = types.OrderStatusCancelled
   481  	}
   482  	return order
   483  }
   484  
   485  func (tm *testMarket) StartOpeningAuction() *testMarket {
   486  	err := tm.market.StartOpeningAuction(context.Background())
   487  	require.NoError(tm.t, err)
   488  	return tm
   489  }
   490  
   491  func (tm *testMarket) WithAccountAndAmount(id string, amount uint64) *testMarket {
   492  	addAccountWithAmount(tm, id, amount)
   493  	return tm
   494  }
   495  
   496  func (tm *testMarket) PartyGeneralAccount(t *testing.T, party string) *types.Account {
   497  	t.Helper()
   498  	acc, err := tm.collateralEngine.GetPartyGeneralAccount(party, tm.asset)
   499  	require.NoError(t, err)
   500  	require.NotNil(t, acc)
   501  	return acc
   502  }
   503  
   504  func (tm *testMarket) PartyMarginAccount(t *testing.T, party string) *types.Account {
   505  	t.Helper()
   506  	acc, err := tm.collateralEngine.GetPartyMarginAccount(tm.market.GetID(), party, tm.asset)
   507  	require.NoError(t, err)
   508  	require.NotNil(t, acc)
   509  	return acc
   510  }
   511  
   512  func getTestMarket(
   513  	t *testing.T,
   514  	now time.Time,
   515  	pMonitorSettings *types.PriceMonitoringSettings,
   516  	openingAuctionDuration *types.AuctionDuration,
   517  ) *testMarket {
   518  	t.Helper()
   519  	return getTestMarket2(t, now, pMonitorSettings, openingAuctionDuration, true, 0.99)
   520  }
   521  
   522  func getTestMarketWithDP(
   523  	t *testing.T,
   524  	now time.Time,
   525  	pMonitorSettings *types.PriceMonitoringSettings,
   526  	openingAuctionDuration *types.AuctionDuration,
   527  	decimalPlaces uint64,
   528  	lpRange float64,
   529  ) *testMarket {
   530  	t.Helper()
   531  	return getTestMarket2WithDP(t, now, pMonitorSettings, openingAuctionDuration, true, decimalPlaces, lpRange)
   532  }
   533  
   534  func getTestMarket2(
   535  	t *testing.T,
   536  	now time.Time,
   537  	pMonitorSettings *types.PriceMonitoringSettings,
   538  	openingAuctionDuration *types.AuctionDuration,
   539  	startOpeningAuction bool,
   540  	lpRange float64,
   541  ) *testMarket {
   542  	t.Helper()
   543  	return getTestMarket2WithDP(t, now, pMonitorSettings, openingAuctionDuration, startOpeningAuction, 1, lpRange)
   544  }
   545  
   546  func getTestMarket2WithDP(
   547  	t *testing.T,
   548  	now time.Time,
   549  	pMonitorSettings *types.PriceMonitoringSettings,
   550  	openingAuctionDuration *types.AuctionDuration,
   551  	startOpeningAuction bool,
   552  	decimalPlaces uint64,
   553  	lpRange float64,
   554  ) *testMarket {
   555  	t.Helper()
   556  	ctrl := gomock.NewController(t)
   557  	log := logging.NewTestLogger()
   558  	riskConfig := risk.NewDefaultConfig()
   559  	positionConfig := positions.NewDefaultConfig()
   560  	settlementConfig := settlement.NewDefaultConfig()
   561  	matchingConfig := matching.NewDefaultConfig()
   562  	feeConfig := fee.NewDefaultConfig()
   563  	liquidityConfig := liquidity.NewDefaultConfig()
   564  	broker := bmocks.NewMockBroker(ctrl)
   565  	timeService := mocks.NewMockTimeService(ctrl)
   566  
   567  	tm := &testMarket{
   568  		log:         log,
   569  		ctrl:        ctrl,
   570  		broker:      broker,
   571  		timeService: timeService,
   572  		now:         now,
   573  	}
   574  
   575  	timeService.EXPECT().GetTimeNow().DoAndReturn(
   576  		func() time.Time {
   577  			return tm.now
   578  		}).AnyTimes()
   579  
   580  	handleEvent := func(evt events.Event) {
   581  		te := evt.Type()
   582  		if te == events.OrderEvent {
   583  			tm.orderEventCount++
   584  			tm.orderEvents = append(tm.orderEvents, evt)
   585  		}
   586  		tm.eventCount++
   587  		tm.events = append(tm.events, evt)
   588  	}
   589  
   590  	// catch all expected calls
   591  	broker.EXPECT().SendBatch(gomock.Any()).AnyTimes().Do(
   592  		func(evts []events.Event) {
   593  			for _, evt := range evts {
   594  				handleEvent(evt)
   595  			}
   596  		},
   597  	)
   598  
   599  	broker.EXPECT().Send(gomock.Any()).AnyTimes().Do(handleEvent)
   600  
   601  	collateralEngine := collateral.New(log, collateral.NewDefaultConfig(), timeService, broker)
   602  	err := collateralEngine.EnableAsset(context.Background(), types.Asset{
   603  		ID: "ETH",
   604  		Details: &types.AssetDetails{
   605  			Symbol:   "ETH",
   606  			Decimals: 0, // no decimals
   607  			Quantum:  num.DecimalOne(),
   608  		},
   609  	})
   610  	require.NoError(t, err)
   611  	// create asset stub to match the test asset:
   612  	cfgAsset := NewAssetStub("ETH", 0)
   613  
   614  	oracleEngine := spec.NewEngine(log, spec.NewDefaultConfig(), timeService, broker)
   615  	tm.oracleEngine = oracleEngine
   616  	tm.builtinOracle = spec.NewBuiltin(tm.oracleEngine, tm.timeService)
   617  
   618  	// add the token asset
   619  	tokAsset := types.Asset{
   620  		ID: "VOTE",
   621  		Details: &types.AssetDetails{
   622  			Name:     "VOTE",
   623  			Symbol:   "VOTE",
   624  			Decimals: 5,
   625  			Quantum:  num.DecimalOne(),
   626  			Source: &types.AssetDetailsBuiltinAsset{
   627  				BuiltinAsset: &types.BuiltinAsset{},
   628  			},
   629  		},
   630  	}
   631  
   632  	err = collateralEngine.EnableAsset(context.Background(), tokAsset)
   633  	if pMonitorSettings == nil {
   634  		pMonitorSettings = &types.PriceMonitoringSettings{
   635  			Parameters: &types.PriceMonitoringParameters{
   636  				Triggers: []*types.PriceMonitoringTrigger{},
   637  			},
   638  		}
   639  	}
   640  	require.NoError(t, err)
   641  	mkt := getMarketWithDP(pMonitorSettings, openingAuctionDuration, decimalPlaces, lpRange)
   642  	// ensure nextMTM is happening every block
   643  	mktCfg := &mkt
   644  	mktCfg.DecimalPlaces = cfgAsset.DecimalPlaces()
   645  
   646  	mas := monitor.NewAuctionState(mktCfg, now)
   647  	statevar := stubs.NewStateVar()
   648  
   649  	epoch := mocks.NewMockEpochEngine(ctrl)
   650  	epoch.EXPECT().NotifyOnEpoch(gomock.Any(), gomock.Any()).Times(1)
   651  	teams := mocks.NewMockTeams(tm.ctrl)
   652  	bc := mocks.NewMockAccountBalanceChecker(tm.ctrl)
   653  	marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
   654  	epoch.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
   655  
   656  	referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl)
   657  	volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl)
   658  	volumeRebate := fmocks.NewMockVolumeRebateService(tm.ctrl)
   659  
   660  	referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes()
   661  	referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   662  	referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   663  	volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
   664  	volumeRebate.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
   665  	banking := mocks.NewMockBanking(ctrl)
   666  	parties := mocks.NewMockParties(ctrl)
   667  
   668  	mktEngine, err := future.NewMarket(context.Background(),
   669  		log, riskConfig, positionConfig, settlementConfig, matchingConfig,
   670  		feeConfig, liquidityConfig, collateralEngine, oracleEngine, mktCfg, timeService, broker, mas, statevar, marketActivityTracker, cfgAsset,
   671  		peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties)
   672  	if err != nil {
   673  		t.Fatalf("couldn't create a market: %v", err)
   674  	}
   675  	// ensure MTM settlements happen every block
   676  	mktEngine.OnMarkPriceUpdateMaximumFrequency(context.Background(), time.Duration(0))
   677  	mktEngine.UpdateRiskFactorsForTest()
   678  
   679  	if startOpeningAuction {
   680  		d := time.Second
   681  		if openingAuctionDuration != nil {
   682  			d = time.Duration(openingAuctionDuration.Duration) * time.Second
   683  		}
   684  		mktEngine.OnMarketAuctionMinimumDurationUpdate(context.Background(), d)
   685  		err := mktEngine.StartOpeningAuction(context.Background())
   686  		require.NoError(t, err)
   687  	}
   688  
   689  	settlementAssets, err := mkt.GetAssets()
   690  	assert.NoError(t, err)
   691  
   692  	// ignore response ids here + this cannot fail
   693  	_, _, err = collateralEngine.CreateMarketAccounts(context.Background(), mktEngine.GetID(), settlementAssets[0])
   694  	assert.NoError(t, err)
   695  
   696  	tm.market = &marketW{mktEngine}
   697  	tm.collateralEngine = collateralEngine
   698  	tm.asset = settlementAssets[0]
   699  	tm.mas = mas
   700  	tm.mktCfg = mktCfg
   701  	tm.stateVar = statevar
   702  
   703  	// Reset event counters
   704  	tm.eventCount = 0
   705  	tm.orderEventCount = 0
   706  
   707  	return tm
   708  }
   709  
   710  func getMarket(pMonitorSettings *types.PriceMonitoringSettings, openingAuctionDuration *types.AuctionDuration) types.Market {
   711  	return getMarketWithDP(pMonitorSettings, openingAuctionDuration, 1, 0.99)
   712  }
   713  
   714  func getMarketWithDP(pMonitorSettings *types.PriceMonitoringSettings, openingAuctionDuration *types.AuctionDuration, decimalPlaces uint64, _ float64) types.Market {
   715  	pubKeys := []*dstypes.Signer{
   716  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
   717  	}
   718  
   719  	mkt := types.Market{
   720  		ID:            vgcrypto.RandomHash(),
   721  		DecimalPlaces: decimalPlaces,
   722  		Fees: &types.Fees{
   723  			Factors: &types.FeeFactors{
   724  				InfrastructureFee: num.DecimalFromFloat(0.001),
   725  				MakerFee:          num.DecimalFromFloat(0.004),
   726  			},
   727  			LiquidityFeeSettings: &types.LiquidityFeeSettings{
   728  				Method: types.LiquidityFeeMethodMarginalCost,
   729  			},
   730  		},
   731  		TradableInstrument: &types.TradableInstrument{
   732  			Instrument: &types.Instrument{
   733  				ID:   "Crypto/ETHUSD/Futures/Dec19",
   734  				Code: "CRYPTO:ETHUSD/DEC19",
   735  				Name: "December 2019 ETH vs USD future",
   736  				Metadata: &types.InstrumentMetadata{
   737  					Tags: []string{
   738  						"asset_class:fx/crypto",
   739  						"product:futures",
   740  					},
   741  				},
   742  				Product: &types.InstrumentFuture{
   743  					Future: &types.Future{
   744  						SettlementAsset: "ETH",
   745  						QuoteName:       "USD",
   746  						DataSourceSpecForSettlementData: &datasource.Spec{
   747  							ID: "1",
   748  							Data: datasource.NewDefinition(
   749  								datasource.ContentTypeOracle,
   750  							).SetOracleConfig(
   751  								&signedoracle.SpecConfiguration{
   752  									Signers: pubKeys,
   753  									Filters: []*dstypes.SpecFilter{
   754  										{
   755  											Key: &dstypes.SpecPropertyKey{
   756  												Name: "prices.ETH.value",
   757  												Type: datapb.PropertyKey_TYPE_INTEGER,
   758  											},
   759  											Conditions: []*dstypes.SpecCondition{},
   760  										},
   761  									},
   762  								},
   763  							),
   764  						},
   765  						DataSourceSpecForTradingTermination: &datasource.Spec{
   766  							ID: "2",
   767  							Data: datasource.NewDefinition(
   768  								datasource.ContentTypeOracle,
   769  							).SetOracleConfig(
   770  								&signedoracle.SpecConfiguration{
   771  									Signers: pubKeys,
   772  									Filters: []*dstypes.SpecFilter{
   773  										{
   774  											Key: &dstypes.SpecPropertyKey{
   775  												Name: "trading.terminated",
   776  												Type: datapb.PropertyKey_TYPE_BOOLEAN,
   777  											},
   778  											Conditions: []*dstypes.SpecCondition{},
   779  										},
   780  									},
   781  								},
   782  							),
   783  						},
   784  						DataSourceSpecBinding: &datasource.SpecBindingForFuture{
   785  							SettlementDataProperty:     "prices.ETH.value",
   786  							TradingTerminationProperty: "trading.terminated",
   787  						},
   788  					},
   789  				},
   790  			},
   791  			MarginCalculator: &types.MarginCalculator{
   792  				ScalingFactors: &types.ScalingFactors{
   793  					SearchLevel:       num.DecimalFromFloat(1.1),
   794  					InitialMargin:     num.DecimalFromFloat(1.2),
   795  					CollateralRelease: num.DecimalFromFloat(1.4),
   796  				},
   797  			},
   798  			RiskModel: &types.TradableInstrumentSimpleRiskModel{
   799  				SimpleRiskModel: &types.SimpleRiskModel{
   800  					Params: &types.SimpleModelParams{
   801  						FactorLong:           num.DecimalFromFloat(0.15),
   802  						FactorShort:          num.DecimalFromFloat(0.25),
   803  						MaxMoveUp:            MAXMOVEUP,
   804  						MinMoveDown:          MINMOVEDOWN,
   805  						ProbabilityOfTrading: num.DecimalFromFloat(0.1),
   806  					},
   807  				},
   808  			},
   809  		},
   810  		OpeningAuction:          openingAuctionDuration,
   811  		PriceMonitoringSettings: pMonitorSettings,
   812  		LiquidityMonitoringParameters: &types.LiquidityMonitoringParameters{
   813  			TargetStakeParameters: &types.TargetStakeParameters{
   814  				TimeWindow:    3600, // seconds = 1h
   815  				ScalingFactor: num.DecimalFromFloat(10),
   816  			},
   817  		},
   818  		LiquiditySLAParams: &types.LiquiditySLAParams{
   819  			PriceRange:                  num.DecimalOne(),
   820  			CommitmentMinTimeFraction:   num.DecimalFromFloat(0.5),
   821  			SlaCompetitionFactor:        num.DecimalOne(),
   822  			PerformanceHysteresisEpochs: 1,
   823  		},
   824  		LinearSlippageFactor:    num.DecimalFromFloat(0.1),
   825  		QuadraticSlippageFactor: num.DecimalFromFloat(0.1),
   826  		MarkPriceConfiguration: &types.CompositePriceConfiguration{
   827  			DecayWeight:        num.DecimalZero(),
   828  			DecayPower:         num.DecimalZero(),
   829  			CashAmount:         num.UintZero(),
   830  			CompositePriceType: types.CompositePriceTypeByLastTrade,
   831  		},
   832  		TickSize: num.UintOne(),
   833  	}
   834  
   835  	return mkt
   836  }
   837  
   838  func addAccount(t *testing.T, market *testMarket, party string) {
   839  	t.Helper()
   840  	_, err := market.collateralEngine.Deposit(context.Background(), party, market.asset, num.NewUint(1000000000))
   841  	if err != nil {
   842  		t.Fatalf("couldn't deposit asset \"%s\" for party \"%s\": %v", market.asset, party, err)
   843  	}
   844  }
   845  
   846  func addAccountWithAmount(market *testMarket, party string, amnt uint64) *types.LedgerMovement {
   847  	r, _ := market.collateralEngine.Deposit(context.Background(), party, market.asset, num.NewUint(amnt))
   848  	return r
   849  }
   850  
   851  // WithSubmittedLiquidityProvision Submits a Liquidity Provision and asserts that it was created without errors.
   852  func (tm *testMarket) WithSubmittedLiquidityProvision(t *testing.T, party string, amount uint64, fee string) *testMarket {
   853  	t.Helper()
   854  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   855  
   856  	f, _ := num.DecimalFromString(fee)
   857  	lps := &types.LiquidityProvisionSubmission{
   858  		MarketID:         tm.market.GetID(),
   859  		CommitmentAmount: num.NewUint(amount),
   860  		Fee:              f,
   861  	}
   862  
   863  	require.NoError(t,
   864  		tm.market.SubmitLiquidityProvision(ctx, lps, party, vgcrypto.RandomHash()),
   865  	)
   866  
   867  	return tm
   868  }
   869  
   870  // WithSubmittedOrder returns a market with Submitted orders defined in `orders`.
   871  // If one submission fails, it will make the test fail and stop.
   872  func (tm *testMarket) WithSubmittedOrders(t *testing.T, orders ...*types.Order) *testMarket {
   873  	t.Helper()
   874  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
   875  	for i, order := range orders {
   876  		order.MarketID = tm.market.GetID()
   877  		_, err := tm.market.SubmitOrder(ctx, order)
   878  		require.NoError(t, err, "Submitting Order(@index#%d): '%s' failed", i, order.String())
   879  	}
   880  	return tm
   881  }
   882  
   883  func (tm *testMarket) EventHasBeenEmitted(t *testing.T, e events.Event) {
   884  	t.Helper()
   885  	for _, event := range tm.events {
   886  		if reflect.DeepEqual(e, event) {
   887  			return
   888  		}
   889  	}
   890  	t.Fatalf("Expected event: '%s', has not been emitted", e)
   891  }
   892  
   893  func TestMarketClosing(t *testing.T) {
   894  	pubKeys := []*dstypes.Signer{
   895  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
   896  	}
   897  
   898  	party1 := "party1"
   899  	party2 := "party2"
   900  	lp1 := "lp1"
   901  	lp2 := "lp2"
   902  	now := time.Unix(10, 0)
   903  	closingAt := time.Unix(20, 0)
   904  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{Duration: 1})
   905  	defer tm.ctrl.Finish()
   906  	addAccount(t, tm, party1)
   907  	addAccount(t, tm, party2)
   908  	addAccount(t, tm, lp1)
   909  	addAccount(t, tm, lp2)
   910  
   911  	// submit liquidity with varying fee levels
   912  	commitment1 := num.NewUint(30000)
   913  	fee1 := num.DecimalFromFloat(0.01)
   914  	commitment2 := num.NewUint(20000)
   915  	fee2 := num.DecimalFromFloat(0.02)
   916  	lps := &types.LiquidityProvisionSubmission{
   917  		MarketID:         tm.market.GetID(),
   918  		CommitmentAmount: commitment1,
   919  		Fee:              fee1,
   920  	}
   921  
   922  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp1, vgcrypto.RandomHash()))
   923  	lps.Fee = fee2
   924  	lps.CommitmentAmount = commitment2
   925  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp2, vgcrypto.RandomHash()))
   926  
   927  	// generate trades so that fees need to be distributed among LPs
   928  	orders := []*types.Order{
   929  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order1", types.SideSell, lp1, 1000, 110),
   930  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order1", types.SideBuy, lp1, 1000, 90),
   931  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order1", types.SideSell, party1, 1, 100),
   932  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order2", types.SideBuy, party2, 1, 100),
   933  	}
   934  	for _, o := range orders {
   935  		conf, err := tm.market.SubmitOrder(context.Background(), o)
   936  		require.NoError(t, err)
   937  		require.NotNil(t, conf)
   938  	}
   939  
   940  	// leave opening auction
   941  	now = now.Add(2 * time.Second)
   942  	tm.now = now
   943  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
   944  	md := tm.market.GetMarketData()
   945  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
   946  
   947  	properties := map[string]string{}
   948  	properties["trading.terminated"] = "true"
   949  	err := tm.oracleEngine.BroadcastData(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), dstypes.Data{
   950  		Signers: pubKeys,
   951  		Data:    properties,
   952  	})
   953  	require.NoError(t, err)
   954  
   955  	closingAt = closingAt.Add(time.Second)
   956  	tm.now = closingAt
   957  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingAt)
   958  
   959  	// there's no settlement data yet
   960  	assert.False(t, closed)
   961  	assert.Equal(t, types.MarketStateTradingTerminated, tm.market.State())
   962  
   963  	// let time pass still no settlement data
   964  	closingAt = closingAt.Add(time.Second)
   965  	tm.now = closingAt
   966  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingAt)
   967  	assert.False(t, closed)
   968  	assert.Equal(t, types.MarketStateTradingTerminated, tm.market.State())
   969  
   970  	// now update the market with different trading terminated key
   971  	tm.mktCfg.TradableInstrument.Instrument.GetFuture().DataSourceSpecForTradingTermination = &datasource.Spec{
   972  		ID: "2",
   973  		Data: datasource.NewDefinition(
   974  			datasource.ContentTypeOracle,
   975  		).SetOracleConfig(&signedoracle.SpecConfiguration{
   976  			Signers: pubKeys,
   977  			Filters: []*dstypes.SpecFilter{
   978  				{
   979  					Key: &dstypes.SpecPropertyKey{
   980  						Name: "tradingTerminated",
   981  						Type: datapb.PropertyKey_TYPE_BOOLEAN,
   982  					},
   983  				},
   984  			},
   985  		}),
   986  	}
   987  	tm.mktCfg.TradableInstrument.Instrument.GetFuture().DataSourceSpecBinding.TradingTerminationProperty = "tradingTerminated"
   988  	err = tm.market.Update(context.Background(), tm.mktCfg, tm.oracleEngine)
   989  	require.NoError(t, err)
   990  
   991  	// now update the market again with the *same* spec ID
   992  	err = tm.market.Update(context.Background(), tm.mktCfg, tm.oracleEngine)
   993  	require.NoError(t, err)
   994  
   995  	properties = map[string]string{}
   996  	properties["tradingTerminated"] = "true"
   997  	err = tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
   998  		Signers: pubKeys,
   999  		Data:    properties,
  1000  	})
  1001  	require.NoError(t, err)
  1002  
  1003  	// let the oracle update settlement data
  1004  	delete(properties, "tradingTerminated")
  1005  	properties["prices.ETH.value"] = "100"
  1006  	err = tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1007  		Signers: pubKeys,
  1008  		Data:    properties,
  1009  	})
  1010  	require.NoError(t, err)
  1011  
  1012  	assert.Equal(t, closingAt.UnixNano(), tm.market.Mkt().MarketTimestamps.Close)
  1013  	assert.Equal(t, types.MarketStateSettled, tm.market.State())
  1014  
  1015  	closingAt = closingAt.Add(time.Second)
  1016  	tm.now = closingAt
  1017  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingAt)
  1018  	assert.True(t, closed)
  1019  	assert.Equal(t, types.MarketStateSettled, tm.market.State())
  1020  
  1021  	// call on epoch event to replicate system behaviour
  1022  	tm.market.OnEpochEvent(context.Background(), types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
  1023  }
  1024  
  1025  func TestMarketClosingAfterUpdate(t *testing.T) {
  1026  	// given
  1027  	party1 := "party1"
  1028  	party2 := "party2"
  1029  	now := time.Unix(10, 0)
  1030  	closingAt := time.Unix(20, 0)
  1031  	tm := getTestMarket(t, now, nil, nil)
  1032  	defer tm.ctrl.Finish()
  1033  
  1034  	pubKeys := []*dstypes.Signer{
  1035  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1036  	}
  1037  
  1038  	// setup
  1039  	addAccount(t, tm, party1)
  1040  	addAccount(t, tm, party2)
  1041  
  1042  	// then
  1043  	assert.Equal(t, types.MarketStateActive.String(), tm.market.State().String())
  1044  
  1045  	// when
  1046  	err := tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1047  		Signers: pubKeys,
  1048  		Data: map[string]string{
  1049  			"trading.terminated": "true",
  1050  		},
  1051  	})
  1052  
  1053  	// then
  1054  	require.NoError(t, err)
  1055  
  1056  	// given
  1057  	closingTimePlus1Sec := closingAt.Add(1 * time.Second)
  1058  
  1059  	// when
  1060  	tm.now = closingTimePlus1Sec
  1061  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingTimePlus1Sec)
  1062  
  1063  	// then
  1064  	require.False(t, closed)
  1065  	assert.Equal(t, types.MarketStateTradingTerminated.String(), tm.market.State().String())
  1066  
  1067  	// Update the market's oracle spec for settlement data.
  1068  
  1069  	// given
  1070  	updatedMkt := tm.mktCfg.DeepClone()
  1071  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForSettlementData.Data.UpdateFilters(
  1072  		[]*dstypes.SpecFilter{
  1073  			{
  1074  				Key: &dstypes.SpecPropertyKey{
  1075  					Name: "prices.ETHEREUM.value",
  1076  					Type: datapb.PropertyKey_TYPE_INTEGER,
  1077  				},
  1078  			},
  1079  		},
  1080  	)
  1081  
  1082  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecBinding.SettlementDataProperty = "prices.ETHEREUM.value"
  1083  
  1084  	// when
  1085  	err = tm.market.Update(context.Background(), updatedMkt, tm.oracleEngine)
  1086  
  1087  	// Sending an oracle data aiming at older oracle spec of the market.
  1088  
  1089  	// then
  1090  	require.NoError(t, err)
  1091  
  1092  	// when
  1093  	err = tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1094  		Signers: pubKeys,
  1095  		Data: map[string]string{
  1096  			"prices.ETH.value": "10",
  1097  		},
  1098  	})
  1099  
  1100  	// then
  1101  	require.NoError(t, err)
  1102  
  1103  	// Verify the market didn't catch the oracle data since the oracle spec has
  1104  	// been updated.
  1105  
  1106  	// given
  1107  	closingTimePlus2Sec := closingAt.Add(2 * time.Second)
  1108  
  1109  	// when
  1110  	tm.now = closingTimePlus2Sec
  1111  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingTimePlus2Sec)
  1112  
  1113  	// then
  1114  	require.False(t, closed)
  1115  	assert.Equal(t, types.MarketStateTradingTerminated.String(), tm.market.State().String())
  1116  
  1117  	// Verify the market did catch the oracle data according to the oracle spec
  1118  	// update.
  1119  
  1120  	// when
  1121  	err = tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1122  		Signers: pubKeys,
  1123  		Data: map[string]string{
  1124  			"prices.ETHEREUM.value": "100",
  1125  		},
  1126  	})
  1127  
  1128  	// then
  1129  	require.NoError(t, err)
  1130  
  1131  	// given
  1132  	closingTimePlus3Sec := closingAt.Add(2 * time.Second)
  1133  
  1134  	// when
  1135  	tm.now = closingTimePlus3Sec
  1136  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), closingTimePlus3Sec)
  1137  
  1138  	// then
  1139  	require.True(t, closed)
  1140  	assert.Equal(t, types.MarketStateSettled.String(), tm.market.State().String())
  1141  }
  1142  
  1143  func TestUnsubscribeTradingTerminatedOracle(t *testing.T) {
  1144  	// given
  1145  	party1 := "party1"
  1146  	party2 := "party2"
  1147  	now := time.Unix(10, 0)
  1148  	tm := getTestMarket(t, now, nil, nil)
  1149  	defer tm.ctrl.Finish()
  1150  
  1151  	// setup
  1152  	addAccount(t, tm, party1)
  1153  	addAccount(t, tm, party2)
  1154  
  1155  	// then
  1156  	assert.Equal(t, types.MarketStateActive.String(), tm.market.State().String())
  1157  
  1158  	// when
  1159  	err := tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1160  		Signers: []*dstypes.Signer{
  1161  			dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1162  		},
  1163  		Data: map[string]string{
  1164  			"trading.terminated": "true",
  1165  		},
  1166  	})
  1167  
  1168  	// then
  1169  	require.NoError(t, err)
  1170  
  1171  	count := tm.eventCount
  1172  
  1173  	for i := 0; i < 10; i++ {
  1174  		err := tm.oracleEngine.BroadcastData(context.Background(), dstypes.Data{
  1175  			Signers: []*dstypes.Signer{
  1176  				dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1177  			},
  1178  			Data: map[string]string{
  1179  				"trading.terminated": "true",
  1180  			},
  1181  		})
  1182  
  1183  		// then
  1184  		require.NoError(t, err)
  1185  	}
  1186  
  1187  	require.Equal(t, count, tm.eventCount)
  1188  }
  1189  
  1190  func TestMarketLiquidityFeeAfterUpdate(t *testing.T) {
  1191  	// given
  1192  	now := time.Unix(10, 0)
  1193  	tm := getTestMarket(t, now, nil, nil)
  1194  	defer tm.ctrl.Finish()
  1195  
  1196  	// then
  1197  	// We need to ensure this has been updated
  1198  	require.NotEqual(t, tm.market.GetLiquidityFee(), num.DecimalZero())
  1199  
  1200  	// given
  1201  	previousLiqFee := tm.market.GetLiquidityFee()
  1202  	updatedMkt := tm.mktCfg.DeepClone()
  1203  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForSettlementData.Data.UpdateFilters(
  1204  		[]*dstypes.SpecFilter{
  1205  			{
  1206  				Key: &dstypes.SpecPropertyKey{
  1207  					Name: "prices.ETHEREUM.value",
  1208  					Type: datapb.PropertyKey_TYPE_INTEGER,
  1209  				},
  1210  			},
  1211  		},
  1212  	)
  1213  
  1214  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecBinding.SettlementDataProperty = "prices.ETHEREUM.value"
  1215  
  1216  	// when
  1217  	err := tm.market.Update(context.Background(), updatedMkt, tm.oracleEngine)
  1218  
  1219  	// then
  1220  	require.NoError(t, err)
  1221  	assert.Equal(t, previousLiqFee, tm.market.GetLiquidityFee())
  1222  }
  1223  
  1224  func TestLiquidityFeeWhenTargetStakeDropsDueToFlowOfTime(t *testing.T) {
  1225  	party1 := "party1"
  1226  	party2 := "party2"
  1227  	lp1 := "lp1"
  1228  	lp2 := "lp2"
  1229  	maxOI := uint64(124)
  1230  	matchingPrice := uint64(111)
  1231  	now := time.Unix(10, 0)
  1232  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
  1233  		Duration: 1,
  1234  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  1235  	}, true, 1)
  1236  	tm.market.OnMarketTargetStakeTimeWindowUpdate(5 * time.Second)
  1237  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  1238  
  1239  	addAccount(t, tm, party1)
  1240  	addAccount(t, tm, party2)
  1241  	addAccountWithAmount(tm, lp1, 100000000000)
  1242  	addAccountWithAmount(tm, lp2, 100000000000)
  1243  
  1244  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
  1245  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, lp1, 1, 10)
  1246  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  1247  	require.NotNil(t, conf)
  1248  	require.NoError(t, err)
  1249  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1250  
  1251  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, lp2, 1, 100000)
  1252  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  1253  	require.NotNil(t, conf)
  1254  	require.NoError(t, err)
  1255  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1256  
  1257  	orders := []*types.Order{
  1258  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "ord1", types.SideSell, party1, maxOI, matchingPrice),
  1259  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "ord2", types.SideBuy, party2, maxOI, matchingPrice),
  1260  	}
  1261  	for _, o := range orders {
  1262  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  1263  		require.NoError(t, err)
  1264  		require.NotNil(t, conf)
  1265  	}
  1266  
  1267  	// submit liquidity with varying fee levels
  1268  	commitment1 := num.NewUint(30000)
  1269  	fee1 := num.DecimalFromFloat(0.01)
  1270  	commitment2 := num.NewUint(20000)
  1271  	fee2 := num.DecimalFromFloat(0.02)
  1272  	lps := &types.LiquidityProvisionSubmission{
  1273  		MarketID:         tm.market.GetID(),
  1274  		CommitmentAmount: commitment1,
  1275  		Fee:              fee1,
  1276  	}
  1277  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp1, vgcrypto.RandomHash()))
  1278  	lps.Fee = fee2
  1279  	lps.CommitmentAmount = commitment2
  1280  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lps, lp2, vgcrypto.RandomHash()))
  1281  
  1282  	// leave opening auction
  1283  	now = now.Add(2 * time.Second)
  1284  	tm.now = now
  1285  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  1286  	md := tm.market.GetMarketData()
  1287  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  1288  	require.Equal(t, maxOI, md.OpenInterest)
  1289  	now = now.Add(2 * time.Second)
  1290  	tm.now = now
  1291  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  1292  	// move time and decrase open interest
  1293  	orders = []*types.Order{
  1294  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "ord1", types.SideBuy, party1, maxOI-100, matchingPrice),
  1295  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "ord2", types.SideSell, party2, maxOI-100, matchingPrice),
  1296  	}
  1297  	for _, o := range orders {
  1298  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  1299  		require.NoError(t, err)
  1300  		require.NotNil(t, conf)
  1301  	}
  1302  	md = tm.market.GetMarketData()
  1303  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  1304  	targetStake1 := md.TargetStake
  1305  	require.Equal(t, fee2, tm.market.GetLiquidityFee())
  1306  
  1307  	// move time beyond taret stake window (so max OI drops and hence target stake)
  1308  	now = now.Add(6 * time.Second)
  1309  	tm.now = now
  1310  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  1311  
  1312  	md = tm.market.GetMarketData()
  1313  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  1314  	targetStake2 := md.TargetStake
  1315  
  1316  	require.Less(t, targetStake2, targetStake1)
  1317  	require.Equal(t, fee1, tm.market.GetLiquidityFee())
  1318  }
  1319  
  1320  func TestMarketNotActive(t *testing.T) {
  1321  	now := time.Unix(10, 0)
  1322  	closingAt := time.Unix(20, 0)
  1323  
  1324  	// this will create a market in Proposed Mode
  1325  	tm := getTestMarket2(t, now, nil, nil, false, 0.99)
  1326  	defer tm.ctrl.Finish()
  1327  
  1328  	require.Equal(t, types.MarketStateProposed, tm.market.State())
  1329  
  1330  	party1 := "party1"
  1331  	tm.WithAccountAndAmount(party1, 1000000)
  1332  
  1333  	hash := vgcrypto.RandomHash()
  1334  	order := &types.Order{
  1335  		ID:            hash,
  1336  		Type:          types.OrderTypeLimit,
  1337  		TimeInForce:   types.OrderTimeInForceGTT,
  1338  		Status:        types.OrderStatusActive,
  1339  		Side:          types.SideBuy,
  1340  		Party:         party1,
  1341  		MarketID:      tm.market.GetID(),
  1342  		Size:          100,
  1343  		Price:         num.NewUint(100),
  1344  		OriginalPrice: num.NewUint(100),
  1345  		Remaining:     100,
  1346  		CreatedAt:     now.UnixNano(),
  1347  		ExpiresAt:     closingAt.UnixNano(),
  1348  		Reference:     "party1-buy-order",
  1349  	}
  1350  
  1351  	tm.events = nil
  1352  	cpy := *order
  1353  	cpy.Status = types.OrderStatusRejected
  1354  	cpy.Reason = types.OrderErrorMarketClosed
  1355  	expectedEvent := events.NewOrderEvent(context.Background(), &cpy)
  1356  
  1357  	_, err := tm.market.SubmitOrderWithHash(context.Background(), order, hash)
  1358  	require.Error(t, err)
  1359  	tm.EventHasBeenEmitted(t, expectedEvent)
  1360  }
  1361  
  1362  func TestSubmittedOrderIdIsTheDeterministicId(t *testing.T) {
  1363  	now := time.Unix(10, 0)
  1364  	closingAt := time.Unix(20, 0)
  1365  	tm := getTestMarket(t, now, nil, nil)
  1366  	defer tm.ctrl.Finish()
  1367  
  1368  	party1 := "party1"
  1369  	order := &types.Order{
  1370  		Type:          types.OrderTypeLimit,
  1371  		TimeInForce:   types.OrderTimeInForceGTT,
  1372  		Status:        types.OrderStatusActive,
  1373  		ID:            "",
  1374  		Side:          types.SideBuy,
  1375  		Party:         party1,
  1376  		MarketID:      tm.market.GetID(),
  1377  		Size:          100,
  1378  		Price:         num.NewUint(100),
  1379  		OriginalPrice: num.NewUint(100),
  1380  		Remaining:     100,
  1381  		CreatedAt:     now.UnixNano(),
  1382  		ExpiresAt:     closingAt.UnixNano(),
  1383  		Reference:     "party1-buy-order",
  1384  	}
  1385  	addAccount(t, tm, party1)
  1386  
  1387  	deterministicID := vgcrypto.RandomHash()
  1388  	conf, err := tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), order.Party, deterministicID)
  1389  	if err != nil {
  1390  		t.Fatalf("failed to submit order:%s", err)
  1391  	}
  1392  
  1393  	assert.Equal(t, deterministicID, conf.Order.ID)
  1394  
  1395  	event := tm.orderEvents[0].(*events.Order)
  1396  	assert.Equal(t, event.Order().Id, deterministicID)
  1397  }
  1398  
  1399  func TestSubmitOrderWithInvalidTickSize(t *testing.T) {
  1400  	now := time.Unix(10, 0)
  1401  	closingAt := time.Unix(20, 0)
  1402  	tm := getTestMarket(t, now, nil, nil)
  1403  	tm.mktCfg.TickSize = num.NewUint(1000)
  1404  	defer tm.ctrl.Finish()
  1405  
  1406  	party1 := "party1"
  1407  	order := &types.Order{
  1408  		Type:        types.OrderTypeLimit,
  1409  		TimeInForce: types.OrderTimeInForceGTT,
  1410  		Status:      types.OrderStatusActive,
  1411  		ID:          "",
  1412  		Side:        types.SideBuy,
  1413  		Party:       party1,
  1414  		MarketID:    tm.market.GetID(),
  1415  		Size:        100,
  1416  		Price:       num.NewUint(1100),
  1417  		Remaining:   100,
  1418  		CreatedAt:   now.UnixNano(),
  1419  		ExpiresAt:   closingAt.UnixNano(),
  1420  		Reference:   "party1-buy-order",
  1421  	}
  1422  	addAccount(t, tm, party1)
  1423  
  1424  	deterministicID := vgcrypto.RandomHash()
  1425  	_, err := tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), order.Party, deterministicID)
  1426  	require.Error(t, types.ErrOrderNotInTickSize, err)
  1427  
  1428  	tm.mktCfg.TickSize = num.NewUint(100)
  1429  	_, err = tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), order.Party, deterministicID)
  1430  	require.NoError(t, err)
  1431  }
  1432  
  1433  func TestPeggingWithTickSize(t *testing.T) {
  1434  	now := time.Unix(10, 0)
  1435  	tm := getTestMarket(t, now, nil, nil)
  1436  	tm.mktCfg.TickSize = num.NewUint(50)
  1437  	defer tm.ctrl.Finish()
  1438  
  1439  	auxParty := "auxParty"
  1440  	auxParty2 := "auxParty2"
  1441  	addAccount(t, tm, auxParty)
  1442  	addAccount(t, tm, auxParty2)
  1443  
  1444  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
  1445  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 50)
  1446  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  1447  	require.NotNil(t, conf)
  1448  	require.NoError(t, err)
  1449  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1450  
  1451  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  1452  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  1453  	require.NotNil(t, conf)
  1454  	require.NoError(t, err)
  1455  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  1456  	auxOrders := []*types.Order{
  1457  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  1458  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  1459  	}
  1460  	for _, o := range auxOrders {
  1461  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  1462  		require.NoError(t, err)
  1463  		require.NotNil(t, conf)
  1464  	}
  1465  
  1466  	party1 := "party1"
  1467  	order := &types.Order{
  1468  		Type:        types.OrderTypeLimit,
  1469  		TimeInForce: types.OrderTimeInForceGTT,
  1470  		Status:      types.OrderStatusActive,
  1471  		ID:          "",
  1472  		Side:        types.SideBuy,
  1473  		Party:       party1,
  1474  		MarketID:    tm.market.GetID(),
  1475  		Size:        100,
  1476  		Remaining:   100,
  1477  		CreatedAt:   now.UnixNano(),
  1478  		ExpiresAt:   math.MaxInt64,
  1479  		Reference:   "party1-buy-order",
  1480  	}
  1481  	addAccount(t, tm, party1)
  1482  	// submit a pegged order pegged to the mid
  1483  	order.PeggedOrder = &types.PeggedOrder{
  1484  		Reference: types.PeggedReferenceMid,
  1485  		Offset:    num.NewUint(100),
  1486  	}
  1487  	// mid price is 50025 - 100 = 49,925 => 49950 bid rounded to the nearest tick size up
  1488  	conf, err = tm.market.SubmitOrder(context.Background(), order)
  1489  	require.NoError(t, err)
  1490  	require.Equal(t, "49950", conf.Order.OriginalPrice.String())
  1491  
  1492  	order.Side = types.SideSell
  1493  	// mid price is 50025 + 100 = 50125 => 50100 ask rounded to the nearest tick size down
  1494  	conf, err = tm.market.SubmitOrder(context.Background(), order)
  1495  	require.NoError(t, err)
  1496  	require.Equal(t, "50100", conf.Order.OriginalPrice.String())
  1497  
  1498  	mkt := tm.mktCfg.DeepClone()
  1499  	// offset is still divisible by ticksize so nothing happens
  1500  	mkt.TickSize = num.NewUint(50)
  1501  	require.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1502  	require.NoError(t, tm.market.Market.Update(context.Background(), mkt, tm.oracleEngine))
  1503  	require.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1504  
  1505  	mkt = tm.mktCfg.DeepClone()
  1506  	mkt.TickSize = num.NewUint(79)
  1507  	// offset is not divisible by ticksize so pegged orders get cancelled
  1508  	require.Equal(t, 2, tm.market.GetPeggedOrderCount())
  1509  	require.NoError(t, tm.market.Market.Update(context.Background(), mkt, tm.oracleEngine))
  1510  	require.Equal(t, 0, tm.market.GetPeggedOrderCount())
  1511  }
  1512  
  1513  func TestAmendOrderWithInvalidTickSize(t *testing.T) {
  1514  	now := time.Unix(10, 0)
  1515  	closingAt := time.Unix(20, 0)
  1516  	tm := getTestMarket(t, now, nil, nil)
  1517  	tm.mktCfg.TickSize = num.NewUint(100)
  1518  	defer tm.ctrl.Finish()
  1519  
  1520  	party1 := "party1"
  1521  	order := &types.Order{
  1522  		Type:        types.OrderTypeLimit,
  1523  		TimeInForce: types.OrderTimeInForceGTT,
  1524  		Status:      types.OrderStatusActive,
  1525  		ID:          "",
  1526  		Side:        types.SideBuy,
  1527  		Party:       party1,
  1528  		MarketID:    tm.market.GetID(),
  1529  		Size:        100,
  1530  		Price:       num.NewUint(100),
  1531  		Remaining:   100,
  1532  		CreatedAt:   now.UnixNano(),
  1533  		ExpiresAt:   closingAt.UnixNano(),
  1534  		Reference:   "party1-buy-order",
  1535  	}
  1536  	addAccount(t, tm, party1)
  1537  
  1538  	deterministicID := vgcrypto.RandomHash()
  1539  	conf, err := tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), order.Party, deterministicID)
  1540  	require.NoError(t, err)
  1541  
  1542  	orderAmendment := &types.OrderAmendment{
  1543  		OrderID:  conf.Order.ID,
  1544  		MarketID: conf.Order.MarketID,
  1545  		Price:    num.NewUint(1150),
  1546  	}
  1547  	_, err = tm.market.Market.AmendOrder(context.Background(), orderAmendment, party1, deterministicID)
  1548  	require.Error(t, types.ErrOrderNotInTickSize, err)
  1549  
  1550  	tm.mktCfg.TickSize = num.NewUint(50)
  1551  	_, err = tm.market.Market.AmendOrder(context.Background(), orderAmendment, party1, deterministicID)
  1552  	require.NoError(t, err)
  1553  
  1554  	// pegged order
  1555  	order.Price = nil
  1556  	order.OriginalPrice = nil
  1557  	// market tick is 50, lets set a peg offset of 75
  1558  	order.Side = types.SideBuy
  1559  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 75)
  1560  	_, err = tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), party1, deterministicID)
  1561  	require.Error(t, types.ErrOrderNotInTickSize, err)
  1562  
  1563  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 100)
  1564  	_, err = tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), party1, vgcrypto.RandomHash())
  1565  	require.NoError(t, err)
  1566  
  1567  	order.Side = types.SideSell
  1568  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 75)
  1569  	_, err = tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), party1, deterministicID)
  1570  	require.Error(t, types.ErrOrderNotInTickSize, err)
  1571  
  1572  	order.ID = crypto.RandomHash()
  1573  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 100)
  1574  	conf, err = tm.market.Market.SubmitOrder(context.Background(), order.IntoSubmission(), party1, vgcrypto.RandomHash())
  1575  	require.NoError(t, err)
  1576  
  1577  	order.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 75)
  1578  	orderAmendment = &types.OrderAmendment{
  1579  		OrderID:      conf.Order.ID,
  1580  		MarketID:     conf.Order.MarketID,
  1581  		PeggedOffset: num.NewUint(75),
  1582  	}
  1583  	_, err = tm.market.Market.AmendOrder(context.Background(), orderAmendment, party1, vgcrypto.RandomHash())
  1584  	require.Error(t, types.ErrOrderNotInTickSize, err)
  1585  }
  1586  
  1587  func TestMarketWithTradeClosing(t *testing.T) {
  1588  	party1 := "party1"
  1589  	party2 := "party2"
  1590  	now := time.Unix(10, 0)
  1591  	closingAt := time.Unix(20, 0)
  1592  	tm := getTestMarket(t, now, nil, nil)
  1593  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1594  	defer tm.ctrl.Finish()
  1595  	// add 2 parties to the party engine
  1596  	// this will create 2 parties, credit their account
  1597  	// and move some monies to the market
  1598  	// this will also output the closed accounts
  1599  	addAccount(t, tm, party1)
  1600  	addAccount(t, tm, party2)
  1601  	pubKeys := []*dstypes.Signer{
  1602  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1603  	}
  1604  
  1605  	// submit orders
  1606  	// party1 buys
  1607  	// party2 sells
  1608  	orderBuy := &types.Order{
  1609  		Type:        types.OrderTypeLimit,
  1610  		TimeInForce: types.OrderTimeInForceGTT,
  1611  		Status:      types.OrderStatusActive,
  1612  		ID:          "",
  1613  		Side:        types.SideBuy,
  1614  		Party:       party1,
  1615  		MarketID:    tm.market.GetID(),
  1616  		Size:        100,
  1617  		Price:       num.NewUint(100),
  1618  		Remaining:   100,
  1619  		CreatedAt:   now.UnixNano(),
  1620  		ExpiresAt:   closingAt.UnixNano(),
  1621  		Reference:   "party1-buy-order",
  1622  	}
  1623  	orderSell := &types.Order{
  1624  		Type:        types.OrderTypeLimit,
  1625  		TimeInForce: types.OrderTimeInForceGTT,
  1626  		Status:      types.OrderStatusActive,
  1627  		ID:          "",
  1628  		Side:        types.SideSell,
  1629  		Party:       party2,
  1630  		MarketID:    tm.market.GetID(),
  1631  		Size:        100,
  1632  		Price:       num.NewUint(100),
  1633  		Remaining:   100,
  1634  		CreatedAt:   now.UnixNano(),
  1635  		ExpiresAt:   closingAt.UnixNano(),
  1636  		Reference:   "party2-sell-order",
  1637  	}
  1638  
  1639  	// submit orders
  1640  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  1641  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  1642  
  1643  	_, err := tm.market.SubmitOrder(ctx, orderBuy)
  1644  	assert.Nil(t, err)
  1645  	if err != nil {
  1646  		t.Fail()
  1647  	}
  1648  	tm.now = tm.now.Add(time.Second)
  1649  	tm.market.OnTick(ctx, tm.now)
  1650  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  1651  
  1652  	_, err = tm.market.SubmitOrder(ctx, orderSell)
  1653  	assert.Nil(t, err)
  1654  	if err != nil {
  1655  		t.Fail()
  1656  	}
  1657  	tm.now = tm.now.Add(time.Second)
  1658  	tm.market.OnTick(ctx, tm.now)
  1659  
  1660  	// update collateral time first, normally done by execution engine
  1661  	futureTime := closingAt.Add(1 * time.Second)
  1662  	properties := map[string]string{}
  1663  	properties["trading.terminated"] = "true"
  1664  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  1665  		Signers: pubKeys,
  1666  		Data:    properties,
  1667  	})
  1668  	require.NoError(t, err)
  1669  
  1670  	properties = map[string]string{}
  1671  	properties["prices.ETH.value"] = "100"
  1672  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  1673  		Signers: pubKeys,
  1674  		Data:    properties,
  1675  	})
  1676  	require.NoError(t, err)
  1677  
  1678  	tm.now = futureTime
  1679  	closed := tm.market.OnTick(ctx, futureTime)
  1680  	assert.True(t, closed)
  1681  }
  1682  
  1683  func TestUpdateMarketWithOracleSpecEarlyTermination(t *testing.T) {
  1684  	party1 := "party1"
  1685  	party2 := "party2"
  1686  	now := time.Unix(10, 0)
  1687  	closingAt := time.Unix(20, 0)
  1688  	tm := getTestMarket(t, now, nil, nil)
  1689  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1690  	defer tm.ctrl.Finish()
  1691  	// add 2 parties to the party engine
  1692  	// this will create 2 parties, credit their account
  1693  	// and move some monies to the market
  1694  	// this will also output the closed accounts
  1695  	addAccount(t, tm, party1)
  1696  	addAccount(t, tm, party2)
  1697  
  1698  	// submit orders
  1699  	// party1 buys
  1700  	// party2 sells
  1701  	orderBuy := &types.Order{
  1702  		Type:        types.OrderTypeLimit,
  1703  		TimeInForce: types.OrderTimeInForceGTT,
  1704  		Status:      types.OrderStatusActive,
  1705  		ID:          "",
  1706  		Side:        types.SideBuy,
  1707  		Party:       party1,
  1708  		MarketID:    tm.market.GetID(),
  1709  		Size:        100,
  1710  		Price:       num.NewUint(100),
  1711  		Remaining:   100,
  1712  		CreatedAt:   now.UnixNano(),
  1713  		ExpiresAt:   closingAt.UnixNano(),
  1714  		Reference:   "party1-buy-order",
  1715  	}
  1716  	orderSell := &types.Order{
  1717  		Type:        types.OrderTypeLimit,
  1718  		TimeInForce: types.OrderTimeInForceGTT,
  1719  		Status:      types.OrderStatusActive,
  1720  		ID:          "",
  1721  		Side:        types.SideSell,
  1722  		Party:       party2,
  1723  		MarketID:    tm.market.GetID(),
  1724  		Size:        100,
  1725  		Price:       num.NewUint(100),
  1726  		Remaining:   100,
  1727  		CreatedAt:   now.UnixNano(),
  1728  		ExpiresAt:   closingAt.UnixNano(),
  1729  		Reference:   "party2-sell-order",
  1730  	}
  1731  
  1732  	// submit orders
  1733  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  1734  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  1735  
  1736  	_, err := tm.market.SubmitOrder(ctx, orderBuy)
  1737  	assert.Nil(t, err)
  1738  	if err != nil {
  1739  		t.Fail()
  1740  	}
  1741  	tm.now = tm.now.Add(time.Second)
  1742  	tm.market.OnTick(ctx, tm.now)
  1743  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  1744  
  1745  	_, err = tm.market.SubmitOrder(ctx, orderSell)
  1746  	assert.Nil(t, err)
  1747  	if err != nil {
  1748  		t.Fail()
  1749  	}
  1750  	tm.now = tm.now.Add(time.Second)
  1751  	tm.market.OnTick(ctx, tm.now)
  1752  
  1753  	// now update the market
  1754  	updatedMkt := tm.mktCfg.DeepClone()
  1755  
  1756  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForTradingTermination.Data.UpdateFilters(
  1757  		[]*dstypes.SpecFilter{
  1758  			{
  1759  				Key: &dstypes.SpecPropertyKey{
  1760  					Name: spec.BuiltinTimestamp,
  1761  					Type: datapb.PropertyKey_TYPE_TIMESTAMP,
  1762  				},
  1763  				Conditions: []*dstypes.SpecCondition{
  1764  					{
  1765  						Operator: datapb.Condition_OPERATOR_GREATER_THAN_OR_EQUAL,
  1766  						Value:    "0",
  1767  					},
  1768  				},
  1769  			},
  1770  		},
  1771  	)
  1772  
  1773  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecBinding.TradingTerminationProperty = spec.BuiltinTimestamp
  1774  
  1775  	err = tm.market.Update(context.Background(), updatedMkt, tm.oracleEngine)
  1776  	require.NoError(t, err)
  1777  	tm.builtinOracle.OnTick(ctx, tm.now)
  1778  	tm.market.OnTick(ctx, tm.now)
  1779  	require.Equal(t, types.MarketStateTradingTerminated, tm.market.State())
  1780  
  1781  	pubKeys := []*dstypes.Signer{
  1782  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1783  	}
  1784  	properties := map[string]string{}
  1785  	properties["prices.ETH.value"] = "100"
  1786  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  1787  		Signers: pubKeys,
  1788  		Data:    properties,
  1789  	})
  1790  	require.NoError(t, err)
  1791  
  1792  	tm.now = tm.now.Add(time.Second)
  1793  	closed := tm.market.OnTick(ctx, tm.now)
  1794  	assert.True(t, closed)
  1795  }
  1796  
  1797  func Test6056(t *testing.T) {
  1798  	party1 := "party1"
  1799  	party2 := "party2"
  1800  	now := time.Unix(10, 0)
  1801  	closingAt := time.Unix(20, 0)
  1802  	tm := getTestMarket(t, now, nil, nil)
  1803  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1804  	defer tm.ctrl.Finish()
  1805  	// add 2 parties to the party engine
  1806  	// this will create 2 parties, credit their account
  1807  	// and move some monies to the market
  1808  	// this will also output the closed accounts
  1809  	addAccount(t, tm, party1)
  1810  	addAccount(t, tm, party2)
  1811  
  1812  	// submit orders
  1813  	// party1 buys
  1814  	// party2 sells
  1815  	orderBuy := &types.Order{
  1816  		Type:        types.OrderTypeLimit,
  1817  		TimeInForce: types.OrderTimeInForceGTT,
  1818  		Status:      types.OrderStatusActive,
  1819  		ID:          "",
  1820  		Side:        types.SideBuy,
  1821  		Party:       party1,
  1822  		MarketID:    tm.market.GetID(),
  1823  		Size:        100,
  1824  		Price:       num.NewUint(100),
  1825  		Remaining:   100,
  1826  		CreatedAt:   now.UnixNano(),
  1827  		ExpiresAt:   closingAt.UnixNano(),
  1828  		Reference:   "party1-buy-order",
  1829  	}
  1830  	orderSell := &types.Order{
  1831  		Type:        types.OrderTypeLimit,
  1832  		TimeInForce: types.OrderTimeInForceGTT,
  1833  		Status:      types.OrderStatusActive,
  1834  		ID:          "",
  1835  		Side:        types.SideSell,
  1836  		Party:       party2,
  1837  		MarketID:    tm.market.GetID(),
  1838  		Size:        100,
  1839  		Price:       num.NewUint(100),
  1840  		Remaining:   100,
  1841  		CreatedAt:   now.UnixNano(),
  1842  		ExpiresAt:   closingAt.UnixNano(),
  1843  		Reference:   "party2-sell-order",
  1844  	}
  1845  
  1846  	// submit orders
  1847  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  1848  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  1849  
  1850  	_, err := tm.market.SubmitOrder(ctx, orderBuy)
  1851  	assert.Nil(t, err)
  1852  	if err != nil {
  1853  		t.Fail()
  1854  	}
  1855  	tm.now = tm.now.Add(time.Second)
  1856  	tm.market.OnTick(ctx, tm.now)
  1857  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  1858  
  1859  	_, err = tm.market.SubmitOrder(ctx, orderSell)
  1860  	assert.Nil(t, err)
  1861  	if err != nil {
  1862  		t.Fail()
  1863  	}
  1864  	tm.now = tm.now.Add(time.Second)
  1865  	tm.market.OnTick(ctx, tm.now)
  1866  
  1867  	// now update the market
  1868  	updatedMkt := tm.mktCfg.DeepClone()
  1869  
  1870  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForSettlementData.Data.UpdateFilters(
  1871  		[]*dstypes.SpecFilter{
  1872  			{
  1873  				Key: &dstypes.SpecPropertyKey{
  1874  					Name: "prices.ETH.value",
  1875  					Type: datapb.PropertyKey_TYPE_INTEGER,
  1876  				},
  1877  				Conditions: []*dstypes.SpecCondition{
  1878  					{
  1879  						Operator: datapb.Condition_OPERATOR_GREATER_THAN_OR_EQUAL,
  1880  						Value:    "1",
  1881  					},
  1882  				},
  1883  			},
  1884  		},
  1885  	)
  1886  
  1887  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForTradingTermination.Data.UpdateFilters(
  1888  		[]*dstypes.SpecFilter{
  1889  			{
  1890  				Key: &dstypes.SpecPropertyKey{
  1891  					Name: "trading.terminated",
  1892  					Type: datapb.PropertyKey_TYPE_BOOLEAN,
  1893  				},
  1894  				Conditions: []*dstypes.SpecCondition{
  1895  					{
  1896  						Operator: datapb.Condition_OPERATOR_EQUALS,
  1897  						Value:    "false",
  1898  					},
  1899  				},
  1900  			},
  1901  		},
  1902  	)
  1903  
  1904  	pubKeys := []*dstypes.Signer{
  1905  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  1906  	}
  1907  	err = tm.market.Update(context.Background(), updatedMkt, tm.oracleEngine)
  1908  	require.NoError(t, err)
  1909  
  1910  	properties := map[string]string{}
  1911  	properties["trading.terminated"] = "false"
  1912  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  1913  		Signers: pubKeys,
  1914  		Data:    properties,
  1915  	})
  1916  	require.NoError(t, err)
  1917  	tm.market.OnTick(ctx, tm.now)
  1918  	require.Equal(t, types.MarketStateTradingTerminated, tm.market.State())
  1919  
  1920  	properties = map[string]string{}
  1921  	properties["prices.ETH.value"] = "100"
  1922  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  1923  		Signers: pubKeys,
  1924  		Data:    properties,
  1925  	})
  1926  	require.NoError(t, err)
  1927  
  1928  	tm.now = tm.now.Add(time.Second)
  1929  	closed := tm.market.OnTick(ctx, tm.now)
  1930  	assert.True(t, closed)
  1931  }
  1932  
  1933  func TestOraclesWithMultipleFilterNameFails(t *testing.T) {
  1934  	party1 := "party1"
  1935  	party2 := "party2"
  1936  	now := time.Unix(10, 0)
  1937  	closingAt := time.Unix(20, 0)
  1938  	tm := getTestMarket(t, now, nil, nil)
  1939  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  1940  	defer tm.ctrl.Finish()
  1941  	// add 2 parties to the party engine
  1942  	// this will create 2 parties, credit their account
  1943  	// and move some monies to the market
  1944  	// this will also output the closed accounts
  1945  	addAccount(t, tm, party1)
  1946  	addAccount(t, tm, party2)
  1947  
  1948  	// submit orders
  1949  	// party1 buys
  1950  	// party2 sells
  1951  	orderBuy := &types.Order{
  1952  		Type:        types.OrderTypeLimit,
  1953  		TimeInForce: types.OrderTimeInForceGTT,
  1954  		Status:      types.OrderStatusActive,
  1955  		ID:          "",
  1956  		Side:        types.SideBuy,
  1957  		Party:       party1,
  1958  		MarketID:    tm.market.GetID(),
  1959  		Size:        100,
  1960  		Price:       num.NewUint(100),
  1961  		Remaining:   100,
  1962  		CreatedAt:   now.UnixNano(),
  1963  		ExpiresAt:   closingAt.UnixNano(),
  1964  		Reference:   "party1-buy-order",
  1965  	}
  1966  	orderSell := &types.Order{
  1967  		Type:        types.OrderTypeLimit,
  1968  		TimeInForce: types.OrderTimeInForceGTT,
  1969  		Status:      types.OrderStatusActive,
  1970  		ID:          "",
  1971  		Side:        types.SideSell,
  1972  		Party:       party2,
  1973  		MarketID:    tm.market.GetID(),
  1974  		Size:        100,
  1975  		Price:       num.NewUint(100),
  1976  		Remaining:   100,
  1977  		CreatedAt:   now.UnixNano(),
  1978  		ExpiresAt:   closingAt.UnixNano(),
  1979  		Reference:   "party2-sell-order",
  1980  	}
  1981  
  1982  	// submit orders
  1983  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  1984  
  1985  	_, err := tm.market.SubmitOrder(ctx, orderBuy)
  1986  	assert.Nil(t, err)
  1987  	if err != nil {
  1988  		t.Fail()
  1989  	}
  1990  	tm.now = tm.now.Add(time.Second)
  1991  	tm.market.OnTick(ctx, tm.now)
  1992  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  1993  
  1994  	_, err = tm.market.SubmitOrder(ctx, orderSell)
  1995  	assert.Nil(t, err)
  1996  	if err != nil {
  1997  		t.Fail()
  1998  	}
  1999  	tm.now = tm.now.Add(time.Second)
  2000  	tm.market.OnTick(ctx, tm.now)
  2001  
  2002  	// now update the market
  2003  	updatedMkt := tm.mktCfg.DeepClone()
  2004  
  2005  	f1 := uint64(12)
  2006  	f2 := uint64(21)
  2007  	err = updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForSettlementData.Data.UpdateFilters(
  2008  		[]*dstypes.SpecFilter{
  2009  			{
  2010  				Key: &dstypes.SpecPropertyKey{
  2011  					Name:                "prices.ETH.value",
  2012  					Type:                datapb.PropertyKey_TYPE_INTEGER,
  2013  					NumberDecimalPlaces: &f1,
  2014  				},
  2015  				Conditions: []*dstypes.SpecCondition{
  2016  					{
  2017  						Operator: datapb.Condition_OPERATOR_GREATER_THAN,
  2018  						Value:    "717098987000000000000000000000000000000",
  2019  					},
  2020  				},
  2021  			},
  2022  			{
  2023  				Key: &dstypes.SpecPropertyKey{
  2024  					Name:                "prices.ETH.value",
  2025  					Type:                datapb.PropertyKey_TYPE_INTEGER,
  2026  					NumberDecimalPlaces: &f2,
  2027  				},
  2028  				Conditions: []*dstypes.SpecCondition{
  2029  					{
  2030  						Operator: datapb.Condition_OPERATOR_GREATER_THAN,
  2031  						Value:    "957586060000000000000000000000000000000000000000",
  2032  					},
  2033  				},
  2034  			},
  2035  		},
  2036  	)
  2037  
  2038  	assert.ErrorIs(t, dserrors.ErrDataSourceSpecHasMultipleSameKeyNamesInFilterList, err)
  2039  
  2040  	updatedMkt.TradableInstrument.Instrument.GetFuture().DataSourceSpecForTradingTermination.Data.UpdateFilters(
  2041  		[]*dstypes.SpecFilter{
  2042  			{
  2043  				Key: &dstypes.SpecPropertyKey{
  2044  					Name: "trading.terminated",
  2045  					Type: datapb.PropertyKey_TYPE_BOOLEAN,
  2046  				},
  2047  				Conditions: []*dstypes.SpecCondition{
  2048  					{
  2049  						Operator: datapb.Condition_OPERATOR_EQUALS,
  2050  						Value:    "false",
  2051  					},
  2052  				},
  2053  			},
  2054  		},
  2055  	)
  2056  
  2057  	pubKeys := []*dstypes.Signer{
  2058  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
  2059  	}
  2060  	err = tm.market.Update(context.Background(), updatedMkt, tm.oracleEngine)
  2061  	require.NoError(t, err)
  2062  
  2063  	properties := map[string]string{}
  2064  	properties["trading.terminated"] = "false"
  2065  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  2066  		Signers: pubKeys,
  2067  		Data:    properties,
  2068  	})
  2069  	require.NoError(t, err)
  2070  	tm.market.OnTick(ctx, tm.now)
  2071  	require.Equal(t, types.MarketStateTradingTerminated, tm.market.State())
  2072  
  2073  	properties = map[string]string{}
  2074  	properties["prices.ETH.value"] = "100"
  2075  	err = tm.oracleEngine.BroadcastData(ctx, dstypes.Data{
  2076  		Signers: pubKeys,
  2077  		Data:    properties,
  2078  	})
  2079  	require.NoError(t, err)
  2080  
  2081  	tm.now = tm.now.Add(time.Second)
  2082  	closed := tm.market.OnTick(ctx, tm.now)
  2083  
  2084  	// The market should be closed, because it was never updated
  2085  	assert.True(t, closed)
  2086  }
  2087  
  2088  func TestMarketGetMarginOnNewOrderEmptyBook(t *testing.T) {
  2089  	party1 := "party1"
  2090  	now := time.Unix(10, 0)
  2091  	closingAt := time.Unix(10000000000, 0)
  2092  	tm := getTestMarket(t, now, nil, nil)
  2093  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2094  	defer tm.ctrl.Finish()
  2095  	// add 2 parties to the party engine
  2096  	// this will create 2 parties, credit their account
  2097  	// and move some monies to the market
  2098  	addAccount(t, tm, party1)
  2099  
  2100  	// submit orders
  2101  	// party1 buys
  2102  	// party2 sells
  2103  	orderBuy := &types.Order{
  2104  		Type:        types.OrderTypeLimit,
  2105  		TimeInForce: types.OrderTimeInForceGTT,
  2106  		Status:      types.OrderStatusActive,
  2107  		ID:          "",
  2108  		Side:        types.SideBuy,
  2109  		Party:       party1,
  2110  		MarketID:    tm.market.GetID(),
  2111  		Size:        100,
  2112  		Price:       num.NewUint(100),
  2113  		Remaining:   100,
  2114  		CreatedAt:   now.UnixNano(),
  2115  		ExpiresAt:   closingAt.UnixNano(),
  2116  		Reference:   "party1-buy-order",
  2117  	}
  2118  
  2119  	// submit orders
  2120  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2121  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  2122  
  2123  	_, err := tm.market.SubmitOrder(context.Background(), orderBuy)
  2124  	assert.Nil(t, err)
  2125  	if err != nil {
  2126  		t.Fail()
  2127  	}
  2128  	tm.now = tm.now.Add(time.Second)
  2129  	tm.market.OnTick(ctx, tm.now)
  2130  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  2131  }
  2132  
  2133  func TestMarketGetMarginOnFailNoFund(t *testing.T) {
  2134  	party1, party2, party3 := "party1", "party2", "party3"
  2135  	now := time.Unix(10, 0)
  2136  	closingAt := time.Unix(10000000000, 0)
  2137  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
  2138  		Duration: 1,
  2139  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  2140  	}, true, 1)
  2141  	defer tm.ctrl.Finish()
  2142  	// add 2 parties to the party engine
  2143  	// this will create 2 parties, credit their account
  2144  	// and move some monies to the market
  2145  	addAccountWithAmount(tm, party1, 0)
  2146  	addAccountWithAmount(tm, party2, 1000000)
  2147  	addAccountWithAmount(tm, party3, 1000000)
  2148  	addAccountWithAmount(tm, "lpprov", 100000000)
  2149  
  2150  	auxParty := "auxParty"
  2151  	auxParty2 := "auxParty2"
  2152  	addAccount(t, tm, auxParty)
  2153  	addAccount(t, tm, auxParty2)
  2154  
  2155  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
  2156  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  2157  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  2158  	require.NotNil(t, conf)
  2159  	require.NoError(t, err)
  2160  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2161  
  2162  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  2163  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  2164  	require.NotNil(t, conf)
  2165  	require.NoError(t, err)
  2166  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2167  	auxOrders := []*types.Order{
  2168  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  2169  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  2170  	}
  2171  	for _, o := range auxOrders {
  2172  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  2173  		require.NoError(t, err)
  2174  		require.NotNil(t, conf)
  2175  	}
  2176  	lp := &types.LiquidityProvisionSubmission{
  2177  		MarketID:         tm.market.GetID(),
  2178  		CommitmentAmount: num.NewUint(500),
  2179  		Fee:              num.DecimalFromFloat(0.01),
  2180  	}
  2181  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2182  	// leave opening auction
  2183  	now = now.Add(time.Second * 2)
  2184  	tm.now = now
  2185  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  2186  
  2187  	order1 := &types.Order{
  2188  		Status:      types.OrderStatusActive,
  2189  		Type:        types.OrderTypeLimit,
  2190  		TimeInForce: types.OrderTimeInForceGTC,
  2191  		ID:          "someid12",
  2192  		Side:        types.SideBuy,
  2193  		Party:       party2,
  2194  		MarketID:    tm.market.GetID(),
  2195  		Size:        100,
  2196  		Price:       num.NewUint(100),
  2197  		Remaining:   100,
  2198  		CreatedAt:   now.UnixNano(),
  2199  		Reference:   "party2-buy-order",
  2200  	}
  2201  	order2 := &types.Order{
  2202  		Status:      types.OrderStatusActive,
  2203  		Type:        types.OrderTypeLimit,
  2204  		TimeInForce: types.OrderTimeInForceGTC,
  2205  		ID:          "someid123",
  2206  		Side:        types.SideSell,
  2207  		Party:       party3,
  2208  		MarketID:    tm.market.GetID(),
  2209  		Size:        100,
  2210  		Price:       num.NewUint(100),
  2211  		Remaining:   100,
  2212  		CreatedAt:   now.UnixNano(),
  2213  		Reference:   "party3-buy-order",
  2214  	}
  2215  	_, err = tm.market.SubmitOrder(context.TODO(), order1)
  2216  	assert.NoError(t, err)
  2217  	confirmation, err := tm.market.SubmitOrder(context.TODO(), order2)
  2218  	assert.NoError(t, err)
  2219  	assert.Equal(t, 1, len(confirmation.Trades))
  2220  
  2221  	// submit orders
  2222  	// party1 buys
  2223  	// party2 sells
  2224  	orderBuy := &types.Order{
  2225  		Type:        types.OrderTypeLimit,
  2226  		TimeInForce: types.OrderTimeInForceGTT,
  2227  		Status:      types.OrderStatusActive,
  2228  		ID:          "",
  2229  		Side:        types.SideBuy,
  2230  		Party:       party1,
  2231  		MarketID:    tm.market.GetID(),
  2232  		Size:        100,
  2233  		Price:       num.NewUint(100),
  2234  		Remaining:   100,
  2235  		CreatedAt:   now.UnixNano(),
  2236  		ExpiresAt:   closingAt.UnixNano(),
  2237  		Reference:   "party1-buy-order",
  2238  	}
  2239  
  2240  	// submit orders
  2241  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2242  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  2243  
  2244  	_, err = tm.market.SubmitOrder(context.Background(), orderBuy)
  2245  	assert.NotNil(t, err)
  2246  	assert.EqualError(t, err, "margin check failed")
  2247  }
  2248  
  2249  func TestMarketGetMarginOnAmendOrderCancelReplace(t *testing.T) {
  2250  	party1 := "party1"
  2251  	now := time.Unix(100000, 0)
  2252  	closingAt := time.Unix(1000000, 0)
  2253  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  2254  	tm := getTestMarket(t, now, nil, nil)
  2255  	defer tm.ctrl.Finish()
  2256  
  2257  	addAccount(t, tm, party1)
  2258  
  2259  	// submit orders
  2260  	// party1 buys
  2261  	// party2 sells
  2262  	orderBuy := &types.Order{
  2263  		Type:        types.OrderTypeLimit,
  2264  		TimeInForce: types.OrderTimeInForceGTT,
  2265  		Status:      types.OrderStatusActive,
  2266  		ID:          "someid",
  2267  		Side:        types.SideBuy,
  2268  		Party:       party1,
  2269  		MarketID:    tm.market.GetID(),
  2270  		Size:        100,
  2271  		Price:       num.NewUint(100),
  2272  		Remaining:   100,
  2273  		CreatedAt:   now.UnixNano(),
  2274  		ExpiresAt:   closingAt.UnixNano(),
  2275  		Reference:   "party1-buy-order",
  2276  		Version:     common.InitialOrderVersion,
  2277  	}
  2278  
  2279  	// submit orders
  2280  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2281  	// tm.transferResponseStore.EXPECT().Add(gomock.Any()).AnyTimes()
  2282  
  2283  	_, err := tm.market.SubmitOrder(context.Background(), orderBuy)
  2284  	assert.Nil(t, err)
  2285  	if err != nil {
  2286  		t.Fail()
  2287  	}
  2288  	tm.now = tm.now.Add(time.Second)
  2289  	tm.market.OnTick(ctx, tm.now)
  2290  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  2291  	t.Log("amending order now")
  2292  
  2293  	// now try to amend and make sure monies are updated
  2294  	amendedOrder := &types.OrderAmendment{
  2295  		OrderID:     orderBuy.ID,
  2296  		Price:       num.NewUint(200),
  2297  		SizeDelta:   -50,
  2298  		TimeInForce: types.OrderTimeInForceGTT,
  2299  		ExpiresAt:   &orderBuy.ExpiresAt,
  2300  	}
  2301  
  2302  	_, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash())
  2303  	if !assert.Nil(t, err) {
  2304  		t.Fatalf("Error: %v", err)
  2305  	}
  2306  	tm.now = tm.now.Add(time.Second)
  2307  	tm.market.OnTick(ctx, tm.now)
  2308  }
  2309  
  2310  func TestTriggerByPriceNoTradesInAuction(t *testing.T) {
  2311  	party1 := "party1"
  2312  	party2 := "party2"
  2313  	auxParty := "auxParty"
  2314  	auxParty2 := "auxParty2"
  2315  	now := time.Unix(10, 0)
  2316  	closingAt := time.Unix(10000000000, 0)
  2317  	auctionExtensionSeconds := int64(45)
  2318  	openEnd := now.Add(time.Duration(auctionExtensionSeconds)*time.Second + time.Second)
  2319  	auctionEndTime := openEnd.Add(time.Duration(auctionExtensionSeconds) * time.Second)
  2320  	afterAuction := auctionEndTime.Add(time.Nanosecond)
  2321  	pMonitorSettings := &types.PriceMonitoringSettings{
  2322  		Parameters: &types.PriceMonitoringParameters{
  2323  			Triggers: []*types.PriceMonitoringTrigger{
  2324  				{
  2325  					Horizon:          60,
  2326  					HorizonDec:       num.DecimalFromFloat(60),
  2327  					Probability:      num.DecimalFromFloat(0.95),
  2328  					AuctionExtension: auctionExtensionSeconds,
  2329  				},
  2330  			},
  2331  		},
  2332  	}
  2333  	initialPrice := uint64(600)
  2334  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  2335  	auctionTriggeringPrice := initialPrice + 1 + mmu.Uint64()
  2336  	tm := getTestMarket2(t, now, pMonitorSettings, &types.AuctionDuration{
  2337  		Duration: 1,
  2338  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  2339  	}, true, 1)
  2340  
  2341  	addAccount(t, tm, party1)
  2342  	addAccount(t, tm, party2)
  2343  	addAccount(t, tm, auxParty)
  2344  	addAccount(t, tm, auxParty2)
  2345  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2346  	addAccountWithAmount(tm, "lpprov", 100000)
  2347  
  2348  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(auctionExtensionSeconds)*time.Second)
  2349  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  2350  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  2351  	require.NotNil(t, conf)
  2352  	require.NoError(t, err)
  2353  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2354  
  2355  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100*initialPrice)
  2356  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  2357  	require.NotNil(t, conf)
  2358  	require.NoError(t, err)
  2359  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2360  
  2361  	auxOrders := []*types.Order{
  2362  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, initialPrice),
  2363  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, initialPrice),
  2364  	}
  2365  	for _, o := range auxOrders {
  2366  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  2367  		require.NoError(t, err)
  2368  		require.NotNil(t, conf)
  2369  	}
  2370  	lp := &types.LiquidityProvisionSubmission{
  2371  		MarketID:         tm.market.GetID(),
  2372  		CommitmentAmount: num.NewUint(5000),
  2373  		Fee:              num.DecimalFromFloat(0.01),
  2374  	}
  2375  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2376  	// leave opening auction by moving time
  2377  	tm.now = openEnd
  2378  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), openEnd)
  2379  	now = openEnd
  2380  
  2381  	orderBuy1 := &types.Order{
  2382  		Type:        types.OrderTypeLimit,
  2383  		TimeInForce: types.OrderTimeInForceGTT,
  2384  		Status:      types.OrderStatusActive,
  2385  		ID:          "someid1",
  2386  		Side:        types.SideBuy,
  2387  		Party:       party1,
  2388  		MarketID:    tm.market.GetID(),
  2389  		Size:        100,
  2390  		Price:       num.NewUint(initialPrice),
  2391  		Remaining:   100,
  2392  		CreatedAt:   now.UnixNano(),
  2393  		ExpiresAt:   closingAt.UnixNano(),
  2394  		Reference:   "party1-buy-order-1",
  2395  	}
  2396  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  2397  	assert.NotNil(t, confirmationBuy)
  2398  	assert.NoError(t, err)
  2399  
  2400  	orderSell1 := &types.Order{
  2401  		Type:        types.OrderTypeLimit,
  2402  		TimeInForce: types.OrderTimeInForceFOK,
  2403  		Status:      types.OrderStatusActive,
  2404  		ID:          "someid2",
  2405  		Side:        types.SideSell,
  2406  		Party:       party2,
  2407  		MarketID:    tm.market.GetID(),
  2408  		Size:        100,
  2409  		Price:       num.NewUint(initialPrice),
  2410  		Remaining:   100,
  2411  		CreatedAt:   now.UnixNano(),
  2412  		Reference:   "party2-sell-order-1",
  2413  	}
  2414  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  2415  	require.NotNil(t, confirmationSell)
  2416  	require.NoError(t, err)
  2417  
  2418  	require.Equal(t, 1, len(confirmationSell.Trades))
  2419  
  2420  	auctionEnd := tm.market.GetMarketData().AuctionEnd
  2421  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  2422  
  2423  	orderBuy2 := &types.Order{
  2424  		Type:        types.OrderTypeLimit,
  2425  		TimeInForce: types.OrderTimeInForceGTT,
  2426  		Status:      types.OrderStatusActive,
  2427  		ID:          "someid3",
  2428  		Side:        types.SideBuy,
  2429  		Party:       party1,
  2430  		MarketID:    tm.market.GetID(),
  2431  		Size:        100,
  2432  		Price:       num.NewUint(auctionTriggeringPrice),
  2433  		Remaining:   100,
  2434  		CreatedAt:   now.UnixNano(),
  2435  		ExpiresAt:   closingAt.UnixNano(),
  2436  		Reference:   "party1-buy-order-2",
  2437  	}
  2438  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  2439  	assert.NotNil(t, confirmationBuy)
  2440  	assert.NoError(t, err)
  2441  
  2442  	orderSell2 := &types.Order{
  2443  		Type:        types.OrderTypeLimit,
  2444  		TimeInForce: types.OrderTimeInForceGTC,
  2445  		Status:      types.OrderStatusActive,
  2446  		ID:          "someid4",
  2447  		Side:        types.SideSell,
  2448  		Party:       party2,
  2449  		MarketID:    tm.market.GetID(),
  2450  		Size:        100,
  2451  		Price:       num.NewUint(auctionTriggeringPrice),
  2452  		Remaining:   100,
  2453  		CreatedAt:   now.UnixNano(),
  2454  		Reference:   "party2-sell-order-2",
  2455  	}
  2456  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  2457  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  2458  	require.NotNil(t, confirmationSell)
  2459  	require.NoError(t, err)
  2460  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  2461  
  2462  	require.Empty(t, confirmationSell.Trades)
  2463  
  2464  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2465  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  2466  
  2467  	tm.now = auctionEndTime
  2468  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  2469  	assert.False(t, closed)
  2470  
  2471  	tm.now = afterAuction
  2472  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), afterAuction)
  2473  	require.Equal(t, types.MarketStateActive, tm.market.State())
  2474  	assert.False(t, closed)
  2475  }
  2476  
  2477  func TestTriggerByPriceAuctionPriceInBounds(t *testing.T) {
  2478  	party1 := "party1"
  2479  	party2 := "party2"
  2480  	auxParty := "auxParty"
  2481  	auxParty2 := "auxParty2"
  2482  	now := time.Unix(10, 0)
  2483  	closingAt := time.Unix(10000000000, 0)
  2484  	auctionExtensionSeconds := int64(45)
  2485  	openEnd := now.Add(time.Duration(auctionExtensionSeconds)*time.Second + time.Second)
  2486  	auctionEndTime := openEnd.Add(time.Duration(auctionExtensionSeconds) * time.Second)
  2487  	afterAuction := auctionEndTime.Add(time.Nanosecond)
  2488  	pMonitorSettings := &types.PriceMonitoringSettings{
  2489  		Parameters: &types.PriceMonitoringParameters{
  2490  			Triggers: []*types.PriceMonitoringTrigger{
  2491  				{
  2492  					Horizon:          60,
  2493  					HorizonDec:       num.DecimalFromFloat(60),
  2494  					Probability:      num.DecimalFromFloat(0.95),
  2495  					AuctionExtension: auctionExtensionSeconds,
  2496  				},
  2497  			},
  2498  		},
  2499  	}
  2500  	initialPrice := uint64(600)
  2501  	deltaD := MAXMOVEUP
  2502  	delta, _ := num.UintFromDecimal(deltaD.Add(MINMOVEDOWN).Div(num.DecimalFromFloat(2)))
  2503  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  2504  	validPrice := initialPrice + delta.Uint64()
  2505  	auctionTriggeringPrice := initialPrice + mmu.Uint64() + 1
  2506  	// let's not start this in opening auction, it complicates the matter
  2507  	tm := getTestMarket2(t, now, pMonitorSettings, &types.AuctionDuration{
  2508  		Duration: auctionExtensionSeconds,
  2509  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  2510  	}, true, 1)
  2511  
  2512  	addAccount(t, tm, party1)
  2513  	addAccount(t, tm, party2)
  2514  	addAccount(t, tm, auxParty)
  2515  	addAccount(t, tm, auxParty2)
  2516  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2517  	addAccountWithAmount(tm, "lpprov", 100000)
  2518  
  2519  	// set auction duration
  2520  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(auctionExtensionSeconds)*time.Second)
  2521  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  2522  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  2523  	require.NotNil(t, conf)
  2524  	require.NoError(t, err)
  2525  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2526  
  2527  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100*initialPrice)
  2528  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  2529  	require.NotNil(t, conf)
  2530  	require.NoError(t, err)
  2531  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2532  	auxOrders := []*types.Order{
  2533  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, initialPrice),
  2534  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, initialPrice),
  2535  	}
  2536  	for _, o := range auxOrders {
  2537  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  2538  		require.NoError(t, err)
  2539  		require.NotNil(t, conf)
  2540  	}
  2541  	lp := &types.LiquidityProvisionSubmission{
  2542  		MarketID:         tm.market.GetID(),
  2543  		CommitmentAmount: num.NewUint(5000),
  2544  		Fee:              num.DecimalFromFloat(0.01),
  2545  	}
  2546  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2547  	// leave auction
  2548  	tm.now = openEnd
  2549  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), openEnd)
  2550  	now = openEnd
  2551  
  2552  	orderSell1 := &types.Order{
  2553  		Type:        types.OrderTypeLimit,
  2554  		TimeInForce: types.OrderTimeInForceGTT,
  2555  		Status:      types.OrderStatusActive,
  2556  		ID:          "someid2",
  2557  		Side:        types.SideSell,
  2558  		Party:       party2,
  2559  		MarketID:    tm.market.GetID(),
  2560  		Size:        100,
  2561  		Price:       num.NewUint(initialPrice),
  2562  		Remaining:   100,
  2563  		CreatedAt:   now.UnixNano(),
  2564  		ExpiresAt:   closingAt.UnixNano(),
  2565  		Reference:   "party2-sell-order-1",
  2566  	}
  2567  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  2568  	require.NotNil(t, confirmationSell)
  2569  	require.NoError(t, err)
  2570  
  2571  	orderBuy1 := &types.Order{
  2572  		Type:        types.OrderTypeLimit,
  2573  		TimeInForce: types.OrderTimeInForceFOK,
  2574  		Status:      types.OrderStatusActive,
  2575  		ID:          "someid1",
  2576  		Side:        types.SideBuy,
  2577  		Party:       party1,
  2578  		MarketID:    tm.market.GetID(),
  2579  		Size:        100,
  2580  		Price:       num.NewUint(initialPrice),
  2581  		Remaining:   100,
  2582  		CreatedAt:   now.UnixNano(),
  2583  		Reference:   "party1-buy-order-1",
  2584  	}
  2585  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  2586  	require.NotNil(t, confirmationBuy)
  2587  	assert.NoError(t, err)
  2588  
  2589  	require.Equal(t, 1, len(confirmationBuy.Trades))
  2590  
  2591  	auctionEnd := tm.market.GetMarketData().AuctionEnd
  2592  	require.Equal(t, int64(0), auctionEnd, "we are in auction?") // Not in auction
  2593  	require.Equal(t, types.MarketStateActive, tm.market.State())
  2594  
  2595  	orderSell2 := &types.Order{
  2596  		Type:        types.OrderTypeLimit,
  2597  		TimeInForce: types.OrderTimeInForceGTT,
  2598  		Status:      types.OrderStatusActive,
  2599  		ID:          "someid4",
  2600  		Side:        types.SideSell,
  2601  		Party:       party2,
  2602  		MarketID:    tm.market.GetID(),
  2603  		Size:        100,
  2604  		Price:       num.NewUint(auctionTriggeringPrice),
  2605  		Remaining:   100,
  2606  		CreatedAt:   now.UnixNano(),
  2607  		ExpiresAt:   closingAt.UnixNano(),
  2608  		Reference:   "party2-sell-order-2",
  2609  	}
  2610  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  2611  	require.NotNil(t, confirmationSell)
  2612  	require.NoError(t, err)
  2613  
  2614  	orderBuy2 := &types.Order{
  2615  		Type:        types.OrderTypeLimit,
  2616  		TimeInForce: types.OrderTimeInForceGTC,
  2617  		Status:      types.OrderStatusActive,
  2618  		ID:          "someid3",
  2619  		Side:        types.SideBuy,
  2620  		Party:       party1,
  2621  		MarketID:    tm.market.GetID(),
  2622  		Size:        100,
  2623  		Price:       num.NewUint(auctionTriggeringPrice),
  2624  		Remaining:   100,
  2625  		CreatedAt:   now.UnixNano(),
  2626  		Reference:   "party1-buy-order-2",
  2627  	}
  2628  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  2629  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  2630  	assert.NotNil(t, confirmationBuy)
  2631  	assert.NoError(t, err)
  2632  
  2633  	require.Empty(t, confirmationSell.Trades)
  2634  
  2635  	tm.now = auctionEndTime
  2636  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  2637  	assert.False(t, closed)
  2638  
  2639  	now = auctionEndTime
  2640  	orderSell3 := &types.Order{
  2641  		Type:        types.OrderTypeLimit,
  2642  		TimeInForce: types.OrderTimeInForceGFA,
  2643  		Status:      types.OrderStatusActive,
  2644  		ID:          "someid6",
  2645  		Side:        types.SideSell,
  2646  		Party:       party2,
  2647  		MarketID:    tm.market.GetID(),
  2648  		Size:        100,
  2649  		Price:       num.NewUint(validPrice),
  2650  		Remaining:   100,
  2651  		CreatedAt:   now.UnixNano(),
  2652  		Reference:   "party2-sell-order-3",
  2653  	}
  2654  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell3)
  2655  	assert.NotNil(t, confirmationSell)
  2656  	assert.NoError(t, err)
  2657  
  2658  	orderBuy3 := &types.Order{
  2659  		Type:        types.OrderTypeLimit,
  2660  		TimeInForce: types.OrderTimeInForceGFA,
  2661  		Status:      types.OrderStatusActive,
  2662  		ID:          "someid5",
  2663  		Side:        types.SideBuy,
  2664  		Party:       party1,
  2665  		MarketID:    tm.market.GetID(),
  2666  		Size:        100,
  2667  		Price:       num.NewUint(validPrice),
  2668  		Remaining:   100,
  2669  		CreatedAt:   now.UnixNano(),
  2670  		ExpiresAt:   closingAt.UnixNano(),
  2671  		Reference:   "party1-buy-order-3",
  2672  	}
  2673  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy3)
  2674  	assert.NotNil(t, confirmationBuy)
  2675  	assert.NoError(t, err)
  2676  	require.Empty(t, confirmationBuy.Trades)
  2677  
  2678  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2679  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd)         // In auction
  2680  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  2681  
  2682  	tm.now = afterAuction
  2683  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), afterAuction)
  2684  	require.Equal(t, tm.market.State(), types.MarketStateActive)
  2685  	assert.False(t, closed)
  2686  
  2687  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2688  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  2689  
  2690  	// TODO: Check that `party2-sell-order-3` & `party1-buy-order-3` get matched in auction and a trade is generated
  2691  
  2692  	// Test that orders get matched as expected upon returning to continuous trading
  2693  	now = afterAuction.Add(time.Second)
  2694  	orderSell4 := &types.Order{
  2695  		Type:        types.OrderTypeLimit,
  2696  		TimeInForce: types.OrderTimeInForceGTT,
  2697  		Status:      types.OrderStatusActive,
  2698  		ID:          "someid8",
  2699  		Side:        types.SideSell,
  2700  		Party:       party2,
  2701  		MarketID:    tm.market.GetID(),
  2702  		Size:        1,
  2703  		Price:       num.NewUint(validPrice),
  2704  		Remaining:   1,
  2705  		CreatedAt:   now.UnixNano(),
  2706  		ExpiresAt:   closingAt.UnixNano(),
  2707  		Reference:   "party2-sell-order-4",
  2708  	}
  2709  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell4)
  2710  	assert.NotNil(t, confirmationSell)
  2711  	assert.NoError(t, err)
  2712  
  2713  	orderBuy4 := &types.Order{
  2714  		Type:        types.OrderTypeLimit,
  2715  		TimeInForce: types.OrderTimeInForceGTT,
  2716  		Status:      types.OrderStatusActive,
  2717  		ID:          "someid7",
  2718  		Side:        types.SideBuy,
  2719  		Party:       party1,
  2720  		MarketID:    tm.market.GetID(),
  2721  		Size:        1,
  2722  		Price:       num.NewUint(validPrice),
  2723  		Remaining:   1,
  2724  		CreatedAt:   now.UnixNano(),
  2725  		ExpiresAt:   closingAt.UnixNano(),
  2726  		Reference:   "party1-buy-order-4",
  2727  	}
  2728  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy4)
  2729  	require.NotNil(t, confirmationBuy)
  2730  	require.NoError(t, err)
  2731  	require.Equal(t, 1, len(confirmationBuy.Trades))
  2732  }
  2733  
  2734  func TestTriggerByPriceAuctionPriceOutsideBounds(t *testing.T) {
  2735  	party1 := "party1"
  2736  	party2 := "party2"
  2737  	auxParty, auxParty2 := "auxParty", "auxParty2"
  2738  	now := time.Unix(10, 0)
  2739  	closingAt := time.Unix(10000000000, 0)
  2740  	auctionExtensionSeconds := int64(45)
  2741  	openingAuctionDuration := &types.AuctionDuration{Duration: auctionExtensionSeconds}
  2742  	openEnd := now.Add(time.Duration(openingAuctionDuration.Duration)*time.Second + time.Second)
  2743  	auctionEndTime := openEnd.Add(time.Duration(auctionExtensionSeconds) * time.Second)
  2744  	initialAuctionEnd := auctionEndTime.Add(time.Second)
  2745  	pMonitorSettings := &types.PriceMonitoringSettings{
  2746  		Parameters: &types.PriceMonitoringParameters{
  2747  			Triggers: []*types.PriceMonitoringTrigger{
  2748  				{
  2749  					Horizon:          60,
  2750  					HorizonDec:       num.DecimalFromFloat(60),
  2751  					Probability:      num.DecimalFromFloat(0.95),
  2752  					AuctionExtension: auctionExtensionSeconds,
  2753  				},
  2754  			},
  2755  		},
  2756  	}
  2757  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  2758  	initialPrice := uint64(600)
  2759  	auctionTriggeringPrice := initialPrice + 1 + mmu.Uint64()
  2760  	// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  2761  	tm := getTestMarket2(t, now, pMonitorSettings, openingAuctionDuration, true, 1)
  2762  
  2763  	addAccount(t, tm, party1)
  2764  	addAccount(t, tm, party2)
  2765  	addAccount(t, tm, auxParty)
  2766  	addAccount(t, tm, auxParty2)
  2767  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2768  	addAccountWithAmount(tm, "lpprov", 100000)
  2769  
  2770  	// set auction duration
  2771  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(auctionExtensionSeconds)*time.Second)
  2772  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  2773  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  2774  	require.Equal(t, types.MarketStatePending, tm.market.State()) // enter auction
  2775  	require.NotNil(t, conf)
  2776  	require.NoError(t, err)
  2777  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2778  
  2779  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100*initialPrice)
  2780  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  2781  	require.NotNil(t, conf)
  2782  	require.NoError(t, err)
  2783  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  2784  	auxOrders := []*types.Order{
  2785  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideBuy, auxParty, 1, initialPrice),
  2786  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideSell, auxParty2, 1, initialPrice),
  2787  	}
  2788  	for _, o := range auxOrders {
  2789  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  2790  		require.NotNil(t, conf)
  2791  		require.NoError(t, err)
  2792  	}
  2793  	lp := &types.LiquidityProvisionSubmission{
  2794  		MarketID:         tm.market.GetID(),
  2795  		CommitmentAmount: num.NewUint(5000),
  2796  		Fee:              num.DecimalFromFloat(0.01),
  2797  	}
  2798  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  2799  	// increase time, so we can leave opening auction
  2800  	tm.now = openEnd
  2801  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), openEnd)
  2802  
  2803  	md := tm.market.GetMarketData()
  2804  
  2805  	require.Equal(t, types.AuctionTriggerUnspecified, md.Trigger)
  2806  
  2807  	require.Equal(t, types.MarketStateActive, tm.market.State())
  2808  	now = openEnd
  2809  
  2810  	orderSell1 := &types.Order{
  2811  		Type:        types.OrderTypeLimit,
  2812  		TimeInForce: types.OrderTimeInForceGTT,
  2813  		Status:      types.OrderStatusActive,
  2814  		ID:          "someid2",
  2815  		Side:        types.SideSell,
  2816  		Party:       party2,
  2817  		MarketID:    tm.market.GetID(),
  2818  		Size:        100,
  2819  		Price:       num.NewUint(initialPrice),
  2820  		Remaining:   100,
  2821  		CreatedAt:   now.UnixNano(),
  2822  		ExpiresAt:   closingAt.UnixNano(),
  2823  		Reference:   "party2-sell-order-1",
  2824  	}
  2825  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  2826  	require.NotNil(t, confirmationSell)
  2827  	require.NoError(t, err)
  2828  
  2829  	orderBuy1 := &types.Order{
  2830  		Type:        types.OrderTypeLimit,
  2831  		TimeInForce: types.OrderTimeInForceFOK,
  2832  		Status:      types.OrderStatusActive,
  2833  		ID:          "someid1",
  2834  		Side:        types.SideBuy,
  2835  		Party:       party1,
  2836  		MarketID:    tm.market.GetID(),
  2837  		Size:        100,
  2838  		Price:       num.NewUint(initialPrice),
  2839  		Remaining:   100,
  2840  		CreatedAt:   now.UnixNano(),
  2841  		Reference:   "party1-buy-order-1",
  2842  	}
  2843  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  2844  	require.NotNil(t, confirmationBuy)
  2845  	assert.NoError(t, err)
  2846  
  2847  	require.Equal(t, 1, len(confirmationBuy.Trades))
  2848  
  2849  	auctionEnd := tm.market.GetMarketData().AuctionEnd
  2850  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  2851  
  2852  	orderSell2 := &types.Order{
  2853  		Type:        types.OrderTypeLimit,
  2854  		TimeInForce: types.OrderTimeInForceGTT,
  2855  		Status:      types.OrderStatusActive,
  2856  		ID:          "someid4",
  2857  		Side:        types.SideSell,
  2858  		Party:       party2,
  2859  		MarketID:    tm.market.GetID(),
  2860  		Size:        100,
  2861  		Price:       num.NewUint(auctionTriggeringPrice),
  2862  		Remaining:   100,
  2863  		CreatedAt:   now.UnixNano(),
  2864  		ExpiresAt:   closingAt.UnixNano(),
  2865  		Reference:   "party2-sell-order-2",
  2866  	}
  2867  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  2868  	require.NotNil(t, confirmationSell)
  2869  	require.NoError(t, err)
  2870  
  2871  	orderBuy2 := &types.Order{
  2872  		Type:        types.OrderTypeLimit,
  2873  		TimeInForce: types.OrderTimeInForceGTC,
  2874  		Status:      types.OrderStatusActive,
  2875  		ID:          "someid3",
  2876  		Side:        types.SideBuy,
  2877  		Party:       party1,
  2878  		MarketID:    tm.market.GetID(),
  2879  		Size:        100,
  2880  		Price:       num.NewUint(auctionTriggeringPrice - 1),
  2881  		Remaining:   100,
  2882  		CreatedAt:   now.UnixNano(),
  2883  		Reference:   "party1-buy-order-2",
  2884  	}
  2885  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  2886  	assert.NotNil(t, confirmationBuy)
  2887  	assert.NoError(t, err)
  2888  
  2889  	require.Empty(t, confirmationBuy.Trades)
  2890  
  2891  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2892  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  2893  
  2894  	amendedOrder := &types.OrderAmendment{
  2895  		OrderID:     orderBuy2.ID,
  2896  		Price:       num.NewUint(auctionTriggeringPrice),
  2897  		SizeDelta:   0,
  2898  		TimeInForce: types.OrderTimeInForceGTC,
  2899  	}
  2900  
  2901  	conf, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash())
  2902  	require.NoError(t, err)
  2903  	require.NotNil(t, conf)
  2904  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  2905  
  2906  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2907  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  2908  
  2909  	tm.now = auctionEndTime
  2910  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  2911  	assert.False(t, closed)
  2912  
  2913  	now = auctionEndTime
  2914  	orderSell3 := &types.Order{
  2915  		Type:        types.OrderTypeLimit,
  2916  		TimeInForce: types.OrderTimeInForceGFA,
  2917  		Status:      types.OrderStatusActive,
  2918  		ID:          "someid6",
  2919  		Side:        types.SideSell,
  2920  		Party:       party2,
  2921  		MarketID:    tm.market.GetID(),
  2922  		Size:        100,
  2923  		Price:       num.NewUint(auctionTriggeringPrice),
  2924  		Remaining:   100,
  2925  		CreatedAt:   now.UnixNano(),
  2926  		Reference:   "party2-sell-order-3",
  2927  	}
  2928  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell3)
  2929  	assert.NotNil(t, confirmationSell)
  2930  	assert.NoError(t, err)
  2931  
  2932  	orderBuy3 := &types.Order{
  2933  		Type:        types.OrderTypeLimit,
  2934  		TimeInForce: types.OrderTimeInForceGFA,
  2935  		Status:      types.OrderStatusActive,
  2936  		ID:          "someid5",
  2937  		Side:        types.SideBuy,
  2938  		Party:       party1,
  2939  		MarketID:    tm.market.GetID(),
  2940  		Size:        100,
  2941  		Price:       num.NewUint(auctionTriggeringPrice),
  2942  		Remaining:   100,
  2943  		CreatedAt:   now.UnixNano(),
  2944  		ExpiresAt:   closingAt.UnixNano(),
  2945  		Reference:   "party1-buy-order-3",
  2946  	}
  2947  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy3)
  2948  	assert.NotNil(t, confirmationBuy)
  2949  	assert.NoError(t, err)
  2950  	require.Empty(t, confirmationBuy.Trades)
  2951  
  2952  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2953  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  2954  
  2955  	// Expecting market to still be in auction as auction resulted in invalid price
  2956  	tm.now = initialAuctionEnd
  2957  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), initialAuctionEnd)
  2958  	assert.False(t, closed)
  2959  
  2960  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  2961  	require.Equal(t, int64(0), auctionEnd) // Not in auction (trigger can only start auction, but can't stop it from concluding at a higher price)
  2962  }
  2963  
  2964  func TestTriggerByMarketOrder(t *testing.T) {
  2965  	party1 := "party1"
  2966  	party2 := "party2"
  2967  	auxParty := "auxParty"
  2968  	auxParty2 := "auxParty2"
  2969  	now := time.Unix(10, 0)
  2970  	closingAt := time.Unix(10000000000, 0)
  2971  	var auctionExtensionSeconds int64 = 45
  2972  	openingEnd := now.Add(time.Duration(auctionExtensionSeconds+1) * time.Second)
  2973  	auctionEndTime := openingEnd.Add(time.Duration(auctionExtensionSeconds) * time.Second)
  2974  	pMonitorSettings := &types.PriceMonitoringSettings{
  2975  		Parameters: &types.PriceMonitoringParameters{
  2976  			Triggers: []*types.PriceMonitoringTrigger{
  2977  				{
  2978  					Horizon:          60,
  2979  					HorizonDec:       num.DecimalFromFloat(60),
  2980  					Probability:      num.DecimalFromFloat(0.95),
  2981  					AuctionExtension: auctionExtensionSeconds,
  2982  				},
  2983  			},
  2984  		},
  2985  	}
  2986  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  2987  	initialPrice := uint64(600)
  2988  	auctionTriggeringPriceHigh := initialPrice + 1 + mmu.Uint64()
  2989  	tm := getTestMarket2(t, now, pMonitorSettings, &types.AuctionDuration{
  2990  		Duration: auctionExtensionSeconds,
  2991  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  2992  	}, true, 1)
  2993  
  2994  	addAccount(t, tm, party1)
  2995  	addAccount(t, tm, party2)
  2996  	addAccount(t, tm, auxParty)
  2997  	addAccount(t, tm, auxParty2)
  2998  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  2999  	addAccountWithAmount(tm, "lpprov", 100000)
  3000  
  3001  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(auctionExtensionSeconds)*time.Second)
  3002  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  3003  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  3004  	require.NotNil(t, conf)
  3005  	require.NoError(t, err)
  3006  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3007  
  3008  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100*initialPrice)
  3009  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  3010  	require.NotNil(t, conf)
  3011  	require.NoError(t, err)
  3012  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3013  
  3014  	auxOrders := []*types.Order{
  3015  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, initialPrice),
  3016  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, initialPrice),
  3017  	}
  3018  	for _, o := range auxOrders {
  3019  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  3020  		require.NotNil(t, conf)
  3021  		require.NoError(t, err)
  3022  	}
  3023  	lp := &types.LiquidityProvisionSubmission{
  3024  		MarketID:         tm.market.GetID(),
  3025  		CommitmentAmount: num.NewUint(5000),
  3026  		Fee:              num.DecimalFromFloat(0.01),
  3027  	}
  3028  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  3029  	// now leave auction
  3030  	tm.now = openingEnd
  3031  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), openingEnd)
  3032  	now = openingEnd
  3033  
  3034  	orderSell1 := &types.Order{
  3035  		Type:        types.OrderTypeLimit,
  3036  		TimeInForce: types.OrderTimeInForceGTT,
  3037  		Status:      types.OrderStatusActive,
  3038  		ID:          "someid2",
  3039  		Side:        types.SideSell,
  3040  		Party:       party2,
  3041  		MarketID:    tm.market.GetID(),
  3042  		Size:        100,
  3043  		Price:       num.NewUint(initialPrice),
  3044  		Remaining:   100,
  3045  		CreatedAt:   now.UnixNano(),
  3046  		ExpiresAt:   closingAt.UnixNano(),
  3047  		Reference:   "party2-sell-order-1",
  3048  	}
  3049  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  3050  	require.NotNil(t, confirmationSell)
  3051  	require.NoError(t, err)
  3052  
  3053  	orderBuy1 := &types.Order{
  3054  		Type:        types.OrderTypeLimit,
  3055  		TimeInForce: types.OrderTimeInForceFOK,
  3056  		Status:      types.OrderStatusActive,
  3057  		ID:          "someid1",
  3058  		Side:        types.SideBuy,
  3059  		Party:       party1,
  3060  		MarketID:    tm.market.GetID(),
  3061  		Size:        100,
  3062  		Price:       num.NewUint(initialPrice),
  3063  		Remaining:   100,
  3064  		CreatedAt:   now.UnixNano(),
  3065  		Reference:   "party1-buy-order-1",
  3066  	}
  3067  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  3068  	require.NotNil(t, confirmationBuy)
  3069  	assert.NoError(t, err)
  3070  
  3071  	require.Equal(t, 1, len(confirmationBuy.Trades))
  3072  
  3073  	auctionEnd := tm.market.GetMarketData().AuctionEnd
  3074  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3075  
  3076  	orderSell2 := &types.Order{
  3077  		Type:        types.OrderTypeLimit,
  3078  		TimeInForce: types.OrderTimeInForceGTT,
  3079  		Status:      types.OrderStatusActive,
  3080  		ID:          "someid3",
  3081  		Side:        types.SideSell,
  3082  		Party:       party2,
  3083  		MarketID:    tm.market.GetID(),
  3084  		Size:        3,
  3085  		Price:       num.NewUint(auctionTriggeringPriceHigh - 1),
  3086  		Remaining:   3,
  3087  		CreatedAt:   now.UnixNano(),
  3088  		ExpiresAt:   closingAt.UnixNano(),
  3089  		Reference:   "party2-sell-order-2",
  3090  	}
  3091  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  3092  	require.NotNil(t, confirmationSell)
  3093  	require.NoError(t, err)
  3094  
  3095  	require.Empty(t, confirmationSell.Trades)
  3096  
  3097  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  3098  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3099  
  3100  	orderSell3 := &types.Order{
  3101  		Type:        types.OrderTypeLimit,
  3102  		TimeInForce: types.OrderTimeInForceGTT,
  3103  		Status:      types.OrderStatusActive,
  3104  		ID:          "someid4",
  3105  		Side:        types.SideSell,
  3106  		Party:       party2,
  3107  		MarketID:    tm.market.GetID(),
  3108  		Size:        1,
  3109  		Price:       num.NewUint(auctionTriggeringPriceHigh),
  3110  		Remaining:   1,
  3111  		CreatedAt:   now.UnixNano(),
  3112  		ExpiresAt:   closingAt.UnixNano(),
  3113  		Reference:   "party2-sell-order-3",
  3114  	}
  3115  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell3)
  3116  	require.NotNil(t, confirmationSell)
  3117  	require.NoError(t, err)
  3118  
  3119  	require.Empty(t, confirmationSell.Trades)
  3120  
  3121  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  3122  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3123  
  3124  	orderBuy2 := &types.Order{
  3125  		Type:      types.OrderTypeMarket,
  3126  		Status:    types.OrderStatusActive,
  3127  		ID:        "someid5",
  3128  		Side:      types.SideBuy,
  3129  		Party:     party1,
  3130  		MarketID:  tm.market.GetID(),
  3131  		Size:      4,
  3132  		Price:     num.UintZero(),
  3133  		Remaining: 4,
  3134  		CreatedAt: now.UnixNano(),
  3135  		Reference: "party1-buy-order-2",
  3136  	}
  3137  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  3138  	assert.NotNil(t, confirmationBuy)
  3139  	assert.NoError(t, err)
  3140  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  3141  
  3142  	require.Empty(t, confirmationSell.Trades)
  3143  
  3144  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  3145  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  3146  
  3147  	tm.now = auctionEndTime
  3148  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  3149  	assert.False(t, closed)
  3150  
  3151  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  3152  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // Still in auction
  3153  	require.Equal(t, types.MarketStateSuspended, tm.market.State())
  3154  
  3155  	tm.now = auctionEndTime.Add(time.Nanosecond)
  3156  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), tm.now)
  3157  	require.Equal(t, types.MarketStateActive, tm.market.State()) // left auction
  3158  	assert.False(t, closed)
  3159  
  3160  	md := tm.market.GetMarketData()
  3161  	auctionEnd = md.AuctionEnd
  3162  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3163  
  3164  	require.True(t, md.MarkPrice.EQ(num.NewUint(initialPrice)))
  3165  }
  3166  
  3167  func TestPriceMonitoringBoundsInGetMarketData(t *testing.T) {
  3168  	party1 := "party1"
  3169  	party2 := "party2"
  3170  	auxParty := "auxParty"
  3171  	auxParty2 := "auxParty2"
  3172  	now := time.Unix(10, 0)
  3173  	closingAt := time.Unix(10000000000, 0)
  3174  	extension := int64(45)
  3175  	t1 := &types.PriceMonitoringTrigger{
  3176  		Horizon:          60,
  3177  		HorizonDec:       num.DecimalFromFloat(60),
  3178  		Probability:      num.DecimalFromFloat(0.95),
  3179  		AuctionExtension: extension,
  3180  	}
  3181  	t2 := &types.PriceMonitoringTrigger{
  3182  		Horizon:          120,
  3183  		HorizonDec:       num.DecimalFromFloat(120),
  3184  		Probability:      num.DecimalFromFloat(0.99),
  3185  		AuctionExtension: extension * 2,
  3186  	}
  3187  	pMonitorSettings := &types.PriceMonitoringSettings{
  3188  		Parameters: &types.PriceMonitoringParameters{
  3189  			Triggers: []*types.PriceMonitoringTrigger{
  3190  				t1,
  3191  				t2,
  3192  			},
  3193  		},
  3194  	}
  3195  	openEnd := now.Add(time.Duration(extension)*time.Second + time.Second)
  3196  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  3197  	initialPrice := uint64(600)
  3198  	auctionTriggeringPrice := initialPrice + mmu.Uint64() + 1
  3199  	tm := getTestMarket2(t, now, pMonitorSettings, &types.AuctionDuration{
  3200  		Duration: extension,
  3201  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  3202  	}, true, 1)
  3203  
  3204  	initDec := num.DecimalFromFloat(float64(initialPrice))
  3205  	// add 1 for the ceil
  3206  	min, _ := num.UintFromDecimal(initDec.Sub(MINMOVEDOWN).Add(num.DecimalFromFloat(1)))
  3207  	max, _ := num.UintFromDecimal(initDec.Add(MAXMOVEUP).Floor())
  3208  	expectedPmRange1 := types.PriceMonitoringBounds{
  3209  		MinValidPrice:  min,
  3210  		MaxValidPrice:  max,
  3211  		Trigger:        t1,
  3212  		ReferencePrice: initDec,
  3213  	}
  3214  	expectedPmRange2 := types.PriceMonitoringBounds{
  3215  		MinValidPrice:  min.Clone(),
  3216  		MaxValidPrice:  max.Clone(),
  3217  		Trigger:        t2,
  3218  		ReferencePrice: initDec,
  3219  	}
  3220  
  3221  	addAccount(t, tm, party1)
  3222  	addAccount(t, tm, party2)
  3223  	addAccount(t, tm, auxParty)
  3224  	addAccount(t, tm, auxParty2)
  3225  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3226  	addAccountWithAmount(tm, "lpprov", 100000)
  3227  
  3228  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(extension)*time.Second)
  3229  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  3230  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  3231  	require.NotNil(t, conf)
  3232  	require.NoError(t, err)
  3233  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3234  
  3235  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  3236  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  3237  	require.NotNil(t, conf)
  3238  	require.NoError(t, err)
  3239  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3240  
  3241  	auxOrders := []*types.Order{
  3242  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, initialPrice),
  3243  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, initialPrice),
  3244  	}
  3245  	for _, o := range auxOrders {
  3246  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  3247  		require.NoError(t, err)
  3248  		require.NotNil(t, conf)
  3249  	}
  3250  	lp := &types.LiquidityProvisionSubmission{
  3251  		MarketID:         tm.market.GetID(),
  3252  		CommitmentAmount: num.NewUint(5000),
  3253  		Fee:              num.DecimalFromFloat(0.01),
  3254  	}
  3255  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  3256  	// leave auction
  3257  	tm.now = openEnd
  3258  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), openEnd)
  3259  	now = openEnd
  3260  
  3261  	orderBuy1 := &types.Order{
  3262  		Type:        types.OrderTypeLimit,
  3263  		TimeInForce: types.OrderTimeInForceGTT,
  3264  		Status:      types.OrderStatusActive,
  3265  		ID:          "someid1",
  3266  		Side:        types.SideBuy,
  3267  		Party:       party1,
  3268  		MarketID:    tm.market.GetID(),
  3269  		Size:        100,
  3270  		Price:       num.NewUint(initialPrice),
  3271  		Remaining:   100,
  3272  		CreatedAt:   now.UnixNano(),
  3273  		ExpiresAt:   closingAt.UnixNano(),
  3274  		Reference:   "party1-buy-order-1",
  3275  	}
  3276  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  3277  	assert.NotNil(t, confirmationBuy)
  3278  	assert.NoError(t, err)
  3279  
  3280  	orderSell1 := &types.Order{
  3281  		Type:        types.OrderTypeLimit,
  3282  		TimeInForce: types.OrderTimeInForceFOK,
  3283  		Status:      types.OrderStatusActive,
  3284  		ID:          "someid2",
  3285  		Side:        types.SideSell,
  3286  		Party:       party2,
  3287  		MarketID:    tm.market.GetID(),
  3288  		Size:        100,
  3289  		Price:       num.NewUint(initialPrice),
  3290  		Remaining:   100,
  3291  		CreatedAt:   now.UnixNano(),
  3292  		Reference:   "party2-sell-order-1",
  3293  	}
  3294  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  3295  	require.NotNil(t, confirmationSell)
  3296  	require.NoError(t, err)
  3297  	require.Equal(t, 1, len(confirmationSell.Trades))
  3298  
  3299  	md := tm.market.GetMarketData()
  3300  	require.NotNil(t, md)
  3301  
  3302  	auctionEnd := md.AuctionEnd
  3303  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3304  
  3305  	pmBounds := md.PriceMonitoringBounds
  3306  	require.Equal(t, 2, len(pmBounds))
  3307  	require.True(t, expectedPmRange1.MinValidPrice.EQ(pmBounds[0].MinValidPrice), "%s != %s", expectedPmRange1.MinValidPrice, pmBounds[0].MinValidPrice)
  3308  	require.True(t, expectedPmRange1.MaxValidPrice.EQ(pmBounds[0].MaxValidPrice))
  3309  	require.True(t, expectedPmRange1.ReferencePrice.Equals(pmBounds[0].ReferencePrice))
  3310  	require.Equal(t, *expectedPmRange1.Trigger, *pmBounds[0].Trigger)
  3311  
  3312  	require.True(t, expectedPmRange2.MinValidPrice.EQ(pmBounds[1].MinValidPrice))
  3313  	require.True(t, expectedPmRange2.MaxValidPrice.EQ(pmBounds[1].MaxValidPrice))
  3314  	require.True(t, expectedPmRange2.ReferencePrice.Equals(pmBounds[1].ReferencePrice))
  3315  	require.Equal(t, *expectedPmRange2.Trigger, *pmBounds[1].Trigger)
  3316  
  3317  	orderBuy2 := &types.Order{
  3318  		Type:        types.OrderTypeLimit,
  3319  		TimeInForce: types.OrderTimeInForceGTT,
  3320  		Status:      types.OrderStatusActive,
  3321  		ID:          "someid3",
  3322  		Side:        types.SideBuy,
  3323  		Party:       party1,
  3324  		MarketID:    tm.market.GetID(),
  3325  		Size:        100,
  3326  		Price:       num.NewUint(auctionTriggeringPrice),
  3327  		Remaining:   100,
  3328  		CreatedAt:   now.UnixNano(),
  3329  		ExpiresAt:   closingAt.UnixNano(),
  3330  		Reference:   "party1-buy-order-2",
  3331  	}
  3332  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  3333  	assert.NotNil(t, confirmationBuy)
  3334  	assert.NoError(t, err)
  3335  
  3336  	orderSell2 := &types.Order{
  3337  		Type:        types.OrderTypeLimit,
  3338  		TimeInForce: types.OrderTimeInForceGTC,
  3339  		Status:      types.OrderStatusActive,
  3340  		ID:          "someid4",
  3341  		Side:        types.SideSell,
  3342  		Party:       party2,
  3343  		MarketID:    tm.market.GetID(),
  3344  		Size:        100,
  3345  		Price:       num.NewUint(auctionTriggeringPrice),
  3346  		Remaining:   100,
  3347  		CreatedAt:   now.UnixNano(),
  3348  		Reference:   "party2-sell-order-2",
  3349  	}
  3350  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  3351  	require.NotNil(t, confirmationSell)
  3352  	require.NoError(t, err)
  3353  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  3354  
  3355  	require.Empty(t, confirmationSell.Trades)
  3356  
  3357  	md = tm.market.GetMarketData()
  3358  	require.NotNil(t, md)
  3359  	auctionEnd = md.AuctionEnd
  3360  	auctionEndTime := openEnd.Add(time.Duration(t1.AuctionExtension) * time.Second)
  3361  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  3362  	require.Equal(t, types.MarketStateSuspended, tm.market.State())
  3363  	// 2 in total
  3364  	require.Equal(t, 2, len(md.PriceMonitoringBounds))
  3365  	active, triggerd := 0, 0
  3366  	for _, v := range md.PriceMonitoringBounds {
  3367  		if v.Active {
  3368  			active++
  3369  			continue
  3370  		}
  3371  		triggerd++
  3372  	}
  3373  	// 1 active
  3374  	require.Equal(t, 1, active)
  3375  	// 1 triggered
  3376  	require.Equal(t, 1, triggerd)
  3377  
  3378  	tm.now = auctionEndTime
  3379  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  3380  	assert.False(t, closed)
  3381  
  3382  	md = tm.market.GetMarketData()
  3383  	require.NotNil(t, md)
  3384  	auctionEnd = md.AuctionEnd
  3385  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  3386  	require.Equal(t, types.MarketStateSuspended, tm.market.State())
  3387  
  3388  	require.Equal(t, 1, len(md.PriceMonitoringBounds))
  3389  
  3390  	tm.now = auctionEndTime.Add(time.Nanosecond)
  3391  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), tm.now)
  3392  	assert.False(t, closed)
  3393  
  3394  	auctionEndTime = openEnd.Add(time.Duration(t1.AuctionExtension+t2.AuctionExtension) * time.Second)
  3395  	md = tm.market.GetMarketData()
  3396  	require.NotNil(t, md)
  3397  	auctionEnd = md.AuctionEnd
  3398  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  3399  	require.Equal(t, types.MarketStateSuspended, tm.market.State())
  3400  
  3401  	tm.now = auctionEndTime
  3402  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), auctionEndTime)
  3403  	assert.False(t, closed)
  3404  
  3405  	md = tm.market.GetMarketData()
  3406  	require.NotNil(t, md)
  3407  	auctionEnd = md.AuctionEnd
  3408  	require.Equal(t, auctionEndTime.UnixNano(), auctionEnd) // In auction
  3409  	require.Equal(t, types.MarketStateSuspended, tm.market.State())
  3410  
  3411  	tm.now = auctionEndTime.Add(time.Nanosecond)
  3412  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), tm.now)
  3413  	assert.False(t, closed)
  3414  
  3415  	md = tm.market.GetMarketData()
  3416  	require.NotNil(t, md)
  3417  	auctionEnd = md.AuctionEnd
  3418  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  3419  	require.Equal(t, types.MarketStateActive, tm.market.State())
  3420  
  3421  	require.Equal(t, 2, len(md.PriceMonitoringBounds))
  3422  	require.True(t, expectedPmRange1.MinValidPrice.EQ(pmBounds[0].MinValidPrice))
  3423  	require.True(t, expectedPmRange1.MaxValidPrice.EQ(pmBounds[0].MaxValidPrice))
  3424  	require.True(t, expectedPmRange1.ReferencePrice.Equals(pmBounds[0].ReferencePrice))
  3425  	require.Equal(t, *expectedPmRange1.Trigger, *pmBounds[0].Trigger)
  3426  
  3427  	require.True(t, expectedPmRange2.MinValidPrice.EQ(pmBounds[1].MinValidPrice))
  3428  	require.True(t, expectedPmRange2.MaxValidPrice.EQ(pmBounds[1].MaxValidPrice))
  3429  	require.True(t, expectedPmRange2.ReferencePrice.Equals(pmBounds[1].ReferencePrice))
  3430  	require.Equal(t, *expectedPmRange2.Trigger, *pmBounds[1].Trigger)
  3431  }
  3432  
  3433  func TestTargetStakeReturnedAndCorrect(t *testing.T) {
  3434  	party1 := "party1"
  3435  	party2 := "party2"
  3436  	auxParty := "auxParty"
  3437  	auxParty2 := "auxParty2"
  3438  	oi := uint64(124)
  3439  	matchingPrice := uint64(111)
  3440  	now := time.Unix(10, 0)
  3441  	closingAt := time.Unix(10000000000, 0)
  3442  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  3443  		Duration: 1,
  3444  	})
  3445  
  3446  	rmParams := tm.mktCfg.TradableInstrument.GetSimpleRiskModel().Params
  3447  	expectedTargetStake := num.DecimalFromFloat(float64(matchingPrice * oi)).Mul(tm.mktCfg.LiquidityMonitoringParameters.TargetStakeParameters.ScalingFactor)
  3448  	if rmParams.FactorLong.GreaterThan(rmParams.FactorShort) {
  3449  		expectedTargetStake = expectedTargetStake.Mul(rmParams.FactorLong)
  3450  	} else {
  3451  		expectedTargetStake = expectedTargetStake.Mul(rmParams.FactorShort)
  3452  	}
  3453  
  3454  	addAccount(t, tm, party1)
  3455  	addAccount(t, tm, party2)
  3456  	addAccount(t, tm, auxParty)
  3457  	addAccount(t, tm, auxParty2)
  3458  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3459  	addAccountWithAmount(tm, "lpprov", 100000000000)
  3460  
  3461  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Second)
  3462  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  3463  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  3464  	require.NotNil(t, conf)
  3465  	require.NoError(t, err)
  3466  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3467  
  3468  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  3469  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  3470  	require.NotNil(t, conf)
  3471  	require.NoError(t, err)
  3472  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3473  
  3474  	auxOrders := []*types.Order{
  3475  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, matchingPrice),
  3476  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, matchingPrice),
  3477  	}
  3478  	for _, o := range auxOrders {
  3479  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  3480  		require.NoError(t, err)
  3481  		require.NotNil(t, conf)
  3482  	}
  3483  	lp := &types.LiquidityProvisionSubmission{
  3484  		MarketID:         tm.market.GetID(),
  3485  		CommitmentAmount: num.NewUint(50000),
  3486  		Fee:              num.DecimalFromFloat(0.01),
  3487  	}
  3488  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  3489  	// leave opening auction
  3490  	now = now.Add(2 * time.Second)
  3491  	tm.now = now
  3492  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3493  
  3494  	orderSell1 := &types.Order{
  3495  		Type:        types.OrderTypeLimit,
  3496  		TimeInForce: types.OrderTimeInForceGTT,
  3497  		Status:      types.OrderStatusActive,
  3498  		ID:          "someid2",
  3499  		Side:        types.SideSell,
  3500  		Party:       party2,
  3501  		MarketID:    tm.market.GetID(),
  3502  		Size:        oi - 1, // -1 because we trade during opening auction
  3503  		Price:       num.NewUint(matchingPrice),
  3504  		Remaining:   oi - 1,
  3505  		CreatedAt:   now.UnixNano(),
  3506  		ExpiresAt:   closingAt.UnixNano(),
  3507  		Reference:   "party2-sell-order-1",
  3508  	}
  3509  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  3510  	require.NotNil(t, confirmationSell)
  3511  	require.NoError(t, err)
  3512  
  3513  	orderBuy1 := &types.Order{
  3514  		Type:        types.OrderTypeLimit,
  3515  		TimeInForce: types.OrderTimeInForceFOK,
  3516  		Status:      types.OrderStatusActive,
  3517  		ID:          "someid1",
  3518  		Side:        types.SideBuy,
  3519  		Party:       party1,
  3520  		MarketID:    tm.market.GetID(),
  3521  		Size:        oi - 1,
  3522  		Price:       num.NewUint(matchingPrice),
  3523  		Remaining:   oi - 1,
  3524  		CreatedAt:   now.UnixNano(),
  3525  		Reference:   "party1-buy-order-1",
  3526  	}
  3527  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  3528  	require.NotNil(t, confirmationBuy)
  3529  	assert.NoError(t, err)
  3530  	require.NotZero(t, len(confirmationBuy.Trades))
  3531  
  3532  	mktData := tm.market.GetMarketData()
  3533  	require.NotNil(t, mktData)
  3534  	require.Equal(t, expectedTargetStake.String(), mktData.TargetStake)
  3535  }
  3536  
  3537  func TestSuppliedStakeReturnedAndCorrect(t *testing.T) {
  3538  	party1 := "party1"
  3539  	party2 := "party2"
  3540  	now := time.Unix(10, 0)
  3541  	closingAt := time.Unix(10000000000, 0)
  3542  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3543  	tm := getTestMarket(t, now, nil, nil)
  3544  	var matchingPrice uint64 = 111
  3545  
  3546  	addAccount(t, tm, party1)
  3547  	addAccount(t, tm, party2)
  3548  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3549  
  3550  	orderSell1 := &types.Order{
  3551  		Type:        types.OrderTypeLimit,
  3552  		TimeInForce: types.OrderTimeInForceGTT,
  3553  		Status:      types.OrderStatusActive,
  3554  		ID:          "someid2",
  3555  		Side:        types.SideSell,
  3556  		Party:       party2,
  3557  		MarketID:    tm.market.GetID(),
  3558  		Size:        1,
  3559  		Price:       num.NewUint(matchingPrice + 1),
  3560  		Remaining:   1,
  3561  		CreatedAt:   now.UnixNano(),
  3562  		ExpiresAt:   closingAt.UnixNano(),
  3563  		Reference:   "party2-sell-order-1",
  3564  	}
  3565  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  3566  	tm.now = tm.now.Add(time.Second)
  3567  	tm.market.OnTick(ctx, tm.now)
  3568  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  3569  	require.NotNil(t, confirmationSell)
  3570  	require.NoError(t, err)
  3571  
  3572  	orderBuy1 := &types.Order{
  3573  		Type:        types.OrderTypeLimit,
  3574  		TimeInForce: types.OrderTimeInForceGTT,
  3575  		Status:      types.OrderStatusActive,
  3576  		ID:          "someid1",
  3577  		Side:        types.SideBuy,
  3578  		Party:       party1,
  3579  		MarketID:    tm.market.GetID(),
  3580  		Size:        1,
  3581  		Price:       num.NewUint(matchingPrice - 1),
  3582  		Remaining:   1,
  3583  		CreatedAt:   now.UnixNano(),
  3584  		ExpiresAt:   closingAt.UnixNano(),
  3585  		Reference:   "party1-buy-order-1",
  3586  	}
  3587  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  3588  	tm.now = tm.now.Add(time.Second)
  3589  	tm.market.OnTick(ctx, tm.now)
  3590  	assert.NotNil(t, confirmationBuy)
  3591  	assert.NoError(t, err)
  3592  
  3593  	require.Equal(t, 0, len(confirmationBuy.Trades))
  3594  
  3595  	lp1 := &types.LiquidityProvisionSubmission{
  3596  		MarketID:         tm.market.GetID(),
  3597  		CommitmentAmount: num.NewUint(200),
  3598  		Fee:              num.DecimalFromFloat(0.05),
  3599  	}
  3600  
  3601  	err = tm.market.SubmitLiquidityProvision(context.Background(), lp1, party1, vgcrypto.RandomHash())
  3602  	require.NoError(t, err)
  3603  	tm.now = tm.now.Add(time.Second)
  3604  	tm.market.OnTick(ctx, tm.now)
  3605  
  3606  	lp2 := &types.LiquidityProvisionSubmission{
  3607  		MarketID:         tm.market.GetID(),
  3608  		CommitmentAmount: num.NewUint(100),
  3609  		Fee:              num.DecimalFromFloat(0.06),
  3610  	}
  3611  
  3612  	err = tm.market.SubmitLiquidityProvision(context.Background(), lp2, party2, vgcrypto.RandomHash())
  3613  	require.NoError(t, err)
  3614  	tm.now = tm.now.Add(time.Second)
  3615  	tm.market.OnTick(ctx, tm.now)
  3616  
  3617  	mktData := tm.market.GetMarketData()
  3618  	require.NotNil(t, mktData)
  3619  	expectedSuppliedStake := num.DecimalFromUint(num.Sum(lp1.CommitmentAmount, lp2.CommitmentAmount))
  3620  
  3621  	require.Equal(t, expectedSuppliedStake.String(), mktData.SuppliedStake)
  3622  }
  3623  
  3624  func TestSubmitLiquidityProvisionInOpeningAuction(t *testing.T) {
  3625  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3626  	mainParty := "mainParty"
  3627  	auxParty := "auxParty"
  3628  	p1, p2 := "party1", "party2"
  3629  	now := time.Unix(10, 0)
  3630  	var auctionDuration int64 = 5
  3631  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{Duration: auctionDuration}, true, 0.99)
  3632  	var midPrice uint64 = 100
  3633  
  3634  	addAccount(t, tm, mainParty)
  3635  	addAccount(t, tm, auxParty)
  3636  	addAccount(t, tm, p1)
  3637  	addAccount(t, tm, p2)
  3638  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3639  
  3640  	lp1 := &types.LiquidityProvisionSubmission{
  3641  		MarketID:         tm.market.GetID(),
  3642  		CommitmentAmount: num.NewUint(250),
  3643  		Fee:              num.DecimalFromFloat(0.05),
  3644  	}
  3645  
  3646  	require.Equal(t, types.MarketTradingModeOpeningAuction, tm.market.GetMarketData().MarketTradingMode)
  3647  
  3648  	err := tm.market.SubmitLiquidityProvision(ctx, lp1, mainParty, vgcrypto.RandomHash())
  3649  	require.NoError(t, err)
  3650  
  3651  	tradingOrders := []*types.Order{
  3652  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "p1-sell-order", types.SideSell, p1, 1, midPrice),
  3653  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "p2-buy-order", types.SideBuy, p2, 1, midPrice),
  3654  	}
  3655  	for _, o := range tradingOrders {
  3656  		conf, err := tm.market.SubmitOrder(ctx, o)
  3657  		assert.NoError(t, err)
  3658  		assert.NotNil(t, conf)
  3659  	}
  3660  	orderSell1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "auxParty-sell-order-1", types.SideSell, auxParty, 1, midPrice+2)
  3661  
  3662  	confirmationSell, err := tm.market.SubmitOrder(ctx, orderSell1)
  3663  	require.NotNil(t, confirmationSell)
  3664  	require.NoError(t, err)
  3665  
  3666  	orderBuy1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "auxParty-buy-order-1", types.SideBuy, auxParty, 1, midPrice-2)
  3667  
  3668  	confirmationBuy, err := tm.market.SubmitOrder(ctx, orderBuy1)
  3669  	assert.NotNil(t, confirmationBuy)
  3670  	assert.NoError(t, err)
  3671  
  3672  	now = now.Add(time.Duration((auctionDuration + 1) * time.Second.Nanoseconds()))
  3673  	tm.now = now
  3674  	tm.market.OnTick(ctx, now)
  3675  
  3676  	// Check that liquidity orders appear on the book once reference prices exist
  3677  	mktData := tm.market.GetMarketData()
  3678  	require.Equal(t, types.MarketTradingModeContinuous, mktData.MarketTradingMode)
  3679  }
  3680  
  3681  func getMarketOrder(tm *testMarket,
  3682  	now time.Time,
  3683  	orderType types.OrderType,
  3684  	orderTIF types.OrderTimeInForce,
  3685  	id string,
  3686  	side types.Side,
  3687  	partyID string,
  3688  	size uint64,
  3689  	price uint64,
  3690  ) *types.Order {
  3691  	order := &types.Order{
  3692  		Type:        orderType,
  3693  		TimeInForce: orderTIF,
  3694  		Status:      types.OrderStatusActive,
  3695  		ID:          id,
  3696  		Side:        side,
  3697  		Party:       partyID,
  3698  		MarketID:    tm.market.GetID(),
  3699  		Size:        size,
  3700  		Price:       num.NewUint(price),
  3701  		Remaining:   size,
  3702  		CreatedAt:   now.UnixNano(),
  3703  		Reference:   "marketorder",
  3704  	}
  3705  	return order
  3706  }
  3707  
  3708  func newPeggedOrder(reference types.PeggedReference, offset uint64) *types.PeggedOrder {
  3709  	return &types.PeggedOrder{
  3710  		Reference: reference,
  3711  		Offset:    num.NewUint(offset),
  3712  	}
  3713  }
  3714  
  3715  func TestOrderBook_Crash2651(t *testing.T) {
  3716  	now := time.Unix(10, 0)
  3717  	tm := getTestMarket(t, now, nil, nil)
  3718  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3719  
  3720  	addAccount(t, tm, "613f")
  3721  	addAccount(t, tm, "f9e7")
  3722  	addAccount(t, tm, "98e1")
  3723  	addAccount(t, tm, "qqqq")
  3724  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3725  
  3726  	// Switch to auction mode
  3727  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 10})
  3728  	tm.mas.AuctionStarted(ctx, now)
  3729  	tm.market.EnterAuction(ctx)
  3730  
  3731  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order01", types.SideBuy, "613f", 5, 9000)
  3732  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  3733  	require.NotNil(t, o1conf)
  3734  	require.NoError(t, err)
  3735  
  3736  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order02", types.SideSell, "f9e7", 5, 9000)
  3737  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  3738  	require.NotNil(t, o2conf)
  3739  	require.NoError(t, err)
  3740  
  3741  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order03", types.SideBuy, "613f", 4, 8000)
  3742  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  3743  	require.NotNil(t, o3conf)
  3744  	require.NoError(t, err)
  3745  
  3746  	o4 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order04", types.SideSell, "f9e7", 4, 8000)
  3747  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  3748  	require.NotNil(t, o4conf)
  3749  	require.NoError(t, err)
  3750  
  3751  	o5 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order05", types.SideBuy, "613f", 4, 3000)
  3752  	o5conf, err := tm.market.SubmitOrder(ctx, o5)
  3753  	require.NotNil(t, o5conf)
  3754  	require.NoError(t, err)
  3755  
  3756  	o6 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order06", types.SideSell, "f9e7", 3, 3000)
  3757  	o6conf, err := tm.market.SubmitOrder(ctx, o6)
  3758  	require.NotNil(t, o6conf)
  3759  	require.NoError(t, err)
  3760  
  3761  	o7 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order07", types.SideSell, "f9e7", 20, 0)
  3762  	o7.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 1000)
  3763  	o7conf, err := tm.market.SubmitOrder(ctx, o7)
  3764  	require.NotNil(t, o7conf)
  3765  	require.NoError(t, err)
  3766  
  3767  	o8 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order08", types.SideSell, "613f", 5, 10001)
  3768  	o8conf, err := tm.market.SubmitOrder(ctx, o8)
  3769  	require.NotNil(t, o8conf)
  3770  	require.NoError(t, err)
  3771  
  3772  	o9 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFA, "Order09", types.SideBuy, "613f", 5, 15001)
  3773  	o9conf, err := tm.market.SubmitOrder(ctx, o9)
  3774  	require.NotNil(t, o9conf)
  3775  	require.NoError(t, err)
  3776  
  3777  	o10 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order10", types.SideBuy, "f9e7", 12, 0)
  3778  	o10.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 1000)
  3779  	o10conf, err := tm.market.SubmitOrder(ctx, o10)
  3780  	require.NotNil(t, o10conf)
  3781  	require.NoError(t, err)
  3782  
  3783  	o11 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order11", types.SideBuy, "613f", 21, 0)
  3784  	o11.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 2000)
  3785  	o11conf, err := tm.market.SubmitOrder(ctx, o11)
  3786  	require.NotNil(t, o11conf)
  3787  	require.NoError(t, err)
  3788  
  3789  	// Leave auction and uncross the book
  3790  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  3791  	require.Equal(t, 3, tm.market.GetPeggedOrderCount())
  3792  	require.Equal(t, 3, tm.market.GetParkedOrderCount())
  3793  	require.Equal(t, types.MarketStateActive, tm.market.State()) // still in auction
  3794  
  3795  	o12 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order12", types.SideSell, "613f", 22, 9023)
  3796  	o12conf, err := tm.market.SubmitOrder(ctx, o12)
  3797  	require.NotNil(t, o12conf)
  3798  	require.NoError(t, err)
  3799  
  3800  	o13 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order13", types.SideBuy, "98e1", 23, 11119)
  3801  	o13conf, err := tm.market.SubmitOrder(ctx, o13)
  3802  	require.NotNil(t, o13conf)
  3803  	require.NoError(t, err)
  3804  
  3805  	// This order should cause a crash
  3806  	o14 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order14", types.SideBuy, "qqqq", 34, 11513)
  3807  	o14conf, err := tm.market.SubmitOrder(ctx, o14)
  3808  	require.NotNil(t, o14conf)
  3809  	require.NoError(t, err)
  3810  }
  3811  
  3812  func TestOrderBook_Crash2599(t *testing.T) {
  3813  	now := time.Unix(10, 0)
  3814  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  3815  		Duration: 1,
  3816  	})
  3817  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  3818  
  3819  	addAccount(t, tm, "A")
  3820  	addAccount(t, tm, "B")
  3821  	addAccount(t, tm, "C")
  3822  	addAccount(t, tm, "D")
  3823  	addAccount(t, tm, "E")
  3824  	addAccount(t, tm, "F")
  3825  	addAccount(t, tm, "G")
  3826  	auxParty := "auxParty"
  3827  	auxParty2 := "auxParty2"
  3828  	addAccount(t, tm, auxParty)
  3829  	addAccount(t, tm, auxParty2)
  3830  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3831  	addAccountWithAmount(tm, "lpprov", 10000000)
  3832  
  3833  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  3834  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  3835  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  3836  	require.NotNil(t, conf)
  3837  	require.NoError(t, err)
  3838  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3839  
  3840  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  3841  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  3842  	require.NotNil(t, conf)
  3843  	require.NoError(t, err)
  3844  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  3845  	auxOrders := []*types.Order{
  3846  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 11000),
  3847  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 11000),
  3848  	}
  3849  	for _, o := range auxOrders {
  3850  		conf, err := tm.market.SubmitOrder(ctx, o)
  3851  		require.NoError(t, err)
  3852  		require.NotNil(t, conf)
  3853  	}
  3854  	lp := &types.LiquidityProvisionSubmission{
  3855  		MarketID:         tm.market.GetID(),
  3856  		CommitmentAmount: num.NewUint(27500),
  3857  		Fee:              num.DecimalFromFloat(0.01),
  3858  	}
  3859  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  3860  	// leave opening auction
  3861  	now = now.Add(2 * time.Second)
  3862  	tm.now = now
  3863  	tm.market.OnTick(ctx, now)
  3864  
  3865  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order01", types.SideBuy, "A", 5, 11500)
  3866  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  3867  	require.NotNil(t, o1conf)
  3868  	require.NoError(t, err)
  3869  	now = now.Add(time.Second * 1)
  3870  	tm.now = now
  3871  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3872  
  3873  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order02", types.SideSell, "B", 25, 11000)
  3874  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  3875  	require.NotNil(t, o2conf)
  3876  	require.NoError(t, err)
  3877  	now = now.Add(time.Second * 1)
  3878  	tm.now = now
  3879  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3880  
  3881  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order03", types.SideBuy, "A", 10, 10500)
  3882  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  3883  	require.NotNil(t, o3conf)
  3884  	require.NoError(t, err)
  3885  	now = now.Add(time.Second * 1)
  3886  	tm.now = now
  3887  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3888  
  3889  	o4 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceIOC, "Order04", types.SideSell, "C", 5, 0)
  3890  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  3891  	require.NotNil(t, o4conf)
  3892  	require.NoError(t, err)
  3893  	now = now.Add(time.Second * 1)
  3894  	tm.now = now
  3895  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3896  
  3897  	o5 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order05", types.SideBuy, "C", 35, 0)
  3898  	o5.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 500)
  3899  	o5conf, err := tm.market.SubmitOrder(ctx, o5)
  3900  	require.NotNil(t, o5conf)
  3901  	require.NoError(t, err)
  3902  	now = now.Add(time.Second * 1)
  3903  	tm.now = now
  3904  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3905  
  3906  	o6 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order06", types.SideBuy, "D", 16, 0)
  3907  	o6.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 2000)
  3908  	o6conf, err := tm.market.SubmitOrder(ctx, o6)
  3909  	require.NotNil(t, o6conf)
  3910  	require.NoError(t, err)
  3911  	now = now.Add(time.Second * 1)
  3912  	tm.now = now
  3913  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3914  
  3915  	o7 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order07", types.SideSell, "E", 19, 0)
  3916  	o7.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 3000)
  3917  	o7.ExpiresAt = now.Add(time.Second * 60).UnixNano()
  3918  	o7conf, err := tm.market.SubmitOrder(ctx, o7)
  3919  	require.NotNil(t, o7conf)
  3920  	require.NoError(t, err)
  3921  	now = now.Add(time.Second * 1)
  3922  	tm.now = now
  3923  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3924  
  3925  	o8 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order08", types.SideBuy, "F", 25, 10000)
  3926  	o8conf, err := tm.market.SubmitOrder(ctx, o8)
  3927  	require.NotNil(t, o8conf)
  3928  	require.NoError(t, err)
  3929  	now = now.Add(time.Second * 1)
  3930  	tm.now = now
  3931  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3932  
  3933  	// This one should crash
  3934  	o9 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order09", types.SideSell, "F", 25, 10250)
  3935  	o9conf, err := tm.market.SubmitOrder(ctx, o9)
  3936  	require.NotNil(t, o9conf)
  3937  	require.NoError(t, err)
  3938  	now = now.Add(time.Second * 1)
  3939  	tm.now = now
  3940  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3941  
  3942  	o10 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order10", types.SideBuy, "G", 45, 14000)
  3943  	o10conf, err := tm.market.SubmitOrder(ctx, o10)
  3944  	require.NotNil(t, o10conf)
  3945  	require.NoError(t, err)
  3946  	now = now.Add(time.Second * 1)
  3947  	tm.now = now
  3948  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3949  
  3950  	o11 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order11", types.SideSell, "G", 45, 8500)
  3951  	o11conf, err := tm.market.SubmitOrder(ctx, o11)
  3952  	require.NotNil(t, o11conf)
  3953  	require.NoError(t, err)
  3954  	now = now.Add(time.Second * 1)
  3955  	tm.now = now
  3956  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  3957  }
  3958  
  3959  func TestTriggerAfterOpeningAuction(t *testing.T) {
  3960  	party1 := "party1"
  3961  	party2 := "party2"
  3962  	party3 := "party3"
  3963  	party4 := "party4"
  3964  	auxParty := "auxParty"
  3965  	auxParty2 := "auxParty2"
  3966  	now := time.Unix(10, 0)
  3967  	closingAt := time.Unix(10000000000, 0)
  3968  	auctionExtensionSeconds := int64(45)
  3969  	openingAuctionDuration := &types.AuctionDuration{Duration: auctionExtensionSeconds}
  3970  	openingAuctionEndTime := now.Add(time.Duration(openingAuctionDuration.Duration) * time.Second)
  3971  	afterOpeningAuction := openingAuctionEndTime.Add(time.Nanosecond)
  3972  	pMonitorAuctionEndTime := afterOpeningAuction.Add(time.Duration(auctionExtensionSeconds) * time.Second)
  3973  	afterPMonitorAuction := pMonitorAuctionEndTime.Add(time.Nanosecond)
  3974  	pMonitorSettings := &types.PriceMonitoringSettings{
  3975  		Parameters: &types.PriceMonitoringParameters{
  3976  			Triggers: []*types.PriceMonitoringTrigger{
  3977  				{
  3978  					Horizon:          60,
  3979  					HorizonDec:       num.DecimalFromFloat(60),
  3980  					Probability:      num.DecimalFromFloat(0.95),
  3981  					AuctionExtension: auctionExtensionSeconds,
  3982  				},
  3983  			},
  3984  		},
  3985  	}
  3986  	mmu, _ := num.UintFromDecimal(MAXMOVEUP)
  3987  	initialPrice := uint64(100)
  3988  	auctionTriggeringPrice := initialPrice + 1 + mmu.Uint64()
  3989  
  3990  	tm := getTestMarket(t, now, pMonitorSettings, openingAuctionDuration)
  3991  
  3992  	addAccount(t, tm, party1)
  3993  	addAccount(t, tm, party2)
  3994  	addAccount(t, tm, party3)
  3995  	addAccount(t, tm, party4)
  3996  	addAccount(t, tm, auxParty)
  3997  	addAccount(t, tm, auxParty2)
  3998  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  3999  	addAccountWithAmount(tm, "lpprov", 10000000)
  4000  
  4001  	tm.market.OnMarketAuctionMinimumDurationUpdate(context.Background(), time.Duration(auctionExtensionSeconds)*time.Second)
  4002  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4003  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4004  	require.NotNil(t, conf)
  4005  	require.NoError(t, err)
  4006  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4007  
  4008  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  4009  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4010  	require.NotNil(t, conf)
  4011  	require.NoError(t, err)
  4012  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4013  
  4014  	gtcOrders := []*types.Order{
  4015  		{
  4016  			Type:        types.OrderTypeLimit,
  4017  			TimeInForce: types.OrderTimeInForceGTC,
  4018  			Status:      types.OrderStatusActive,
  4019  			ID:          "someid3",
  4020  			Side:        types.SideBuy,
  4021  			Party:       party3,
  4022  			MarketID:    tm.market.GetID(),
  4023  			Size:        1,
  4024  			Price:       num.NewUint(initialPrice - 5),
  4025  			Remaining:   1,
  4026  			CreatedAt:   now.UnixNano(),
  4027  			ExpiresAt:   closingAt.UnixNano(),
  4028  			Reference:   "party3-buy-order-1",
  4029  		},
  4030  		{
  4031  			Type:        types.OrderTypeLimit,
  4032  			TimeInForce: types.OrderTimeInForceGTC,
  4033  			Status:      types.OrderStatusActive,
  4034  			ID:          "someid4",
  4035  			Side:        types.SideSell,
  4036  			Party:       party4,
  4037  			MarketID:    tm.market.GetID(),
  4038  			Size:        1,
  4039  			Price:       num.NewUint(initialPrice + 10),
  4040  			Remaining:   1,
  4041  			CreatedAt:   now.UnixNano(),
  4042  			Reference:   "party4-sell-order-1",
  4043  		},
  4044  	}
  4045  	for _, o := range gtcOrders {
  4046  		conf, err := tm.market.SubmitOrder(context.Background(), o)
  4047  		assert.NotNil(t, conf)
  4048  		assert.NoError(t, err)
  4049  	}
  4050  	orderBuy1 := &types.Order{
  4051  		Type:        types.OrderTypeLimit,
  4052  		TimeInForce: types.OrderTimeInForceGTT,
  4053  		Status:      types.OrderStatusActive,
  4054  		ID:          "someid1",
  4055  		Side:        types.SideBuy,
  4056  		Party:       party1,
  4057  		MarketID:    tm.market.GetID(),
  4058  		Size:        100,
  4059  		Price:       num.NewUint(initialPrice),
  4060  		Remaining:   100,
  4061  		CreatedAt:   now.UnixNano(),
  4062  		ExpiresAt:   closingAt.UnixNano(),
  4063  		Reference:   "party1-buy-order-1",
  4064  	}
  4065  	confirmationBuy, err := tm.market.SubmitOrder(context.Background(), orderBuy1)
  4066  	assert.NotNil(t, confirmationBuy)
  4067  	assert.NoError(t, err)
  4068  
  4069  	orderSell1 := &types.Order{
  4070  		Type:        types.OrderTypeLimit,
  4071  		TimeInForce: types.OrderTimeInForceGTC,
  4072  		Status:      types.OrderStatusActive,
  4073  		ID:          "someid2",
  4074  		Side:        types.SideSell,
  4075  		Party:       party2,
  4076  		MarketID:    tm.market.GetID(),
  4077  		Size:        100,
  4078  		Price:       num.NewUint(initialPrice),
  4079  		Remaining:   100,
  4080  		CreatedAt:   now.UnixNano(),
  4081  		Reference:   "party2-sell-order-1",
  4082  	}
  4083  	confirmationSell, err := tm.market.SubmitOrder(context.Background(), orderSell1)
  4084  	require.NotNil(t, confirmationSell)
  4085  	require.NoError(t, err)
  4086  
  4087  	require.Empty(t, confirmationSell.Trades)
  4088  
  4089  	auctionEnd := tm.market.GetMarketData().AuctionEnd
  4090  	require.Equal(t, openingAuctionEndTime.UnixNano(), auctionEnd) // In opening auction
  4091  
  4092  	lp := &types.LiquidityProvisionSubmission{
  4093  		MarketID:         tm.market.GetID(),
  4094  		CommitmentAmount: num.NewUint(25000),
  4095  		Fee:              num.DecimalFromFloat(0.01),
  4096  	}
  4097  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4098  	tm.now = afterOpeningAuction
  4099  	closed := tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), afterOpeningAuction)
  4100  	assert.False(t, closed)
  4101  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  4102  	require.Equal(t, int64(0), auctionEnd) // Not in auction
  4103  
  4104  	// let's cancel the orders we had to place to end opening auction
  4105  	for _, o := range gtcOrders {
  4106  		_, err := tm.market.CancelOrder(context.Background(), o.Party, o.ID, vgcrypto.RandomHash())
  4107  		assert.NoError(t, err)
  4108  	}
  4109  	orderBuy2 := &types.Order{
  4110  		Type:        types.OrderTypeLimit,
  4111  		TimeInForce: types.OrderTimeInForceGTT,
  4112  		Status:      types.OrderStatusActive,
  4113  		ID:          "someid3",
  4114  		Side:        types.SideBuy,
  4115  		Party:       party1,
  4116  		MarketID:    tm.market.GetID(),
  4117  		Size:        100,
  4118  		Price:       num.NewUint(auctionTriggeringPrice),
  4119  		Remaining:   100,
  4120  		CreatedAt:   now.UnixNano(),
  4121  		ExpiresAt:   closingAt.UnixNano(),
  4122  		Reference:   "party1-buy-order-2",
  4123  	}
  4124  	confirmationBuy, err = tm.market.SubmitOrder(context.Background(), orderBuy2)
  4125  	assert.NotNil(t, confirmationBuy)
  4126  	assert.NoError(t, err)
  4127  
  4128  	orderSell2 := &types.Order{
  4129  		Type:        types.OrderTypeLimit,
  4130  		TimeInForce: types.OrderTimeInForceGTC,
  4131  		Status:      types.OrderStatusActive,
  4132  		ID:          "someid4",
  4133  		Side:        types.SideSell,
  4134  		Party:       party2,
  4135  		MarketID:    tm.market.GetID(),
  4136  		Size:        100,
  4137  		Price:       num.NewUint(auctionTriggeringPrice),
  4138  		Remaining:   100,
  4139  		CreatedAt:   now.UnixNano(),
  4140  		Reference:   "party2-sell-order-2",
  4141  	}
  4142  	confirmationSell, err = tm.market.SubmitOrder(context.Background(), orderSell2)
  4143  	require.NotNil(t, confirmationSell)
  4144  	require.NoError(t, err)
  4145  
  4146  	require.Empty(t, confirmationSell.Trades)
  4147  
  4148  	auctionEnd = tm.market.GetMarketData().AuctionEnd
  4149  	require.Equal(t, pMonitorAuctionEndTime.UnixNano(), auctionEnd) // In auction
  4150  
  4151  	tm.now = pMonitorAuctionEndTime
  4152  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), pMonitorAuctionEndTime)
  4153  	assert.False(t, closed)
  4154  
  4155  	tm.now = afterPMonitorAuction
  4156  	closed = tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), afterPMonitorAuction)
  4157  	assert.False(t, closed)
  4158  }
  4159  
  4160  func TestOrderBook_Crash2718(t *testing.T) {
  4161  	now := time.Unix(10, 0)
  4162  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4163  		Duration: 1,
  4164  	})
  4165  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4166  
  4167  	addAccount(t, tm, "aaa")
  4168  	addAccount(t, tm, "bbb")
  4169  	auxParty := "auxParty"
  4170  	auxParty2 := "auxParty2"
  4171  	addAccount(t, tm, auxParty)
  4172  	addAccount(t, tm, auxParty2)
  4173  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4174  	addAccountWithAmount(tm, "lpprov", 10000000)
  4175  
  4176  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4177  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4178  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4179  	require.NotNil(t, conf)
  4180  	require.NoError(t, err)
  4181  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4182  
  4183  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  4184  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4185  	require.NotNil(t, conf)
  4186  	require.NoError(t, err)
  4187  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4188  
  4189  	auxOrders := []*types.Order{
  4190  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  4191  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  4192  	}
  4193  	for _, o := range auxOrders {
  4194  		conf, err := tm.market.SubmitOrder(ctx, o)
  4195  		require.NoError(t, err)
  4196  		require.NotNil(t, conf)
  4197  	}
  4198  	lp := &types.LiquidityProvisionSubmission{
  4199  		MarketID:         tm.market.GetID(),
  4200  		CommitmentAmount: num.NewUint(5000),
  4201  		Fee:              num.DecimalFromFloat(0.01),
  4202  	}
  4203  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4204  	// leave opening auction
  4205  	now = now.Add(2 * time.Second)
  4206  	tm.now = now
  4207  	tm.market.OnTick(ctx, now)
  4208  
  4209  	// We start in continuous trading, create order to set best bid
  4210  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "aaa", 1, 100)
  4211  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4212  	require.NotNil(t, o1conf)
  4213  	require.NoError(t, err)
  4214  	now = now.Add(time.Second * 1)
  4215  	tm.now = now
  4216  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4217  
  4218  	// Now the pegged order which will be live
  4219  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "bbb", 1, 0)
  4220  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  4221  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4222  	require.NotNil(t, o2conf)
  4223  	require.NoError(t, err)
  4224  	now = now.Add(time.Second * 1)
  4225  	tm.now = now
  4226  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4227  	assert.Equal(t, types.OrderStatusActive, o2.Status, o2.Status.String())
  4228  	assert.Equal(t, num.NewUint(90), o2.Price)
  4229  
  4230  	// Force the pegged order to reprice
  4231  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order03", types.SideBuy, "aaa", 1, 110)
  4232  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  4233  	require.NotNil(t, o3conf)
  4234  	require.NoError(t, err)
  4235  	now = now.Add(time.Second * 1)
  4236  	tm.now = now
  4237  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4238  
  4239  	o2Update := tm.lastOrderUpdate(o2.ID)
  4240  	assert.Equal(t, types.OrderStatusActive, o2Update.Status)
  4241  	assert.Equal(t, num.NewUint(100), o2Update.Price)
  4242  
  4243  	// Flip to auction so the pegged order will be parked
  4244  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 10})
  4245  	tm.mas.AuctionStarted(ctx, now)
  4246  	tm.market.EnterAuction(ctx)
  4247  	o2Update = tm.lastOrderUpdate(o2.ID)
  4248  	assert.Equal(t, types.OrderStatusParked, o2Update.Status)
  4249  	assert.True(t, o2Update.Price.IsZero())
  4250  
  4251  	// Flip out of auction to un-park it
  4252  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  4253  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  4254  
  4255  	o2Update = tm.lastOrderUpdate(o2.ID)
  4256  	assert.Equal(t, types.OrderStatusActive, o2Update.Status)
  4257  	assert.Equal(t, num.NewUint(100), o2Update.Price)
  4258  }
  4259  
  4260  func TestOrderBook_AmendPriceInParkedOrder(t *testing.T) {
  4261  	now := time.Unix(10, 0)
  4262  	tm := getTestMarket(t, now, nil, nil)
  4263  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4264  
  4265  	addAccount(t, tm, "aaa")
  4266  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4267  
  4268  	// Create a parked pegged order
  4269  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "aaa", 1, 0)
  4270  	o1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 10)
  4271  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4272  	tm.now = tm.now.Add(time.Second)
  4273  	tm.market.OnTick(ctx, tm.now)
  4274  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  4275  	require.NotNil(t, o1conf)
  4276  	require.NoError(t, err)
  4277  	tm.now = tm.now.Add(time.Second)
  4278  	tm.market.OnTick(ctx, tm.now)
  4279  	assert.Equal(t, types.OrderStatusParked, o1.Status)
  4280  	assert.True(t, o1.Price.IsZero())
  4281  
  4282  	// Try to amend the price
  4283  	amendment := &types.OrderAmendment{
  4284  		OrderID: o1.ID,
  4285  		Price:   num.NewUint(200),
  4286  	}
  4287  
  4288  	// This should fail as we cannot amend a pegged order price
  4289  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "aaa", vgcrypto.RandomHash())
  4290  	tm.now = tm.now.Add(time.Second)
  4291  	tm.market.OnTick(ctx, tm.now)
  4292  	require.Nil(t, amendConf)
  4293  	require.Error(t, types.OrderErrorUnableToAmendPriceOnPeggedOrder, err)
  4294  }
  4295  
  4296  func TestOrderBook_ExpiredOrderTriggersReprice(t *testing.T) {
  4297  	now := time.Unix(10, 0)
  4298  	tm := getTestMarket(t, now, nil, nil)
  4299  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4300  
  4301  	addAccount(t, tm, "aaa")
  4302  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4303  
  4304  	// Create an expiring order
  4305  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order01", types.SideBuy, "aaa", 1, 10)
  4306  	o1.ExpiresAt = now.Add(5 * time.Second).UnixNano()
  4307  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4308  	require.NotNil(t, o1conf)
  4309  	require.NoError(t, err)
  4310  
  4311  	// Create a pegged order that references its price
  4312  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "aaa", 1, 0)
  4313  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 2)
  4314  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4315  	require.NotNil(t, o2conf)
  4316  	require.NoError(t, err)
  4317  
  4318  	// Move the clock forward to expire the first order
  4319  	now = now.Add(time.Second * 10)
  4320  	tm.now = now
  4321  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4322  
  4323  	t.Run("order is parked", func(t *testing.T) {
  4324  		// First collect all the orders events
  4325  		found := map[string]*proto.Order{}
  4326  		for _, e := range tm.events {
  4327  			switch evt := e.(type) {
  4328  			case *events.Order:
  4329  				found[evt.Order().Id] = evt.Order()
  4330  			case *events.ExpiredOrders:
  4331  				for _, oid := range evt.OrderIDs() {
  4332  					found[oid] = &proto.Order{
  4333  						Status: types.OrderStatusExpired,
  4334  					}
  4335  				}
  4336  			}
  4337  		}
  4338  
  4339  		require.Len(t, found, 2)
  4340  
  4341  		expects := map[string]types.OrderStatus{
  4342  			o1.ID: types.OrderStatusExpired,
  4343  			o2.ID: types.OrderStatusParked,
  4344  		}
  4345  
  4346  		for id, v := range found {
  4347  			require.Equal(t, expects[id], v.Status)
  4348  		}
  4349  	})
  4350  }
  4351  
  4352  // This is a scenario to test issue: 2734
  4353  // Party A - 100000000
  4354  //
  4355  //	A - Buy 5@15000 GTC
  4356  //
  4357  // Party B - 100000000
  4358  //
  4359  //	B - Sell 10 IOC Market
  4360  //
  4361  // Party C - Deposit 100000
  4362  //
  4363  //	C - Buy GTT 6@1001 (60s)
  4364  //
  4365  // Party D- Fund 578
  4366  //
  4367  //	D - Pegged 3@BA +1
  4368  //
  4369  // Party E - Deposit 100000
  4370  //
  4371  //	E - Sell GTC 3@1002
  4372  //
  4373  // C amends order price=1002.
  4374  func TestOrderBook_CrashWithDistressedPartyPeggedOrderNotRemovedFromPeggedList2734(t *testing.T) {
  4375  	now := time.Unix(10, 0)
  4376  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4377  		Duration: 1,
  4378  	})
  4379  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4380  
  4381  	addAccountWithAmount(tm, "party-A", 100000000)
  4382  	addAccountWithAmount(tm, "party-B", 100000000)
  4383  	addAccountWithAmount(tm, "party-C", 100000)
  4384  	addAccountWithAmount(tm, "party-D", 578)
  4385  	addAccountWithAmount(tm, "party-E", 100000)
  4386  	auxParty := "auxParty"
  4387  	auxParty2 := "auxParty2"
  4388  	addAccount(t, tm, auxParty)
  4389  	addAccount(t, tm, auxParty2)
  4390  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4391  	addAccountWithAmount(tm, "lpprov", 10000000)
  4392  
  4393  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4394  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4395  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4396  	require.NotNil(t, conf)
  4397  	require.NoError(t, err)
  4398  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4399  
  4400  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000)
  4401  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4402  	require.NotNil(t, conf)
  4403  	require.NoError(t, err)
  4404  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4405  	auxOrders := []*types.Order{
  4406  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 1000),
  4407  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 1000),
  4408  	}
  4409  	for _, o := range auxOrders {
  4410  		conf, err := tm.market.SubmitOrder(ctx, o)
  4411  		require.NoError(t, err)
  4412  		require.NotNil(t, conf)
  4413  	}
  4414  	// leave opening auction
  4415  	lp := &types.LiquidityProvisionSubmission{
  4416  		MarketID:         tm.market.GetID(),
  4417  		CommitmentAmount: num.NewUint(5000),
  4418  		Fee:              num.DecimalFromFloat(0.01),
  4419  	}
  4420  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4421  	now = now.Add(2 * time.Second)
  4422  	tm.now = now
  4423  	tm.market.OnTick(ctx, now)
  4424  
  4425  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-A", 5, 15000)
  4426  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4427  	require.NotNil(t, o1conf)
  4428  	require.NoError(t, err)
  4429  
  4430  	o2 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceIOC, "Order02", types.SideSell, "party-B", 10, 0)
  4431  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4432  	require.NotNil(t, o2conf)
  4433  	require.NoError(t, err)
  4434  	tm.now = tm.now.Add(time.Second)
  4435  	tm.market.OnTick(ctx, tm.now)
  4436  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  4437  
  4438  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order03", types.SideBuy, "party-C", 6, 1001)
  4439  	o3.ExpiresAt = now.Add(60 * time.Second).UnixNano()
  4440  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  4441  	require.NotNil(t, o3conf)
  4442  	require.NoError(t, err)
  4443  
  4444  	o4 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order04", types.SideSell, "party-D", 3, 0)
  4445  	o4.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 1)
  4446  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  4447  	require.Nil(t, o4conf)
  4448  	require.Error(t, err)
  4449  
  4450  	o5 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order05", types.SideSell, "party-E", 3, 1002)
  4451  	o5conf, err := tm.market.SubmitOrder(ctx, o5)
  4452  	require.NotNil(t, o5conf)
  4453  	require.NoError(t, err)
  4454  
  4455  	// Try to amend the price
  4456  	amendment := &types.OrderAmendment{
  4457  		OrderID: o3.ID,
  4458  		Price:   num.NewUint(1002),
  4459  	}
  4460  
  4461  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-C", vgcrypto.RandomHash())
  4462  	require.NotNil(t, amendConf)
  4463  	require.NoError(t, err)
  4464  
  4465  	// nothing to do we just expect no crash.
  4466  }
  4467  
  4468  func TestOrderBook_Crash2733(t *testing.T) {
  4469  	now := time.Unix(10, 0)
  4470  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{Duration: 30})
  4471  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4472  
  4473  	addAccountWithAmount(tm, "party-A", 1000000)
  4474  	addAccountWithAmount(tm, "party-B", 1000000)
  4475  	addAccountWithAmount(tm, "party-C", 100000000)
  4476  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4477  
  4478  	for i := 1; i <= 10; i++ {
  4479  		o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, fmt.Sprintf("Order1%v", i), types.SideBuy, "party-A", uint64(i), 0)
  4480  		o1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, uint64(i*15))
  4481  		o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4482  		require.NotNil(t, o1conf)
  4483  		require.NoError(t, err)
  4484  
  4485  		o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, fmt.Sprintf("Order2%v", i), types.SideSell, "party-A", uint64(i), 0)
  4486  		o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, uint64(i*10))
  4487  		o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4488  		require.NotNil(t, o2conf)
  4489  		require.NoError(t, err)
  4490  
  4491  		o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, fmt.Sprintf("Order3%v", i), types.SideBuy, "party-A", uint64(i), 0)
  4492  		o3.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, uint64(i*5))
  4493  		o3conf, err := tm.market.SubmitOrder(ctx, o3)
  4494  		require.NotNil(t, o3conf)
  4495  		require.NoError(t, err)
  4496  	}
  4497  
  4498  	// now move time to after auction
  4499  	now = now.Add(31 * time.Second)
  4500  	tm.now = now
  4501  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4502  
  4503  	for i := 1; i <= 10; i++ {
  4504  		o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, fmt.Sprintf("Order4%v", i), types.SideSell, "party-B", uint64(i), uint64(i*150))
  4505  		o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4506  		require.NotNil(t, o1conf)
  4507  		require.NoError(t, err)
  4508  	}
  4509  
  4510  	for i := 1; i <= 20; i++ {
  4511  		o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, fmt.Sprintf("Order5%v", i), types.SideBuy, "party-C", uint64(i), uint64(i*100))
  4512  		o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4513  		require.NotNil(t, o1conf)
  4514  		require.NoError(t, err)
  4515  	}
  4516  }
  4517  
  4518  func TestOrderBook_Bug2747(t *testing.T) {
  4519  	now := time.Unix(10, 0)
  4520  	tm := getTestMarket(t, now, nil, nil)
  4521  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4522  
  4523  	addAccountWithAmount(tm, "party-A", 100000000)
  4524  	addAccountWithAmount(tm, "party-B", 100000000)
  4525  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4526  
  4527  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-A", 100, 0)
  4528  	o1.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 15)
  4529  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4530  	tm.now = tm.now.Add(time.Second)
  4531  	tm.market.OnTick(ctx, tm.now)
  4532  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  4533  	require.NotNil(t, o1conf)
  4534  	require.NoError(t, err)
  4535  
  4536  	// Try to amend the price
  4537  	amendment := &types.OrderAmendment{
  4538  		OrderID:         o1.ID,
  4539  		PeggedOffset:    num.NewUint(20),
  4540  		PeggedReference: types.PeggedReferenceBestAsk,
  4541  	}
  4542  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash())
  4543  	assert.Nil(t, amendConf)
  4544  	assert.EqualError(t, err, "OrderError: buy cannot reference best ask price")
  4545  }
  4546  
  4547  func TestOrderBook_AmendTIME_IN_FORCEForPeggedOrder(t *testing.T) {
  4548  	now := time.Unix(10, 0)
  4549  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4550  		Duration: 1,
  4551  	})
  4552  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4553  
  4554  	addAccount(t, tm, "aaa")
  4555  	auxParty := "auxParty"
  4556  	auxParty2 := "auxParty2"
  4557  	addAccount(t, tm, auxParty)
  4558  	addAccount(t, tm, auxParty2)
  4559  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4560  	addAccountWithAmount(tm, "lpprov", 10000000)
  4561  
  4562  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4563  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4564  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4565  	require.NotNil(t, conf)
  4566  	require.NoError(t, err)
  4567  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4568  
  4569  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000)
  4570  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4571  	require.NotNil(t, conf)
  4572  	require.NoError(t, err)
  4573  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4574  	auxOrders := []*types.Order{
  4575  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  4576  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  4577  	}
  4578  	for _, o := range auxOrders {
  4579  		conf, err := tm.market.SubmitOrder(ctx, o)
  4580  		require.NoError(t, err)
  4581  		require.NotNil(t, conf)
  4582  	}
  4583  	lp := &types.LiquidityProvisionSubmission{
  4584  		MarketID:         tm.market.GetID(),
  4585  		CommitmentAmount: num.NewUint(5000),
  4586  		Fee:              num.DecimalFromFloat(0.01),
  4587  	}
  4588  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4589  	// leave opening auction
  4590  	now = now.Add(time.Second * 2)
  4591  	tm.now = now
  4592  	tm.market.OnTick(ctx, now)
  4593  	// Create a normal order to set a BB price
  4594  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "aaa", 1, 10)
  4595  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4596  	require.NotNil(t, o1conf)
  4597  	require.NoError(t, err)
  4598  
  4599  	// Create a pegged order that references the BB price with an expiry time
  4600  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTT, "Order02", types.SideBuy, "aaa", 1, 0)
  4601  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 2)
  4602  	o2.ExpiresAt = now.Add(5 * time.Second).UnixNano()
  4603  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4604  	require.NotNil(t, o2conf)
  4605  	require.NoError(t, err)
  4606  
  4607  	// Amend the pegged order from GTT to GTC
  4608  	amendment := &types.OrderAmendment{
  4609  		OrderID:     o2.ID,
  4610  		TimeInForce: types.OrderTimeInForceGTC,
  4611  	}
  4612  
  4613  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "aaa", vgcrypto.RandomHash())
  4614  	require.NotNil(t, amendConf)
  4615  	require.NoError(t, err)
  4616  	assert.Equal(t, types.OrderStatusActive, o2.Status)
  4617  
  4618  	// Move the clock forward to expire any old orders
  4619  	now = now.Add(time.Second * 10)
  4620  	tm.now = now
  4621  	tm.events = nil
  4622  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4623  	t.Run("no orders expired", func(t *testing.T) {
  4624  		// First collect all the orders events
  4625  		orders := []*types.Order{}
  4626  		for _, e := range tm.events {
  4627  			switch evt := e.(type) {
  4628  			case *events.Order:
  4629  				if evt.Order().Status == types.OrderStatusExpired {
  4630  					orders = append(orders, mustOrderFromProto(evt.Order()))
  4631  				}
  4632  			}
  4633  		}
  4634  		require.Equal(t, 0, len(orders))
  4635  	})
  4636  
  4637  	// The pegged order should not be expired
  4638  	assert.Equal(t, types.OrderStatusActive.String(), o2.Status.String())
  4639  	assert.Equal(t, 0, tm.market.GetPeggedExpiryOrderCount())
  4640  }
  4641  
  4642  func TestOrderBook_AmendTIME_IN_FORCEForPeggedOrder2(t *testing.T) {
  4643  	now := time.Unix(10, 0)
  4644  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4645  		Duration: 1,
  4646  	})
  4647  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4648  
  4649  	addAccount(t, tm, "aaa")
  4650  	auxParty := "auxParty"
  4651  	auxParty2 := "auxParty2"
  4652  	addAccount(t, tm, auxParty)
  4653  	addAccount(t, tm, auxParty2)
  4654  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4655  	addAccountWithAmount(tm, "lpprov", 10000000)
  4656  
  4657  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4658  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4659  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4660  	require.NotNil(t, conf)
  4661  	require.NoError(t, err)
  4662  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4663  
  4664  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000)
  4665  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4666  	require.NotNil(t, conf)
  4667  	require.NoError(t, err)
  4668  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4669  
  4670  	auxOrders := []*types.Order{
  4671  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100),
  4672  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 100),
  4673  	}
  4674  	for _, o := range auxOrders {
  4675  		conf, err := tm.market.SubmitOrder(ctx, o)
  4676  		require.NoError(t, err)
  4677  		require.NotNil(t, conf)
  4678  	}
  4679  	lp := &types.LiquidityProvisionSubmission{
  4680  		MarketID:         tm.market.GetID(),
  4681  		CommitmentAmount: num.NewUint(5000),
  4682  		Fee:              num.DecimalFromFloat(0.01),
  4683  	}
  4684  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4685  	// leave opening auction
  4686  	now = now.Add(2 * time.Second)
  4687  	tm.now = now
  4688  	tm.market.OnTick(ctx, now)
  4689  
  4690  	// Create a normal order to set a BB price
  4691  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "aaa", 1, 10)
  4692  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4693  	require.NotNil(t, o1conf)
  4694  	require.NoError(t, err)
  4695  
  4696  	// Create a pegged order that references the BB price
  4697  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "aaa", 1, 0)
  4698  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestBid, 2)
  4699  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4700  	require.NotNil(t, o2conf)
  4701  	require.NoError(t, err)
  4702  
  4703  	exp := now.Add(5 * time.Second).UnixNano()
  4704  	// Amend the pegged order so that it has an expiry
  4705  	amendment := &types.OrderAmendment{
  4706  		OrderID:     o2.ID,
  4707  		TimeInForce: types.OrderTimeInForceGTT,
  4708  		ExpiresAt:   &exp,
  4709  	}
  4710  
  4711  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "aaa", vgcrypto.RandomHash())
  4712  	require.NotNil(t, amendConf)
  4713  	require.NoError(t, err)
  4714  	assert.Equal(t, types.OrderStatusActive, o2.Status)
  4715  	assert.Equal(t, 1, tm.market.GetPeggedExpiryOrderCount())
  4716  
  4717  	// Move the clock forward to expire any old orders
  4718  	now = now.Add(time.Second * 10)
  4719  	tm.now = now
  4720  	tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now)
  4721  	t.Run("1 order expired", func(t *testing.T) {
  4722  		// First collect all the orders events
  4723  		orders := []*types.Order{}
  4724  		for _, e := range tm.events {
  4725  			switch evt := e.(type) {
  4726  			case *events.ExpiredOrders:
  4727  				for _, oid := range evt.OrderIDs() {
  4728  					orders = append(orders, &types.Order{
  4729  						ID: oid,
  4730  					})
  4731  				}
  4732  			}
  4733  		}
  4734  		require.Equal(t, 1, len(orders))
  4735  		assert.Equal(t, orders[0].ID, o2.ID)
  4736  	})
  4737  
  4738  	assert.Equal(t, 0, tm.market.GetPeggedExpiryOrderCount())
  4739  }
  4740  
  4741  func TestOrderBook_AmendFilledWithActiveStatus2736(t *testing.T) {
  4742  	now := time.Unix(10, 0)
  4743  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4744  		Duration: 1,
  4745  	})
  4746  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4747  
  4748  	addAccount(t, tm, "party-A")
  4749  	addAccount(t, tm, "party-B")
  4750  	auxParty := "auxParty"
  4751  	auxParty2 := "auxParty2"
  4752  	addAccount(t, tm, auxParty)
  4753  	addAccount(t, tm, auxParty2)
  4754  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4755  	addAccountWithAmount(tm, "lpprov", 10000000)
  4756  
  4757  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4758  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4759  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4760  	require.NotNil(t, conf)
  4761  	require.NoError(t, err)
  4762  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4763  
  4764  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000)
  4765  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4766  	require.NotNil(t, conf)
  4767  	require.NoError(t, err)
  4768  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4769  
  4770  	auxOrders := []*types.Order{
  4771  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 5000),
  4772  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 5000),
  4773  	}
  4774  	for _, o := range auxOrders {
  4775  		conf, err := tm.market.SubmitOrder(ctx, o)
  4776  		require.NoError(t, err)
  4777  		require.NotNil(t, conf)
  4778  	}
  4779  	lp := &types.LiquidityProvisionSubmission{
  4780  		MarketID:         tm.market.GetID(),
  4781  		CommitmentAmount: num.NewUint(25000),
  4782  		Fee:              num.DecimalFromFloat(0.01),
  4783  	}
  4784  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4785  	// leave opening auction
  4786  	now = now.Add(2 * time.Second)
  4787  	tm.now = now
  4788  	tm.market.OnTick(ctx, now)
  4789  	require.Equal(t, types.MarketTradingModeContinuous, tm.market.GetMarketData().MarketTradingMode)
  4790  
  4791  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-A", 5, 5000)
  4792  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4793  	assert.NotNil(t, o1conf)
  4794  	assert.NoError(t, err)
  4795  
  4796  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "party-B", 5, 4500)
  4797  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4798  	assert.NotNil(t, o2conf)
  4799  	assert.NoError(t, err)
  4800  
  4801  	// Amend the pegged order so that it has an expiry
  4802  	amendment := &types.OrderAmendment{
  4803  		OrderID: o2.ID,
  4804  		Price:   num.NewUint(5000),
  4805  	}
  4806  
  4807  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-B", vgcrypto.RandomHash())
  4808  	assert.NotNil(t, amendConf)
  4809  	assert.NoError(t, err)
  4810  	o2Update := tm.lastOrderUpdate(o2.ID)
  4811  	assert.Equal(t, types.OrderStatusFilled, o2Update.Status, o2Update.Status.String())
  4812  }
  4813  
  4814  func TestOrderBook_PeggedOrderReprice2748(t *testing.T) {
  4815  	now := time.Unix(10, 0)
  4816  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4817  		Duration: 1,
  4818  	})
  4819  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4820  
  4821  	addAccountWithAmount(tm, "party-A", 100000000)
  4822  	addAccountWithAmount(tm, "party-B", 100000000)
  4823  	addAccountWithAmount(tm, "party-C", 100000000)
  4824  	auxParty, auxParty2 := "aux1", "aux2"
  4825  	addAccount(t, tm, auxParty)
  4826  	addAccount(t, tm, auxParty2)
  4827  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4828  	addAccountWithAmount(tm, "lpprov", 10000000)
  4829  
  4830  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4831  	auxOrders := []*types.Order{
  4832  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideBuy, auxParty, 1, 1),
  4833  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 10000),
  4834  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 5000),
  4835  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 5000),
  4836  	}
  4837  	for _, o := range auxOrders {
  4838  		conf, err := tm.market.SubmitOrder(ctx, o)
  4839  		require.NoError(t, err)
  4840  		require.NotNil(t, conf)
  4841  	}
  4842  	lp := &types.LiquidityProvisionSubmission{
  4843  		MarketID:         tm.market.GetID(),
  4844  		CommitmentAmount: num.NewUint(12500),
  4845  		Fee:              num.DecimalFromFloat(0.01),
  4846  	}
  4847  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4848  	// leave opening auction
  4849  	now = now.Add(2 * time.Second)
  4850  	tm.now = now
  4851  	tm.market.OnTick(ctx, now)
  4852  	// set the mid-price first to 6.5k
  4853  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-A", 5, 6000)
  4854  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4855  	require.NotNil(t, o1conf)
  4856  	require.NoError(t, err)
  4857  
  4858  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideSell, "party-B", 5, 7000)
  4859  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4860  	require.NotNil(t, o2conf)
  4861  	require.NoError(t, err)
  4862  
  4863  	// then place pegged order
  4864  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order03", types.SideBuy, "party-C", 100, 0)
  4865  	o3.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 15)
  4866  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  4867  	require.NotNil(t, o3conf)
  4868  	require.NoError(t, err)
  4869  
  4870  	assert.Equal(t, o3conf.Order.Status, types.OrderStatusActive)
  4871  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  4872  
  4873  	// then
  4874  	// Amend the pegged order so that it has an expiry
  4875  	amendment := &types.OrderAmendment{
  4876  		OrderID:      o3.ID,
  4877  		PeggedOffset: num.NewUint(6500),
  4878  	}
  4879  
  4880  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-C", vgcrypto.RandomHash())
  4881  	require.NotNil(t, amendConf)
  4882  	require.NoError(t, err)
  4883  
  4884  	assert.Equal(t, amendConf.Order.Status, types.OrderStatusParked)
  4885  	assert.Equal(t, 1, tm.market.GetParkedOrderCount())
  4886  }
  4887  
  4888  func TestOrderBook_AmendGFNToGTCOrGTTNotAllowed2486(t *testing.T) {
  4889  	now := time.Unix(10, 0)
  4890  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  4891  		Duration: 1,
  4892  	})
  4893  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4894  
  4895  	addAccountWithAmount(tm, "party-A", 100000000)
  4896  	auxParty := "auxParty"
  4897  	auxParty2 := "auxParty2"
  4898  	addAccount(t, tm, auxParty)
  4899  	addAccount(t, tm, auxParty2)
  4900  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4901  	addAccountWithAmount(tm, "lpprov", 10000000)
  4902  
  4903  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  4904  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  4905  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  4906  	require.NotNil(t, conf)
  4907  	require.NoError(t, err)
  4908  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4909  
  4910  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000)
  4911  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  4912  	require.NotNil(t, conf)
  4913  	require.NoError(t, err)
  4914  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  4915  
  4916  	auxOrders := []*types.Order{
  4917  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 6000),
  4918  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 6000),
  4919  	}
  4920  	for _, o := range auxOrders {
  4921  		conf, err := tm.market.SubmitOrder(ctx, o)
  4922  		require.NoError(t, err)
  4923  		require.NotNil(t, conf)
  4924  	}
  4925  	lp := &types.LiquidityProvisionSubmission{
  4926  		MarketID:         tm.market.GetID(),
  4927  		CommitmentAmount: num.NewUint(25000),
  4928  		Fee:              num.DecimalFromFloat(0.01),
  4929  	}
  4930  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  4931  	// leave opening auction
  4932  	now = now.Add(2 * time.Second)
  4933  	tm.now = now
  4934  	tm.market.OnTick(ctx, now)
  4935  
  4936  	// set the mid-price first to 6.5k
  4937  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order01", types.SideBuy, "party-A", 5, 6000)
  4938  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4939  	require.NotNil(t, o1conf)
  4940  	require.NoError(t, err)
  4941  
  4942  	// then
  4943  	// Amend the pegged order so that it has an expiry
  4944  	amendment := &types.OrderAmendment{
  4945  		OrderID:     o1.ID,
  4946  		TimeInForce: types.OrderTimeInForceGTC,
  4947  	}
  4948  
  4949  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash())
  4950  	assert.Nil(t, amendConf)
  4951  	assert.EqualError(t, err, "OrderError: Cannot amend TIF from GFA or GFN")
  4952  }
  4953  
  4954  func TestOrderBook_CancelAll2771(t *testing.T) {
  4955  	now := time.Unix(10, 0)
  4956  	tm := getTestMarket(t, now, nil, nil)
  4957  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4958  
  4959  	addAccountWithAmount(tm, "party-A", 100000000)
  4960  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4961  
  4962  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-A", 1, 0)
  4963  	o1.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  4964  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4965  	require.NotNil(t, o1conf)
  4966  	require.NoError(t, err)
  4967  	tm.now = tm.now.Add(time.Second)
  4968  	tm.market.OnTick(ctx, tm.now)
  4969  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  4970  	assert.Equal(t, o1conf.Order.Status, types.OrderStatusParked)
  4971  
  4972  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideSell, "party-A", 1, 0)
  4973  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  4974  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  4975  	require.NotNil(t, o2conf)
  4976  	require.NoError(t, err)
  4977  	assert.Equal(t, o2conf.Order.Status, types.OrderStatusParked)
  4978  
  4979  	confs, err := tm.market.CancelAllOrders(ctx, "party-A")
  4980  	assert.NoError(t, err)
  4981  	assert.Len(t, confs, 2)
  4982  }
  4983  
  4984  func TestOrderBook_RejectAmendPriceOnPeggedOrder2658(t *testing.T) {
  4985  	now := time.Unix(10, 0)
  4986  	tm := getTestMarket(t, now, nil, nil)
  4987  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  4988  
  4989  	addAccount(t, tm, "party-A")
  4990  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  4991  
  4992  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-A", 5, 5000)
  4993  	o1.PeggedOrder = newPeggedOrder(types.PeggedReferenceMid, 10)
  4994  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  4995  	assert.NotNil(t, o1conf)
  4996  	assert.NoError(t, err)
  4997  	tm.now = tm.now.Add(time.Second)
  4998  	tm.market.OnTick(ctx, tm.now)
  4999  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  5000  
  5001  	// Try to amend the price
  5002  	amendment := &types.OrderAmendment{
  5003  		OrderID:   o1.ID,
  5004  		Price:     num.NewUint(4000),
  5005  		SizeDelta: 10,
  5006  	}
  5007  
  5008  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash())
  5009  	assert.Nil(t, amendConf)
  5010  	assert.Error(t, types.OrderErrorUnableToAmendPriceOnPeggedOrder, err)
  5011  	assert.Equal(t, types.OrderStatusParked, o1.Status)
  5012  	assert.Equal(t, uint64(1), o1.Version)
  5013  }
  5014  
  5015  func TestOrderBook_AmendToCancelForceReprice(t *testing.T) {
  5016  	now := time.Unix(10, 0)
  5017  	tm := getTestMarket(t, now, nil, nil)
  5018  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5019  
  5020  	addAccount(t, tm, "party-A")
  5021  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  5022  
  5023  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-A", 1, 5000)
  5024  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5025  	assert.NotNil(t, o1conf)
  5026  	assert.NoError(t, err)
  5027  	tm.now = tm.now.Add(time.Second)
  5028  	tm.market.OnTick(ctx, tm.now)
  5029  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  5030  
  5031  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideSell, "party-A", 1, 0)
  5032  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 10)
  5033  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5034  	assert.NotNil(t, o2conf)
  5035  	assert.NoError(t, err)
  5036  
  5037  	// Try to amend the price
  5038  	amendment := &types.OrderAmendment{
  5039  		OrderID:   o1.ID,
  5040  		SizeDelta: -1,
  5041  	}
  5042  
  5043  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash())
  5044  	assert.NotNil(t, amendConf)
  5045  	assert.NoError(t, err)
  5046  
  5047  	assert.Equal(t, types.OrderStatusActive, o2.Status)
  5048  	o1Update := tm.lastOrderUpdate(o1.ID)
  5049  	assert.Equal(t, types.OrderStatusCancelled, o1Update.Status)
  5050  }
  5051  
  5052  func TestOrderBook_AmendExpPersistParkPeggedOrder(t *testing.T) {
  5053  	now := time.Unix(10, 0)
  5054  	tm := getTestMarket(t, now, nil, nil)
  5055  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5056  
  5057  	addAccount(t, tm, "party-A")
  5058  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  5059  
  5060  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-A", 10, 4550)
  5061  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5062  	assert.NotNil(t, o1conf)
  5063  	assert.NoError(t, err)
  5064  	tm.now = tm.now.Add(time.Second)
  5065  	tm.market.OnTick(ctx, tm.now)
  5066  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  5067  
  5068  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideSell, "party-A", 105, 0)
  5069  	o2.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 100)
  5070  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5071  	assert.NotNil(t, o2conf)
  5072  	assert.NoError(t, err)
  5073  
  5074  	// Try to amend the price
  5075  	amendment := &types.OrderAmendment{
  5076  		OrderID:   o1.ID,
  5077  		SizeDelta: -10,
  5078  	}
  5079  
  5080  	amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash())
  5081  	assert.NotNil(t, amendConf)
  5082  	assert.NoError(t, err)
  5083  	assert.Equal(t, types.OrderStatusActive, o2.Status)
  5084  	assert.False(t, o2.Price.IsZero())
  5085  	o1Update := tm.lastOrderUpdate(o1.ID)
  5086  	assert.Equal(t, types.OrderStatusCancelled, o1Update.Status)
  5087  }
  5088  
  5089  // This test is to make sure when we move into a price monitoring auction that we
  5090  // do not allow the parked orders to be repriced.
  5091  func TestOrderBook_ParkPeggedOrderWhenMovingToAuction(t *testing.T) {
  5092  	now := time.Unix(10, 0)
  5093  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
  5094  		Duration: 1,
  5095  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  5096  	}, true, 1.01)
  5097  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5098  
  5099  	addAccount(t, tm, "party-A")
  5100  	auxParty := "auxParty"
  5101  	auxParty2 := "auxParty2"
  5102  	addAccount(t, tm, auxParty)
  5103  	addAccount(t, tm, auxParty2)
  5104  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  5105  	addAccountWithAmount(tm, "lpprov", 10000000)
  5106  
  5107  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  5108  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  5109  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  5110  	require.NotNil(t, conf)
  5111  	require.NoError(t, err)
  5112  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5113  
  5114  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 1000000)
  5115  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  5116  	require.NotNil(t, conf)
  5117  	require.NoError(t, err)
  5118  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5119  
  5120  	auxOrders := []*types.Order{
  5121  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 1000),
  5122  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty2, 1, 1000),
  5123  	}
  5124  	for _, o := range auxOrders {
  5125  		conf, err := tm.market.SubmitOrder(ctx, o)
  5126  		require.NoError(t, err)
  5127  		require.NotNil(t, conf)
  5128  	}
  5129  	lp := &types.LiquidityProvisionSubmission{
  5130  		MarketID:         tm.market.GetID(),
  5131  		CommitmentAmount: num.NewUint(25000),
  5132  		Fee:              num.DecimalFromFloat(0.01),
  5133  	}
  5134  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  5135  	// leave opening auction
  5136  	now = now.Add(2 * time.Second)
  5137  	tm.now = now
  5138  	tm.market.OnTick(ctx, now)
  5139  
  5140  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order01", types.SideSell, "party-A", 10, 1010)
  5141  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5142  	require.NotNil(t, o1conf)
  5143  	require.NoError(t, err)
  5144  
  5145  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGFN, "Order02", types.SideBuy, "party-A", 10, 990)
  5146  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5147  	require.NotNil(t, o2conf)
  5148  	require.NoError(t, err)
  5149  
  5150  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "PeggyWeggy", types.SideSell, "party-A", 10, 0)
  5151  	o3.PeggedOrder = newPeggedOrder(types.PeggedReferenceBestAsk, 100)
  5152  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5153  	require.NotNil(t, o3conf)
  5154  	require.NoError(t, err)
  5155  	assert.Equal(t, int64(5), tm.market.GetOrdersOnBookCount())
  5156  
  5157  	// Move into a price monitoring auction so that the pegged orders are parked and the other orders are cancelled
  5158  	tm.market.StartPriceAuction(now)
  5159  	tm.market.EnterAuction(ctx)
  5160  	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  5161  
  5162  	require.Equal(t, 1, tm.market.GetPeggedOrderCount())
  5163  	require.Equal(t, 1, tm.market.GetParkedOrderCount())
  5164  	assert.Equal(t, int64(2), tm.market.GetOrdersOnBookCount())
  5165  }
  5166  
  5167  func TestMarket_LeaveAuctionRepricePeggedOrdersShouldFailIfNoMargin(t *testing.T) {
  5168  	now := time.Unix(10, 0)
  5169  	tm := getTestMarket(t, now, nil, nil)
  5170  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5171  
  5172  	// Create a new party account with very little funding
  5173  	addAccountWithAmount(tm, "party-C", 1)
  5174  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  5175  
  5176  	// Start the opening auction
  5177  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 10})
  5178  	tm.mas.AuctionStarted(ctx, now)
  5179  	tm.market.EnterAuction(ctx)
  5180  
  5181  	lps := &types.LiquidityProvisionSubmission{
  5182  		Fee:              num.DecimalFromFloat(0.01),
  5183  		MarketID:         tm.market.GetID(),
  5184  		CommitmentAmount: num.NewUint(1000000000),
  5185  	}
  5186  
  5187  	// Because we do not have enough funds to support our commitment level, we should reject this call
  5188  	err := tm.market.SubmitLiquidityProvision(ctx, lps, "party-C", vgcrypto.RandomHash())
  5189  	require.Error(t, err)
  5190  }
  5191  
  5192  func TestMarket_LeaveAuctionAndRepricePeggedOrders(t *testing.T) {
  5193  	now := time.Unix(10, 0)
  5194  	tm := getTestMarket(t, now, nil, nil)
  5195  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5196  
  5197  	addAccount(t, tm, "party-A")
  5198  	addAccount(t, tm, "party-B")
  5199  	addAccount(t, tm, "party-C")
  5200  	auxParty := "auxParty"
  5201  	addAccount(t, tm, auxParty)
  5202  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  5203  
  5204  	// Start the opening auction
  5205  	tm.mas.StartOpeningAuction(now, &types.AuctionDuration{Duration: 10})
  5206  	tm.mas.AuctionStarted(ctx, now)
  5207  	tm.market.EnterAuction(ctx)
  5208  
  5209  	// Add orders that will outlive the auction to set the reference prices
  5210  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-A", 10, 1010)
  5211  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5212  	require.NotNil(t, o1conf)
  5213  	require.NoError(t, err)
  5214  
  5215  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "party-A", 10, 990)
  5216  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5217  	require.NotNil(t, o2conf)
  5218  	require.NoError(t, err)
  5219  
  5220  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order03", types.SideSell, "party-A", 1, 1000)
  5221  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5222  	require.NotNil(t, o3conf)
  5223  	require.NoError(t, err)
  5224  
  5225  	o4 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order04", types.SideBuy, "party-A", 1, 1000)
  5226  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  5227  	require.NotNil(t, o4conf)
  5228  	require.NoError(t, err)
  5229  
  5230  	require.Equal(t, int64(4), tm.market.GetOrdersOnBookCount())
  5231  
  5232  	lps := &types.LiquidityProvisionSubmission{
  5233  		Fee:              num.DecimalFromFloat(0.01),
  5234  		MarketID:         tm.market.GetID(),
  5235  		CommitmentAmount: num.NewUint(1000000000),
  5236  	}
  5237  
  5238  	err = tm.market.SubmitLiquidityProvision(ctx, lps, "party-C", vgcrypto.RandomHash())
  5239  	require.NoError(t, err)
  5240  
  5241  	// Leave the auction so pegged orders are unparked
  5242  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  5243  
  5244  	require.Equal(t, int64(2), tm.market.GetOrdersOnBookCount())
  5245  	require.Equal(t, 0, tm.market.GetPeggedOrderCount())
  5246  	require.Equal(t, 0, tm.market.GetParkedOrderCount())
  5247  
  5248  	// Remove an order to invalidate reference prices and force pegged orders to park
  5249  	_, err = tm.market.CancelOrder(ctx, o1.Party, o1.ID, vgcrypto.RandomHash())
  5250  	require.NoError(t, err)
  5251  	tm.now = tm.now.Add(time.Second)
  5252  	tm.market.OnTick(ctx, tm.now)
  5253  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  5254  
  5255  	// 1 live orders, 1 normal
  5256  	// all LP have been removed as cannot be repriced.
  5257  	assert.Equal(t, int64(1), tm.market.GetOrdersOnBookCount())
  5258  	assert.Equal(t, 0, tm.market.GetPeggedOrderCount())
  5259  	assert.Equal(t, 0, tm.market.GetParkedOrderCount())
  5260  }
  5261  
  5262  func TestOrderBook_PartiallyFilledMarketOrderThatWouldWashIOC(t *testing.T) {
  5263  	now := time.Unix(10, 0)
  5264  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  5265  		Duration: 1000,
  5266  	})
  5267  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5268  
  5269  	addAccountWithAmount(tm, "party-A", 10000000)
  5270  	addAccountWithAmount(tm, "party-B", 10000000)
  5271  	auxParty := "auxParty"
  5272  	addAccount(t, tm, auxParty)
  5273  
  5274  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  5275  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  5276  	require.NotNil(t, conf)
  5277  	require.NoError(t, err)
  5278  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5279  
  5280  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  5281  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  5282  	require.NotNil(t, conf)
  5283  	require.NoError(t, err)
  5284  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5285  
  5286  	// Leave auction right away
  5287  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  5288  
  5289  	// Create 2 buy orders that we will try to match against
  5290  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-B", 10, 100)
  5291  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5292  	require.NotNil(t, o1conf)
  5293  	require.NoError(t, err)
  5294  
  5295  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "party-A", 10, 90)
  5296  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5297  	require.NotNil(t, o2conf)
  5298  	require.NoError(t, err)
  5299  
  5300  	// Send the sell order with enough volume to match both existing trades
  5301  	o3 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceIOC, "Order03", types.SideSell, "party-A", 20, 0)
  5302  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5303  	require.NotNil(t, o3conf)
  5304  	require.NoError(t, err)
  5305  	assert.Equal(t, types.OrderStatusPartiallyFilled, o3.Status)
  5306  	assert.Equal(t, uint64(10), o3.Remaining)
  5307  }
  5308  
  5309  func TestOrderBook_PartiallyFilledMarketOrderThatWouldWashFOKSell(t *testing.T) {
  5310  	now := time.Unix(10, 0)
  5311  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  5312  		Duration: 1000,
  5313  	})
  5314  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5315  
  5316  	addAccountWithAmount(tm, "party-A", 10000000)
  5317  	addAccountWithAmount(tm, "party-B", 10000000)
  5318  	auxParty := "auxParty"
  5319  	addAccount(t, tm, auxParty)
  5320  
  5321  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  5322  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  5323  	require.NotNil(t, conf)
  5324  	require.NoError(t, err)
  5325  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5326  
  5327  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  5328  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  5329  	require.NotNil(t, conf)
  5330  	require.NoError(t, err)
  5331  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5332  
  5333  	// Leave auction right away
  5334  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  5335  
  5336  	// Create 2 buy orders that we will try to match against
  5337  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-B", 10, 100)
  5338  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5339  	require.NotNil(t, o1conf)
  5340  	require.NoError(t, err)
  5341  
  5342  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "party-A", 10, 90)
  5343  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5344  	require.NotNil(t, o2conf)
  5345  	require.NoError(t, err)
  5346  
  5347  	// Send the sell order with enough volume to match both existing trades
  5348  	o3 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceFOK, "Order03", types.SideSell, "party-A", 20, 0)
  5349  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5350  	require.NotNil(t, o3conf)
  5351  	require.NoError(t, err)
  5352  
  5353  	// A wash trade during a FOK order will stop the order fully unfilled
  5354  	require.Equal(t, types.OrderStatusStopped, o3.Status)
  5355  	assert.Equal(t, uint64(20), o3.Remaining)
  5356  
  5357  	// Send the sell order with only enough volume to match the opposite party
  5358  	o4 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceFOK, "Order04", types.SideSell, "party-A", 5, 0)
  5359  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  5360  	require.NotNil(t, o4conf)
  5361  	require.NoError(t, err)
  5362  
  5363  	// Fully matches
  5364  	require.Equal(t, types.OrderStatusFilled, o4.Status)
  5365  	assert.Equal(t, uint64(0), o4.Remaining)
  5366  }
  5367  
  5368  func TestOrderBook_PartiallyFilledMarketOrderThatWouldWashFOKBuy(t *testing.T) {
  5369  	now := time.Unix(10, 0)
  5370  	tm := getTestMarket2(t, now, nil, &types.AuctionDuration{
  5371  		Duration: 1,
  5372  		// increase lpRange so that LP orders don't get pushed too close to MID and test can behave as expected
  5373  	}, true, 1)
  5374  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5375  
  5376  	auxParty, auxParty2 := "auxParty", "auxParty2"
  5377  	addAccountWithAmount(tm, "party-A", 10000000)
  5378  	addAccountWithAmount(tm, "party-B", 10000000)
  5379  	addAccount(t, tm, auxParty)
  5380  	addAccount(t, tm, auxParty2)
  5381  	addAccountWithAmount(tm, "lpprov", 10000000)
  5382  
  5383  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  5384  
  5385  	auxOrders := []*types.Order{
  5386  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux1", types.SideSell, auxParty, 1, 100000),
  5387  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux2", types.SideBuy, auxParty, 1, 1),
  5388  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux3", types.SideSell, auxParty, 1, 100),
  5389  		getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "aux4", types.SideBuy, auxParty2, 1, 100),
  5390  	}
  5391  	for _, o := range auxOrders {
  5392  		conf, err := tm.market.SubmitOrder(ctx, o)
  5393  		require.NoError(t, err)
  5394  		require.NotNil(t, conf)
  5395  	}
  5396  	lp := &types.LiquidityProvisionSubmission{
  5397  		MarketID:         tm.market.GetID(),
  5398  		CommitmentAmount: num.NewUint(25000),
  5399  		Fee:              num.DecimalFromFloat(0.01),
  5400  	}
  5401  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  5402  	// Leave auction
  5403  	now = now.Add(2 * time.Second)
  5404  	tm.now = now
  5405  	tm.market.OnTick(ctx, now)
  5406  
  5407  	// Create 2 buy orders that we will try to match against
  5408  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideSell, "party-B", 10, 100)
  5409  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5410  	require.NotNil(t, o1conf)
  5411  	require.NoError(t, err)
  5412  
  5413  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideSell, "party-A", 10, 110)
  5414  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5415  	require.NotNil(t, o2conf)
  5416  	require.NoError(t, err)
  5417  
  5418  	o5 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order05", types.SideBuy, "party-B", 10, 90)
  5419  	o5conf, err := tm.market.SubmitOrder(ctx, o5)
  5420  	require.NotNil(t, o5conf)
  5421  	require.NoError(t, err)
  5422  
  5423  	// Send the sell order with enough volume to match both existing trades
  5424  	o3 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceFOK, "Order03", types.SideBuy, "party-A", 15, 0)
  5425  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5426  	require.NotNil(t, o3conf)
  5427  	require.NoError(t, err)
  5428  
  5429  	// A wash trade during a FOK order will stop the order fully unfilled
  5430  	require.Equal(t, types.OrderStatusStopped, o3.Status)
  5431  	assert.EqualValues(t, 15, o3.Remaining)
  5432  
  5433  	// Send the sell order with only enough volume to match the opposite party
  5434  	o4 := getMarketOrder(tm, now, types.OrderTypeMarket, types.OrderTimeInForceFOK, "Order04", types.SideBuy, "party-A", 5, 0)
  5435  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  5436  	require.NotNil(t, o4conf)
  5437  	require.NoError(t, err)
  5438  
  5439  	// A wash trade during a FOK order will stop the order fully unfilled
  5440  	require.Equal(t, types.OrderStatusFilled, o4.Status)
  5441  	assert.Equal(t, uint64(0), o4.Remaining)
  5442  }
  5443  
  5444  func TestOrderBook_PartiallyFilledLimitOrderThatWouldWashFOK(t *testing.T) {
  5445  	now := time.Unix(10, 0)
  5446  	tm := getTestMarket(t, now, nil, &types.AuctionDuration{
  5447  		Duration: 1000,
  5448  	})
  5449  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5450  
  5451  	addAccountWithAmount(tm, "party-A", 10000000)
  5452  	addAccountWithAmount(tm, "party-B", 10000000)
  5453  	auxParty := "auxParty"
  5454  	addAccount(t, tm, auxParty)
  5455  
  5456  	alwaysOnBid := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnBid", types.SideBuy, auxParty, 1, 1)
  5457  	conf, err := tm.market.SubmitOrder(context.Background(), alwaysOnBid)
  5458  	require.NotNil(t, conf)
  5459  	require.NoError(t, err)
  5460  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5461  
  5462  	alwaysOnAsk := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "alwaysOnAsk", types.SideSell, auxParty, 1, 100000)
  5463  	conf, err = tm.market.SubmitOrder(context.Background(), alwaysOnAsk)
  5464  	require.NotNil(t, conf)
  5465  	require.NoError(t, err)
  5466  	require.Equal(t, types.OrderStatusActive, conf.Order.Status)
  5467  
  5468  	// Leave auction right away
  5469  	tm.market.LeaveAuctionWithIDGen(ctx, now.Add(time.Second*20), newTestIDGenerator())
  5470  
  5471  	md := tm.market.GetMarketData()
  5472  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  5473  
  5474  	// Create 2 buy orders that we will try to match against
  5475  	o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-B", 10, 100)
  5476  	o1conf, err := tm.market.SubmitOrder(ctx, o1)
  5477  	require.NotNil(t, o1conf)
  5478  	require.NoError(t, err)
  5479  
  5480  	o2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order02", types.SideBuy, "party-A", 10, 90)
  5481  	o2conf, err := tm.market.SubmitOrder(ctx, o2)
  5482  	require.NotNil(t, o2conf)
  5483  	require.NoError(t, err)
  5484  
  5485  	// Send the sell order with enough volume to match both existing trades
  5486  	o3 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceFOK, "Order03", types.SideSell, "party-A", 20, 90)
  5487  	o3conf, err := tm.market.SubmitOrder(ctx, o3)
  5488  	require.NotNil(t, o3conf)
  5489  	require.NoError(t, err)
  5490  
  5491  	// A wash trade during FOK will stop the order filly unfilled
  5492  	require.Equal(t, types.OrderStatusStopped, o3.Status)
  5493  	assert.Equal(t, uint64(20), o3.Remaining)
  5494  
  5495  	// Send the sell order with only enough volume to match the opposite party
  5496  	o4 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceFOK, "Order04", types.SideSell, "party-A", 5, 90)
  5497  	o4conf, err := tm.market.SubmitOrder(ctx, o4)
  5498  	require.NotNil(t, o4conf)
  5499  	require.NoError(t, err)
  5500  
  5501  	// A wash trade during FOK will stop the order filly unfilled
  5502  	require.Equal(t, types.OrderStatusFilled, o4.Status)
  5503  	assert.Equal(t, uint64(0), o4.Remaining)
  5504  }
  5505  
  5506  func Test3008And3007CancelLiquidityProvision(t *testing.T) {
  5507  	now := time.Unix(10, 0)
  5508  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5509  
  5510  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
  5511  		Duration: 10000,
  5512  	})
  5513  	mktCfg.Fees.Factors = &types.FeeFactors{
  5514  		LiquidityFee:      num.DecimalFromFloat(0.001),
  5515  		InfrastructureFee: num.DecimalFromFloat(0.0005),
  5516  		MakerFee:          num.DecimalFromFloat(0.00025),
  5517  	}
  5518  	mktCfg.TradableInstrument.RiskModel = &types.TradableInstrumentLogNormalRiskModel{
  5519  		LogNormalRiskModel: &types.LogNormalRiskModel{
  5520  			RiskAversionParameter: num.DecimalFromFloat(0.001),
  5521  			Tau:                   num.DecimalFromFloat(0.00011407711613050422),
  5522  			Params: &types.LogNormalModelParams{
  5523  				Mu:    num.DecimalZero(),
  5524  				R:     num.DecimalFromFloat(0.016),
  5525  				Sigma: num.DecimalFromFloat(20),
  5526  			},
  5527  		},
  5528  	}
  5529  
  5530  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
  5531  	tm.StartOpeningAuction().
  5532  		WithAccountAndAmount("party-0", 1000000).
  5533  		WithAccountAndAmount("party-1", 1000000).
  5534  		WithAccountAndAmount("party-2", 10000000000).
  5535  		// provide stake as well but will cancel
  5536  		WithAccountAndAmount("party-2-bis", 10000000000).
  5537  		WithAccountAndAmount("party-3", 1000000).
  5538  		WithAccountAndAmount("party-4", 1000000)
  5539  
  5540  	tm.now = now
  5541  	tm.market.OnTick(ctx, now)
  5542  
  5543  	orderParams := []struct {
  5544  		id        string
  5545  		size      uint64
  5546  		side      types.Side
  5547  		tif       types.OrderTimeInForce
  5548  		pegRef    types.PeggedReference
  5549  		pegOffset *num.Uint
  5550  	}{
  5551  		{"party-4", 1, types.SideBuy, types.OrderTimeInForceGTC, types.PeggedReferenceBestBid, num.NewUint(2000)},
  5552  		{"party-3", 1, types.SideSell, types.OrderTimeInForceGTC, types.PeggedReferenceBestAsk, num.NewUint(1000)},
  5553  	}
  5554  	partyA, partyB := orderParams[0], orderParams[1]
  5555  
  5556  	tpl := OrderTemplate{
  5557  		Type: types.OrderTypeLimit,
  5558  	}
  5559  	orders := []*types.Order{
  5560  		// Limit Orders
  5561  		tpl.New(types.Order{
  5562  			Size:        20,
  5563  			Remaining:   20,
  5564  			Price:       num.UintZero().Sub(num.NewUint(5500), partyA.pegOffset), // 3500
  5565  			Side:        types.SideBuy,
  5566  			Party:       "party-0",
  5567  			TimeInForce: types.OrderTimeInForceGFA,
  5568  		}),
  5569  		tpl.New(types.Order{
  5570  			Size:        20,
  5571  			Remaining:   20,
  5572  			Price:       num.UintZero().Sub(num.NewUint(5000), partyB.pegOffset), // 4000
  5573  			Side:        types.SideSell,
  5574  			Party:       "party-1",
  5575  			TimeInForce: types.OrderTimeInForceGFA,
  5576  		}),
  5577  		tpl.New(types.Order{
  5578  			Size:        10,
  5579  			Remaining:   10,
  5580  			Price:       num.NewUint(5500),
  5581  			Side:        types.SideBuy,
  5582  			Party:       "party-2",
  5583  			TimeInForce: types.OrderTimeInForceGFA,
  5584  		}),
  5585  		tpl.New(types.Order{
  5586  			Size:        100,
  5587  			Remaining:   100,
  5588  			Price:       num.NewUint(5000),
  5589  			Side:        types.SideSell,
  5590  			Party:       "party-2",
  5591  			TimeInForce: types.OrderTimeInForceGTC,
  5592  		}),
  5593  		tpl.New(types.Order{
  5594  			Size:        100,
  5595  			Remaining:   100,
  5596  			Price:       num.NewUint(3500),
  5597  			Side:        types.SideBuy,
  5598  			Party:       "party-0",
  5599  			TimeInForce: types.OrderTimeInForceGTC,
  5600  		}),
  5601  		tpl.New(types.Order{
  5602  			Size:        20,
  5603  			Remaining:   20,
  5604  			Price:       num.NewUint(8500),
  5605  			Side:        types.SideBuy,
  5606  			Party:       "party-0",
  5607  			TimeInForce: types.OrderTimeInForceGTC,
  5608  		}),
  5609  
  5610  		// Pegged Orders
  5611  		tpl.New(types.Order{
  5612  			Party:       partyA.id,
  5613  			Side:        partyA.side,
  5614  			Size:        partyA.size,
  5615  			Remaining:   partyA.size,
  5616  			TimeInForce: partyA.tif,
  5617  			PeggedOrder: &types.PeggedOrder{Reference: partyA.pegRef, Offset: partyA.pegOffset},
  5618  		}),
  5619  		tpl.New(types.Order{
  5620  			Party:       partyB.id,
  5621  			Side:        partyB.side,
  5622  			Size:        partyB.size,
  5623  			Remaining:   partyB.size,
  5624  			TimeInForce: partyB.tif,
  5625  			PeggedOrder: &types.PeggedOrder{Reference: partyB.pegRef, Offset: partyB.pegOffset},
  5626  		}),
  5627  	}
  5628  
  5629  	tm.WithSubmittedOrders(t, orders...)
  5630  
  5631  	// Add a LPSubmission
  5632  	// this is a log of stake, enough to cover all
  5633  	// the required stake for the market
  5634  	lp := &types.LiquidityProvisionSubmission{
  5635  		MarketID:         tm.market.GetID(),
  5636  		CommitmentAmount: num.NewUint(2000000),
  5637  		Fee:              num.DecimalFromFloat(0.01),
  5638  	}
  5639  
  5640  	require.NoError(t, tm.market.SubmitLiquidityProvision(ctx, lp, "party-2", vgcrypto.RandomHash()))
  5641  	// Leave the auction
  5642  	tm.now = now.Add(10001 * time.Second)
  5643  	tm.market.OnTick(ctx, tm.now)
  5644  
  5645  	assert.Equal(t, 1, tm.market.GetLPSCount())
  5646  
  5647  	// this is our second stake provider
  5648  	// small player
  5649  	lp2 := &types.LiquidityProvisionSubmission{
  5650  		MarketID:         tm.market.GetID(),
  5651  		CommitmentAmount: num.NewUint(1000),
  5652  		Fee:              num.DecimalFromFloat(0.01),
  5653  	}
  5654  
  5655  	// cleanup the events, we want to make sure our orders are created
  5656  	tm.events = nil
  5657  
  5658  	require.NoError(t, tm.market.SubmitLiquidityProvision(
  5659  		ctx, lp2, "party-2-bis", vgcrypto.RandomHash()))
  5660  
  5661  	tm.market.OnEpochEvent(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_START})
  5662  
  5663  	assert.Equal(t, 2, tm.market.GetLPSCount())
  5664  
  5665  	tm.now = now.Add(10011 * time.Second)
  5666  	tm.market.OnTick(ctx, tm.now)
  5667  
  5668  	// now we do a cancellation
  5669  	lpCancel := &types.LiquidityProvisionCancellation{
  5670  		MarketID: tm.market.GetID(),
  5671  	}
  5672  
  5673  	// cleanup the events before we continue
  5674  	tm.events = nil
  5675  
  5676  	require.NoError(t, tm.market.CancelLiquidityProvision(
  5677  		ctx, lpCancel, "party-2-bis"))
  5678  
  5679  	assert.Equal(t, 2, tm.market.GetLPSCount())
  5680  
  5681  	t.Run("LiquidityProvision_CANCELLED", func(t *testing.T) {
  5682  		// Filter events until LP is found
  5683  		var found *vegapb.LiquidityProvision
  5684  		for _, e := range tm.events {
  5685  			switch evt := e.(type) {
  5686  			case *events.LiquidityProvision:
  5687  				if evt.LiquidityProvision().PartyId == "party-2-bis" {
  5688  					found = evt.LiquidityProvision()
  5689  				}
  5690  			}
  5691  		}
  5692  		require.NotNil(t, found)
  5693  		assert.Equal(t, types.LiquidityProvisionStatusPending.String(), found.Status.String())
  5694  	})
  5695  }
  5696  
  5697  func Test2963EnsureEquityShareAreInMarketData(t *testing.T) {
  5698  	now := time.Unix(10, 0)
  5699  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5700  
  5701  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
  5702  		Duration: 10000,
  5703  	})
  5704  	mktCfg.Fees.Factors = &types.FeeFactors{
  5705  		LiquidityFee:      num.DecimalFromFloat(0.001),
  5706  		InfrastructureFee: num.DecimalFromFloat(0.0005),
  5707  		MakerFee:          num.DecimalFromFloat(0.00025),
  5708  	}
  5709  	mktCfg.TradableInstrument.RiskModel = &types.TradableInstrumentLogNormalRiskModel{
  5710  		LogNormalRiskModel: &types.LogNormalRiskModel{
  5711  			RiskAversionParameter: num.DecimalFromFloat(0.001),
  5712  			Tau:                   num.DecimalFromFloat(0.00011407711613050422),
  5713  			Params: &types.LogNormalModelParams{
  5714  				Mu:    num.DecimalZero(),
  5715  				R:     num.DecimalFromFloat(0.016),
  5716  				Sigma: num.DecimalFromFloat(20),
  5717  			},
  5718  		},
  5719  	}
  5720  
  5721  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
  5722  	tm.StartOpeningAuction().
  5723  		WithAccountAndAmount("party-0", 1000000).
  5724  		WithAccountAndAmount("party-1", 1000000).
  5725  		WithAccountAndAmount("party-2", 10000000000).
  5726  		// provide stake as well but will cancel
  5727  		WithAccountAndAmount("party-2-bis", 10000000000).
  5728  		WithAccountAndAmount("party-3", 1000000).
  5729  		WithAccountAndAmount("party-4", 1000000)
  5730  
  5731  	tm.now = now
  5732  	tm.market.OnTick(ctx, now)
  5733  
  5734  	orderParams := []struct {
  5735  		id        string
  5736  		size      uint64
  5737  		side      types.Side
  5738  		tif       types.OrderTimeInForce
  5739  		pegRef    types.PeggedReference
  5740  		pegOffset *num.Uint
  5741  	}{
  5742  		{"party-4", 1, types.SideBuy, types.OrderTimeInForceGTC, types.PeggedReferenceBestBid, num.NewUint(2000)},
  5743  		{"party-3", 1, types.SideSell, types.OrderTimeInForceGTC, types.PeggedReferenceBestAsk, num.NewUint(1000)},
  5744  	}
  5745  	partyA, partyB := orderParams[0], orderParams[1]
  5746  
  5747  	tpl := OrderTemplate{
  5748  		Type: types.OrderTypeLimit,
  5749  	}
  5750  	orders := []*types.Order{
  5751  		// Limit Orders
  5752  		tpl.New(types.Order{
  5753  			Size:        20,
  5754  			Remaining:   20,
  5755  			Price:       num.Sum(num.NewUint(5500), partyA.pegOffset), // 3500
  5756  			Side:        types.SideBuy,
  5757  			Party:       "party-0",
  5758  			TimeInForce: types.OrderTimeInForceGFA,
  5759  		}),
  5760  		tpl.New(types.Order{
  5761  			Size:        20,
  5762  			Remaining:   20,
  5763  			Price:       num.Sum(num.NewUint(5000), partyA.pegOffset), // 4000
  5764  			Side:        types.SideSell,
  5765  			Party:       "party-1",
  5766  			TimeInForce: types.OrderTimeInForceGFA,
  5767  		}),
  5768  		tpl.New(types.Order{
  5769  			Size:        10,
  5770  			Remaining:   10,
  5771  			Price:       num.NewUint(5500),
  5772  			Side:        types.SideBuy,
  5773  			Party:       "party-2",
  5774  			TimeInForce: types.OrderTimeInForceGFA,
  5775  		}),
  5776  		tpl.New(types.Order{
  5777  			Size:        100,
  5778  			Remaining:   100,
  5779  			Price:       num.NewUint(5000),
  5780  			Side:        types.SideSell,
  5781  			Party:       "party-2",
  5782  			TimeInForce: types.OrderTimeInForceGTC,
  5783  		}),
  5784  		tpl.New(types.Order{
  5785  			Size:        100,
  5786  			Remaining:   100,
  5787  			Price:       num.NewUint(3500),
  5788  			Side:        types.SideBuy,
  5789  			Party:       "party-0",
  5790  			TimeInForce: types.OrderTimeInForceGTC,
  5791  		}),
  5792  		tpl.New(types.Order{
  5793  			Size:        20,
  5794  			Remaining:   20,
  5795  			Price:       num.NewUint(8500),
  5796  			Side:        types.SideBuy,
  5797  			Party:       "party-0",
  5798  			TimeInForce: types.OrderTimeInForceGTC,
  5799  		}),
  5800  
  5801  		// Pegged Orders
  5802  		tpl.New(types.Order{
  5803  			Party:       partyA.id,
  5804  			Side:        partyA.side,
  5805  			Size:        partyA.size,
  5806  			Remaining:   partyA.size,
  5807  			TimeInForce: partyA.tif,
  5808  			PeggedOrder: &types.PeggedOrder{Reference: partyA.pegRef, Offset: partyA.pegOffset},
  5809  		}),
  5810  		tpl.New(types.Order{
  5811  			Party:       partyB.id,
  5812  			Side:        partyB.side,
  5813  			Size:        partyB.size,
  5814  			Remaining:   partyB.size,
  5815  			TimeInForce: partyB.tif,
  5816  			PeggedOrder: &types.PeggedOrder{Reference: partyB.pegRef, Offset: partyB.pegOffset},
  5817  		}),
  5818  	}
  5819  
  5820  	tm.WithSubmittedOrders(t, orders...)
  5821  
  5822  	// Add a LPSubmission
  5823  	// this is a log of stake, enough to cover all
  5824  	// the required stake for the market
  5825  	lp := &types.LiquidityProvisionSubmission{
  5826  		MarketID:         tm.market.GetID(),
  5827  		CommitmentAmount: num.NewUint(2000000),
  5828  		Fee:              num.DecimalFromFloat(0.01),
  5829  	}
  5830  
  5831  	// Leave the auction
  5832  	tm.now = now.Add(10001 * time.Second)
  5833  	tm.market.OnTick(ctx, tm.now)
  5834  
  5835  	require.NoError(t, tm.market.SubmitLiquidityProvision(ctx, lp, "party-2", vgcrypto.RandomHash()))
  5836  	assert.Equal(t, 0, tm.market.GetLPSCount())
  5837  
  5838  	// this is our second stake provider
  5839  	// small player
  5840  	lp2 := &types.LiquidityProvisionSubmission{
  5841  		MarketID:         tm.market.GetID(),
  5842  		CommitmentAmount: num.NewUint(1000),
  5843  		Fee:              num.DecimalFromFloat(0.01),
  5844  	}
  5845  
  5846  	// cleanup the events, we want to make sure our orders are created
  5847  	tm.events = nil
  5848  
  5849  	require.NoError(t, tm.market.SubmitLiquidityProvision(
  5850  		ctx, lp2, "party-2-bis", vgcrypto.RandomHash()))
  5851  	assert.Equal(t, 0, tm.market.GetLPSCount())
  5852  
  5853  	tm.now = now.Add(10011 * time.Second)
  5854  	tm.market.OnTick(ctx, tm.now)
  5855  	tm.market.OnEpochEvent(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_START})
  5856  
  5857  	mktData := tm.market.GetMarketData()
  5858  	assert.Len(t, mktData.LiquidityProviderFeeShare, 2)
  5859  }
  5860  
  5861  func TestAverageEntryValuation(t *testing.T) {
  5862  	now := time.Unix(10, 0)
  5863  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5864  
  5865  	auctionEnd := now.Add(10001 * time.Second)
  5866  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
  5867  		Duration: 10000,
  5868  	})
  5869  	mktCfg.Fees.Factors = &types.FeeFactors{
  5870  		LiquidityFee:      num.DecimalFromFloat(0.001),
  5871  		InfrastructureFee: num.DecimalFromFloat(0.0005),
  5872  		MakerFee:          num.DecimalFromFloat(0.00025),
  5873  	}
  5874  	mktCfg.TradableInstrument.RiskModel = &types.TradableInstrumentLogNormalRiskModel{
  5875  		LogNormalRiskModel: &types.LogNormalRiskModel{
  5876  			RiskAversionParameter: num.DecimalFromFloat(0.001),
  5877  			Tau:                   num.DecimalFromFloat(0.00011407711613050422),
  5878  			Params: &types.LogNormalModelParams{
  5879  				Mu:    num.DecimalZero(),
  5880  				R:     num.DecimalFromFloat(0.016),
  5881  				Sigma: num.DecimalFromFloat(20),
  5882  			},
  5883  		},
  5884  	}
  5885  
  5886  	lpparty := "lp-party-1"
  5887  	lpparty2 := "lp-party-2"
  5888  	lpparty3 := "lp-party-3"
  5889  
  5890  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
  5891  	tm.StartOpeningAuction().
  5892  		// the liquidity provider
  5893  		WithAccountAndAmount(lpparty, 500000000000).
  5894  		WithAccountAndAmount(lpparty2, 500000000000).
  5895  		WithAccountAndAmount(lpparty3, 500000000000)
  5896  
  5897  	// Add a LPSubmission
  5898  	// this is a log of stake, enough to cover all
  5899  	// the required stake for the market
  5900  	lpSubmission := types.LiquidityProvisionSubmission{
  5901  		MarketID:         tm.market.GetID(),
  5902  		CommitmentAmount: num.NewUint(80000),
  5903  		Fee:              num.DecimalFromFloat(0.01),
  5904  		Reference:        "ref-lp-submission-1",
  5905  	}
  5906  
  5907  	// submit our lp
  5908  	require.NoError(t,
  5909  		tm.market.SubmitLiquidityProvision(
  5910  			ctx, &lpSubmission, lpparty, vgcrypto.RandomHash()),
  5911  	)
  5912  
  5913  	lpSubmission2 := lpSubmission
  5914  	lpSubmission2.CommitmentAmount = lpSubmission.CommitmentAmount.Clone()
  5915  	lpSubmission2.Reference = "lp-submission-2"
  5916  	// submit our lp
  5917  	require.NoError(t,
  5918  		tm.market.SubmitLiquidityProvision(
  5919  			ctx, &lpSubmission2, lpparty2, vgcrypto.RandomHash()),
  5920  	)
  5921  
  5922  	lpSubmission3 := lpSubmission
  5923  	lpSubmission3.CommitmentAmount = lpSubmission.CommitmentAmount.Clone()
  5924  	lpSubmission3.Reference = "lp-submission-3"
  5925  	// submit our lp
  5926  	require.NoError(t,
  5927  		tm.market.SubmitLiquidityProvision(
  5928  			ctx, &lpSubmission3, lpparty3, vgcrypto.RandomHash()),
  5929  	)
  5930  	// after LP submission
  5931  	tm.EndOpeningAuction(t, auctionEnd, false)
  5932  
  5933  	marketData := tm.market.GetMarketData()
  5934  	/*
  5935  		expects := map[string]struct {
  5936  			found bool
  5937  			value string
  5938  		}{
  5939  			lpparty:  {value: "0.5454545454545455"}, // 6/9
  5940  			lpparty2: {value: "0.2727272727272727"}, // 3/9
  5941  			lpparty3: {value: "0.1818181818181818"}, // 2/9
  5942  		}*/
  5943  	// because we now have to submit the LP before leaving auction, all LPs provide the same
  5944  	expects := map[string]struct {
  5945  		found bool
  5946  		value string
  5947  	}{
  5948  		lpparty:  {value: "0.3333333333333333"},
  5949  		lpparty2: {value: "0.3333333333333333"},
  5950  		lpparty3: {value: "0.3333333333333333"},
  5951  	}
  5952  
  5953  	for _, v := range marketData.LiquidityProviderFeeShare {
  5954  		expv, ok := expects[v.Party]
  5955  		assert.True(t, ok, "unexpected lp provider in market data", v.Party)
  5956  		assert.Equal(t, expv.value, v.EquityLikeShare)
  5957  		expv.found = true
  5958  		expects[v.Party] = expv
  5959  	}
  5960  
  5961  	// now ensure all are found
  5962  	for k, v := range expects {
  5963  		assert.True(t, v.found, "was not in the list of lp providers", k)
  5964  	}
  5965  }
  5966  
  5967  func TestBondAccountIsReleasedItMarketRejected(t *testing.T) {
  5968  	now := time.Unix(10, 0)
  5969  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  5970  
  5971  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
  5972  		Duration: 10000,
  5973  	})
  5974  	mktCfg.Fees.Factors = &types.FeeFactors{
  5975  		LiquidityFee:      num.DecimalFromFloat(0.001),
  5976  		InfrastructureFee: num.DecimalFromFloat(0.0005),
  5977  		MakerFee:          num.DecimalFromFloat(0.00025),
  5978  	}
  5979  	mktCfg.TradableInstrument.RiskModel = &types.TradableInstrumentLogNormalRiskModel{
  5980  		LogNormalRiskModel: &types.LogNormalRiskModel{
  5981  			RiskAversionParameter: num.DecimalFromFloat(0.001),
  5982  			Tau:                   num.DecimalFromFloat(0.00011407711613050422),
  5983  			Params: &types.LogNormalModelParams{
  5984  				Mu:    num.DecimalZero(),
  5985  				R:     num.DecimalFromFloat(0.016),
  5986  				Sigma: num.DecimalFromFloat(20),
  5987  			},
  5988  		},
  5989  	}
  5990  
  5991  	lpparty := "lp-party-1"
  5992  
  5993  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
  5994  	tm.WithAccountAndAmount(lpparty, 500000)
  5995  
  5996  	tm.now = now
  5997  	tm.market.OnTick(ctx, now)
  5998  
  5999  	// Add a LPSubmission
  6000  	// this is a log of stake, enough to cover all
  6001  	// the required stake for the market
  6002  	lpSubmission := &types.LiquidityProvisionSubmission{
  6003  		MarketID:         tm.market.GetID(),
  6004  		CommitmentAmount: num.NewUint(150000),
  6005  		Fee:              num.DecimalFromFloat(0.01),
  6006  		Reference:        "ref-lp-submission-1",
  6007  	}
  6008  
  6009  	// submit our lp
  6010  	require.NoError(t,
  6011  		tm.market.SubmitLiquidityProvision(
  6012  			ctx, lpSubmission, lpparty, vgcrypto.RandomHash()),
  6013  	)
  6014  
  6015  	t.Run("bond account is updated with the new commitment", func(t *testing.T) {
  6016  		bacc, err := tm.collateralEngine.GetPartyBondAccount(
  6017  			tm.market.GetID(), lpparty, tm.asset)
  6018  		assert.NoError(t, err)
  6019  		assert.Equal(t, num.NewUint(150000), bacc.Balance)
  6020  		gacc, err := tm.collateralEngine.GetPartyGeneralAccount(
  6021  			lpparty, tm.asset)
  6022  		assert.NoError(t, err)
  6023  		assert.Equal(t, num.NewUint(350000), gacc.Balance)
  6024  	})
  6025  
  6026  	// now we reject the network and our party bond account should be released to general
  6027  	assert.NoError(t,
  6028  		tm.market.Reject(context.Background()),
  6029  	)
  6030  
  6031  	t.Run("bond is released to general account", func(t *testing.T) {
  6032  		// an error as the bond account is being deleted
  6033  		_, err := tm.collateralEngine.GetPartyBondAccount(
  6034  			tm.market.GetID(), lpparty, tm.asset)
  6035  		require.Error(t, err)
  6036  		assert.Contains(t, err.Error(), "account does not exist:")
  6037  		gacc, err := tm.collateralEngine.GetPartyGeneralAccount(
  6038  			lpparty, tm.asset)
  6039  		assert.NoError(t, err)
  6040  		assert.Equal(t, num.NewUint(500000), gacc.Balance)
  6041  	})
  6042  }
  6043  
  6044  // TODO karel - write a test with new liquidity
  6045  // func TestLiquidityMonitoring_GoIntoAndOutOfAuction(t *testing.T) {
  6046  // 	now := time.Unix(10, 0)
  6047  // 	openingDuration := &types.AuctionDuration{
  6048  // 		Duration: 1,
  6049  // 	}
  6050  // 	tm := getTestMarket(t, now, nil, openingDuration)
  6051  // 	c1 := 0.7
  6052  // 	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6053  // 	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  6054  
  6055  // 	md := tm.market.GetMarketData()
  6056  // 	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6057  
  6058  // 	lp1 := "lp1"
  6059  // 	lp2 := "lp2"
  6060  // 	party1 := "party1"
  6061  // 	party2 := "party2"
  6062  // 	auxParty, auxParty2 := "auxParty", "auxParty2"
  6063  
  6064  // 	addAccount(t, tm, lp1)
  6065  // 	addAccount(t, tm, lp2)
  6066  // 	addAccount(t, tm, party1)
  6067  // 	addAccount(t, tm, party2)
  6068  // 	addAccount(t, tm, auxParty)
  6069  // 	addAccount(t, tm, auxParty2)
  6070  
  6071  // 	lp1Commitment := num.NewUint(50000)
  6072  // 	lp2Commitment := num.NewUint(10000)
  6073  
  6074  // 	matchingPrice := uint64(100)
  6075  // 	// Add orders that will stay on the book thus maintaining best_bid and best_ask
  6076  // 	buyOrder1 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder1", types.SideBuy, party1, 1, matchingPrice-10)
  6077  // 	buyConf1, err := tm.market.SubmitOrder(ctx, buyOrder1)
  6078  // 	require.NoError(t, err)
  6079  // 	require.Equal(t, types.OrderStatusActive, buyConf1.Order.Status)
  6080  
  6081  // 	md = tm.market.GetMarketData()
  6082  // 	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6083  
  6084  // 	sellOrder1 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder1", types.SideSell, party2, 1, matchingPrice+10)
  6085  // 	sellConf1, err := tm.market.SubmitOrder(ctx, sellOrder1)
  6086  // 	require.NoError(t, err)
  6087  // 	require.Equal(t, types.OrderStatusActive, sellConf1.Order.Status)
  6088  
  6089  // 	md = tm.market.GetMarketData()
  6090  // 	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6091  
  6092  // 	lp1sub := &types.LiquidityProvisionSubmission{
  6093  // 		MarketID:         tm.market.GetID(),
  6094  // 		CommitmentAmount: lp1Commitment,
  6095  // 		Fee:              num.DecimalFromFloat(0.05),
  6096  // 	}
  6097  
  6098  // 	lp2sub := &types.LiquidityProvisionSubmission{
  6099  // 		MarketID:         tm.market.GetID(),
  6100  // 		CommitmentAmount: lp2Commitment,
  6101  // 		Fee:              num.DecimalFromFloat(0.1),
  6102  // 	}
  6103  
  6104  // 	require.NoError(t,
  6105  // 		tm.market.SubmitLiquidityProvision(ctx, lp1sub, lp1, vgcrypto.RandomHash()),
  6106  // 	)
  6107  
  6108  // 	require.NoError(t,
  6109  // 		tm.market.SubmitLiquidityProvision(ctx, lp2sub, lp2, vgcrypto.RandomHash()),
  6110  // 	)
  6111  
  6112  // 	md = tm.market.GetMarketData()
  6113  // 	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6114  
  6115  // 	buyOrder2 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder2", types.SideBuy, party1, 1, matchingPrice)
  6116  // 	buyConf2, err := tm.market.SubmitOrder(ctx, buyOrder2)
  6117  // 	require.NoError(t, err)
  6118  // 	require.Equal(t, types.OrderStatusActive, buyConf2.Order.Status)
  6119  
  6120  // 	sellOrder2 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder2", types.SideSell, party2, 1, matchingPrice)
  6121  // 	sellConf2, err := tm.market.SubmitOrder(ctx, sellOrder2)
  6122  // 	require.NoError(t, err)
  6123  // 	require.Equal(t, types.OrderStatusActive, sellConf2.Order.Status)
  6124  // 	require.Equal(t, 0, len(sellConf2.Trades))
  6125  
  6126  // 	md = tm.market.GetMarketData()
  6127  // 	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6128  // 	require.Equal(t, num.Sum(lp1Commitment, lp2Commitment).String(), md.SuppliedStake)
  6129  
  6130  // 	// leave opening auction
  6131  // 	tm.now = now.Add(2 * time.Second)
  6132  // 	closed := tm.market.OnTick(ctx, tm.now)
  6133  // 	require.False(t, closed)
  6134  // 	tm.stateVar.ReadyForTimeTrigger(tm.asset, tm.market.GetID())
  6135  // 	tm.stateVar.OnTick(context.Background(), tm.now.Add(6*time.Minute))
  6136  
  6137  // 	totalCommitment := num.Sum(lp1Commitment, lp2Commitment)
  6138  // 	currentStake := num.DecimalFromUint(totalCommitment)
  6139  // 	md = tm.market.GetMarketData()
  6140  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode, md.MarketTradingMode.String())
  6141  // 	require.Equal(t, totalCommitment.String(), md.SuppliedStake)
  6142  // 	require.True(t, md.MarkPrice.EQ(num.NewUint(matchingPrice)))
  6143  
  6144  // 	factor := num.DecimalFromFloat(c1)
  6145  // 	supplied, err := num.DecimalFromString(md.SuppliedStake)
  6146  // 	require.NoError(t, err)
  6147  // 	target, err := num.DecimalFromString(md.TargetStake)
  6148  // 	require.NoError(t, err)
  6149  // 	require.True(t, supplied.GreaterThan(target.Mul(factor)))
  6150  
  6151  // 	// current = (target * c1) auction not triggered
  6152  // 	riskParams := tm.mktCfg.TradableInstrument.GetSimpleRiskModel().Params
  6153  // 	require.NotNil(t, riskParams)
  6154  
  6155  // 	matchingPriceDec := num.DecimalFromFloat(float64(matchingPrice))
  6156  // 	if riskParams.FactorLong.GreaterThan(riskParams.FactorShort) {
  6157  // 		matchingPriceDec = matchingPriceDec.Mul(riskParams.FactorLong)
  6158  // 	} else {
  6159  // 		matchingPriceDec = matchingPriceDec.Mul(riskParams.FactorShort)
  6160  // 	}
  6161  // 	maxOrderSizeFp := currentStake.Div(factor.Mul(matchingPriceDec).Mul(tm.mktCfg.LiquidityMonitoringParameters.TargetStakeParameters.ScalingFactor))
  6162  // 	maxOrderSizeFp = maxOrderSizeFp.Sub(num.DecimalFromFloat(float64(sellConf2.Order.Size)))
  6163  // 	// maxOrderSizeFp := currentStake/(c1*float64(matchingPrice)*math.Max(riskParams.FactorShort, riskParams.FactorLong)*tm.mktCfg.LiquidityMonitoringParameters.TargetStakeParameters.ScalingFactor) - float64(sellConf2.Order.Size)
  6164  // 	require.True(t, maxOrderSizeFp.GreaterThan(num.DecimalFromFloat(1)))
  6165  // 	maxOSize, _ := num.UintFromDecimal(maxOrderSizeFp.Floor())
  6166  // 	maxOrderSize := maxOSize.Uint64()
  6167  
  6168  // 	tm.stateVar.OnTick(context.Background(), tm.now.Add(11*time.Minute))
  6169  
  6170  // 	// Add orders that will trade (no auction triggered yet)
  6171  // 	buyOrder3 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder3", types.SideBuy, party1, maxOrderSize, matchingPrice)
  6172  // 	buyConf3, err := tm.market.SubmitOrder(ctx, buyOrder3)
  6173  // 	require.NoError(t, err)
  6174  // 	require.Equal(t, types.OrderStatusActive, buyConf3.Order.Status)
  6175  
  6176  // 	md = tm.market.GetMarketData()
  6177  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6178  
  6179  // 	sellOrder3 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder3", types.SideSell, party2, maxOrderSize, matchingPrice)
  6180  // 	sellConf3, err := tm.market.SubmitOrder(ctx, sellOrder3)
  6181  
  6182  // 	tm.now = tm.now.Add(time.Second)
  6183  // 	tm.market.OnTick(ctx, tm.now)
  6184  // 	require.NoError(t, err)
  6185  // 	require.Equal(t, types.OrderStatusFilled, sellConf3.Order.Status)
  6186  // 	require.Equal(t, 1, len(sellConf3.Trades))
  6187  
  6188  // 	md = tm.market.GetMarketData()
  6189  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6190  
  6191  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6192  // 	require.NoError(t, err)
  6193  // 	target, err = num.DecimalFromString(md.TargetStake)
  6194  // 	require.NoError(t, err)
  6195  // 	require.True(t, supplied.GreaterThan(target.Mul(factor)))
  6196  
  6197  // 	// Add orders that will trade and trigger liquidity auction
  6198  // 	buyOrder4 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder4", types.SideBuy, party1, 1, matchingPrice)
  6199  // 	buyConf4, err := tm.market.SubmitOrder(ctx, buyOrder4)
  6200  // 	require.NoError(t, err)
  6201  // 	require.Equal(t, types.OrderStatusActive, buyConf4.Order.Status)
  6202  
  6203  // 	md = tm.market.GetMarketData()
  6204  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6205  
  6206  // 	sellOrder4 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder4", types.SideSell, party2, 1, matchingPrice)
  6207  // 	sellConf4, err := tm.market.SubmitOrder(ctx, sellOrder4)
  6208  
  6209  // 	tm.now = tm.now.Add(time.Second)
  6210  // 	tm.market.OnTick(ctx, tm.now)
  6211  // 	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  6212  // 	require.NoError(t, err)
  6213  // 	// this order will now get filled before triggering auction
  6214  // 	require.Equal(t, types.OrderStatusFilled, sellConf4.Order.Status, sellConf4.Order.Status.String())
  6215  // 	require.Equal(t, 1, len(sellConf4.Trades))
  6216  
  6217  // 	md = tm.market.GetMarketData()
  6218  // 	require.Equal(t, types.MarketTradingModeMonitoringAuction, md.MarketTradingMode)
  6219  // 	require.Equal(t, types.AuctionTriggerLiquidityTargetNotMet, md.Trigger)
  6220  
  6221  // 	// don't use AddSum, we need to keep the original amount somewhere
  6222  // 	lpa2 := &types.LiquidityProvisionAmendment{
  6223  // 		CommitmentAmount: num.Sum(lp2sub.CommitmentAmount, num.NewUint(25750)),
  6224  // 	}
  6225  // 	require.NoError(t,
  6226  // 		tm.market.AmendLiquidityProvision(ctx, lpa2, lp2, vgcrypto.RandomHash()),
  6227  // 	)
  6228  
  6229  // 	// progress time so liquidity auction ends
  6230  // 	tm.now = tm.now.Add(2 * time.Second)
  6231  // 	tm.market.OnTick(ctx, tm.now)
  6232  // 	require.Equal(t, types.MarketStateActive, tm.market.State()) // left auction
  6233  
  6234  // 	md = tm.market.GetMarketData()
  6235  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6236  
  6237  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6238  // 	require.NoError(t, err)
  6239  // 	target, err = num.DecimalFromString(md.TargetStake)
  6240  // 	require.NoError(t, err)
  6241  // 	require.True(t, supplied.GreaterThanOrEqual(target))
  6242  
  6243  // 	require.NoError(t, err)
  6244  // 	require.Equal(t, types.OrderStatusFilled, sellConf4.Order.Status)
  6245  
  6246  // 	// Bringing commitment back to old level shouldn't be allowed
  6247  
  6248  // 	lpa2.CommitmentAmount = lp2Commitment.Clone()
  6249  // 	require.Error(t,
  6250  // 		tm.market.AmendLiquidityProvision(ctx, lpa2, lp2, vgcrypto.RandomHash()),
  6251  // 	)
  6252  
  6253  // 	md = tm.market.GetMarketData()
  6254  // 	var zero uint64
  6255  // 	require.Greater(t, md.BestStaticBidVolume, zero)
  6256  
  6257  // 	// Cancelling best_bid should start auction
  6258  // 	conf, err := tm.market.CancelOrder(ctx, buyOrder1.Party, buyOrder1.ID, vgcrypto.RandomHash())
  6259  // 	require.NoError(t, err)
  6260  // 	require.NotNil(t, conf)
  6261  // 	tm.now = tm.now.Add(time.Second)
  6262  // 	tm.market.OnTick(ctx, tm.now)
  6263  // 	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  6264  
  6265  // 	// Submitting an order on buy side so that best_bid does exist should stop an auction
  6266  // 	md = tm.market.GetMarketData()
  6267  // 	require.Equal(t, zero, md.BestStaticBidVolume)
  6268  // 	require.Equal(t, types.MarketTradingModeMonitoringAuction, md.MarketTradingMode)
  6269  // 	require.Equal(t, types.AuctionTriggerUnableToDeployLPOrders, md.Trigger)
  6270  
  6271  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6272  // 	require.NoError(t, err)
  6273  // 	target, err = num.DecimalFromString(md.TargetStake)
  6274  // 	require.NoError(t, err)
  6275  // 	require.True(t, supplied.GreaterThanOrEqual(target))
  6276  
  6277  // 	buyOrder5 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder5", types.SideBuy, party1, 1, matchingPrice-10)
  6278  // 	buyConf5, err := tm.market.SubmitOrder(ctx, buyOrder5)
  6279  // 	require.NoError(t, err)
  6280  // 	require.Equal(t, types.OrderStatusActive, buyConf5.Order.Status)
  6281  
  6282  // 	// progress time to end auction
  6283  // 	tm.now = tm.now.Add(2 * time.Second)
  6284  // 	tm.market.OnTick(ctx, tm.now)
  6285  // 	require.Equal(t, types.MarketStateActive, tm.market.State()) // left auction
  6286  
  6287  // 	// Submitting an order on buy side so that best_bid does exist should stop an auction
  6288  // 	md = tm.market.GetMarketData()
  6289  // 	require.Equal(t, buyOrder5.Size, md.BestStaticBidVolume)
  6290  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6291  
  6292  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6293  // 	require.NoError(t, err)
  6294  // 	target, err = num.DecimalFromString(md.TargetStake)
  6295  // 	require.NoError(t, err)
  6296  // 	require.True(t, supplied.GreaterThanOrEqual(target))
  6297  
  6298  // 	// Trading with best-ask, so it disappears should start an auction
  6299  // 	buyOrder6 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder6", types.SideBuy, party1, 1, sellOrder1.Price.Uint64())
  6300  // 	buyConf6, err := tm.market.SubmitOrder(ctx, buyOrder6)
  6301  // 	require.NoError(t, err)
  6302  // 	require.Equal(t, types.OrderStatusFilled, buyConf6.Order.Status)
  6303  // 	require.Equal(t, 1, len(buyConf6.Trades))
  6304  // 	tm.now = tm.now.Add(time.Second)
  6305  // 	tm.market.OnTick(ctx, tm.now)
  6306  // 	require.Equal(t, types.MarketStateSuspended, tm.market.State()) // enter auction
  6307  
  6308  // 	md = tm.market.GetMarketData()
  6309  // 	require.Equal(t, zero, md.BestStaticOfferVolume)
  6310  // 	require.Equal(t, types.MarketTradingModeMonitoringAuction, md.MarketTradingMode)
  6311  // 	require.Equal(t, types.AuctionTriggerUnableToDeployLPOrders, md.Trigger)
  6312  
  6313  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6314  // 	require.NoError(t, err)
  6315  // 	target, err = num.DecimalFromString(md.TargetStake)
  6316  // 	require.NoError(t, err)
  6317  // 	require.True(t, supplied.LessThan(target))
  6318  // 	require.True(t, supplied.GreaterThan(target.Mul(factor)))
  6319  
  6320  // 	// Increasing total stake so that the new target stake is accommodated AND adding a sell so best_ask exists should stop the auction
  6321  
  6322  // 	lpa1 := &types.LiquidityProvisionAmendment{
  6323  // 		CommitmentAmount: num.Sum(lp1Commitment, num.NewUint(10000)),
  6324  // 	}
  6325  // 	err = tm.market.AmendLiquidityProvision(ctx, lpa1, lp1, vgcrypto.RandomHash())
  6326  // 	require.NoError(t, err)
  6327  
  6328  // 	md = tm.market.GetMarketData()
  6329  // 	require.Equal(t, types.MarketTradingModeMonitoringAuction, md.MarketTradingMode)
  6330  // 	require.Equal(t, types.AuctionTriggerUnableToDeployLPOrders, md.Trigger)
  6331  
  6332  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6333  // 	require.NoError(t, err)
  6334  // 	target, err = num.DecimalFromString(md.TargetStake)
  6335  // 	require.NoError(t, err)
  6336  // 	require.True(t, supplied.GreaterThanOrEqual(target))
  6337  
  6338  // 	sellOrder5 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder5", types.SideSell, party2, 1, matchingPrice-5)
  6339  // 	sellConf5, err := tm.market.SubmitOrder(ctx, sellOrder5)
  6340  
  6341  // 	require.NoError(t, err)
  6342  // 	require.Equal(t, types.OrderStatusActive, sellConf5.Order.Status)
  6343  // 	require.Equal(t, 0, len(sellConf5.Trades))
  6344  
  6345  // 	tm.now = tm.now.Add(2 * time.Second)
  6346  // 	tm.market.OnTick(ctx, tm.now)
  6347  // 	require.Equal(t, types.MarketStateActive, tm.market.State()) // left auction
  6348  
  6349  // 	md = tm.market.GetMarketData()
  6350  // 	require.Equal(t, sellOrder5.Size, md.BestStaticOfferVolume)
  6351  // 	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6352  
  6353  // 	supplied, err = num.DecimalFromString(md.SuppliedStake)
  6354  // 	require.NoError(t, err)
  6355  // 	target, err = num.DecimalFromString(md.TargetStake)
  6356  // 	require.NoError(t, err)
  6357  // 	require.True(t, supplied.GreaterThanOrEqual(target))
  6358  // }
  6359  
  6360  func TestLiquidityMonitoring_BestBidAskExistAfterAuction(t *testing.T) {
  6361  	now := time.Unix(10, 0)
  6362  	openingDuration := &types.AuctionDuration{
  6363  		Duration: 1,
  6364  	}
  6365  	tm := getTestMarket(t, now, nil, openingDuration)
  6366  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6367  	err := tm.market.OnMarketTargetStakeScalingFactorUpdate(num.DecimalFromFloat(0.0))
  6368  	require.NoError(t, err)
  6369  	md := tm.market.GetMarketData()
  6370  	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6371  
  6372  	lp1 := "lp1"
  6373  	party1 := "party1"
  6374  	party2 := "party2"
  6375  
  6376  	addAccount(t, tm, lp1)
  6377  	addAccount(t, tm, party1)
  6378  	addAccount(t, tm, party2)
  6379  
  6380  	var lp1Commitment uint64 = 50000
  6381  
  6382  	var matchingPrice uint64 = 100
  6383  	// Add orders that will stay on the book thus maintaining best_bid and best_ask
  6384  	buyOrder1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder1", types.SideBuy, party1, 1, matchingPrice-10)
  6385  	buyConf1, err := tm.market.SubmitOrder(ctx, buyOrder1)
  6386  	require.NoError(t, err)
  6387  	require.Equal(t, types.OrderStatusActive, buyConf1.Order.Status)
  6388  
  6389  	md = tm.market.GetMarketData()
  6390  	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6391  
  6392  	sellOrder1 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder1", types.SideSell, party2, 1, matchingPrice+10)
  6393  	sellConf1, err := tm.market.SubmitOrder(ctx, sellOrder1)
  6394  	require.NoError(t, err)
  6395  	require.Equal(t, types.OrderStatusActive, sellConf1.Order.Status)
  6396  	tm.market.OnTick(ctx, tm.now)
  6397  
  6398  	md = tm.market.GetMarketData()
  6399  	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6400  
  6401  	lp1sub := &types.LiquidityProvisionSubmission{
  6402  		MarketID:         tm.market.GetID(),
  6403  		CommitmentAmount: num.NewUint(lp1Commitment),
  6404  		Fee:              num.DecimalFromFloat(0.05),
  6405  	}
  6406  
  6407  	require.NoError(t,
  6408  		tm.market.SubmitLiquidityProvision(ctx, lp1sub, lp1, vgcrypto.RandomHash()),
  6409  	)
  6410  
  6411  	md = tm.market.GetMarketData()
  6412  	require.Equal(t, types.MarketTradingModeOpeningAuction, md.MarketTradingMode)
  6413  
  6414  	buyOrder2 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder2", types.SideBuy, party1, 1, matchingPrice)
  6415  	buyConf2, err := tm.market.SubmitOrder(ctx, buyOrder2)
  6416  	require.NoError(t, err)
  6417  	require.Equal(t, types.OrderStatusActive, buyConf2.Order.Status)
  6418  
  6419  	sellOrder2 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder2", types.SideSell, party2, 1, matchingPrice)
  6420  	sellConf2, err := tm.market.SubmitOrder(ctx, sellOrder2)
  6421  	require.NoError(t, err)
  6422  	require.Equal(t, types.OrderStatusActive, sellConf2.Order.Status)
  6423  	require.Equal(t, 0, len(sellConf2.Trades))
  6424  
  6425  	tm.now = tm.now.Add(time.Second * time.Duration(openingDuration.Duration)).Add(time.Millisecond)
  6426  	closed := tm.market.OnTick(ctx, tm.now)
  6427  	require.False(t, closed)
  6428  
  6429  	md = tm.market.GetMarketData()
  6430  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6431  	require.True(t, md.MarkPrice.EQ(num.NewUint(matchingPrice)))
  6432  	require.Equal(t, "0", md.TargetStake)
  6433  
  6434  	sellOrder3 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder3", types.SideSell, party2, 1, buyOrder1.Price.Uint64())
  6435  	sellConf3, err := tm.market.SubmitOrder(ctx, sellOrder3)
  6436  	tm.now = tm.now.Add(time.Second)
  6437  	tm.market.OnTick(ctx, tm.now)
  6438  	require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction
  6439  	require.NoError(t, err)
  6440  	require.Equal(t, types.OrderStatusFilled, sellConf3.Order.Status)
  6441  
  6442  	md = tm.market.GetMarketData()
  6443  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6444  	// require.Equal(t, types.AuctionTriggerLiquidityTargetNotMet, md.Trigger)
  6445  
  6446  	buyOrder3 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder3", types.SideBuy, party1, 1, sellOrder1.Price.Uint64())
  6447  	buyConf3, err := tm.market.SubmitOrder(ctx, buyOrder3)
  6448  	require.NoError(t, err)
  6449  	require.Equal(t, types.OrderStatusFilled, buyConf3.Order.Status)
  6450  
  6451  	md = tm.market.GetMarketData()
  6452  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6453  	// require.Equal(t, types.AuctionTriggerLiquidityTargetNotMet, md.Trigger)
  6454  
  6455  	sellOrder4 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "sellOrder4", types.SideSell, party2, 11, sellOrder1.Price.Uint64()+1)
  6456  	sellConf4, err := tm.market.SubmitOrder(ctx, sellOrder4)
  6457  	require.NoError(t, err)
  6458  	require.Equal(t, types.OrderStatusActive, sellConf4.Order.Status)
  6459  	tm.now = tm.now.Add(time.Second)
  6460  	tm.market.OnTick(ctx, tm.now)
  6461  
  6462  	md = tm.market.GetMarketData()
  6463  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6464  	// require.Equal(t, types.AuctionTriggerLiquidityTargetNotMet, md.Trigger)
  6465  
  6466  	buyOrder4 := getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "buyOrder4", types.SideBuy, party1, 1, buyOrder1.Price.Uint64()-1)
  6467  	buyConf4, err := tm.market.SubmitOrder(ctx, buyOrder4)
  6468  	require.NoError(t, err)
  6469  	require.Equal(t, types.OrderStatusActive, buyConf4.Order.Status)
  6470  
  6471  	// we have to wait for the auction to end
  6472  	tm.now = tm.now.Add(2 * time.Second)
  6473  	tm.market.OnTick(ctx, tm.now)
  6474  	require.Equal(t, types.MarketStateActive, tm.market.State()) // left auction
  6475  
  6476  	md = tm.market.GetMarketData()
  6477  	require.Equal(t, types.MarketTradingModeContinuous, md.MarketTradingMode)
  6478  	require.Equal(t, types.AuctionTriggerUnspecified, md.Trigger)
  6479  }
  6480  
  6481  func TestAmendTrade(t *testing.T) {
  6482  	now := time.Unix(10, 0)
  6483  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6484  
  6485  	auctionEnd := now.Add(10001 * time.Second)
  6486  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{
  6487  		Duration: 10000,
  6488  	})
  6489  	mktCfg.Fees.Factors = &types.FeeFactors{
  6490  		LiquidityFee:      num.DecimalFromFloat(0.001),
  6491  		InfrastructureFee: num.DecimalFromFloat(0.0005),
  6492  		MakerFee:          num.DecimalFromFloat(0.00025),
  6493  	}
  6494  	mktCfg.TradableInstrument.RiskModel = &types.TradableInstrumentLogNormalRiskModel{
  6495  		LogNormalRiskModel: &types.LogNormalRiskModel{
  6496  			RiskAversionParameter: num.DecimalFromFloat(0.001),
  6497  			Tau:                   num.DecimalFromFloat(0.00011407711613050422),
  6498  			Params: &types.LogNormalModelParams{
  6499  				Mu:    num.DecimalZero(),
  6500  				R:     num.DecimalFromFloat(0.016),
  6501  				Sigma: num.DecimalFromFloat(20),
  6502  			},
  6503  		},
  6504  	}
  6505  
  6506  	lpparty := "lp-party-1"
  6507  	lpparty2 := "lp-party-2"
  6508  	lpparty3 := "lp-party-3"
  6509  
  6510  	p1 := "p1"
  6511  	p2 := "p2"
  6512  
  6513  	tm := newTestMarket(t, now).Run(ctx, mktCfg)
  6514  	tm.StartOpeningAuction().
  6515  		// the liquidity provider
  6516  		WithAccountAndAmount(lpparty, 500000000000).
  6517  		WithAccountAndAmount(lpparty2, 500000000000).
  6518  		WithAccountAndAmount(lpparty3, 500000000000).
  6519  		WithAccountAndAmount(p1, 500000000000).
  6520  		WithAccountAndAmount(p2, 500000000000)
  6521  	addAccountWithAmount(tm, "lpprov", 10000000)
  6522  
  6523  	lp := &types.LiquidityProvisionSubmission{
  6524  		MarketID:         tm.market.GetID(),
  6525  		CommitmentAmount: num.NewUint(55000),
  6526  		Fee:              num.DecimalFromFloat(0.01),
  6527  	}
  6528  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  6529  	tm.EndOpeningAuction(t, auctionEnd, false)
  6530  
  6531  	assert.Equal(t, types.MarketTradingModeContinuous, tm.market.GetMarketData().MarketTradingMode)
  6532  
  6533  	tm.events = nil
  6534  
  6535  	p1Order := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "pid1", types.SideBuy, p1, 10, 1010)
  6536  	p2Order := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "pid2", types.SideSell, p2, 10, 1050)
  6537  
  6538  	p1conf, err := tm.market.SubmitOrder(ctx, p1Order)
  6539  	assert.NoError(t, err)
  6540  	assert.Len(t, p1conf.Trades, 0)
  6541  
  6542  	p2conf, err := tm.market.SubmitOrder(ctx, p2Order)
  6543  	assert.NoError(t, err)
  6544  	assert.Len(t, p2conf.Trades, 0)
  6545  
  6546  	assert.Equal(t, types.MarketTradingModeContinuous, tm.market.GetMarketData().MarketTradingMode)
  6547  
  6548  	// now we
  6549  	amend := types.OrderAmendment{
  6550  		OrderID:  p1conf.Order.ID,
  6551  		MarketID: p1conf.Order.MarketID,
  6552  		Price:    num.NewUint(1050),
  6553  	}
  6554  
  6555  	tm.events = nil
  6556  	amendConf, err := tm.market.AmendOrder(ctx, &amend, p1conf.Order.Party, vgcrypto.RandomHash())
  6557  	assert.NoError(t, err)
  6558  	assert.Len(t, amendConf.Trades, 1)
  6559  
  6560  	ps := map[string]*events.PositionState{}
  6561  	for _, v := range tm.events {
  6562  		if e, ok := v.(*events.PositionState); ok {
  6563  			ps[e.PartyID()] = e
  6564  		}
  6565  	}
  6566  
  6567  	assert.Len(t, ps, 2)
  6568  	assert.Equal(t, int(ps[p1].Size()), 10)
  6569  	assert.Equal(t, int(ps[p2].Size()), -10)
  6570  }
  6571  
  6572  func Test_7017_UpdatingMarketDuringOpeningAuction(t *testing.T) {
  6573  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6574  	pMonitorSettings := &types.PriceMonitoringSettings{
  6575  		Parameters: &types.PriceMonitoringParameters{
  6576  			Triggers: []*types.PriceMonitoringTrigger{},
  6577  		},
  6578  	}
  6579  	openingAuctionDuration := 10 * time.Minute
  6580  	mktCfg := getMarket(pMonitorSettings, &types.AuctionDuration{
  6581  		Duration: int64(openingAuctionDuration.Seconds()),
  6582  	})
  6583  	lpParty := "party-LP"
  6584  	trader1 := "party-trader-1"
  6585  	trader2 := "party-trader-2"
  6586  	tm := newTestMarket(t, time.Unix(10, 0)).Run(ctx, mktCfg)
  6587  	tm.market.OnTick(ctx, tm.now)
  6588  	tm.StartOpeningAuction().
  6589  		WithAccountAndAmount(lpParty, 1000000).
  6590  		WithAccountAndAmount(trader1, 100000).
  6591  		WithAccountAndAmount(trader2, 100000)
  6592  
  6593  	// submit limit orders
  6594  	midPrice := uint64(1000)
  6595  	limitOrders := []*types.Order{
  6596  		getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "lo-1", types.SideBuy, trader1, 10, midPrice-uint64(250)),
  6597  		getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "lo-2", types.SideBuy, trader1, 10, midPrice),
  6598  		getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "lo-3", types.SideSell, trader2, 10, midPrice),
  6599  		getMarketOrder(tm, tm.now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "lo-4", types.SideSell, trader2, 10, midPrice+uint64(250)),
  6600  	}
  6601  	for _, o := range limitOrders {
  6602  		conf, err := tm.market.SubmitOrder(ctx, o)
  6603  		require.NoError(t, err)
  6604  		require.NotNil(t, conf)
  6605  	}
  6606  
  6607  	tm.now = tm.now.Add(time.Minute)
  6608  	tm.market.OnTick(ctx, tm.now)
  6609  
  6610  	require.NoError(t, tm.market.Update(ctx, &mktCfg, tm.oracleEngine))
  6611  
  6612  	tm.now = tm.now.Add(time.Minute)
  6613  	tm.market.OnTick(ctx, tm.now)
  6614  
  6615  	lps := &types.LiquidityProvisionSubmission{
  6616  		MarketID:         tm.market.GetID(),
  6617  		CommitmentAmount: num.NewUint(70000),
  6618  		Fee:              num.DecimalFromFloat(0.05),
  6619  		Reference:        "ref-lp-submission-1",
  6620  	}
  6621  
  6622  	require.NoError(t,
  6623  		tm.market.SubmitLiquidityProvision(
  6624  			ctx, lps, lpParty, vgcrypto.RandomHash()),
  6625  	)
  6626  
  6627  	// leave opening auction
  6628  	tm.now = tm.now.Add(openingAuctionDuration)
  6629  	tm.market.OnTick(ctx, tm.now)
  6630  	require.Equal(t, types.MarketTradingModeContinuous, tm.market.GetMarketData().MarketTradingMode)
  6631  }
  6632  
  6633  func TestLiquidityFeeSettingsWeightedAverage(t *testing.T) {
  6634  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6635  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{Duration: 1})
  6636  	mktCfg.Fees.LiquidityFeeSettings = &types.LiquidityFeeSettings{
  6637  		Method: proto.LiquidityFeeSettings_METHOD_WEIGHTED_AVERAGE,
  6638  	}
  6639  
  6640  	now := time.Unix(10, 0)
  6641  	tm := newTestMarket(t, now).Run(context.Background(), mktCfg)
  6642  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  6643  
  6644  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  6645  	addAccountWithAmount(tm, "lpprov", 10000000)
  6646  	addAccountWithAmount(tm, "lpprov2", 10000000)
  6647  	tm.StartOpeningAuction()
  6648  
  6649  	lp := &types.LiquidityProvisionSubmission{
  6650  		MarketID:         tm.market.GetID(),
  6651  		CommitmentAmount: num.NewUint(27500),
  6652  		Fee:              num.DecimalFromFloat(0.01),
  6653  	}
  6654  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  6655  
  6656  	lp2 := &types.LiquidityProvisionSubmission{
  6657  		MarketID:         tm.market.GetID(),
  6658  		CommitmentAmount: num.NewUint(27500),
  6659  		Fee:              num.DecimalFromFloat(0.02),
  6660  	}
  6661  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp2, "lpprov2", vgcrypto.RandomHash()))
  6662  
  6663  	// leave opening auction
  6664  	now = now.Add(2 * time.Second)
  6665  	tm.now = now
  6666  	tm.market.OnTick(ctx, now)
  6667  
  6668  	var fee string
  6669  	for _, evt := range tm.events {
  6670  		if mup, ok := evt.(*events.MarketUpdated); ok {
  6671  			fee = mup.Market().Fees.Factors.LiquidityFee
  6672  		}
  6673  	}
  6674  	// two LPs with same comittment, fee should be the average (0.01 + 0.02) / 2 = 0.015
  6675  	assert.Equal(t, "0.015", fee)
  6676  }
  6677  
  6678  func TestLiquidityFeeSettingsConstantFee(t *testing.T) {
  6679  	ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
  6680  	mktCfg := getMarket(defaultPriceMonitorSettings, &types.AuctionDuration{Duration: 1})
  6681  	mktCfg.Fees.LiquidityFeeSettings = &types.LiquidityFeeSettings{
  6682  		Method:      proto.LiquidityFeeSettings_METHOD_CONSTANT,
  6683  		FeeConstant: num.NewDecimalFromFloat(0.8),
  6684  	}
  6685  
  6686  	now := time.Unix(10, 0)
  6687  	tm := newTestMarket(t, now).Run(context.Background(), mktCfg)
  6688  	tm.market.OnMarketAuctionMinimumDurationUpdate(ctx, time.Second)
  6689  
  6690  	tm.broker.EXPECT().Send(gomock.Any()).AnyTimes()
  6691  	addAccountWithAmount(tm, "lpprov", 10000000)
  6692  	addAccountWithAmount(tm, "lpprov2", 10000000)
  6693  	tm.StartOpeningAuction()
  6694  
  6695  	lp := &types.LiquidityProvisionSubmission{
  6696  		MarketID:         tm.market.GetID(),
  6697  		CommitmentAmount: num.NewUint(27500),
  6698  		Fee:              num.DecimalFromFloat(0.01),
  6699  	}
  6700  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash()))
  6701  
  6702  	lp2 := &types.LiquidityProvisionSubmission{
  6703  		MarketID:         tm.market.GetID(),
  6704  		CommitmentAmount: num.NewUint(27500),
  6705  		Fee:              num.DecimalFromFloat(0.02),
  6706  	}
  6707  	require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp2, "lpprov2", vgcrypto.RandomHash()))
  6708  
  6709  	// leave opening auction
  6710  	now = now.Add(2 * time.Second)
  6711  	tm.now = now
  6712  	tm.market.OnTick(ctx, now)
  6713  
  6714  	var fee string
  6715  	for _, evt := range tm.events {
  6716  		if mup, ok := evt.(*events.MarketUpdated); ok {
  6717  			fee = mup.Market().Fees.Factors.LiquidityFee
  6718  		}
  6719  	}
  6720  	// doesn't matter what the LP's set in their nomination, the fee is going to be a constant 0.8
  6721  	assert.Equal(t, "0.8", fee)
  6722  }
  6723  
  6724  func TestVerifyAMMBounds(t *testing.T) {
  6725  	tests := []struct {
  6726  		name        string
  6727  		params      *types.ConcentratedLiquidityParameters
  6728  		maxCap      *num.Uint
  6729  		priceFactor num.Decimal
  6730  		expectedErr error
  6731  	}{
  6732  		{
  6733  			name: "normal valid bounds",
  6734  			params: &types.ConcentratedLiquidityParameters{
  6735  				LowerBound: num.NewUint(82),
  6736  				Base:       num.NewUint(85),
  6737  				UpperBound: num.NewUint(88),
  6738  			},
  6739  			priceFactor: num.NewDecimalFromFloat(1.1),
  6740  		},
  6741  		{
  6742  			name: "lower greater than base with fewer decimals",
  6743  			params: &types.ConcentratedLiquidityParameters{
  6744  				LowerBound: num.NewUint(80),
  6745  				Base:       num.NewUint(85),
  6746  				UpperBound: num.NewUint(90),
  6747  			},
  6748  			priceFactor: num.NewDecimalFromFloat(0.1),
  6749  			expectedErr: fmt.Errorf("base (8) as factored by market and asset decimals must be greater than lower bound (8)"),
  6750  		},
  6751  		{
  6752  			name: "base greater than base with fewer decimals",
  6753  			params: &types.ConcentratedLiquidityParameters{
  6754  				LowerBound: num.NewUint(80),
  6755  				Base:       num.NewUint(85),
  6756  				UpperBound: num.NewUint(88),
  6757  			},
  6758  			priceFactor: num.NewDecimalFromFloat(0.1),
  6759  			expectedErr: fmt.Errorf("base (8) as factored by market and asset decimals must be greater than lower bound (8)"),
  6760  		},
  6761  		{
  6762  			name: "both bounds too close with fewer decimals",
  6763  			params: &types.ConcentratedLiquidityParameters{
  6764  				LowerBound: num.NewUint(82),
  6765  				Base:       num.NewUint(85),
  6766  				UpperBound: num.NewUint(88),
  6767  			},
  6768  			priceFactor: num.NewDecimalFromFloat(0.1),
  6769  			expectedErr: fmt.Errorf("base (8) as factored by market and asset decimals must be greater than lower bound (8)"),
  6770  		},
  6771  		{
  6772  			name: "upper bound higher than cap",
  6773  			params: &types.ConcentratedLiquidityParameters{
  6774  				LowerBound: num.NewUint(82),
  6775  				Base:       num.NewUint(85),
  6776  				UpperBound: num.NewUint(88),
  6777  			},
  6778  			priceFactor: num.NewDecimalFromFloat(1),
  6779  			maxCap:      num.NewUint(86),
  6780  			expectedErr: common.ErrAMMBoundsOutsidePriceCap,
  6781  		},
  6782  		{
  6783  			name: "upper bound equal cap",
  6784  			params: &types.ConcentratedLiquidityParameters{
  6785  				LowerBound: num.NewUint(82),
  6786  				Base:       num.NewUint(85),
  6787  				UpperBound: num.NewUint(88),
  6788  			},
  6789  			priceFactor: num.NewDecimalFromFloat(1),
  6790  			maxCap:      num.NewUint(88),
  6791  			expectedErr: common.ErrAMMBoundsOutsidePriceCap,
  6792  		},
  6793  		{
  6794  			name: "base higher than cap",
  6795  			params: &types.ConcentratedLiquidityParameters{
  6796  				LowerBound: num.NewUint(82),
  6797  				Base:       num.NewUint(100),
  6798  			},
  6799  			priceFactor: num.NewDecimalFromFloat(1),
  6800  			maxCap:      num.NewUint(86),
  6801  			expectedErr: common.ErrAMMBoundsOutsidePriceCap,
  6802  		},
  6803  		{
  6804  			name: "base equal cap",
  6805  			params: &types.ConcentratedLiquidityParameters{
  6806  				LowerBound: num.NewUint(82),
  6807  				Base:       num.NewUint(88),
  6808  			},
  6809  			priceFactor: num.NewDecimalFromFloat(1),
  6810  			maxCap:      num.NewUint(88),
  6811  			expectedErr: common.ErrAMMBoundsOutsidePriceCap,
  6812  		},
  6813  	}
  6814  
  6815  	for _, tt := range tests {
  6816  		t.Run(tt.name, func(t *testing.T) {
  6817  			err := future.VerifyAMMBounds(tt.params, tt.maxCap, tt.priceFactor)
  6818  			assert.Equal(t, tt.expectedErr, err)
  6819  		})
  6820  	}
  6821  }