From 2952b41d4af6856c4edc76c8626d54c1eb37623b Mon Sep 17 00:00:00 2001 From: Jeremy Letang Date: Wed, 22 May 2024 13:51:15 +0200 Subject: [PATCH] Merge pull request #11306 from vegaprotocol/11304-2 feat: add additional test coverage for pegged orders --- core/execution/future/market.go | 7 + core/execution/spot/market.go | 7 + .../features/verified/pegged_orders.feature | 165 ++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 core/integration/features/verified/pegged_orders.feature diff --git a/core/execution/future/market.go b/core/execution/future/market.go index 66829b7cf4c..825dc0fc1d9 100644 --- a/core/execution/future/market.go +++ b/core/execution/future/market.go @@ -1786,6 +1786,13 @@ func (m *Market) validateOrder(ctx context.Context, order *types.Order) (err err } return reason } + if order.PeggedOrder.Reference == types.PeggedReferenceMid { + offsetInAsset, _ := num.UintFromDecimal(order.PeggedOrder.Offset.ToDecimal().Mul(m.priceFactor)) + tickSizeInAsset, _ := num.UintFromDecimal(m.mkt.TickSize.ToDecimal().Mul(m.priceFactor)) + if offsetInAsset.IsZero() && tickSizeInAsset.IsZero() { + return fmt.Errorf("invalid offset - pegged mid will cross") + } + } return m.validateTickSize(order.PeggedOrder.Offset) } diff --git a/core/execution/spot/market.go b/core/execution/spot/market.go index 2ffcee16207..78c3d1c776d 100644 --- a/core/execution/spot/market.go +++ b/core/execution/spot/market.go @@ -1046,6 +1046,13 @@ func (m *Market) validateOrder(ctx context.Context, order *types.Order) (err err } return reason } + if order.PeggedOrder.Reference == types.PeggedReferenceMid { + offsetInAsset, _ := num.UintFromDecimal(order.PeggedOrder.Offset.ToDecimal().Mul(m.priceFactor)) + tickSizeInAsset, _ := num.UintFromDecimal(m.mkt.TickSize.ToDecimal().Mul(m.priceFactor)) + if offsetInAsset.IsZero() && tickSizeInAsset.IsZero() { + return fmt.Errorf("invalid offset - pegged mid will cross") + } + } return m.validateTickSize(order.PeggedOrder.Offset) } diff --git a/core/integration/features/verified/pegged_orders.feature b/core/integration/features/verified/pegged_orders.feature new file mode 100644 index 00000000000..a99abf2d611 --- /dev/null +++ b/core/integration/features/verified/pegged_orders.feature @@ -0,0 +1,165 @@ + +Feature: Pegged orders do not cross + + Aiming for full coverage of edge-cases, check the following for both + derivative and spot markets: + + - Market decimals > asset decimals + - Market decimals < asset decimals + + - For each of the above + - tick size cannot be expressed in asset decimals + - tick size can just be expressed in asset decimals + - tick size can be expressed in asset decimals + + - For each of the above + - offset cannot be expressed in asset decimals + - offset can just be expressed in asset decimals + - offset can be expressed in asset decimals + + Background: + + Given the average block duration is "1" + And the following assets are registered: + | id | decimal places | quantum | + | ETH.1.10 | 1 | 1 | + | BTC.1.10 | 1 | 1 | + + And the following network parameters are set: + | name | value | + | limits.markets.maxPeggedOrders | 6 | + + And the parties deposit on asset's general account the following amount: + | party | asset | amount | + | aux1 | ETH.1.10 | 1000000000000000 | + | aux2 | ETH.1.10 | 1000000000000000 | + | party1 | ETH.1.10 | 1000000000000000 | + | party2 | ETH.1.10 | 1000000000000000 | + | aux1 | BTC.1.10 | 1000000000000000 | + | aux2 | BTC.1.10 | 1000000000000000 | + | party1 | BTC.1.10 | 1000000000000000 | + | party2 | BTC.1.10 | 1000000000000000 | + + Scenario Outline: Derivative markets - market decimals > asset decimals + + Given the markets: + | id | quote name | asset | liquidity monitoring | risk model | margin calculator | auction duration | fees | price monitoring | data source config | linear slippage factor | quadratic slippage factor | sla params | decimal places | tick size | + | ETH.1.10/DEC21 | ETH.1.10 | ETH.1.10 | default-parameters | default-simple-risk-model | default-margin-calculator | 1 | default-none | default-none | default-eth-for-future | 0.5 | 0 | default-basic | 2 | | + Given the parties place the following pegged orders: + | party | market id | side | pegged reference | volume | offset | reference | error | + | party1 | ETH.1.10/DEC21 | buy | MID | 10 | | peg-buy | | + | party2 | ETH.1.10/DEC21 | sell | MID | 10 | | peg-sell | | + And the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | reference | + | aux1 | ETH.1.10/DEC21 | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux1 | ETH.1.10/DEC21 | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux2 | ETH.1.10/DEC21 | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + | aux2 | ETH.1.10/DEC21 | sell | 1 | | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + When the opening auction period ends for market "ETH.1.10/DEC21" + Then the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH.1.10/DEC21" + + Examples: + | bo | tick size | offset | error | + | 1010 | 1 | 1 | invalid offset - pegged mid will cross | + | 1010 | 1 | 10 | | + | 1010 | 1 | 100 | | + | 1010 | 10 | 1 | OrderError: price not in tick size | + | 1010 | 10 | 10 | | + | 1010 | 10 | 100 | | + | 1100 | 100 | 1 | OrderError: price not in tick size | + | 1100 | 100 | 10 | OrderError: price not in tick size | + | 1100 | 100 | 100 | | + + + Scenario Outline: Derivative markets - market decimals < asset decimals + + Given the markets: + | id | quote name | asset | liquidity monitoring | risk model | margin calculator | auction duration | fees | price monitoring | data source config | linear slippage factor | quadratic slippage factor | sla params | decimal places | tick size | + | ETH.1.10/DEC21 | ETH.1.10 | ETH.1.10 | default-parameters | default-simple-risk-model | default-margin-calculator | 1 | default-none | default-none | default-eth-for-future | 0.5 | 0 | default-basic | 0 | | + Given the parties place the following pegged orders: + | party | market id | side | pegged reference | volume | offset | reference | error | + | party1 | ETH.1.10/DEC21 | buy | MID | 10 | | peg-buy | | + | party2 | ETH.1.10/DEC21 | sell | MID | 10 | | peg-sell | | + And the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | reference | + | aux1 | ETH.1.10/DEC21 | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux1 | ETH.1.10/DEC21 | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux2 | ETH.1.10/DEC21 | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + | aux2 | ETH.1.10/DEC21 | sell | 1 | | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + When the opening auction period ends for market "ETH.1.10/DEC21" + Then the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH.1.10/DEC21" + + Examples: + | bo | tick size | offset | error | + | 1001 | 1 | 1 | | + | 1001 | 1 | 10 | | + | 1001 | 1 | 100 | | + | 1010 | 10 | 1 | OrderError: price not in tick size | + | 1010 | 10 | 10 | | + | 1010 | 10 | 100 | | + | 1100 | 100 | 1 | OrderError: price not in tick size | + | 1100 | 100 | 10 | OrderError: price not in tick size | + | 1100 | 100 | 100 | | + + + Scenario Outline: Spot market - market decimals > asset decimals + + Given the spot markets: + | id | name | base asset | quote asset | liquidity monitoring | risk model | auction duration | fees | price monitoring | sla params | decimal places | tick size | + | BTC/ETH | BTC/ETH | BTC.1.10 | ETH.1.10 | default-parameters | default-simple-risk-model | 1 | default-none | default-none | default-basic | 2 | | + Given the parties place the following pegged orders: + | party | market id | side | pegged reference | volume | offset | reference | error | + | party1 | BTC/ETH | buy | MID | 10 | | peg-buy | | + | party2 | BTC/ETH | sell | MID | 10 | | peg-sell | | + And the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | reference | + | aux1 | BTC/ETH | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux1 | BTC/ETH | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux2 | BTC/ETH | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + | aux2 | BTC/ETH | sell | 1 | | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + When the opening auction period ends for market "BTC/ETH" + Then the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "BTC/ETH" + + Examples: + | bo | tick size | offset | error | + | 1010 | 1 | 1 | invalid offset - pegged mid will cross | + | 1010 | 1 | 10 | | + | 1010 | 1 | 100 | | + | 1010 | 10 | 1 | OrderError: price not in tick size | + | 1010 | 10 | 10 | | + | 1010 | 10 | 100 | | + | 1100 | 100 | 1 | OrderError: price not in tick size | + | 1100 | 100 | 10 | OrderError: price not in tick size | + | 1100 | 100 | 100 | | + + + Scenario Outline: Spot market - market decimals < asset decimals + + Given the spot markets: + | id | name | base asset | quote asset | liquidity monitoring | risk model | auction duration | fees | price monitoring | sla params | decimal places | tick size | + | BTC/ETH | BTC/ETH | BTC.1.10 | ETH.1.10 | default-parameters | default-simple-risk-model | 1 | default-none | default-none | default-basic | 0 | | + Given the parties place the following pegged orders: + | party | market id | side | pegged reference | volume | offset | reference | error | + | party1 | BTC/ETH | buy | MID | 10 | | peg-buy | | + | party2 | BTC/ETH | sell | MID | 10 | | peg-sell | | + And the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | reference | + | aux1 | BTC/ETH | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux1 | BTC/ETH | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b1-1 | + | aux2 | BTC/ETH | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + | aux2 | BTC/ETH | sell | 1 | | 0 | TYPE_LIMIT | TIF_GTC | p3b2-1 | + When the opening auction period ends for market "BTC/ETH" + Then the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "BTC/ETH" + + Examples: + | bo | tick size | offset | error | + | 1001 | 1 | 1 | | + | 1001 | 1 | 10 | | + | 1001 | 1 | 100 | | + | 1010 | 10 | 1 | OrderError: price not in tick size | + | 1010 | 10 | 10 | | + | 1010 | 10 | 100 | | + | 1100 | 100 | 1 | OrderError: price not in tick size | + | 1100 | 100 | 10 | OrderError: price not in tick size | + | 1100 | 100 | 100 | | +