17 using System.Collections.Generic;
47 CheckCanonicalOptionSymbol(canonicalOption,
"CoveredCall");
48 CheckExpirationDate(expiration,
"CoveredCall", nameof(expiration));
57 CanonicalOption = canonicalOption,
97 CheckCanonicalOptionSymbol(canonicalOption,
"CoveredPut");
98 CheckExpirationDate(expiration,
"CoveredPut", nameof(expiration));
107 CanonicalOption = canonicalOption,
148 if (callStrike < putStrike)
150 throw new ArgumentException(
"ProtectiveCollar: callStrike must be greater than putStrike", $
"{nameof(callStrike)}, {nameof(putStrike)}");
154 var coveredCall =
CoveredCall(canonicalOption, callStrike, expiration);
155 var protectivePut =
ProtectivePut(canonicalOption, putStrike, expiration);
161 CanonicalOption = canonicalOption,
162 OptionLegs = coveredCall.OptionLegs.Concat(protectivePut.OptionLegs).ToList(),
163 UnderlyingLegs = coveredCall.UnderlyingLegs
177 var strategy =
ProtectiveCollar(canonicalOption, strike, strike, expiration);
204 CheckCanonicalOptionSymbol(canonicalOption,
"NakedCall");
205 CheckExpirationDate(expiration,
"NakedCall", nameof(expiration));
211 CanonicalOption = canonicalOption,
231 CheckCanonicalOptionSymbol(canonicalOption,
"NakedPut");
232 CheckExpirationDate(expiration,
"NakedPut", nameof(expiration));
238 CanonicalOption = canonicalOption,
265 CheckCanonicalOptionSymbol(canonicalOption,
"BearCallSpread");
266 CheckExpirationDate(expiration,
"BearCallSpread", nameof(expiration));
268 if (leg1Strike >= leg2Strike)
270 throw new ArgumentException(
"BearCallSpread: leg1Strike must be less than leg2Strike", $
"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
277 CanonicalOption = canonicalOption,
308 CheckCanonicalOptionSymbol(canonicalOption,
"BearPutSpread");
309 CheckExpirationDate(expiration,
"BearPutSpread", nameof(expiration));
311 if (leg1Strike <= leg2Strike)
313 throw new ArgumentException(
"BearPutSpread: leg1Strike must be greater than leg2Strike", $
"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
320 CanonicalOption = canonicalOption,
352 CheckCanonicalOptionSymbol(canonicalOption,
"BullCallSpread");
353 CheckExpirationDate(expiration,
"BullCallSpread", nameof(expiration));
355 if (leg1Strike >= leg2Strike)
357 throw new ArgumentException(
"BullCallSpread: leg1Strike must be less than leg2Strike", $
"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
364 CanonicalOption = canonicalOption,
395 CheckCanonicalOptionSymbol(canonicalOption,
"BullPutSpread");
396 CheckExpirationDate(expiration,
"BullPutSpread", nameof(expiration));
398 if (leg1Strike <= leg2Strike)
400 throw new ArgumentException(
"BullPutSpread: leg1Strike must be greater than leg2Strike", $
"{nameof(leg1Strike)}, {nameof(leg2Strike)}");
407 CanonicalOption = canonicalOption,
432 CheckCanonicalOptionSymbol(canonicalOption,
"Straddle");
433 CheckExpirationDate(expiration,
"Straddle", nameof(expiration));
439 CanonicalOption = canonicalOption,
480 decimal callLegStrike,
481 decimal putLegStrike,
485 CheckCanonicalOptionSymbol(canonicalOption,
"Strangle");
486 CheckExpirationDate(expiration,
"Strangle", nameof(expiration));
488 if (callLegStrike <= putLegStrike)
490 throw new ArgumentException($
"Strangle: {nameof(callLegStrike)} must be greater than {nameof(putLegStrike)}",
491 $
"{nameof(callLegStrike)}, {nameof(putLegStrike)}");
498 CanonicalOption = canonicalOption,
540 decimal higherStrike,
541 decimal middleStrike,
546 CheckCanonicalOptionSymbol(canonicalOption,
"CallButterfly");
547 CheckExpirationDate(expiration,
"CallButterfly", nameof(expiration));
549 if (higherStrike <= middleStrike ||
550 lowerStrike >= middleStrike ||
551 higherStrike - middleStrike != middleStrike - lowerStrike)
553 throw new ArgumentException(
"ButterflyCall: upper and lower strikes must both be equidistant from the middle strike",
554 $
"{nameof(higherStrike)}, {nameof(middleStrike)}, {nameof(lowerStrike)}");
561 CanonicalOption = canonicalOption,
595 return CallButterfly(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration);
613 return InvertStrategy(
ButterflyCall(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration),
629 decimal higherStrike,
630 decimal middleStrike,
635 CheckCanonicalOptionSymbol(canonicalOption,
"PutButterfly");
636 CheckExpirationDate(expiration,
"PutButterfly", nameof(expiration));
638 if (higherStrike <= middleStrike ||
639 lowerStrike >= middleStrike ||
640 higherStrike - middleStrike != middleStrike - lowerStrike)
642 throw new ArgumentException(
"ButterflyPut: upper and lower strikes must both be equidistant from the middle strike",
643 $
"{nameof(higherStrike)}, {nameof(middleStrike)}, {nameof(lowerStrike)}");
650 CanonicalOption = canonicalOption,
687 return PutButterfly(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration);
705 return InvertStrategy(
ButterflyPut(canonicalOption, higherStrike, middleStrike, lowerStrike, expiration),
720 CheckCanonicalOptionSymbol(canonicalOption,
"CallCalendarSpread");
721 CheckExpirationDate(nearExpiration,
"CallCalendarSpread", nameof(nearExpiration));
722 CheckExpirationDate(farExpiration,
"CallCalendarSpread", nameof(farExpiration));
724 if (nearExpiration >= farExpiration)
726 throw new ArgumentException(
"CallCalendarSpread: near expiration must be less than far expiration",
727 $
"{nameof(nearExpiration)}, {nameof(farExpiration)}");
734 CanonicalOption = canonicalOption,
761 return InvertStrategy(
CallCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration),
776 CheckCanonicalOptionSymbol(canonicalOption,
"PutCalendarSpread");
777 CheckExpirationDate(nearExpiration,
"PutCalendarSpread", nameof(nearExpiration));
778 CheckExpirationDate(farExpiration,
"PutCalendarSpread", nameof(farExpiration));
780 if (nearExpiration >= farExpiration)
782 throw new ArgumentException(
"PutCalendarSpread: near expiration must be less than far expiration",
783 $
"{nameof(nearExpiration)}, {nameof(farExpiration)}");
790 CanonicalOption = canonicalOption,
817 return InvertStrategy(
PutCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration),
834 if (atmStrike - otmPutStrike != otmCallStrike - atmStrike)
836 throw new ArgumentException(
"IronButterfly: intervals between exercise prices must be equal");
839 var strategy =
IronCondor(canonicalOption, otmPutStrike, atmStrike, atmStrike, otmCallStrike, expiration);
858 return InvertStrategy(
IronButterfly(canonicalOption, otmPutStrike, atmStrike, otmCallStrike, expiration),
874 decimal longCallStrike, DateTime expiration)
876 CheckCanonicalOptionSymbol(canonicalOption,
"IronCondor");
877 CheckExpirationDate(expiration,
"IronCondor", nameof(expiration));
879 if (longPutStrike >= shortPutStrike || shortPutStrike > shortCallStrike || shortCallStrike >= longCallStrike)
881 throw new ArgumentException(
"IronCondor: strike prices must be in ascending order",
882 $
"{nameof(longPutStrike)}, {nameof(shortPutStrike)}, {nameof(shortCallStrike)}, {nameof(longCallStrike)}");
889 CanonicalOption = canonicalOption,
924 decimal shortCallStrike, DateTime expiration)
926 return InvertStrategy(
IronCondor(canonicalOption, shortPutStrike, longPutStrike, longCallStrike, shortCallStrike, expiration),
941 if (higherStrike <= lowerStrike)
943 throw new ArgumentException($
"BoxSpread: strike prices must be in descending order, {nameof(higherStrike)}, {nameof(lowerStrike)}");
947 var bearPutSpread =
BearPutSpread(canonicalOption, higherStrike, lowerStrike, expiration);
948 var bullCallSpread =
BullCallSpread(canonicalOption, lowerStrike, higherStrike, expiration);
954 CanonicalOption = canonicalOption,
955 OptionLegs = bearPutSpread.OptionLegs.Concat(bullCallSpread.OptionLegs).ToList()
985 var callCalendarSpread =
CallCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration);
986 var shortPutCalendarSpread =
ShortPutCalendarSpread(canonicalOption, strike, nearExpiration, farExpiration);
992 CanonicalOption = canonicalOption,
993 OptionLegs = callCalendarSpread.OptionLegs.Concat(shortPutCalendarSpread.OptionLegs).ToList()
1023 decimal lowerStrike,
1024 decimal middleStrike,
1025 decimal higherStrike,
1029 CheckCanonicalOptionSymbol(canonicalOption,
"BearCallLadder");
1030 CheckExpirationDate(expiration,
"BearCallLadder", nameof(expiration));
1032 if (lowerStrike >= middleStrike || lowerStrike >= higherStrike || middleStrike >= higherStrike)
1034 throw new ArgumentException(
"BearCallLadder: strike prices must be in ascending order",
1035 $
"{nameof(lowerStrike)}, {nameof(middleStrike)}, {nameof(higherStrike)}");
1042 CanonicalOption = canonicalOption,
1073 decimal higherStrike,
1074 decimal middleStrike,
1075 decimal lowerStrike,
1079 CheckCanonicalOptionSymbol(canonicalOption,
"BearPutLadder");
1080 CheckExpirationDate(expiration,
"BearPutLadder", nameof(expiration));
1082 if (higherStrike <= middleStrike || higherStrike <= lowerStrike || middleStrike <= lowerStrike)
1084 throw new ArgumentException(
"BearPutLadder: strike prices must be in descending order",
1085 $
"{nameof(higherStrike)}, {nameof(middleStrike)}, {nameof(lowerStrike)}");
1092 CanonicalOption = canonicalOption,
1124 decimal lowerStrike,
1125 decimal middleStrike,
1126 decimal higherStrike,
1145 decimal higherStrike,
1146 decimal middleStrike,
1147 decimal lowerStrike,
1165 decimal lowerStrike,
1166 decimal higherStrike,
1170 CheckCanonicalOptionSymbol(canonicalOption,
"CallBackspread");
1171 CheckExpirationDate(expiration,
"CallBackspread", nameof(expiration));
1173 if (lowerStrike >= higherStrike)
1175 throw new ArgumentException($
"CallBackspread: strike prices must be in ascending order, {nameof(lowerStrike)}, {nameof(higherStrike)}");
1180 Name =
"Call Backspread",
1182 CanonicalOption = canonicalOption,
1208 decimal higherStrike,
1209 decimal lowerStrike,
1213 CheckCanonicalOptionSymbol(canonicalOption,
"PutBackspread");
1214 CheckExpirationDate(expiration,
"PutBackspread", nameof(expiration));
1216 if (higherStrike <= lowerStrike)
1218 throw new ArgumentException($
"PutBackspread: strike prices must be in descending order, {nameof(higherStrike)}, {nameof(lowerStrike)}");
1223 Name =
"Put Backspread",
1225 CanonicalOption = canonicalOption,
1250 decimal lowerStrike,
1251 decimal higherStrike,
1255 return InvertStrategy(
CallBackspread(canonicalOption, lowerStrike, higherStrike, expiration),
"Short Call Backspread");
1269 decimal higherStrike,
1270 decimal lowerStrike,
1274 return InvertStrategy(
PutBackspread(canonicalOption, higherStrike, lowerStrike, expiration),
"Short Put Backspread");
1280 private static void CheckCanonicalOptionSymbol(
Symbol canonicalOption,
string strategyName)
1284 throw new ArgumentException($
"{strategyName}: canonicalOption must contain canonical option symbol", nameof(canonicalOption));
1291 private static void CheckExpirationDate(DateTime expiration,
string strategyName,
string parameterName)
1293 if (expiration == DateTime.MaxValue || expiration == DateTime.MinValue)
1295 throw new ArgumentException($
"{strategyName}: expiration must contain expiration date", parameterName);
1302 private static OptionStrategy InvertStrategy(OptionStrategy strategy,
string invertedStrategyName)
1304 strategy.Name = invertedStrategyName;
1305 foreach (var leg
in strategy.OptionLegs.Cast<OptionStrategy.LegData>().Concat(strategy.UnderlyingLegs))