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  }