Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: change behaviour of stop orders #11567

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### 🚨 Breaking changes

- [](https://github.com/vegaprotocol/vega/issues/xxx)
- [8777](https://github.com/vegaprotocol/vega/issues/8777) - Stop orders can now be used to create or increase a position.

### 🗑️ Deprecation

Expand Down
34 changes: 2 additions & 32 deletions core/execution/future/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -2141,43 +2141,13 @@ func (m *Market) SubmitStopOrdersWithIDGeneratorAndOrderIDs(
}

// now check for the parties position
positions := m.position.GetPositionsByParty(party)
if len(positions) > 1 {
if positions := m.position.GetPositionsByParty(party); len(positions) > 1 {
m.log.Panic("only one position expected", logging.Int("got", len(positions)))
}

if len(positions) < 1 {
} else if len(positions) < 1 {
rejectStopOrders(types.StopOrderRejectionNotAllowedWithoutAPosition, fallsBelow, risesAbove)
return nil, common.ErrStopOrderSubmissionNotAllowedWithoutExistingPosition
}

pos := positions[0]

// now we will reject if the direction of order if is not
// going to close the position or potential position
potentialSize := pos.Size() - pos.Sell() + pos.Buy()
size := pos.Size()

var stopOrderSide types.Side
if fallsBelow != nil {
stopOrderSide = fallsBelow.OrderSubmission.Side
} else {
stopOrderSide = risesAbove.OrderSubmission.Side
}

switch stopOrderSide {
case types.SideBuy:
if potentialSize >= 0 && size >= 0 {
rejectStopOrders(types.StopOrderRejectionNotClosingThePosition, fallsBelow, risesAbove)
return nil, common.ErrStopOrderSideNotClosingThePosition
}
case types.SideSell:
if potentialSize <= 0 && size <= 0 {
rejectStopOrders(types.StopOrderRejectionNotClosingThePosition, fallsBelow, risesAbove)
return nil, common.ErrStopOrderSideNotClosingThePosition
}
}

fallsBelowTriggered, risesAboveTriggered := m.stopOrderWouldTriggerAtSubmission(fallsBelow),
m.stopOrderWouldTriggerAtSubmission(risesAbove)
triggered := fallsBelowTriggered || risesAboveTriggered
Expand Down
74 changes: 68 additions & 6 deletions core/integration/features/orders/stoporders.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1885,8 +1885,7 @@ Feature: stop orders
| party2 | ETH/DEC19 | STATUS_EXPIRED | stop2-1 |


Scenario: A party with a long position cannot enter a buy stop order,
and a party with a short position cannot enter a sell stop order. (0014-ORDT-137)
Scenario: A party with a long or short position CAN increase their position with stop orders. (0014-ORDT-137)

# setup accounts
Given time is updated to "2019-11-30T00:00:00Z"
Expand Down Expand Up @@ -1933,14 +1932,77 @@ Feature: stop orders

# We should not be able to place a but stop order for party2 as they have a long position and it would make it more long
When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif | only | ra price trigger | fb price trigger | reference | error |
| party2 | ETH/DEC19 | buy | 1 | 0 | 0 | TYPE_MARKET | TIF_IOC | reduce | 75 | 25 | stop | side used in stop order does not close the position |
| party | market id | side | volume | price | resulting trades | type | tif | only | ra price trigger | fb price trigger | reference | error |
| party2 | ETH/DEC19 | buy | 1 | 0 | 0 | TYPE_MARKET | TIF_IOC | reduce | 75 | 25 | stop | |

# We should not be able to place a sell stop order for party1 as they have a short position and it would make it more short
When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif | only | ra price trigger | fb price trigger | reference | error |
| party1 | ETH/DEC19 | sell | 1 | 0 | 0 | TYPE_MARKET | TIF_IOC | reduce | 75 | 25 | stop | side used in stop order does not close the position |
| party | market id | side | volume | price | resulting trades | type | tif | only | ra price trigger | fb price trigger | reference | error |
| party1 | ETH/DEC19 | sell | 1 | 0 | 0 | TYPE_MARKET | TIF_IOC | reduce | 75 | 25 | stop | |

Scenario: A party with a long position cannot flip to short by placing a stop order.
Given time is updated to "2019-11-30T00:00:00Z"
And the parties deposit on asset's general account the following amount:
| party | asset | amount |
| party1 | BTC | 10000000 |
| party2 | BTC | 10000000 |
| party3 | BTC | 10000000 |
| aux | BTC | 10000000 |
| aux2 | BTC | 10000000 |
| aux3 | BTC | 100000 |
| lpprov | BTC | 90000000 |

And the parties submit the following liquidity provision:
| id | party | market id | commitment amount | fee | lp type |
| lp1 | lpprov | ETH/DEC19 | 90000000 | 0.1 | submission |
| lp1 | lpprov | ETH/DEC19 | 90000000 | 0.1 | submission |
And the parties place the following pegged iceberg orders:
| party | market id | peak size | minimum visible size | side | pegged reference | volume | offset |
| lpprov | ETH/DEC19 | 2 | 1 | buy | BID | 50 | 100 |
| lpprov | ETH/DEC19 | 2 | 1 | sell | ASK | 50 | 100 |

# place auxiliary orders so we always have best bid and best offer as to not trigger the liquidity auction
And the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux | ETH/DEC19 | buy | 100 | 1 | 0 | TYPE_LIMIT | TIF_GTC |
| aux | ETH/DEC19 | sell | 100 | 10001 | 0 | TYPE_LIMIT | TIF_GTC |
| aux2 | ETH/DEC19 | buy | 5 | 50 | 0 | TYPE_LIMIT | TIF_GTC |
| aux3 | ETH/DEC19 | sell | 5 | 50 | 0 | TYPE_LIMIT | TIF_GTC |

When the opening auction period ends for market "ETH/DEC19"
Then the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH/DEC19"

When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| party1 | ETH/DEC19 | sell | 10 | 50 | 0 | TYPE_LIMIT | TIF_GTC |
| party2 | ETH/DEC19 | buy | 10 | 50 | 1 | TYPE_LIMIT | TIF_GTC |
Then the following trades should be executed:
| buyer | seller | price | size |
| party2 | party1 | 50 | 10 |

When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| party1 | ETH/DEC19 | sell | 1 | 75 | 0 | TYPE_LIMIT | TIF_GTC |
| party3 | ETH/DEC19 | buy | 50 | 75 | 1 | TYPE_LIMIT | TIF_GTC |
And the network moves ahead "1" blocks
Then the following trades should be executed:
| buyer | seller | price | size |
| party3 | party1 | 75 | 1 |

When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif | only | ra price trigger | fb price trigger | reference | error |
| party2 | ETH/DEC19 | sell | 20 | 0 | 1 | TYPE_MARKET | TIF_IOC | reduce | 75 | 25 | stop | |
Then the following trades should be executed:
| buyer | seller | price | size |
| party3 | party2 | 75 | 10 |

# Ensure the party has closed its position, despite the stop order being for a larger volume than their open position.
When the network moves ahead "1" blocks
Then the parties should have the following profit and loss:
| party | volume | unrealised pnl | realised pnl |
| party1 | -11 | -250 | 0 |
| party2 | 0 | 0 | 250 |
| party3 | 11 | 0 | 0 |

Scenario: If a stop order is placed with a position_fraction equal to 0.5 and the position
size is 5 then the rounding should be equal to 3 (0014-ORDT-138)
Expand Down
Loading