Lean  $LEAN_TAG$
FuturesOptionsMarginModel.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  /// Defines a margin model for future options (an option with a future as its underlying).
23  /// We re-use the <see cref="FutureMarginModel"/> implementation and multiply its results
24  /// by 1.5x to simulate the increased margins seen for future options.
25  /// </summary>
27  {
28  private readonly Option _futureOption;
29 
30  /// <summary>
31  /// Initial Overnight margin requirement for the contract effective from the date of change
32  /// </summary>
33  public override decimal InitialOvernightMarginRequirement => GetMarginRequirement(_futureOption, base.InitialOvernightMarginRequirement);
34 
35  /// <summary>
36  /// Maintenance Overnight margin requirement for the contract effective from the date of change
37  /// </summary>
38  public override decimal MaintenanceOvernightMarginRequirement => GetMarginRequirement(_futureOption, base.MaintenanceOvernightMarginRequirement);
39 
40  /// <summary>
41  /// Initial Intraday margin for the contract effective from the date of change
42  /// </summary>
43  public override decimal InitialIntradayMarginRequirement => GetMarginRequirement(_futureOption, base.InitialIntradayMarginRequirement);
44 
45  /// <summary>
46  /// Maintenance Intraday margin requirement for the contract effective from the date of change
47  /// </summary>
48  public override decimal MaintenanceIntradayMarginRequirement => GetMarginRequirement(_futureOption, base.MaintenanceIntradayMarginRequirement);
49 
50  /// <summary>
51  /// Creates an instance of FutureOptionMarginModel
52  /// </summary>
53  /// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required unused buying power for the account.</param>
54  /// <param name="futureOption">Option Security containing a Future security as the underlying</param>
55  public FuturesOptionsMarginModel(decimal requiredFreeBuyingPowerPercent = 0, Option futureOption = null) : base(requiredFreeBuyingPowerPercent, futureOption?.Underlying)
56  {
57  _futureOption = futureOption;
58  }
59 
60  /// <summary>
61  /// Gets the margin currently alloted to the specified holding.
62  /// </summary>
63  /// <param name="parameters">An object containing the security</param>
64  /// <returns>The maintenance margin required for the option</returns>
65  /// <remarks>
66  /// We fix the option to 1.5x the maintenance because of its close coupling with the underlying.
67  /// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long
68  /// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting
69  /// in a margin greater than the underlying's margin.
70  /// </remarks>
72  {
73  var underlyingRequirement = base.GetMaintenanceMargin(parameters.ForUnderlying(parameters.Quantity));
74  var positionSide = parameters.Quantity > 0 ? PositionSide.Long : PositionSide.Short;
75  return GetMarginRequirement(_futureOption, underlyingRequirement, positionSide);
76  }
77 
78  /// <summary>
79  /// The margin that must be held in order to increase the position by the provided quantity
80  /// </summary>
81  /// <param name="parameters">An object containing the security and quantity of shares</param>
82  /// <returns>The initial margin required for the option (i.e. the equity required to enter a position for this option)</returns>
83  /// <remarks>
84  /// We fix the option to 1.5x the initial because of its close coupling with the underlying.
85  /// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long
86  /// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting
87  /// in a margin greater than the underlying's margin.
88  /// </remarks>
90  {
91  var underlyingRequirement = base.GetInitialMarginRequirement(parameters.ForUnderlying()).Value;
92  var positionSide = parameters.Quantity > 0 ? PositionSide.Long : PositionSide.Short;
93 
94  return new InitialMargin(GetMarginRequirement(_futureOption, underlyingRequirement, positionSide));
95  }
96 
97  /// <summary>
98  /// Get's the margin requirement for a future option based on the underlying future margin requirement and the position side to trade.
99  /// FOPs margin requirement is an 'S' curve based on the underlying requirement around it's current price, see https://en.wikipedia.org/wiki/Logistic_function
100  /// </summary>
101  /// <param name="option">The future option contract to trade</param>
102  /// <param name="underlyingRequirement">The underlying future associated margin requirement</param>
103  /// <param name="positionSide">The position side to trade, long by default. This is because short positions require higher margin requirements</param>
104  public static int GetMarginRequirement(Option option, decimal underlyingRequirement, PositionSide positionSide = PositionSide.Long)
105  {
106  var maximumValue = underlyingRequirement;
107  var curveGrowthRate = -7.8m;
108  var underlyingPrice = option.Underlying.Price;
109 
110  // If the underlying price is 0, we can't calculate a margin requirement, so return the underlying requirement.
111  // This could be removed after GH issue #6523 is resolved.
112  if (option.Underlying == null || option.Underlying.Price == 0m)
113  {
114  return 0;
115  }
116 
117  if (positionSide == PositionSide.Short)
118  {
119  if (option.Right == OptionRight.Call)
120  {
121  // going short the curve growth rate is slower
122  curveGrowthRate = -4m;
123  // curve shifted to the right -> causes a margin requirement increase
124  underlyingPrice *= 1.5m;
125  }
126  else
127  {
128  // higher max requirements
129  maximumValue *= 1.25m;
130  // puts are inverter from calls
131  curveGrowthRate = 2.4m;
132  // curve shifted to the left -> causes a margin requirement increase
133  underlyingPrice *= 0.30m;
134  }
135  }
136  else
137  {
138  if (option.Right == OptionRight.Put)
139  {
140  // fastest change rate
141  curveGrowthRate = 9m;
142  }
143  else
144  {
145  maximumValue *= 1.20m;
146  }
147  }
148 
149  // we normalize the curve growth rate by dividing by the underlyings price
150  // this way, contracts with different order of magnitude price and strike (like CL & ES) share this logic
151  var denominator = Math.Pow(Math.E, (double) (-curveGrowthRate * (option.ScaledStrikePrice - underlyingPrice) / underlyingPrice));
152 
153  if (double.IsInfinity(denominator))
154  {
155  return 0;
156  }
157  if (denominator.IsNaNOrZero())
158  {
159  return (int) maximumValue;
160  }
161 
162  return (int) (maximumValue / (1 + denominator).SafeDecimalCast());
163  }
164  }
165 }