Lean  $LEAN_TAG$
OptionStrategies.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.Generic;
18 using System.Linq;
20 
22 {
23  /// <summary>
24  /// Provides methods for creating popular <see cref="OptionStrategy"/> instances.
25  /// These strategies can be directly bought and sold via:
26  /// QCAlgorithm.Buy(OptionStrategy strategy, int quantity)
27  /// QCAlgorithm.Sell(OptionStrategy strategy, int quantity)
28  ///
29  /// See also <see cref="OptionStrategyDefinitions"/>
30  /// </summary>
31  public static class OptionStrategies
32  {
33  /// <summary>
34  /// Symbol properties database to use to get contract multipliers
35  /// </summary>
36  private static SymbolPropertiesDatabase _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();
37 
38  /// <summary>
39  /// Creates a Covered Call strategy that consists of selling one call contract and buying 1 lot of the underlying.
40  /// </summary>
41  /// <param name="canonicalOption">Option symbol</param>
42  /// <param name="strike">The strike price for the call option contract</param>
43  /// <param name="expiration">The expiration date for the call option contract</param>
44  /// <returns>Option strategy specification</returns>
45  public static OptionStrategy CoveredCall(Symbol canonicalOption, decimal strike, DateTime expiration)
46  {
47  CheckCanonicalOptionSymbol(canonicalOption, "CoveredCall");
48  CheckExpirationDate(expiration, "CoveredCall", nameof(expiration));
49 
50  var underlyingQuantity = (int)_symbolPropertiesDatabase.GetSymbolProperties(canonicalOption.ID.Market, canonicalOption,
51  canonicalOption.SecurityType, "").ContractMultiplier;
52 
53  return new OptionStrategy
54  {
56  Underlying = canonicalOption.Underlying,
57  CanonicalOption = canonicalOption,
58  OptionLegs = new List<OptionStrategy.OptionLegData>
59  {
61  {
62  Right = OptionRight.Call, Strike = strike, Quantity = -1, Expiration = expiration
63  }
64  },
65  UnderlyingLegs = new List<OptionStrategy.UnderlyingLegData>
66  {
68  {
69  Quantity = underlyingQuantity, Symbol = canonicalOption.Underlying
70  }
71  }
72  };
73  }
74 
75  /// <summary>
76  /// Creates a Protective Call strategy that consists of buying one call contract and selling 1 lot of the underlying.
77  /// </summary>
78  /// <param name="canonicalOption">Option symbol</param>
79  /// <param name="strike">The strike price for the call option contract</param>
80  /// <param name="expiration">The expiration date for the call option contract</param>
81  /// <returns>Option strategy specification</returns>
82  public static OptionStrategy ProtectiveCall(Symbol canonicalOption, decimal strike, DateTime expiration)
83  {
84  // Since a protective call is an inverted covered call, we can just use the CoveredCall method and invert the legs
85  return InvertStrategy(CoveredCall(canonicalOption, strike, expiration), OptionStrategyDefinitions.ProtectiveCall.Name);
86  }
87 
88  /// <summary>
89  /// Creates a Covered Put strategy that consists of selling 1 put contract and 1 lot of the underlying.
90  /// </summary>
91  /// <param name="canonicalOption">Option symbol</param>
92  /// <param name="strike">The strike price for the put option contract</param>
93  /// <param name="expiration">The expiration date for the put option contract</param>
94  /// <returns>Option strategy specification</returns>
95  public static OptionStrategy CoveredPut(Symbol canonicalOption, decimal strike, DateTime expiration)
96  {
97  CheckCanonicalOptionSymbol(canonicalOption, "CoveredPut");
98  CheckExpirationDate(expiration, "CoveredPut", nameof(expiration));
99 
100  var underlyingQuantity = -(int)_symbolPropertiesDatabase.GetSymbolProperties(canonicalOption.ID.Market, canonicalOption,
101  canonicalOption.SecurityType, "").ContractMultiplier;
102 
103  return new OptionStrategy
104  {
106  Underlying = canonicalOption.Underlying,
107  CanonicalOption = canonicalOption,
108  OptionLegs = new List<OptionStrategy.OptionLegData>
109  {
111  {
112  Right = OptionRight.Put, Strike = strike, Quantity = -1, Expiration = expiration
113  }
114  },
115  UnderlyingLegs = new List<OptionStrategy.UnderlyingLegData>
116  {
118  {
119  Quantity = underlyingQuantity, Symbol = canonicalOption.Underlying
120  }
121  }
122  };
123  }
124 
125  /// <summary>
126  /// Creates a Protective Put strategy that consists of buying 1 put contract and 1 lot of the underlying.
127  /// </summary>
128  /// <param name="canonicalOption">Option symbol</param>
129  /// <param name="strike">The strike price for the put option contract</param>
130  /// <param name="expiration">The expiration date for the put option contract</param>
131  /// <returns>Option strategy specification</returns>
132  public static OptionStrategy ProtectivePut(Symbol canonicalOption, decimal strike, DateTime expiration)
133  {
134  // Since a protective put is an inverted covered put, we can just use the CoveredPut method and invert the legs
135  return InvertStrategy(CoveredPut(canonicalOption, strike, expiration), OptionStrategyDefinitions.ProtectivePut.Name);
136  }
137 
138  /// <summary>
139  /// Creates a Naked Call strategy that consists of selling 1 call contract.
140  /// </summary>
141  /// <param name="canonicalOption">Option symbol</param>
142  /// <param name="strike">The strike price for the call option contract</param>
143  /// <param name="expiration">The expiration date for the call option contract</param>
144  /// <returns>Option strategy specification</returns>
145  public static OptionStrategy NakedCall(Symbol canonicalOption, decimal strike, DateTime expiration)
146  {
147  CheckCanonicalOptionSymbol(canonicalOption, "NakedCall");
148  CheckExpirationDate(expiration, "NakedCall", nameof(expiration));
149 
150  return new OptionStrategy
151  {
153  Underlying = canonicalOption.Underlying,
154  CanonicalOption = canonicalOption,
155  OptionLegs = new List<OptionStrategy.OptionLegData>
156  {
158  {
159  Right = OptionRight.Call, Strike = strike, Quantity = -1, Expiration = expiration
160  }
161  }
162  };
163  }
164 
165  /// <summary>
166  /// Creates a Naked Put strategy that consists of selling 1 put contract.
167  /// </summary>
168  /// <param name="canonicalOption">Option symbol</param>
169  /// <param name="strike">The strike price for the put option contract</param>
170  /// <param name="expiration">The expiration date for the put option contract</param>
171  /// <returns>Option strategy specification</returns>
172  public static OptionStrategy NakedPut(Symbol canonicalOption, decimal strike, DateTime expiration)
173  {
174  CheckCanonicalOptionSymbol(canonicalOption, "NakedPut");
175  CheckExpirationDate(expiration, "NakedPut", nameof(expiration));
176 
177  return new OptionStrategy
178  {
180  Underlying = canonicalOption.Underlying,
181  CanonicalOption = canonicalOption,
182  OptionLegs = new List<OptionStrategy.OptionLegData>
183  {
185  {
186  Right = OptionRight.Put, Strike = strike, Quantity = -1, Expiration = expiration
187  }
188  }
189  };
190  }
191 
192  /// <summary>
193  /// Method creates new Bear Call Spread strategy, that consists of two calls with the same expiration but different strikes.
194  /// The strike price of the short call is below the strike of the long call. This is a credit spread.
195  /// </summary>
196  /// <param name="canonicalOption">Option symbol</param>
197  /// <param name="leg1Strike">The strike price of the short call</param>
198  /// <param name="leg2Strike">The strike price of the long call</param>
199  /// <param name="expiration">Option expiration date</param>
200  /// <returns>Option strategy specification</returns>
202  Symbol canonicalOption,
203  decimal leg1Strike,
204  decimal leg2Strike,
205  DateTime expiration
206  )
207  {
208  CheckCanonicalOptionSymbol(canonicalOption, "BearCallSpread");
209  CheckExpirationDate(expiration, "BearCallSpread", nameof(expiration));
210 
211  if (leg1Strike >= leg2Strike)
212  {
213  throw new ArgumentException("BearCallSpread: leg1Strike must be less than leg2Strike", $"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
214  }
215 
216  return new OptionStrategy
217  {
219  Underlying = canonicalOption.Underlying,
220  CanonicalOption = canonicalOption,
221  OptionLegs = new List<OptionStrategy.OptionLegData>
222  {
224  {
225  Right = OptionRight.Call, Strike = leg1Strike, Quantity = -1, Expiration = expiration
226  },
228  {
229  Right = OptionRight.Call, Strike = leg2Strike, Quantity = 1, Expiration = expiration
230  }
231  }
232  };
233  }
234 
235  /// <summary>
236  /// Method creates new Bear Put Spread strategy, that consists of two puts with the same expiration but different strikes.
237  /// The strike price of the short put is below the strike of the long put. This is a debit spread.
238  /// </summary>
239  /// <param name="canonicalOption">Option symbol</param>
240  /// <param name="leg1Strike">The strike price of the long put</param>
241  /// <param name="leg2Strike">The strike price of the short put</param>
242  /// <param name="expiration">Option expiration date</param>
243  /// <returns>Option strategy specification</returns>
245  Symbol canonicalOption,
246  decimal leg1Strike,
247  decimal leg2Strike,
248  DateTime expiration
249  )
250  {
251  CheckCanonicalOptionSymbol(canonicalOption, "BearPutSpread");
252  CheckExpirationDate(expiration, "BearPutSpread", nameof(expiration));
253 
254  if (leg1Strike <= leg2Strike)
255  {
256  throw new ArgumentException("BearPutSpread: leg1Strike must be greater than leg2Strike", $"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
257  }
258 
259  return new OptionStrategy
260  {
262  Underlying = canonicalOption.Underlying,
263  CanonicalOption = canonicalOption,
264  OptionLegs = new List<OptionStrategy.OptionLegData>
265  {
267  {
268  Right = OptionRight.Put, Strike = leg1Strike, Quantity = 1,
269  Expiration = expiration
270  },
272  {
273  Right = OptionRight.Put, Strike = leg2Strike, Quantity = -1, Expiration = expiration
274  }
275  }
276  };
277  }
278 
279  /// <summary>
280  /// Method creates new Bull Call Spread strategy, that consists of two calls with the same expiration but different strikes.
281  /// The strike price of the short call is higher than the strike of the long call. This is a debit spread.
282  /// </summary>
283  /// <param name="canonicalOption">Option symbol</param>
284  /// <param name="leg1Strike">The strike price of the long call</param>
285  /// <param name="leg2Strike">The strike price of the short call</param>
286  /// <param name="expiration">Option expiration date</param>
287  /// <returns>Option strategy specification</returns>
289  Symbol canonicalOption,
290  decimal leg1Strike,
291  decimal leg2Strike,
292  DateTime expiration
293  )
294  {
295  CheckCanonicalOptionSymbol(canonicalOption, "BullCallSpread");
296  CheckExpirationDate(expiration, "BullCallSpread", nameof(expiration));
297 
298  if (leg1Strike >= leg2Strike)
299  {
300  throw new ArgumentException("BullCallSpread: leg1Strike must be less than leg2Strike", $"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
301  }
302 
303  return new OptionStrategy
304  {
306  Underlying = canonicalOption.Underlying,
307  CanonicalOption = canonicalOption,
308  OptionLegs = new List<OptionStrategy.OptionLegData>
309  {
311  {
312  Right = OptionRight.Call, Strike = leg1Strike, Quantity = 1, Expiration = expiration
313  },
315  {
316  Right = OptionRight.Call, Strike = leg2Strike, Quantity = -1, Expiration = expiration
317  }
318  }
319  };
320  }
321 
322  /// <summary>
323  /// Method creates new Bull Put Spread strategy, that consists of two puts with the same expiration but different strikes.
324  /// The strike price of the short put is above the strike of the long put. This is a credit spread.
325  /// </summary>
326  /// <param name="canonicalOption">Option symbol</param>
327  /// <param name="leg1Strike">The strike price of the short put</param>
328  /// <param name="leg2Strike">The strike price of the long put</param>
329  /// <param name="expiration">Option expiration date</param>
330  /// <returns>Option strategy specification</returns>
332  Symbol canonicalOption,
333  decimal leg1Strike,
334  decimal leg2Strike,
335  DateTime expiration
336  )
337  {
338  CheckCanonicalOptionSymbol(canonicalOption, "BullPutSpread");
339  CheckExpirationDate(expiration, "BullPutSpread", nameof(expiration));
340 
341  if (leg1Strike <= leg2Strike)
342  {
343  throw new ArgumentException("BullPutSpread: leg1Strike must be greater than leg2Strike", $"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
344  }
345 
346  return new OptionStrategy
347  {
349  Underlying = canonicalOption.Underlying,
350  CanonicalOption = canonicalOption,
351  OptionLegs = new List<OptionStrategy.OptionLegData>
352  {
354  {
355  Right = OptionRight.Put, Strike = leg1Strike, Quantity = -1, Expiration = expiration
356  },
358  {
359  Right = OptionRight.Put, Strike = leg2Strike, Quantity = 1,
360  Expiration = expiration
361  }
362  }
363  };
364  }
365 
366  /// <summary>
367  /// Method creates new Straddle strategy, that is a combination of buying a call and buying a put, both with the same strike price and expiration.
368  /// </summary>
369  /// <param name="canonicalOption">Option symbol</param>
370  /// <param name="strike">The strike price of the both legs</param>
371  /// <param name="expiration">Option expiration date</param>
372  /// <returns>Option strategy specification</returns>
373  public static OptionStrategy Straddle(Symbol canonicalOption, decimal strike, DateTime expiration)
374  {
375  CheckCanonicalOptionSymbol(canonicalOption, "Straddle");
376  CheckExpirationDate(expiration, "Straddle", nameof(expiration));
377 
378  return new OptionStrategy
379  {
381  Underlying = canonicalOption.Underlying,
382  CanonicalOption = canonicalOption,
383  OptionLegs = new List<OptionStrategy.OptionLegData>
384  {
386  {
387  Right = OptionRight.Call, Strike = strike, Quantity = 1,
388  Expiration = expiration
389  },
391  {
392  Right = OptionRight.Put, Strike = strike, Quantity = 1,
393  Expiration = expiration
394  }
395  }
396  };
397  }
398 
399  /// <summary>
400  /// Creates a Short Straddle strategy that consists of selling a call and a put, both with the same strike price and expiration.
401  /// </summary>
402  /// <param name="canonicalOption">Option symbol</param>
403  /// <param name="strike">The strike price for the option contracts</param>
404  /// <param name="expiration">The expiration date for the option contracts</param>
405  /// <returns>Option strategy specification</returns>
406  public static OptionStrategy ShortStraddle(Symbol canonicalOption, decimal strike, DateTime expiration)
407  {
408  // Since a short straddle is an inverted straddle, we can just use the Straddle method and invert the legs
409  return InvertStrategy(Straddle(canonicalOption, strike, expiration), OptionStrategyDefinitions.ShortStraddle.Name);
410  }
411 
412  /// <summary>
413  /// Method creates new Strangle strategy, that buying a call option and a put option with the same expiration date
414  /// The strike price of the call is above the strike of the put.
415  /// </summary>
416  /// <param name="canonicalOption">Option symbol</param>
417  /// <param name="callLegStrike">The strike price of the long call</param>
418  /// <param name="putLegStrike">The strike price of the long put</param>
419  /// <param name="expiration">Option expiration date</param>
420  /// <returns>Option strategy specification</returns>
421  public static OptionStrategy Strangle(
422  Symbol canonicalOption,
423  decimal callLegStrike,
424  decimal putLegStrike,
425  DateTime expiration
426  )
427  {
428  CheckCanonicalOptionSymbol(canonicalOption, "Strangle");
429  CheckExpirationDate(expiration, "Strangle", nameof(expiration));
430 
431  if (callLegStrike <= putLegStrike)
432  {
433  throw new ArgumentException($"Strangle: {nameof(callLegStrike)} must be greater than {nameof(putLegStrike)}",
434  $"{nameof(callLegStrike)}, {nameof(putLegStrike)}");
435  }
436 
437  return new OptionStrategy
438  {
440  Underlying = canonicalOption.Underlying,
441  CanonicalOption = canonicalOption,
442  OptionLegs = new List<OptionStrategy.OptionLegData>
443  {
445  {
446  Right = OptionRight.Call, Strike = callLegStrike, Quantity = 1, Expiration = expiration
447  },
449  {
450  Right = OptionRight.Put, Strike = putLegStrike, Quantity = 1, Expiration = expiration
451  }
452  }
453  };
454  }
455 
456  /// <summary>
457  /// Creates a Short Strangle strategy that consists of selling a call and a put, with the same expiration date and
458  /// the call strike being above the put strike.
459  /// </summary>
460  /// <param name="canonicalOption">Option symbol</param>
461  /// <param name="callLegStrike">The strike price of the short call</param>
462  /// <param name="putLegStrike">The strike price of the short put</param>
463  /// <param name="expiration">Option expiration date</param>
464  /// <returns>Option strategy specification</returns>
465  public static OptionStrategy ShortStrangle(Symbol canonicalOption, decimal callLegStrike, decimal putLegStrike, DateTime expiration)
466  {
467  // Since a short strangle is an inverted strangle, we can just use the Strangle method and invert the legs
468  return InvertStrategy(Strangle(canonicalOption, callLegStrike, putLegStrike, expiration), OptionStrategyDefinitions.ShortStrangle.Name);
469  }
470 
471  /// <summary>
472  /// Method creates new Call Butterfly strategy, that consists of two short calls at a middle strike, and one long call each at a lower and upper strike.
473  /// The upper and lower strikes must both be equidistant from the middle strike.
474  /// </summary>
475  /// <param name="canonicalOption">Option symbol</param>
476  /// <param name="higherStrike">The upper strike price of the long call</param>
477  /// <param name="middleStrike">The middle strike price of the two short calls</param>
478  /// <param name="lowerStrike">The lower strike price of the long call</param>
479  /// <param name="expiration">Option expiration date</param>
480  /// <returns>Option strategy specification</returns>
482  Symbol canonicalOption,
483  decimal higherStrike,
484  decimal middleStrike,
485  decimal lowerStrike,
486  DateTime expiration
487  )
488  {
489  CheckCanonicalOptionSymbol(canonicalOption, "CallButterfly");
490  CheckExpirationDate(expiration, "CallButterfly", nameof(expiration));
491 
492  if (higherStrike <= middleStrike ||
493  lowerStrike >= middleStrike ||
494  higherStrike - middleStrike != middleStrike - lowerStrike)
495  {
496  throw new ArgumentException("ButterflyCall: upper and lower strikes must both be equidistant from the middle strike",
497  $"{nameof(higherStrike)}, {nameof(middleStrike)}, {nameof(lowerStrike)}");
498  }
499 
500  return new OptionStrategy
501  {
503  Underlying = canonicalOption.Underlying,
504  CanonicalOption = canonicalOption,
505  OptionLegs = new List<OptionStrategy.OptionLegData>
506  {
508  {
509  Right = OptionRight.Call, Strike = higherStrike, Quantity = 1, Expiration = expiration
510  },
512  {
513  Right = OptionRight.Call, Strike = middleStrike, Quantity = -2, Expiration = expiration
514  },
516  {
517  Right = OptionRight.Call, Strike = lowerStrike, Quantity = 1, Expiration = expiration
518  }
519  }
520  };
521  }
522 
523  /// <summary>
524  /// Creates a new Butterfly Call strategy that consists of two short calls at a middle strike,
525  /// and one long call each at a lower and upper strike.
526  /// The upper and lower strikes must both be equidistant from the middle strike.
527  /// </summary>
528  /// <param name="canonicalOption">Option symbol</param>
529  /// <param name="higherStrike">The upper strike price of the long call</param>
530  /// <param name="middleStrike">The middle strike price of the two short calls</param>
531  /// <param name="lowerStrike">The lower strike price of the long call</param>
532  /// <param name="expiration">Option expiration date</param>
533  /// <returns>Option strategy specification</returns>
534  /// <remarks>Alias for <see cref="CallButterfly" /></remarks>
535  public static OptionStrategy ButterflyCall(Symbol canonicalOption, decimal higherStrike, decimal middleStrike, decimal lowerStrike,
536  DateTime expiration)
537  {
538  return CallButterfly(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration);
539  }
540 
541  /// <summary>
542  /// Creates a new Butterfly Call strategy that consists of two long calls at a middle strike,
543  /// and one short call each at a lower and upper strike.
544  /// The upper and lower strikes must both be equidistant from the middle strike.
545  /// </summary>
546  /// <param name="canonicalOption">Option symbol</param>
547  /// <param name="higherStrike">The upper strike price of the short call</param>
548  /// <param name="middleStrike">The middle strike price of the two long calls</param>
549  /// <param name="lowerStrike">The lower strike price of the short call</param>
550  /// <param name="expiration">Option expiration date</param>
551  /// <returns>Option strategy specification</returns>
552  public static OptionStrategy ShortButterflyCall(Symbol canonicalOption, decimal higherStrike, decimal middleStrike, decimal lowerStrike,
553  DateTime expiration)
554  {
555  // Since a short butterfly call is an inverted butterfly call, we can just use the ButterflyCall method and invert the legs
556  return InvertStrategy(ButterflyCall(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration),
558  }
559 
560  /// <summary>
561  /// Method creates new Put Butterfly strategy, that consists of two short puts at a middle strike, and one long put each at a lower and upper strike.
562  /// The upper and lower strikes must both be equidistant from the middle strike.
563  /// </summary>
564  /// <param name="canonicalOption">Option symbol</param>
565  /// <param name="higherStrike">The upper strike price of the long put</param>
566  /// <param name="middleStrike">The middle strike price of the two short puts</param>
567  /// <param name="lowerStrike">The lower strike price of the long put</param>
568  /// <param name="expiration">Option expiration date</param>
569  /// <returns>Option strategy specification</returns>
571  Symbol canonicalOption,
572  decimal higherStrike,
573  decimal middleStrike,
574  decimal lowerStrike,
575  DateTime expiration
576  )
577  {
578  CheckCanonicalOptionSymbol(canonicalOption, "PutButterfly");
579  CheckExpirationDate(expiration, "PutButterfly", nameof(expiration));
580 
581  if (higherStrike <= middleStrike ||
582  lowerStrike >= middleStrike ||
583  higherStrike - middleStrike != middleStrike - lowerStrike)
584  {
585  throw new ArgumentException("ButterflyPut: upper and lower strikes must both be equidistant from the middle strike",
586  $"{nameof(higherStrike)}, {nameof(middleStrike)}, {nameof(lowerStrike)}");
587  }
588 
589  return new OptionStrategy
590  {
592  Underlying = canonicalOption.Underlying,
593  CanonicalOption = canonicalOption,
594  OptionLegs = new List<OptionStrategy.OptionLegData>
595  {
597  {
598  Right = OptionRight.Put, Strike = higherStrike, Quantity = 1,
599  Expiration = expiration
600  },
602  {
603  Right = OptionRight.Put, Strike = middleStrike, Quantity = -2,
604  Expiration = expiration
605  },
607  {
608  Right = OptionRight.Put, Strike = lowerStrike, Quantity = 1,
609  Expiration = expiration
610  }
611  }
612  };
613  }
614 
615  /// <summary>
616  /// Creates a new Butterfly Put strategy that consists of two short puts at a middle strike,
617  /// and one long put each at a lower and upper strike.
618  /// The upper and lower strikes must both be equidistant from the middle strike.
619  /// </summary>
620  /// <param name="canonicalOption">Option symbol</param>
621  /// <param name="higherStrike">The upper strike price of the long put</param>
622  /// <param name="middleStrike">The middle strike price of the two short puts</param>
623  /// <param name="lowerStrike">The lower strike price of the long put</param>
624  /// <param name="expiration">Option expiration date</param>
625  /// <returns>Option strategy specification</returns>
626  /// <remarks>Alias for <see cref="PutButterfly" /></remarks>
627  public static OptionStrategy ButterflyPut(Symbol canonicalOption, decimal higherStrike, decimal middleStrike, decimal lowerStrike,
628  DateTime expiration)
629  {
630  return PutButterfly(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration);
631  }
632 
633  /// <summary>
634  /// Creates a new Butterfly Put strategy that consists of two long puts at a middle strike,
635  /// and one short put each at a lower and upper strike.
636  /// The upper and lower strikes must both be equidistant from the middle strike.
637  /// </summary>
638  /// <param name="canonicalOption">Option symbol</param>
639  /// <param name="higherStrike">The upper strike price of the short put</param>
640  /// <param name="middleStrike">The middle strike price of the two long puts</param>
641  /// <param name="lowerStrike">The lower strike price of the short put</param>
642  /// <param name="expiration">Option expiration date</param>
643  /// <returns>Option strategy specification</returns>
644  public static OptionStrategy ShortButterflyPut(Symbol canonicalOption, decimal higherStrike, decimal middleStrike, decimal lowerStrike,
645  DateTime expiration)
646  {
647  // Since a short butterfly put is an inverted butterfly put, we can just use the ButterflyPut method and invert the legs
648  return InvertStrategy(ButterflyPut(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration),
650  }
651 
652  /// <summary>
653  /// Creates new Call Calendar Spread strategy which consists of a short and a long call
654  /// with the same strikes but with the long call having a further expiration date.
655  /// </summary>
656  /// <param name="canonicalOption">Option symbol</param>
657  /// <param name="strike">The strike price of the both legs</param>
658  /// <param name="nearExpiration">Near expiration date for the short option</param>
659  /// <param name="farExpiration">Far expiration date for the long option</param>
660  /// <returns>Option strategy specification</returns>
661  public static OptionStrategy CallCalendarSpread(Symbol canonicalOption, decimal strike, DateTime nearExpiration, DateTime farExpiration)
662  {
663  CheckCanonicalOptionSymbol(canonicalOption, "CallCalendarSpread");
664  CheckExpirationDate(nearExpiration, "CallCalendarSpread", nameof(nearExpiration));
665  CheckExpirationDate(farExpiration, "CallCalendarSpread", nameof(farExpiration));
666 
667  if (nearExpiration >= farExpiration)
668  {
669  throw new ArgumentException("CallCalendarSpread: near expiration must be less than far expiration",
670  $"{nameof(nearExpiration)}, {nameof(farExpiration)}");
671  }
672 
673  return new OptionStrategy
674  {
676  Underlying = canonicalOption.Underlying,
677  CanonicalOption = canonicalOption,
678  OptionLegs = new List<OptionStrategy.OptionLegData>
679  {
681  {
682  Right = OptionRight.Call, Strike = strike, Quantity = -1, Expiration = nearExpiration
683  },
685  {
686  Right = OptionRight.Call, Strike = strike, Quantity = 1, Expiration = farExpiration
687  }
688  }
689  };
690  }
691 
692  /// <summary>
693  /// Creates new Short Call Calendar Spread strategy which consists of a short and a long call
694  /// with the same strikes but with the short call having a further expiration date.
695  /// </summary>
696  /// <param name="canonicalOption">Option symbol</param>
697  /// <param name="strike">The strike price of the both legs</param>
698  /// <param name="nearExpiration">Near expiration date for the long option</param>
699  /// <param name="farExpiration">Far expiration date for the short option</param>
700  /// <returns>Option strategy specification</returns>
701  public static OptionStrategy ShortCallCalendarSpread(Symbol canonicalOption, decimal strike, DateTime nearExpiration, DateTime farExpiration)
702  {
703  // Since a short call calendar spread is an inverted call calendar, we can just use the CallCalendarSpread method and invert the legs
704  return InvertStrategy(CallCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration),
706  }
707 
708  /// <summary>
709  /// Creates new Put Calendar Spread strategy which consists of a short and a long put
710  /// with the same strikes but with the long put having a further expiration date.
711  /// </summary>
712  /// <param name="canonicalOption">Option symbol</param>
713  /// <param name="strike">The strike price of the both legs</param>
714  /// <param name="nearExpiration">Near expiration date for the short option</param>
715  /// <param name="farExpiration">Far expiration date for the long option</param>
716  /// <returns>Option strategy specification</returns>
717  public static OptionStrategy PutCalendarSpread(Symbol canonicalOption, decimal strike, DateTime nearExpiration, DateTime farExpiration)
718  {
719  CheckCanonicalOptionSymbol(canonicalOption, "PutCalendarSpread");
720  CheckExpirationDate(nearExpiration, "PutCalendarSpread", nameof(nearExpiration));
721  CheckExpirationDate(farExpiration, "PutCalendarSpread", nameof(farExpiration));
722 
723  if (nearExpiration >= farExpiration)
724  {
725  throw new ArgumentException("PutCalendarSpread: near expiration must be less than far expiration",
726  $"{nameof(nearExpiration)}, {nameof(farExpiration)}");
727  }
728 
729  return new OptionStrategy
730  {
732  Underlying = canonicalOption.Underlying,
733  CanonicalOption = canonicalOption,
734  OptionLegs = new List<OptionStrategy.OptionLegData>
735  {
737  {
738  Right = OptionRight.Put, Strike = strike, Quantity = -1, Expiration = nearExpiration
739  },
741  {
742  Right = OptionRight.Put, Strike = strike, Quantity = 1, Expiration = farExpiration
743  }
744  }
745  };
746  }
747 
748  /// <summary>
749  /// Creates new Short Put Calendar Spread strategy which consists of a short and a long put
750  /// with the same strikes but with the short put having a further expiration date.
751  /// </summary>
752  /// <param name="canonicalOption">Option symbol</param>
753  /// <param name="strike">The strike price of the both legs</param>
754  /// <param name="nearExpiration">Near expiration date for the long option</param>
755  /// <param name="farExpiration">Far expiration date for the short option</param>
756  /// <returns>Option strategy specification</returns>
757  public static OptionStrategy ShortPutCalendarSpread(Symbol canonicalOption, decimal strike, DateTime nearExpiration, DateTime farExpiration)
758  {
759  // Since a short put calendar spread is an inverted put calendar, we can just use the PutCalendarSpread method and invert the legs
760  return InvertStrategy(PutCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration),
762  }
763 
764  /// <summary>
765  /// Creates a new Iron Condor strategy which consists of a long put, a short put, a short call and a long option,
766  /// all with the same expiration date and with increasing strikes prices in the mentioned order.
767  /// </summary>
768  /// <param name="canonicalOption">Option symbol</param>
769  /// <param name="longPutStrike">Long put option strike price</param>
770  /// <param name="shortPutStrike">Short put option strike price</param>
771  /// <param name="shortCallStrike">Short call option strike price</param>
772  /// <param name="longCallStrike">Long call option strike price</param>
773  /// <param name="expiration">Expiration date for all the options</param>
774  /// <returns>Option strategy specification</returns>
775  public static OptionStrategy IronCondor(Symbol canonicalOption, decimal longPutStrike, decimal shortPutStrike, decimal shortCallStrike,
776  decimal longCallStrike, DateTime expiration)
777  {
778  CheckCanonicalOptionSymbol(canonicalOption, "IronCondor");
779  CheckExpirationDate(expiration, "IronCondor", nameof(expiration));
780 
781  if (longPutStrike >= shortPutStrike || shortPutStrike >= shortCallStrike || shortCallStrike >= longCallStrike)
782  {
783  throw new ArgumentException("IronCondor: strike prices must be in ascending order",
784  $"{nameof(longPutStrike)}, {nameof(shortPutStrike)}, {nameof(shortCallStrike)}, {nameof(longCallStrike)}");
785  }
786 
787  return new OptionStrategy
788  {
790  Underlying = canonicalOption.Underlying,
791  CanonicalOption = canonicalOption,
792  OptionLegs = new List<OptionStrategy.OptionLegData>
793  {
795  {
796  Right = OptionRight.Put, Strike = longPutStrike, Quantity = 1, Expiration = expiration
797  },
799  {
800  Right = OptionRight.Put, Strike = shortPutStrike, Quantity = -1, Expiration = expiration
801  },
803  {
804  Right = OptionRight.Call, Strike = shortCallStrike, Quantity = -1, Expiration = expiration
805  },
807  {
808  Right = OptionRight.Call, Strike = longCallStrike, Quantity = 1, Expiration = expiration
809  }
810  }
811  };
812  }
813 
814  /// <summary>
815  /// Checks that canonical option symbol is valid
816  /// </summary>
817  private static void CheckCanonicalOptionSymbol(Symbol canonicalOption, string strategyName)
818  {
819  if (!canonicalOption.HasUnderlying || canonicalOption.ID.StrikePrice != 0.0m)
820  {
821  throw new ArgumentException($"{strategyName}: canonicalOption must contain canonical option symbol", nameof(canonicalOption));
822  }
823  }
824 
825  /// <summary>
826  /// Checks that expiration date is valid
827  /// </summary>
828  private static void CheckExpirationDate(DateTime expiration, string strategyName, string parameterName)
829  {
830  if (expiration == DateTime.MaxValue || expiration == DateTime.MinValue)
831  {
832  throw new ArgumentException($"{strategyName}: expiration must contain expiration date", parameterName);
833  }
834  }
835 
836  /// <summary>
837  /// Inverts the given strategy by multiplying all legs' quantities by -1 and changing the strategy name.
838  /// </summary>
839  private static OptionStrategy InvertStrategy(OptionStrategy strategy, string invertedStrategyName)
840  {
841  strategy.Name = invertedStrategyName;
842  foreach (var leg in strategy.OptionLegs.Cast<OptionStrategy.LegData>().Concat(strategy.UnderlyingLegs))
843  {
844  leg.Quantity *= -1;
845  }
846 
847  return strategy;
848  }
849  }
850 }