code.vegaprotocol.io/vega@v0.79.0/core/risk/margins_calculation.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 risk 17 18 import ( 19 "sort" 20 21 "code.vegaprotocol.io/vega/core/events" 22 "code.vegaprotocol.io/vega/core/types" 23 "code.vegaprotocol.io/vega/libs/num" 24 ) 25 26 var ( 27 exp = num.UintZero().Exp(num.NewUint(10), num.NewUint(5)) 28 expDec = num.DecimalFromUint(exp) 29 ) 30 31 type scalingFactorsUint struct { 32 search *num.Uint 33 initial *num.Uint 34 release *num.Uint 35 } 36 37 func scalingFactorsUintFromDecimals(sf *types.ScalingFactors) *scalingFactorsUint { 38 search, _ := num.UintFromDecimal(sf.SearchLevel.Mul(expDec)) 39 initial, _ := num.UintFromDecimal(sf.InitialMargin.Mul(expDec)) 40 release, _ := num.UintFromDecimal(sf.CollateralRelease.Mul(expDec)) 41 42 return &scalingFactorsUint{ 43 search: search, 44 initial: initial, 45 release: release, 46 } 47 } 48 49 func newMarginLevelsFull(maintenance num.Decimal) *types.MarginLevels { 50 maint, _ := num.UintFromDecimal(maintenance.Ceil()) 51 return &types.MarginLevels{ 52 MaintenanceMargin: maint, 53 SearchLevel: maint.Clone(), 54 InitialMargin: maint.Clone(), 55 CollateralReleaseLevel: maint.Clone(), 56 OrderMargin: num.UintZero(), 57 MarginMode: types.MarginModeCrossMargin, 58 MarginFactor: num.DecimalZero(), 59 } 60 } 61 62 func newMarginLevels(maintenance num.Decimal, scalingFactors *scalingFactorsUint) *types.MarginLevels { 63 umaintenance, _ := num.UintFromDecimal(maintenance.Ceil()) 64 return &types.MarginLevels{ 65 MaintenanceMargin: umaintenance, 66 SearchLevel: num.UintZero().Div(num.UintZero().Mul(scalingFactors.search, umaintenance), exp), 67 InitialMargin: num.UintZero().Div(num.UintZero().Mul(scalingFactors.initial, umaintenance), exp), 68 CollateralReleaseLevel: num.UintZero().Div(num.UintZero().Mul(scalingFactors.release, umaintenance), exp), 69 OrderMargin: num.UintZero(), 70 MarginMode: types.MarginModeCrossMargin, 71 MarginFactor: num.DecimalZero(), 72 } 73 } 74 75 func (e *Engine) calculateFullCollatMargins(m events.Margin, price *num.Uint, _ types.RiskFactor, withPotential bool) *types.MarginLevels { 76 var ( 77 marginMaintenanceLng num.Decimal 78 marginMaintenanceSht num.Decimal 79 ) 80 // convert volumn to a decimal number from a * 10^pdp 81 openVolume := num.DecimalFromInt64(m.Size()).Div(e.positionFactor) 82 op := m.Price().ToDecimal() 83 base := price.ToDecimal() 84 var ( 85 riskiestLng = openVolume 86 riskiestSht = openVolume 87 ) 88 // the party has no open positions that we need to calculate margin for 89 if riskiestLng.IsZero() && riskiestSht.IsZero() && !withPotential { 90 return &types.MarginLevels{ 91 MaintenanceMargin: num.UintZero(), 92 SearchLevel: num.UintZero(), 93 InitialMargin: num.UintZero(), 94 CollateralReleaseLevel: num.UintZero(), 95 OrderMargin: num.UintZero(), 96 MarginMode: types.MarginModeCrossMargin, 97 MarginFactor: num.DecimalZero(), 98 } 99 } 100 if riskiestLng.IsPositive() { 101 marginMaintenanceLng = riskiestLng.Mul(op) 102 } else { 103 // even our riskies position is short, get the sell AEP 104 marginMaintenanceLng = riskiestLng.Mul(base.Sub(op)).Abs() 105 } 106 if riskiestSht.IsNegative() { 107 marginMaintenanceSht = riskiestSht.Mul(base.Sub(op)).Abs() 108 } else { 109 // even the shortest position is long, get buy AEP 110 marginMaintenanceSht = riskiestSht.Mul(op) 111 } 112 if withPotential { 113 // add margins required to cover the buy and sell orders 114 longSize := num.DecimalFromInt64(m.Buy()).Div(e.positionFactor) 115 // size * order price 116 longMargin := longSize.Mul(m.VWBuy().ToDecimal()) 117 // add limit price * size to the margin required 118 shortSize := num.DecimalFromInt64(m.Sell()).Div(e.positionFactor).Abs() 119 // size * (max price - order price) 120 shortMargin := shortSize.Mul(base.Sub(m.VWSell().ToDecimal())) 121 marginMaintenanceLng = marginMaintenanceLng.Add(longMargin) 122 marginMaintenanceSht = marginMaintenanceSht.Add(shortMargin) 123 } 124 // now get the max margin required 125 if marginMaintenanceLng.GreaterThan(marginMaintenanceSht) { 126 return newMarginLevelsFull(marginMaintenanceLng) 127 } 128 // if short margin level > 0 129 if !marginMaintenanceSht.IsZero() { 130 return newMarginLevelsFull(marginMaintenanceSht) 131 } 132 133 // long margin level <= short, and short is zero, so no margin required. 134 return &types.MarginLevels{ 135 MaintenanceMargin: num.UintZero(), 136 SearchLevel: num.UintZero(), 137 InitialMargin: num.UintZero(), 138 CollateralReleaseLevel: num.UintZero(), 139 OrderMargin: num.UintZero(), 140 MarginMode: types.MarginModeCrossMargin, 141 MarginFactor: num.DecimalZero(), 142 } 143 } 144 145 // Implementation of the margin calculator per specs: 146 // https://github.com/vegaprotocol/product/blob/master/specs/0019-margin-calculator.md 147 func (e *Engine) calculateMargins(m events.Margin, markPrice *num.Uint, rf types.RiskFactor, withPotentialBuyAndSell, auction bool, inc num.Decimal, auctionPrice *num.Uint) *types.MarginLevels { 148 if e.marginCalculator.FullyCollateralised { 149 if auction && auctionPrice != nil { 150 return e.calculateFullCollatMargins(m, auctionPrice, rf, withPotentialBuyAndSell) 151 } 152 return e.calculateFullCollatMargins(m, markPrice, rf, withPotentialBuyAndSell) 153 } 154 var ( 155 marginMaintenanceLng num.Decimal 156 marginMaintenanceSht num.Decimal 157 ) 158 // convert volumn to a decimal number from a * 10^pdp 159 openVolume := num.DecimalFromInt64(m.Size()).Div(e.positionFactor) 160 var ( 161 riskiestLng = openVolume 162 riskiestSht = openVolume 163 ) 164 if withPotentialBuyAndSell { 165 // calculate both long and short riskiest positions 166 riskiestLng = riskiestLng.Add(num.DecimalFromInt64(m.Buy()).Div(e.positionFactor)) 167 riskiestSht = riskiestSht.Sub(num.DecimalFromInt64(m.Sell()).Div(e.positionFactor)) 168 } 169 // the party has no open positions that we need to calculate margin for 170 if riskiestLng.IsZero() && riskiestSht.IsZero() { 171 return &types.MarginLevels{ 172 MaintenanceMargin: num.UintZero(), 173 SearchLevel: num.UintZero(), 174 InitialMargin: num.UintZero(), 175 CollateralReleaseLevel: num.UintZero(), 176 OrderMargin: num.UintZero(), 177 MarginMode: types.MarginModeCrossMargin, 178 MarginFactor: num.DecimalZero(), 179 } 180 } 181 182 mPriceDec := markPrice.ToDecimal() 183 // calculate margin maintenance long only if riskiest is > 0 184 // marginMaintenanceLng will be 0 by default 185 if riskiestLng.IsPositive() { 186 slippageVolume := num.MaxD(openVolume, num.DecimalZero()) 187 minV := mPriceDec.Mul(e.linearSlippageFactor.Mul(slippageVolume).Add(e.quadraticSlippageFactor.Mul(slippageVolume.Mul(slippageVolume)))) 188 if auction { 189 marginMaintenanceLng = minV.Add(slippageVolume.Mul(mPriceDec.Mul(rf.Long))) 190 if withPotentialBuyAndSell { 191 p := m.BuySumProduct() 192 if auctionPrice != nil { 193 p = num.Max(p, num.UintZero().Mul(num.UintFromUint64(uint64(m.Buy())), auctionPrice)) 194 } 195 maintenanceMarginLongOpenOrders := p.ToDecimal().Div(e.positionFactor).Mul(rf.Long) 196 marginMaintenanceLng = marginMaintenanceLng.Add(maintenanceMarginLongOpenOrders) 197 } 198 } else { 199 // maintenance_margin_long_open_position = 200 // max( 201 // 0, 202 // mark_price * (slippage_volume * market.maxSlippageFraction[1] + slippage_volume^2 * market.maxSlippageFraction[2]) 203 // ) + slippage_volume * [ quantitative_model.risk_factors_long ] . [ Product.value(market_observable) ] 204 // 205 // maintenance_margin_long_open_orders = buy_orders * [ quantitative_model.risk_factors_long ] . [ Product.value(market_observable) ] 206 marginMaintenanceLng = num.MaxD( 207 num.DecimalZero(), 208 minV, 209 ).Add(slippageVolume.Mul(rf.Long).Mul(mPriceDec)) 210 if withPotentialBuyAndSell { 211 bDec := num.DecimalFromInt64(m.Buy()).Div(e.positionFactor) 212 maintenanceMarginLongOpenOrders := bDec.Mul(rf.Long).Mul(mPriceDec) 213 marginMaintenanceLng = marginMaintenanceLng.Add(maintenanceMarginLongOpenOrders) 214 } 215 } 216 } 217 // calculate margin maintenance short only if riskiest is < 0 218 // marginMaintenanceSht will be 0 by default 219 if riskiestSht.IsNegative() { 220 absSlippageVolume := num.MinD(openVolume, num.DecimalZero()).Abs() 221 linearSlippage := absSlippageVolume.Mul(e.linearSlippageFactor) 222 quadraticSlipage := absSlippageVolume.Mul(absSlippageVolume).Mul(e.quadraticSlippageFactor) 223 minV := mPriceDec.Mul(linearSlippage.Add(quadraticSlipage)) 224 if auction { 225 marginMaintenanceSht = minV.Add(absSlippageVolume.Mul(mPriceDec.Mul(rf.Short))) 226 if withPotentialBuyAndSell { 227 p := m.SellSumProduct() 228 if auctionPrice != nil { 229 p = num.Max(p, num.UintZero().Mul(num.UintFromUint64(uint64(m.Sell())), auctionPrice)) 230 } 231 maintenanceMarginShortOpenOrders := p.ToDecimal().Div(e.positionFactor).Mul(rf.Short) 232 marginMaintenanceSht = marginMaintenanceSht.Add(maintenanceMarginShortOpenOrders) 233 } 234 } else { 235 // maintenance_margin_short_open_position = 236 // max( 237 // 0, 238 // mark_price * market.maxSlippageFraction[1] + abs(slippage_volume)^2 * market.maxSlippageFraction[2]) 239 // ) + abs(slippage_volume) * [ quantitative_model.risk_factors_short ] . [ Product.value(market_observable) ] 240 // 241 // maintenance_margin_short_open_orders = abs(sell_orders) * [ quantitative_model.risk_factors_short ] . [ Product.value(market_observable) ] 242 marginMaintenanceSht = num.MaxD( 243 num.DecimalZero(), 244 minV, 245 ).Add(absSlippageVolume.Mul(mPriceDec).Mul(rf.Short)) 246 if withPotentialBuyAndSell { 247 sDec := num.DecimalFromInt64(m.Sell()).Div(e.positionFactor) 248 maintenanceMarginShortOpenOrders := sDec.Abs().Mul(mPriceDec).Mul(rf.Short) 249 marginMaintenanceSht = marginMaintenanceSht.Add(maintenanceMarginShortOpenOrders) 250 } 251 } 252 } 253 254 if !inc.IsZero() && !openVolume.IsZero() { 255 // openVolume and inc are signed, but this is fine, we only apply the positive values 256 incD := num.MaxD(num.DecimalZero(), inc.Mul(openVolume)) 257 marginMaintenanceLng = marginMaintenanceLng.Add(incD) 258 marginMaintenanceSht = marginMaintenanceSht.Add(incD) 259 } 260 261 // the greatest liability is the most positive number 262 if marginMaintenanceLng.GreaterThan(marginMaintenanceSht) && marginMaintenanceLng.IsPositive() { 263 return newMarginLevels(marginMaintenanceLng, e.scalingFactorsUint) 264 } 265 if marginMaintenanceSht.IsPositive() { 266 return newMarginLevels(marginMaintenanceSht, e.scalingFactorsUint) 267 } 268 269 return &types.MarginLevels{ 270 MaintenanceMargin: num.UintZero(), 271 SearchLevel: num.UintZero(), 272 InitialMargin: num.UintZero(), 273 CollateralReleaseLevel: num.UintZero(), 274 OrderMargin: num.UintZero(), 275 MarginMode: types.MarginModeCrossMargin, 276 MarginFactor: num.DecimalZero(), 277 } 278 } 279 280 func CalculateMaintenanceMarginWithSlippageFactors(sizePosition int64, buyOrders, sellOrders []*OrderInfo, marketObservable, positionFactor, linearSlippageFactor, quadraticSlippageFactor, riskFactorLong, riskFactorShort, fundingPaymntPerUnitPosition num.Decimal, auction bool, auctionPrice num.Decimal) num.Decimal { 281 buySumProduct, sellSumProduct := num.DecimalZero(), num.DecimalZero() 282 sizeSells, sizeBuys := int64(0), int64(0) 283 for _, o := range buyOrders { 284 size := int64(o.TrueRemaining) 285 if o.IsMarketOrder { 286 // assume market order fills 287 sizePosition += size 288 } else { 289 buySumProduct = buySumProduct.Add(num.DecimalFromInt64(size).Mul(o.Price)) 290 sizeBuys += size 291 } 292 } 293 for _, o := range sellOrders { 294 size := int64(o.TrueRemaining) 295 if o.IsMarketOrder { 296 // assume market order fills 297 sizePosition -= size 298 } else { 299 sellSumProduct = sellSumProduct.Add(num.DecimalFromInt64(size).Mul(o.Price)) 300 sizeSells += size 301 } 302 } 303 return computeMaintenanceMargin(sizePosition, sizeBuys, sizeSells, buySumProduct, sellSumProduct, marketObservable, positionFactor, linearSlippageFactor, quadraticSlippageFactor, riskFactorLong, riskFactorShort, fundingPaymntPerUnitPosition, auction, auctionPrice) 304 } 305 306 func calculateSlippageFactor(slippageVolume, linearSlippageFactor, quadraticSlippageFactor num.Decimal) num.Decimal { 307 return linearSlippageFactor.Mul(slippageVolume.Abs()).Add(quadraticSlippageFactor.Mul(slippageVolume.Mul(slippageVolume))) 308 } 309 310 func computeMaintenanceMargin(sizePosition, buySize, sellSize int64, buySumProduct, sellSumProduct, marketObservable, positionFactor, linearSlippageFactor, quadraticSlippageFactor, riskFactorLong, riskFactorShort, fundingPaymntPerUnitPosition num.Decimal, auction bool, auctionPrice num.Decimal) num.Decimal { 311 var ( 312 marginMaintenanceLng num.Decimal 313 marginMaintenanceSht num.Decimal 314 ) 315 // convert volumn to a decimal number from a * 10^pdp 316 openVolume := num.DecimalFromInt64(sizePosition).Div(positionFactor) 317 // calculate both long and short riskiest positions 318 var ( 319 riskiestLng = openVolume.Add(num.DecimalFromInt64(buySize).Div(positionFactor)) 320 riskiestSht = openVolume.Sub(num.DecimalFromInt64(sellSize).Div(positionFactor)) 321 ) 322 323 // calculate margin maintenance long only if riskiest is > 0 324 // marginMaintenanceLng will be 0 by default 325 if riskiestLng.IsPositive() { 326 slippageVolume := num.MaxD(openVolume, num.DecimalZero()) 327 slippageCap := marketObservable.Mul(calculateSlippageFactor(slippageVolume, linearSlippageFactor, quadraticSlippageFactor)) 328 if auction { 329 marginMaintenanceLng = slippageCap.Add(slippageVolume.Mul(marketObservable.Mul(riskFactorLong))) 330 p := buySumProduct 331 if !auctionPrice.IsZero() { 332 p = num.MaxD(p, auctionPrice.Mul(num.DecimalFromInt64(buySize))) 333 } 334 maintenanceMarginLongOpenOrders := p.Div(positionFactor).Mul(riskFactorLong) 335 marginMaintenanceLng = marginMaintenanceLng.Add(maintenanceMarginLongOpenOrders) 336 } else { 337 marginMaintenanceLng = num.MaxD( 338 num.DecimalZero(), 339 slippageCap, 340 ).Add(slippageVolume.Mul(riskFactorLong).Mul(marketObservable)) 341 if buySize > 0 { 342 maintenanceMarginLongOpenOrders := num.DecimalFromInt64(buySize).Div(positionFactor).Mul(riskFactorLong).Mul(marketObservable) 343 marginMaintenanceLng = marginMaintenanceLng.Add(maintenanceMarginLongOpenOrders) 344 } 345 } 346 } 347 // calculate margin maintenance short only if riskiest is < 0 348 // marginMaintenanceSht will be 0 by default 349 if riskiestSht.IsNegative() { 350 slippageVolume := num.MinD(openVolume, num.DecimalZero()) 351 absSlippageVolume := slippageVolume.Abs() 352 slippageCap := marketObservable.Mul(calculateSlippageFactor(slippageVolume, linearSlippageFactor, quadraticSlippageFactor)) 353 if auction { 354 marginMaintenanceSht = slippageCap.Add(absSlippageVolume.Mul(marketObservable.Mul(riskFactorShort))) 355 p := sellSumProduct 356 if !auctionPrice.IsZero() { 357 p = num.MaxD(p, auctionPrice.Mul(num.DecimalFromInt64(sellSize))) 358 } 359 maintenanceMarginShortOpenOrders := p.Div(positionFactor).Mul(riskFactorShort) 360 marginMaintenanceSht = marginMaintenanceSht.Add(maintenanceMarginShortOpenOrders) 361 } else { 362 marginMaintenanceSht = num.MaxD( 363 num.DecimalZero(), 364 slippageCap, 365 ).Add(absSlippageVolume.Mul(marketObservable).Mul(riskFactorShort)) 366 if sellSize > 0 { 367 maintenanceMarginShortOpenOrders := num.DecimalFromInt64(sellSize).Div(positionFactor).Abs().Mul(marketObservable).Mul(riskFactorShort) 368 marginMaintenanceSht = marginMaintenanceSht.Add(maintenanceMarginShortOpenOrders) 369 } 370 } 371 } 372 373 if !fundingPaymntPerUnitPosition.IsZero() && !openVolume.IsZero() { 374 // calculate margin increase based on position 375 // incD = max(0, inc * open volume) 376 incD := num.MaxD(num.DecimalZero(), fundingPaymntPerUnitPosition.Mul(openVolume)) 377 marginMaintenanceLng = marginMaintenanceLng.Add(incD) 378 marginMaintenanceSht = marginMaintenanceSht.Add(incD) 379 } 380 381 // the greatest liability is the most positive number 382 if marginMaintenanceLng.GreaterThan(marginMaintenanceSht) && marginMaintenanceLng.IsPositive() { 383 return marginMaintenanceLng 384 } 385 if marginMaintenanceSht.IsPositive() { 386 return marginMaintenanceSht 387 } 388 return num.DecimalZero() 389 } 390 391 // CalcOrderMarginIsolatedMode calculates the the order margin required for the party in isolated margin mode given their current orders and margin factor. 392 func CalcOrderMarginIsolatedMode(positionSize int64, buyOrders, sellOrders []*OrderInfo, positionFactor, marginFactor, auctionPrice num.Decimal) num.Decimal { 393 // sort orders from best to worst 394 sort.Slice(buyOrders, func(i, j int) bool { return buyOrders[i].Price.GreaterThan(buyOrders[j].Price) }) 395 sort.Slice(sellOrders, func(i, j int) bool { return sellOrders[i].Price.LessThan(sellOrders[j].Price) }) 396 397 // calc the side margin 398 marginByBuy := calcOrderSideMarginIsolatedMode(positionSize, buyOrders, positionFactor, marginFactor, auctionPrice, true) 399 marginBySell := calcOrderSideMarginIsolatedMode(positionSize, sellOrders, positionFactor, marginFactor, auctionPrice, false) 400 if marginBySell.GreaterThan(marginByBuy) { 401 return marginBySell 402 } 403 return marginByBuy 404 } 405 406 func calcOrderSideMarginIsolatedMode(currentPosition int64, orders []*OrderInfo, positionFactor, marginFactor num.Decimal, auctionPrice num.Decimal, buy bool) num.Decimal { 407 for _, o := range orders { 408 if o.IsMarketOrder { 409 // assume market order fills 410 if buy { 411 currentPosition += int64(o.TrueRemaining) 412 } else { 413 currentPosition -= int64(o.TrueRemaining) 414 } 415 } 416 } 417 418 margin := num.DecimalZero() 419 remainingCovered := int64Abs(currentPosition) 420 for _, o := range orders { 421 size := o.TrueRemaining 422 // for long position we don't need to count margin for the top <currentPosition> size for sell orders 423 // for short position we don't need to count margin for the top <currentPosition> size for buy orders 424 if remainingCovered != 0 && (buy && currentPosition < 0) || (!buy && currentPosition > 0) { 425 if size >= remainingCovered { // part of the order doesn't require margin 426 size = size - remainingCovered 427 remainingCovered = 0 428 } else { // the entire order doesn't require margin 429 remainingCovered -= size 430 size = 0 431 } 432 } 433 if size > 0 { 434 // if we're in auction we need to use the larger between auction price (which is the max(indicativePrice, markPrice)) and the order price 435 p := o.Price 436 if auctionPrice.GreaterThan(p) { 437 p = auctionPrice 438 } 439 // add the margin for the given order 440 margin = margin.Add(num.DecimalFromInt64(int64(size)).Mul(p)) 441 } 442 } 443 // factor the margin by margin factor and divide by position factor to get to the right decimals 444 return margin.Mul(marginFactor).Div(positionFactor) 445 } 446 447 func CalculateRequiredMarginInIsolatedMode(sizePosition int64, averageEntryPrice, marketObservable num.Decimal, buyOrders, sellOrders []*OrderInfo, positionFactor, marginFactor num.Decimal, auctionPrice *num.Uint) (num.Decimal, num.Decimal) { 448 marketOrderAdjustedPositionNotional := averageEntryPrice.Copy().Mul(num.DecimalFromInt64(sizePosition)) 449 var orders []*types.Order = make([]*types.Order, 0, len(buyOrders)+len(sellOrders)) 450 451 // assume market orders fill immediately at marketObservable price 452 for _, o := range buyOrders { 453 if o.IsMarketOrder { 454 sizePosition += int64(o.TrueRemaining) 455 marketOrderAdjustedPositionNotional = marketOrderAdjustedPositionNotional.Add(marketObservable.Mul(num.DecimalFromInt64(int64(o.TrueRemaining)))) 456 } else { 457 price, _ := num.UintFromDecimal(o.Price) 458 ord := &types.Order{ 459 Status: types.OrderStatusActive, 460 Remaining: o.TrueRemaining, 461 Price: price, 462 Side: types.SideBuy, 463 } 464 orders = append(orders, ord) 465 } 466 } 467 for _, o := range sellOrders { 468 if o.IsMarketOrder { 469 sizePosition -= int64(o.TrueRemaining) 470 marketOrderAdjustedPositionNotional = marketOrderAdjustedPositionNotional.Sub(marketObservable.Mul(num.DecimalFromInt64(int64(o.TrueRemaining)))) 471 } else { 472 price, _ := num.UintFromDecimal(o.Price) 473 ord := &types.Order{ 474 Status: types.OrderStatusActive, 475 Remaining: o.TrueRemaining, 476 Price: price, 477 Side: types.SideSell, 478 } 479 orders = append(orders, ord) 480 } 481 } 482 483 requiredPositionMargin := marketOrderAdjustedPositionNotional.Abs().Mul(marginFactor).Div(positionFactor) 484 requiredOrderMargin := CalcOrderMargins(sizePosition, orders, positionFactor, marginFactor, auctionPrice) 485 486 return requiredPositionMargin, requiredOrderMargin.ToDecimal() 487 }