Skip to content

Commit

Permalink
Merge pull request #10936 from vegaprotocol/pos-est-bug
Browse files Browse the repository at this point in the history
refactor: take max of two sides for isolated margin mode order margin estimate
  • Loading branch information
EVODelavega authored Mar 20, 2024
2 parents 353e696 + 584ef03 commit ba8d414
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

- [10946](https://github.com/vegaprotocol/vega/issues/10945) - Save dispatch strategy for recurring governance transfer in the database.
- [10943](https://github.com/vegaprotocol/vega/issues/10943) - Fix error message format when node vote is sent again.
- [10928](https://github.com/vegaprotocol/vega/issues/10928) - Fix `collateralIncreaseEstimate` for limit orders in isolated margin mode

## 0.75.0

Expand Down
8 changes: 4 additions & 4 deletions core/risk/isolated_margin.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (e *Engine) calculateIsolatedMargins(m events.Margin, marketObservable *num
auction := e.as.InAuction() && !e.as.CanLeave()
// NB:we don't include orders when calculating margin for isolated margin as they are margined separately!
margins := e.calculateMargins(m, marketObservable, *e.factors, false, auction, inc)
margins.OrderMargin = calcOrderMargins(m.Size(), orders, e.positionFactor, marginFactor, auctionPrice)
margins.OrderMargin = CalcOrderMargins(m.Size(), orders, e.positionFactor, marginFactor, auctionPrice)
margins.CollateralReleaseLevel = num.UintZero()
margins.SearchLevel = num.UintZero()
margins.MarginMode = types.MarginModeIsolatedMargin
Expand Down Expand Up @@ -497,11 +497,11 @@ func getIsolatedMarginTransfersOnPositionChange(party, asset string, trades []*t
}

func (e *Engine) CalcOrderMarginsForClosedOutParty(orders []*types.Order, marginFactor num.Decimal) *num.Uint {
return calcOrderMargins(0, orders, e.positionFactor, marginFactor, nil)
return CalcOrderMargins(0, orders, e.positionFactor, marginFactor, nil)
}

// calcOrderMargins calculates the the order margin required for the party given their current orders and margin factor.
func calcOrderMargins(positionSize int64, orders []*types.Order, positionFactor, marginFactor num.Decimal, auctionPrice *num.Uint) *num.Uint {
// CalcOrderMargins calculates the the order margin required for the party given their current orders and margin factor.
func CalcOrderMargins(positionSize int64, orders []*types.Order, positionFactor, marginFactor num.Decimal, auctionPrice *num.Uint) *num.Uint {
if len(orders) == 0 {
return num.UintZero()
}
Expand Down
6 changes: 3 additions & 3 deletions core/risk/isolated_margin_ex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestSwithToIsolatedMarginContinuous(t *testing.T) {
require.Equal(t, num.NewUint(0), riskEvent[0].MarginLevels().OrderMargin)

buyOrderInfo, sellOrderInfo := extractOrderInfo(orders)
requiredPositionMarginStatic, requiredOrderMarginStatic := risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor)
requiredPositionMarginStatic, requiredOrderMarginStatic := risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, nil)
require.True(t, !requiredPositionMarginStatic.IsZero())
require.True(t, requiredOrderMarginStatic.IsZero())
transferRecalc := requiredPositionMarginStatic.Sub(evt.MarginBalance().ToDecimal())
Expand Down Expand Up @@ -119,7 +119,7 @@ func TestSwithToIsolatedMarginContinuous(t *testing.T) {
require.Equal(t, num.NewUint(300), riskEvent[0].MarginLevels().OrderMargin)

buyOrderInfo, sellOrderInfo = extractOrderInfo(orders)
requiredPositionMarginStatic, requiredOrderMarginStatic = risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor)
requiredPositionMarginStatic, requiredOrderMarginStatic = risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, nil)
require.True(t, !requiredPositionMarginStatic.IsZero())
require.True(t, !requiredOrderMarginStatic.IsZero())
transferRecalc = requiredPositionMarginStatic.Sub(evt.MarginBalance().ToDecimal())
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestSwithToIsolatedMarginContinuous(t *testing.T) {
require.Equal(t, num.NewUint(300), riskEvent[0].MarginLevels().OrderMargin)

buyOrderInfo, sellOrderInfo = extractOrderInfo(orders)
requiredPositionMarginStatic, requiredOrderMarginStatic = risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor)
requiredPositionMarginStatic, requiredOrderMarginStatic = risk.CalculateRequiredMarginInIsolatedMode(evt.size, evt.AverageEntryPrice().ToDecimal(), evt.Price().ToDecimal(), buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, nil)
require.True(t, !requiredPositionMarginStatic.IsZero())
require.True(t, !requiredOrderMarginStatic.IsZero())
transferRecalc = evt.MarginBalance().ToDecimal().Sub(requiredPositionMarginStatic)
Expand Down
10 changes: 5 additions & 5 deletions core/risk/isolated_margin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func TestCalcOrderMarginContinous(t *testing.T) {
// buy orderMargin = 0.5*(10 * 50 + 20 * 40 + 30 * 20)/10 = 95
// sell orderMargin = 0.5*(10 * 20 + 20 * 40 + 30 * 50)/10 = 125
// order margin = max(95,125) = 125
orderSideMargin := calcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
orderSideMargin := CalcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
require.Equal(t, num.NewUint(125), orderSideMargin)
staticResult := CalcOrderMarginIsolatedMode(currentPos, buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, num.DecimalZero())
require.Equal(t, staticResult.Round(0).String(), orderSideMargin.String())
Expand All @@ -271,7 +271,7 @@ func TestCalcOrderMarginContinous(t *testing.T) {
// buy orderMargin = 0.5*(10 * 50 + 20 * 40 + 30 * 20)/10 = 95
// sell orderMargin = 0.5*(6 * 20 + 20 * 40 + 30 * 50)/10 = 121
currentPos = 4
orderSideMargin = calcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
orderSideMargin = CalcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
require.Equal(t, num.NewUint(121), orderSideMargin)
staticResult = CalcOrderMarginIsolatedMode(currentPos, buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, num.DecimalZero())
require.Equal(t, staticResult.Round(0).String(), orderSideMargin.String())
Expand All @@ -280,7 +280,7 @@ func TestCalcOrderMarginContinous(t *testing.T) {
// buy orderMargin = 0.5*(10 * 50 + 20 * 40 + 30 * 20)/10 = 95
// sell orderMargin = 0.5*(0 * 20 + 5 * 40 + 30 * 50)/10 = 85
currentPos = 25
orderSideMargin = calcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
orderSideMargin = CalcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
require.Equal(t, num.NewUint(95), orderSideMargin)
staticResult = CalcOrderMarginIsolatedMode(currentPos, buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, num.DecimalZero())
require.Equal(t, staticResult.Round(0).String(), orderSideMargin.String())
Expand All @@ -289,7 +289,7 @@ func TestCalcOrderMarginContinous(t *testing.T) {
// buy orderMargin = 0.5*(6 * 50 + 20 * 40 + 30 * 20)/10 = 85
// sell orderMargin = 0.5*(10 * 20 + 20 * 40 + 30 * 50)/10 = 125
currentPos = -4
orderSideMargin = calcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
orderSideMargin = CalcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
require.Equal(t, num.NewUint(125), orderSideMargin)
staticResult = CalcOrderMarginIsolatedMode(currentPos, buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, num.DecimalZero())
require.Equal(t, staticResult.Round(0).String(), orderSideMargin.String())
Expand All @@ -298,7 +298,7 @@ func TestCalcOrderMarginContinous(t *testing.T) {
// buy orderMargin = 0.5*(0 * 50 + 10 * 40 + 30 * 20)/10 = 50
// sell orderMargin = 0.5*(10 * 20 + 20 * 40 + 30 * 50)/10 = 125
currentPos = -20
orderSideMargin = calcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
orderSideMargin = CalcOrderMargins(currentPos, orders, positionFactor, marginFactor, nil)
require.Equal(t, num.NewUint(125), orderSideMargin)
staticResult = CalcOrderMarginIsolatedMode(currentPos, buyOrderInfo, sellOrderInfo, positionFactor, marginFactor, num.DecimalZero())
require.Equal(t, staticResult.Round(0).String(), orderSideMargin.String())
Expand Down
28 changes: 22 additions & 6 deletions core/risk/margins_calculation.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,28 +339,44 @@ func calcOrderSideMarginIsolatedMode(currentPosition int64, orders []*OrderInfo,
return margin.Mul(marginFactor).Div(positionFactor)
}

func CalculateRequiredMarginInIsolatedMode(sizePosition int64, averageEntryPrice, marketObservable num.Decimal, buyOrders, sellOrders []*OrderInfo, positionFactor, marginFactor num.Decimal) (num.Decimal, num.Decimal) {
totalOrderNotional := num.DecimalZero()
func CalculateRequiredMarginInIsolatedMode(sizePosition int64, averageEntryPrice, marketObservable num.Decimal, buyOrders, sellOrders []*OrderInfo, positionFactor, marginFactor num.Decimal, auctionPrice *num.Uint) (num.Decimal, num.Decimal) {
marketOrderAdjustedPositionNotional := averageEntryPrice.Copy().Mul(num.DecimalFromInt64(sizePosition))
var orders []*types.Order = make([]*types.Order, 0, len(buyOrders)+len(sellOrders))

// assume market orders fill immediately at marketObservable price
for _, o := range buyOrders {
if o.IsMarketOrder {
sizePosition += int64(o.TrueRemaining)
marketOrderAdjustedPositionNotional = marketOrderAdjustedPositionNotional.Add(marketObservable.Mul(num.DecimalFromInt64(int64(o.TrueRemaining))))
} else {
totalOrderNotional = totalOrderNotional.Add(o.Price.Mul(num.DecimalFromInt64(int64(o.TrueRemaining))))
price, _ := num.UintFromDecimal(o.Price)
ord := &types.Order{
Status: types.OrderStatusActive,
Remaining: o.TrueRemaining,
Price: price,
Side: types.SideBuy,
}
orders = append(orders, ord)
}
}
for _, o := range sellOrders {
if o.IsMarketOrder {
sizePosition -= int64(o.TrueRemaining)
marketOrderAdjustedPositionNotional = marketOrderAdjustedPositionNotional.Sub(marketObservable.Mul(num.DecimalFromInt64(int64(o.TrueRemaining))))
} else {
totalOrderNotional = totalOrderNotional.Add(o.Price.Mul(num.DecimalFromInt64(int64(o.TrueRemaining))))
price, _ := num.UintFromDecimal(o.Price)
ord := &types.Order{
Status: types.OrderStatusActive,
Remaining: o.TrueRemaining,
Price: price,
Side: types.SideSell,
}
orders = append(orders, ord)
}
}

requiredPositionMargin := marketOrderAdjustedPositionNotional.Abs().Mul(marginFactor).Div(positionFactor)
requiredOrderMargin := totalOrderNotional.Mul(marginFactor).Div(positionFactor)
requiredOrderMargin := CalcOrderMargins(sizePosition, orders, positionFactor, marginFactor, auctionPrice)

return requiredPositionMargin, requiredOrderMargin
return requiredPositionMargin, requiredOrderMargin.ToDecimal()
}
6 changes: 5 additions & 1 deletion datanode/api/trading_data_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -3417,7 +3417,11 @@ func (t *TradingDataServiceV2) EstimatePosition(ctx context.Context, req *v2.Est
var wMarginDelta, bMarginDelta, posMarginDelta num.Decimal
combinedMargin := marginAccountBalance.Add(orderAccountBalance)
if isolatedMarginMode {
requiredPositionMargin, requiredOrderMargin := risk.CalculateRequiredMarginInIsolatedMode(req.OpenVolume, avgEntryPrice, marketObservable, buyOrders, sellOrders, positionFactor, dMarginFactor)
var ap *num.Uint = nil
if !auctionPrice.IsZero() {
ap, _ = num.UintFromDecimal(auctionPrice)
}
requiredPositionMargin, requiredOrderMargin := risk.CalculateRequiredMarginInIsolatedMode(req.OpenVolume, avgEntryPrice, marketObservable, buyOrders, sellOrders, positionFactor, dMarginFactor, ap)
posMarginDelta = requiredPositionMargin.Sub(marginAccountBalance)
wMarginDelta = requiredPositionMargin.Add(requiredOrderMargin).Sub(combinedMargin)
bMarginDelta = wMarginDelta
Expand Down
Loading

0 comments on commit ba8d414

Please sign in to comment.