Lean  $LEAN_TAG$
OptionStrategyDefinitions.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;
17 using System.Collections.Immutable;
18 using System.Linq;
19 using System.Reflection;
20 
22 {
23  /// <summary>
24  /// Provides a listing of pre-defined <see cref="OptionStrategyDefinition"/>
25  /// These definitions are blueprints for <see cref="OptionStrategy"/> instances.
26  /// Factory functions for those can be found at <see cref="OptionStrategies"/>
27  /// </summary>
28  public static class OptionStrategyDefinitions
29  {
30  // lazy since 'AllDefinitions' is at top of file and static members are evaluated in order
31  private static readonly Lazy<ImmutableList<OptionStrategyDefinition>> All
32  = new Lazy<ImmutableList<OptionStrategyDefinition>>(() =>
34  .GetProperties(BindingFlags.Public | BindingFlags.Static)
35  .Where(property => property.PropertyType == typeof(OptionStrategyDefinition))
36  .Select(property => (OptionStrategyDefinition)property.GetValue(null))
37  .ToImmutableList()
38  );
39 
40  /// <summary>
41  /// Collection of all OptionStrategyDefinitions
42  /// </summary>
43  public static ImmutableList<OptionStrategyDefinition> AllDefinitions
44  {
45  get
46  {
47  var strategies = All.Value;
48 
49  return strategies
50  .SelectMany(optionStrategy => {
51  // when selling the strategy can get reverted and it's still valid, we need the definition to match against
52  var inverted = new OptionStrategyDefinition(optionStrategy.Name, optionStrategy.UnderlyingLots * -1,
53  optionStrategy.Legs.Select(leg => new OptionStrategyLegDefinition(leg.Right, leg.Quantity * -1, leg)));
54 
55  if (strategies.Any(strategy => strategy.UnderlyingLots == inverted.UnderlyingLots
56  && strategy.Legs.Count == inverted.Legs.Count
57  && strategy.Legs.All(leg => inverted.Legs.
58  Any(invertedLeg => invertedLeg.Right == leg.Right
59  && leg.Quantity == invertedLeg.Quantity
60  && leg.All(predicate => invertedLeg.Any(invertedPredicate => invertedPredicate.ToString() == predicate.ToString()))))))
61  {
62  // some strategies inverted have a different name we already know, let's skip those
63  return new[] { optionStrategy };
64  }
65  return new[] { optionStrategy, inverted };
66  })
67  .ToImmutableList();
68  }
69  }
70 
71  /// <summary>
72  /// Hold 1 lot of the underlying and sell 1 call contract
73  /// </summary>
74  /// <remarks>Inverse of the <see cref="ProtectiveCall"/></remarks>
75  public static OptionStrategyDefinition CoveredCall { get; }
76  = OptionStrategyDefinition.Create("Covered Call", 1,
78  );
79 
80  /// <summary>
81  /// Hold -1 lot of the underlying and buy 1 call contract
82  /// </summary>
83  /// <remarks>Inverse of the <see cref="CoveredCall"/></remarks>
85  = OptionStrategyDefinition.Create("Protective Call", -1,
87  );
88 
89  /// <summary>
90  /// Hold -1 lot of the underlying and sell 1 put contract
91  /// </summary>
92  /// <remarks>Inverse of the <see cref="ProtectivePut"/></remarks>
93  public static OptionStrategyDefinition CoveredPut { get; }
94  = OptionStrategyDefinition.Create("Covered Put", -1,
96  );
97 
98  /// <summary>
99  /// Hold 1 lot of the underlying and buy 1 put contract
100  /// </summary>
101  /// <remarks>Inverse of the <see cref="CoveredPut"/></remarks>
103  = OptionStrategyDefinition.Create("Protective Put", 1,
105  );
106 
107  /// <summary>
108  /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract.
109  /// The strike price of the short call is below the strike of the long put with the same expiration.
110  /// </summary>
111  /// <remarks>Combination of <see cref="CoveredCall"/> and <see cref="ProtectivePut"/></remarks>
113  = OptionStrategyDefinition.Create("Protective Collar", 1,
115  OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike < legs[0].Strike,
116  (legs, p) => p.Expiration == legs[0].Expiration)
117  );
118 
119  /// <summary>
120  /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract.
121  /// The strike price of the call and put are the same, with the same expiration.
122  /// </summary>
123  /// <remarks>A special case of <see cref="ProtectiveCollar"/></remarks>
124  public static OptionStrategyDefinition Conversion { get; }
125  = OptionStrategyDefinition.Create("Conversion", 1,
127  OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike == legs[0].Strike,
128  (legs, p) => p.Expiration == legs[0].Expiration)
129  );
130 
131  /// <summary>
132  /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract.
133  /// The strike price of the call and put are the same, with the same expiration.
134  /// </summary>
135  /// <remarks>Inverse of <see cref="Conversion"/></remarks>
137  = OptionStrategyDefinition.Create("Reverse Conversion", -1,
139  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
140  (legs, p) => p.Expiration == legs[0].Expiration)
141  );
142 
143  /// <summary>
144  /// Sell 1 call contract without holding the underlying
145  /// </summary>
146  public static OptionStrategyDefinition NakedCall { get; }
147  = OptionStrategyDefinition.Create("Naked Call",
149  );
150 
151  /// <summary>
152  /// Sell 1 put contract without holding the underlying
153  /// </summary>
154  public static OptionStrategyDefinition NakedPut { get; }
155  = OptionStrategyDefinition.Create("Naked Put",
157  );
158 
159  /// <summary>
160  /// Bear Call Spread strategy consists of two calls with the same expiration but different strikes.
161  /// The strike price of the short call is below the strike of the long call. This is a credit spread.
162  /// </summary>
164  = OptionStrategyDefinition.Create("Bear Call Spread",
166  OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[0].Strike,
167  (legs, p) => p.Expiration == legs[0].Expiration)
168  );
169 
170  /// <summary>
171  /// Bear Put Spread strategy consists of two puts with the same expiration but different strikes.
172  /// The strike price of the short put is below the strike of the long put. This is a debit spread.
173  /// </summary>
175  = OptionStrategyDefinition.Create("Bear Put Spread",
177  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike,
178  (legs, p) => p.Expiration == legs[0].Expiration)
179  );
180 
181  /// <summary>
182  /// Bull Call Spread strategy consists of two calls with the same expiration but different strikes.
183  /// The strike price of the short call is higher than the strike of the long call. This is a debit spread.
184  /// </summary>
186  = OptionStrategyDefinition.Create("Bull Call Spread",
188  OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[0].Strike,
189  (legs, p) => p.Expiration == legs[0].Expiration)
190  );
191 
192  /// <summary>
193  /// Method creates new Bull Put Spread strategy, that consists of two puts with the same expiration but
194  /// different strikes. The strike price of the short put is above the strike of the long put. This is a
195  /// credit spread.
196  /// </summary>
198  = OptionStrategyDefinition.Create("Bull Put Spread",
200  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike,
201  (legs, p) => p.Expiration == legs[0].Expiration)
202  );
203 
204  /// <summary>
205  /// Straddle strategy is a combination of buying a call and buying a put, both with the same strike price
206  /// and expiration.
207  /// </summary>
208  public static OptionStrategyDefinition Straddle { get; }
209  = OptionStrategyDefinition.Create("Straddle",
211  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike,
212  (legs, p) => p.Expiration == legs[0].Expiration)
213  );
214 
215  /// <summary>
216  /// Short Straddle strategy is a combination of selling a call and selling a put, both with the same strike price
217  /// and expiration.
218  /// </summary>
219  /// <remarks>Inverse of the <see cref="Straddle"/></remarks>
221  = OptionStrategyDefinition.Create("Short Straddle",
223  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
224  (legs, p) => p.Expiration == legs[0].Expiration)
225  );
226 
227  /// <summary>
228  /// Strangle strategy consists of buying a call option and a put option with the same expiration date.
229  /// The strike price of the call is above the strike of the put.
230  /// </summary>
231  public static OptionStrategyDefinition Strangle { get; }
232  = OptionStrategyDefinition.Create("Strangle",
234  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike,
235  (legs, p) => p.Expiration == legs[0].Expiration)
236  );
237 
238  /// <summary>
239  /// Strangle strategy consists of selling a call option and a put option with the same expiration date.
240  /// The strike price of the call is above the strike of the put.
241  /// </summary>
242  /// <remarks>Inverse of the <see cref="Strangle"/></remarks>
244  = OptionStrategyDefinition.Create("Short Strangle",
246  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike,
247  (legs, p) => p.Expiration == legs[0].Expiration)
248  );
249 
250  /// <summary>
251  /// Short Butterfly Call strategy consists of two short calls at a middle strike, and one long call each at a lower
252  /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike.
253  /// </summary>
255  = OptionStrategyDefinition.Create("Butterfly Call",
257  OptionStrategyDefinition.CallLeg(-2, (legs, p) => p.Strike >= legs[0].Strike,
258  (legs, p) => p.Expiration == legs[0].Expiration),
259  OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike >= legs[1].Strike,
260  (legs, p) => p.Expiration == legs[0].Expiration,
261  (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike)
262  );
263 
264  /// <summary>
265  /// Butterfly Call strategy consists of two long calls at a middle strike, and one short call each at a lower
266  /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike.
267  /// </summary>
269  = OptionStrategyDefinition.Create("Short Butterfly Call",
271  OptionStrategyDefinition.CallLeg(+2, (legs, p) => p.Strike >= legs[0].Strike,
272  (legs, p) => p.Expiration == legs[0].Expiration),
273  OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike >= legs[1].Strike,
274  (legs, p) => p.Expiration == legs[0].Expiration,
275  (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike)
276  );
277 
278  /// <summary>
279  /// Butterfly Put strategy consists of two short puts at a middle strike, and one long put each at a lower and
280  /// upper strike. The upper and lower strikes must both be equidistant from the middle strike.
281  /// </summary>
282  public static OptionStrategyDefinition ButterflyPut { get; }
283  = OptionStrategyDefinition.Create("Butterfly Put",
285  OptionStrategyDefinition.PutLeg(-2, (legs, p) => p.Strike >= legs[0].Strike,
286  (legs, p) => p.Expiration == legs[0].Expiration),
287  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike >= legs[1].Strike,
288  (legs, p) => p.Expiration == legs[0].Expiration,
289  (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike)
290  );
291 
292 
293  /// <summary>
294  /// Short Butterfly Put strategy consists of two long puts at a middle strike, and one short put each at a lower and
295  /// upper strike. The upper and lower strikes must both be equidistant from the middle strike.
296  /// </summary>
298  = OptionStrategyDefinition.Create("Short Butterfly Put",
300  OptionStrategyDefinition.PutLeg(+2, (legs, p) => p.Strike >= legs[0].Strike,
301  (legs, p) => p.Expiration == legs[0].Expiration),
302  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike >= legs[1].Strike,
303  (legs, p) => p.Expiration == legs[0].Expiration,
304  (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike)
305  );
306 
307  /// <summary>
308  /// Call Calendar Spread strategy is a short one call option and long a second call option with a more distant
309  /// expiration.
310  /// </summary>
312  = OptionStrategyDefinition.Create("Call Calendar Spread",
314  OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike == legs[0].Strike,
315  (legs, p) => p.Expiration > legs[0].Expiration)
316  );
317 
318  /// <summary>
319  /// Short Call Calendar Spread strategy is long one call option and short a second call option with a more distant
320  /// expiration.
321  /// </summary>
322  /// <remarks>Inverse of the <see cref="CallCalendarSpread"/></remarks>
324  = OptionStrategyDefinition.Create("Short Call Calendar Spread",
326  OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
327  (legs, p) => p.Expiration > legs[0].Expiration)
328  );
329 
330  /// <summary>
331  /// Put Calendar Spread strategy is a short one put option and long a second put option with a more distant
332  /// expiration.
333  /// </summary>
335  = OptionStrategyDefinition.Create("Put Calendar Spread",
337  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike,
338  (legs, p) => p.Expiration > legs[0].Expiration)
339  );
340 
341  /// <summary>
342  /// Short Put Calendar Spread strategy is long one put option and short a second put option with a more distant
343  /// expiration.
344  /// </summary>
345  /// <remarks>Inverse of the <see cref="PutCalendarSpread"/></remarks>
347  = OptionStrategyDefinition.Create("Short Put Calendar Spread",
349  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
350  (legs, p) => p.Expiration > legs[0].Expiration)
351  );
352 
353  /// <summary>
354  /// Iron Butterfly strategy consists of a short ATM call, a short ATM put, a long OTM call, and a long OTM put.
355  /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date.
356  /// </summary>
358  = OptionStrategyDefinition.Create("Iron Butterfly",
360  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike,
361  (legs, p) => p.Expiration == legs[0].Expiration),
362  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike,
363  (legs, c) => c.Expiration == legs[0].Expiration),
364  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike,
365  (legs, c) => c.Expiration == legs[0].Expiration)
366  );
367 
368  /// <summary>
369  /// Short Iron Butterfly strategy consists of a long ATM call, a long ATM put, a short OTM call, and a short OTM put.
370  /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date.
371  /// </summary>
373  = OptionStrategyDefinition.Create("Short Iron Butterfly",
375  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike,
376  (legs, p) => p.Expiration == legs[0].Expiration),
377  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike,
378  (legs, c) => c.Expiration == legs[0].Expiration),
379  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike,
380  (legs, c) => c.Expiration == legs[0].Expiration)
381  );
382 
383  /// <summary>
384  /// Iron Condor strategy is buying a put, selling a put with a higher strike price, selling a call and buying a call with a higher strike price.
385  /// All at the same expiration date
386  /// </summary>
387  public static OptionStrategyDefinition IronCondor { get; }
388  = OptionStrategyDefinition.Create("Iron Condor",
390  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike > legs[0].Strike,
391  (legs, p) => p.Expiration == legs[0].Expiration),
392  OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[1].Strike,
393  (legs, p) => p.Expiration == legs[0].Expiration),
394  OptionStrategyDefinition.CallLeg(1, (legs, p) => p.Strike > legs[2].Strike,
395  (legs, p) => p.Expiration == legs[0].Expiration)
396  );
397 
398  /// <summary>
399  /// Short Iron Condor strategy is selling a put, buying a put with a higher strike price, buying a call and selling a call with a higher strike price.
400  /// All at the same expiration date
401  /// </summary>
403  = OptionStrategyDefinition.Create("Short Iron Condor",
405  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike > legs[0].Strike,
406  (legs, p) => p.Expiration == legs[0].Expiration),
407  OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[1].Strike,
408  (legs, p) => p.Expiration == legs[0].Expiration),
409  OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[2].Strike,
410  (legs, p) => p.Expiration == legs[0].Expiration)
411  );
412 
413  /// <summary>
414  /// Long Box Spread strategy is long 1 call and short 1 put with the same strike,
415  /// while short 1 call and long 1 put with a higher, same strike. All options have the same expiry.
416  /// expiration.
417  /// </summary>
418  public static OptionStrategyDefinition BoxSpread { get; }
419  = OptionStrategyDefinition.Create("Box Spread",
421  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike,
422  (legs, p) => p.Expiration == legs[0].Expiration),
423  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[1].Strike,
424  (legs, c) => c.Expiration == legs[0].Expiration),
425  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike,
426  (legs, c) => c.Expiration == legs[0].Expiration)
427  );
428 
429  /// <summary>
430  /// Short Box Spread strategy is short 1 call and long 1 put with the same strike,
431  /// while long 1 call and short 1 put with a higher, same strike. All options have the same expiry.
432  /// expiration.
433  /// </summary>
435  = OptionStrategyDefinition.Create("Short Box Spread",
437  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike,
438  (legs, p) => p.Expiration == legs[0].Expiration),
439  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[1].Strike,
440  (legs, c) => c.Expiration == legs[0].Expiration),
441  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike,
442  (legs, c) => c.Expiration == legs[0].Expiration)
443  );
444 
445  /// <summary>
446  /// Jelly Roll is short 1 call and long 1 call with the same strike but further expiry, together with
447  /// long 1 put and short 1 put with the same strike and expiries as calls.
448  /// </summary>
449  public static OptionStrategyDefinition JellyRoll { get; }
450  = OptionStrategyDefinition.Create("Jelly Roll",
452  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike,
453  (legs, c) => c.Expiration > legs[0].Expiration),
454  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike,
455  (legs, p) => p.Expiration == legs[0].Expiration),
456  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
457  (legs, p) => p.Expiration == legs[1].Expiration)
458  );
459 
460  /// <summary>
461  /// Short Jelly Roll is long 1 call and short 1 call with the same strike but further expiry, together with
462  /// short 1 put and long 1 put with the same strike and expiries as calls.
463  /// </summary>
465  = OptionStrategyDefinition.Create("Short Jelly Roll",
467  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike,
468  (legs, c) => c.Expiration > legs[0].Expiration),
469  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike,
470  (legs, p) => p.Expiration == legs[0].Expiration),
471  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike,
472  (legs, p) => p.Expiration == legs[1].Expiration)
473  );
474 
475  /// <summary>
476  /// Bear Call Ladder strategy is short 1 call and long 2 calls, with ascending strike prices in order,
477  /// All options have the same expiry.
478  /// </summary>
480  = OptionStrategyDefinition.Create("Bear Call Ladder",
482  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[0].Strike,
483  (legs, c) => c.Expiration == legs[0].Expiration),
484  OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[1].Strike,
485  (legs, c) => c.Expiration == legs[0].Expiration)
486  );
487 
488  /// <summary>
489  /// Bear Put Ladder strategy is long 1 put and short 2 puts, with descending strike prices in order,
490  /// All options have the same expiry.
491  /// </summary>
493  = OptionStrategyDefinition.Create("Bear Put Ladder",
495  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike,
496  (legs, p) => p.Expiration == legs[0].Expiration),
497  OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[1].Strike,
498  (legs, p) => p.Expiration == legs[0].Expiration)
499  );
500 
501  /// <summary>
502  /// Bull Call Ladder strategy is long 1 call and short 2 calls, with ascending strike prices in order,
503  /// All options have the same expiry.
504  /// </summary>
506  = OptionStrategyDefinition.Create("Bull Call Ladder",
508  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[0].Strike,
509  (legs, c) => c.Expiration == legs[0].Expiration),
510  OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[1].Strike,
511  (legs, c) => c.Expiration == legs[0].Expiration)
512  );
513 
514  /// <summary>
515  /// Bull Put Ladder strategy is short 1 put and long 2 puts, with descending strike prices in order,
516  /// All options have the same expiry.
517  /// </summary>
519  = OptionStrategyDefinition.Create("Bull Put Ladder",
521  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike,
522  (legs, p) => p.Expiration == legs[0].Expiration),
523  OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[1].Strike,
524  (legs, p) => p.Expiration == legs[0].Expiration)
525  );
526  }
527 }