Lean  $LEAN_TAG$
OptionMarginModel.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
18 
20 {
21  /// <summary>
22  /// Represents a simple option margin model.
23  /// </summary>
24  /// <remarks>
25  /// Options are not traded on margin. Margin requirements exist though for those portfolios with short positions.
26  /// Current implementation covers only single long/naked short option positions.
27  /// </remarks>
29  {
30  // initial margin
31  private const decimal OptionMarginRequirement = 1;
32  private const decimal NakedPositionMarginRequirement = 0.1m;
33  private const decimal EquityOptionNakedPositionMarginRequirementOtm = 0.2m;
34  private const decimal IndexOptionNakedPositionMarginRequirementOtm = 0.15m;
35 
36  /// <summary>
37  /// Initializes a new instance of the <see cref="OptionMarginModel"/>
38  /// </summary>
39  /// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required unused buying power for the account.</param>
40  public OptionMarginModel(decimal requiredFreeBuyingPowerPercent = 0)
41  {
42  RequiredFreeBuyingPowerPercent = requiredFreeBuyingPowerPercent;
43  }
44 
45  /// <summary>
46  /// Gets the current leverage of the security
47  /// </summary>
48  /// <param name="security">The security to get leverage for</param>
49  /// <returns>The current leverage in the security</returns>
50  public override decimal GetLeverage(Security security)
51  {
52  // Options are not traded on margin
53  return 1;
54  }
55 
56  /// <summary>
57  /// Sets the leverage for the applicable securities, i.e, options.
58  /// </summary>
59  /// <param name="security"></param>
60  /// <param name="leverage">The new leverage</param>
61  public override void SetLeverage(Security security, decimal leverage)
62  {
63  // Options are leveraged products and different leverage cannot be set by user.
64  throw new InvalidOperationException("Options are leveraged products and different leverage cannot be set by user");
65  }
66 
67  /// <summary>
68  /// Gets the total margin required to execute the specified order in units of the account currency including fees
69  /// </summary>
70  /// <param name="parameters">An object containing the portfolio, the security and the order</param>
71  /// <returns>The total margin in terms of the currency quoted in the order</returns>
74  )
75  {
76  //Get the order value from the non-abstract order classes (MarketOrder, LimitOrder, StopMarketOrder)
77  //Market order is approximated from the current security price and set in the MarketOrder Method in QCAlgorithm.
78 
79  var fees = parameters.Security.FeeModel.GetOrderFee(
80  new OrderFeeParameters(parameters.Security, parameters.Order)
81  );
82 
83  var feesInAccountCurrency = parameters.CurrencyConverter.ConvertToAccountCurrency(fees.Value);
84 
85  var value = parameters.Order.GetValue(parameters.Security);
86  var orderMargin = value * GetMarginRequirement(parameters.Security, parameters.Order.Quantity, value);
87 
88  return orderMargin + Math.Sign(orderMargin) * feesInAccountCurrency.Amount;
89  }
90 
91  /// <summary>
92  /// Gets the margin currently alloted to the specified holding
93  /// </summary>
94  /// <param name="parameters">An object containing the security</param>
95  /// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns>
97  {
98  // Long options have zero maintenance margin requirement
99  return parameters.Quantity >= 0 ? 0 : parameters.AbsoluteHoldingsCost * GetMaintenanceMarginRequirement(parameters);
100  }
101 
102  /// <summary>
103  /// The margin that must be held in order to increase the position by the provided quantity
104  /// </summary>
105  /// <returns>The initial margin required for the provided security and quantity</returns>
107  {
108  var security = parameters.Security;
109  var quantity = parameters.Quantity;
110  var value = security.QuoteCurrency.ConversionRate
111  * security.SymbolProperties.ContractMultiplier
112  * security.Price
113  * quantity;
114 
115  // Initial margin requirement for long options is only the premium that is paid upfront
116  return new OptionInitialMargin(parameters.Quantity >= 0 ? 0 : value * GetMarginRequirement(security, quantity, value), value);
117  }
118 
119  /// <summary>
120  /// The percentage of the holding's absolute cost that must be held in free cash in order to avoid a margin call
121  /// </summary>
122  private decimal GetMaintenanceMarginRequirement(MaintenanceMarginParameters parameters)
123  {
124  return GetMarginRequirement(parameters.Security, parameters.Quantity, parameters.HoldingsCost);
125  }
126 
127  /// <summary>
128  /// Private method takes option security and its holding and returns required margin. Method considers all short positions naked.
129  /// </summary>
130  /// <param name="security">Option security</param>
131  /// <param name="quantity">Holding quantity</param>
132  /// <param name="value">Holding value</param>
133  /// <returns></returns>
134  private decimal GetMarginRequirement(Security security, decimal quantity, decimal value)
135  {
136  var option = (Option)security;
137 
138  if (value == 0m ||
139  option.Close == 0m ||
140  option.StrikePrice == 0m ||
141  option.Underlying == null ||
142  option.Underlying.Close == 0m)
143  {
144  return 0m;
145  }
146 
147  if (value > 0m)
148  {
149  return OptionMarginRequirement;
150  }
151 
152  var absValue = -value;
153  var optionProperties = (OptionSymbolProperties)option.SymbolProperties;
154  var underlying = option.Underlying;
155 
156  // inferring ratios of the option and its underlying to get underlying security value
157  var multiplierRatio = underlying.SymbolProperties.ContractMultiplier / optionProperties.ContractMultiplier;
158  var quantityRatio = optionProperties.ContractUnitOfTrade;
159 
160  // Some options are based on a fraction of their underlying security value, such as NQX for example. Thus,
161  // for them we need to scale the underlying value so that the later comparisons made with the option's strike
162  // value are correct
163  var priceRatio = (underlying.Close / option.SymbolProperties.StrikeMultiplier) / (absValue / quantityRatio);
164  var underlyingValueRatio = multiplierRatio * quantityRatio * priceRatio;
165 
166  // calculating underlying security value less out-of-the-money amount
167  var amountOTM = option.OutOfTheMoneyAmount(underlying.Close);
168  var priceRatioOTM = amountOTM / (absValue / quantityRatio);
169  var underlyingValueRatioOTM = multiplierRatio * quantityRatio * priceRatioOTM;
170 
171  var strikePriceRatio = option.StrikePrice / (absValue / quantityRatio);
172  strikePriceRatio = multiplierRatio * quantityRatio * strikePriceRatio;
173 
174  var nakedMarginRequirement = option.Right == OptionRight.Call
175  ? NakedPositionMarginRequirement * underlyingValueRatio
176  : NakedPositionMarginRequirement * strikePriceRatio;
177  var nakedMarginRequirementOtm = security.Type == SecurityType.Option
178  ? EquityOptionNakedPositionMarginRequirementOtm
179  : IndexOptionNakedPositionMarginRequirementOtm;
180 
181  return OptionMarginRequirement +
182  Math.Abs(quantity) * Math.Max(nakedMarginRequirement,
183  nakedMarginRequirementOtm * underlyingValueRatio - underlyingValueRatioOTM);
184  }
185  }
186 }