/// <summary> /// Gets the margin currently alloted to the specified holding. /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the option</returns> /// <remarks> /// We fix the option to 1.5x the maintenance because of its close coupling with the underlying. /// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long /// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting /// in a margin greater than the underlying's margin. /// </remarks> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { var underlyingRequirement = base.GetMaintenanceMargin(parameters.ForUnderlying(parameters.Quantity)); var positionSide = parameters.Quantity > 0 ? PositionSide.Long : PositionSide.Short; return(GetMarginRequirement(_futureOption, underlyingRequirement, positionSide)); }
/// <summary> /// Gets the margin currently allocated to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns> public MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { using (Py.GIL()) { return((_model.GetMaintenanceMargin(parameters) as PyObject) .GetAndDispose <MaintenanceMargin>()); } }
/// <summary> /// Gets the margin currently allocated to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the </returns> public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceMarginParameters parameters) { // SecurityPositionGroupBuyingPowerModel models buying power the same as non-grouped, so we can simply sum up // the reserved buying power via the security's model. We should really only ever get a single position here, // but it's not incorrect to ask the model for what the reserved buying power would be using default modeling var buyingPower = 0m; foreach (var position in parameters.PositionGroup) { var security = parameters.Portfolio.Securities[position.Symbol]; var result = security.BuyingPowerModel.GetMaintenanceMargin( MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, position.Quantity) ); buyingPower += result; } return(buyingPower); }
/// <summary> /// Gets the margin currently allotted to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the </returns> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { var security = parameters.Security; if (security?.GetLastData() == null || parameters.Quantity == 0m) { return(0m); } var marginReq = GetCurrentMarginRequirements(security); if (EnableIntradayMargins && security.Exchange.ExchangeOpen && !security.Exchange.ClosingSoon) { return(marginReq.MaintenanceIntraday * parameters.AbsoluteQuantity); } // margin is per contract return(marginReq.MaintenanceOvernight * parameters.AbsoluteQuantity); }
public MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { EnsureSecurityExists(parameters.Security); var expected = SecurityModel.GetMaintenanceMargin(parameters); if (reentry) { return(expected); } reentry = true; var actual = PositionGroupModel.GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters( Portfolio, new PositionGroup(PositionGroupModel, new Position(parameters.Security, parameters.Quantity)) )); Assert.AreEqual(expected.Value, actual.Value, $"{PositionGroupModel.GetType().Name}:{nameof(GetMaintenanceMargin)}" ); reentry = false; return(expected); }
/// <summary> /// Gets the margin currently allocated to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { return(parameters.AbsoluteQuantity * _marginRequiredPerUnitInAccountCurrency); }
/// <summary> /// Gets the margin currently allocated to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the </returns> public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceMarginParameters parameters) { if (_optionStrategy.Name == OptionStrategyDefinitions.CoveredCall.Name) { // MAX[In-the-money amount + Margin(long stock evaluated at min(mark price, strike(short call))), min(stock value, max(call value, long stock margin))] var optionPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => position.Symbol.SecurityType.IsOption()); var underlyingPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => !position.Symbol.SecurityType.IsOption()); var optionSecurity = (Option)parameters.Portfolio.Securities[optionPosition.Symbol]; var underlyingSecurity = parameters.Portfolio.Securities[underlyingPosition.Symbol]; var intrinsicValue = optionSecurity.GetIntrinsicValue(underlyingSecurity.Price); var inTheMoneyAmount = intrinsicValue * optionSecurity.ContractUnitOfTrade * Math.Abs(optionPosition.Quantity); var underlyingValue = underlyingSecurity.Holdings.GetQuantityValue(underlyingPosition.Quantity); var optionValue = optionSecurity.Holdings.GetQuantityValue(optionPosition.Quantity); // mark price, strike price var underlyingPriceToEvaluate = Math.Min(optionSecurity.Price, optionSecurity.StrikePrice); var underlyingHypotheticalValue = underlyingSecurity.Holdings.GetQuantityValue(underlyingPosition.Quantity, underlyingPriceToEvaluate); var hypotheticalMarginRequired = underlyingSecurity.BuyingPowerModel.GetMaintenanceMargin( new MaintenanceMarginParameters(underlyingSecurity, underlyingPosition.Quantity, 0, underlyingHypotheticalValue)); var marginRequired = underlyingSecurity.BuyingPowerModel.GetMaintenanceMargin( new MaintenanceMarginParameters(underlyingSecurity, underlyingPosition.Quantity, 0, underlyingValue)); var secondOperand = Math.Min(underlyingValue, Math.Max(optionValue, marginRequired)); var result = Math.Max(inTheMoneyAmount + hypotheticalMarginRequired, secondOperand); var inAccountCurrency = parameters.Portfolio.CashBook.ConvertToAccountCurrency(result, optionSecurity.QuoteCurrency.Symbol); return(new MaintenanceMargin(inAccountCurrency)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.CoveredPut.Name) { // Initial Stock Margin Requirement + In the Money Amount var optionPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => position.Symbol.SecurityType.IsOption()); var underlyingPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => !position.Symbol.SecurityType.IsOption()); var optionSecurity = (Option)parameters.Portfolio.Securities[optionPosition.Symbol]; var underlyingSecurity = parameters.Portfolio.Securities[underlyingPosition.Symbol]; var intrinsicValue = optionSecurity.GetIntrinsicValue(underlyingSecurity.Price); var inTheMoneyAmount = intrinsicValue * optionSecurity.ContractUnitOfTrade * Math.Abs(optionPosition.Quantity); var initialMarginRequirement = underlyingSecurity.BuyingPowerModel.GetInitialMarginRequirement(underlyingSecurity, underlyingPosition.Quantity); var result = Math.Abs(initialMarginRequirement) + inTheMoneyAmount; var inAccountCurrency = parameters.Portfolio.CashBook.ConvertToAccountCurrency(result, optionSecurity.QuoteCurrency.Symbol); return(new MaintenanceMargin(inAccountCurrency)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallSpread.Name || _optionStrategy.Name == OptionStrategyDefinitions.BullCallSpread.Name || _optionStrategy.Name == OptionStrategyDefinitions.CallCalendarSpread.Name) { var result = GetLongCallShortCallStrikeDifferenceMargin(parameters.PositionGroup, parameters.Portfolio); return(new MaintenanceMargin(result)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.BearPutSpread.Name || _optionStrategy.Name == OptionStrategyDefinitions.BullPutSpread.Name || _optionStrategy.Name == OptionStrategyDefinitions.PutCalendarSpread.Name) { var result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup, parameters.Portfolio); return(new MaintenanceMargin(result)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.Straddle.Name || _optionStrategy.Name == OptionStrategyDefinitions.Strangle.Name) { // Margined as two long options. var callOption = parameters.PositionGroup.Positions.Single(position => position.Symbol.ID.OptionRight == OptionRight.Call); var callSecurity = (Option)parameters.Portfolio.Securities[callOption.Symbol]; var callMargin = callSecurity.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice( callSecurity, callOption.Quantity)); var putOption = parameters.PositionGroup.Positions.Single(position => position.Symbol.ID.OptionRight == OptionRight.Put); var putSecurity = (Option)parameters.Portfolio.Securities[putOption.Symbol]; var putMargin = putSecurity.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice( putSecurity, putOption.Quantity)); var result = callMargin.Value + putMargin.Value; return(new MaintenanceMargin(result)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.ButterflyCall.Name || _optionStrategy.Name == OptionStrategyDefinitions.ButterflyPut.Name) { return(new MaintenanceMargin(0)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyPut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyCall.Name) { var result = GetMiddleAndLowStrikeDifference(parameters.PositionGroup, parameters.Portfolio); return(new MaintenanceMargin(result)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.IronCondor.Name) { var result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup, parameters.Portfolio); return(new MaintenanceMargin(result)); } throw new NotImplementedException($"Option strategy {_optionStrategy.Name} margin modeling has yet to be implemented"); }
/// <summary> /// Gets the margin currently alloted to the specified holding. /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the option</returns> /// <remarks> /// We fix the option to 1.5x the maintenance because of its close coupling with the underlying. /// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long /// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting /// in a margin greater than the underlying's margin. /// </remarks> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { return(base.GetMaintenanceMargin(parameters.ForUnderlying(parameters.Quantity)) * FixedMarginMultiplier); }
/// <summary> /// Gets the margin currently alloted to the specified holding /// </summary> /// <param name="parameters">An object containing the security</param> /// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { var security = parameters.Security; return(parameters.AbsoluteHoldingsCost * GetMaintenanceMarginRequirement(security, security.Holdings.HoldingsCost)); }
/// <summary> /// The percentage of the holding's absolute cost that must be held in free cash in order to avoid a margin call /// </summary> public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters) { return(base.GetMaintenanceMargin(parameters) * GetMarginCorrectionFactor(parameters.Security)); }