From 8af18e053bf74f84a56f75b2155c0d2b5786f88d Mon Sep 17 00:00:00 2001 From: LouisSzeto Date: Tue, 10 Sep 2024 10:24:46 +0800 Subject: [PATCH] Refactor all --- ...EquityCallBackspreadRegressionAlgorithm.cs | 4 +- ...nEquityPutBackspreadRegressionAlgorithm.cs | 4 +- ...yShortCallBackspreadRegressionAlgorithm.cs | 5 +- ...tyShortPutBackspreadRegressionAlgorithm.cs | 5 +- Common/Securities/Option/OptionStrategies.cs | 8 +- ...onStrategyPositionGroupBuyingPowerModel.cs | 293 +++++----- .../OptionStrategyDefinitions.cs | 524 ++++++++---------- .../Options/OptionStrategiesTests.cs | 8 +- 8 files changed, 393 insertions(+), 458 deletions(-) diff --git a/Algorithm.CSharp/OptionEquityCallBackspreadRegressionAlgorithm.cs b/Algorithm.CSharp/OptionEquityCallBackspreadRegressionAlgorithm.cs index add5db6a6db0..1b43aa5babd7 100644 --- a/Algorithm.CSharp/OptionEquityCallBackspreadRegressionAlgorithm.cs +++ b/Algorithm.CSharp/OptionEquityCallBackspreadRegressionAlgorithm.cs @@ -59,8 +59,10 @@ public override void OnData(Slice slice) MarketOrder(highStrikeCall.Symbol, 10); var freeMarginPostTrade = Portfolio.MarginRemaining; - AssertOptionStrategyIsPresent(OptionStrategyDefinitions.CallBackspread.Name, 5); + // It is a combination of bear call spread and long call (not a group) + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.BearCallSpread.Name, 5); + // Should only involve the bear call spread part var expectedMarginUsage = (highStrikeCall.Strike - lowStrikeCall.Strike) * Securities[highStrikeCall.Symbol].SymbolProperties.ContractMultiplier * 5; if (expectedMarginUsage != Portfolio.TotalMarginUsed) diff --git a/Algorithm.CSharp/OptionEquityPutBackspreadRegressionAlgorithm.cs b/Algorithm.CSharp/OptionEquityPutBackspreadRegressionAlgorithm.cs index 6fe45f927250..0f6b52d961b3 100644 --- a/Algorithm.CSharp/OptionEquityPutBackspreadRegressionAlgorithm.cs +++ b/Algorithm.CSharp/OptionEquityPutBackspreadRegressionAlgorithm.cs @@ -58,8 +58,10 @@ public override void OnData(Slice slice) MarketOrder(lowStrikePut.Symbol, 10); var freeMarginPostTrade = Portfolio.MarginRemaining; - AssertOptionStrategyIsPresent(OptionStrategyDefinitions.PutBackspread.Name, 5); + // It is a combination of bull put spread and long put + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.BullPutSpread.Name, 5); + // Should only involve the bull put spread part var expectedMarginUsage = (highStrikePut.Strike - lowStrikePut.Strike) * Securities[highStrikePut.Symbol].SymbolProperties.ContractMultiplier * 5; if (expectedMarginUsage != Portfolio.TotalMarginUsed) diff --git a/Algorithm.CSharp/OptionEquityShortCallBackspreadRegressionAlgorithm.cs b/Algorithm.CSharp/OptionEquityShortCallBackspreadRegressionAlgorithm.cs index b533e8a10e3b..6651abdfde0b 100644 --- a/Algorithm.CSharp/OptionEquityShortCallBackspreadRegressionAlgorithm.cs +++ b/Algorithm.CSharp/OptionEquityShortCallBackspreadRegressionAlgorithm.cs @@ -59,8 +59,11 @@ public override void OnData(Slice slice) MarketOrder(highStrikeCall.Symbol, -10); var freeMarginPostTrade = Portfolio.MarginRemaining; - AssertOptionStrategyIsPresent(OptionStrategyDefinitions.ShortCallBackspread.Name, 5); + // It is a combination of bull call spread and naked call + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.BullCallSpread.Name, 5); + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.NakedCall.Name, 5); + // Should only involve the naked call part var security = Securities[highStrikeCall.Symbol]; var expectedMarginUsage = security.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, -5)).Value; diff --git a/Algorithm.CSharp/OptionEquityShortPutBackspreadRegressionAlgorithm.cs b/Algorithm.CSharp/OptionEquityShortPutBackspreadRegressionAlgorithm.cs index 7e1eff6b99a2..5c05a022dc5b 100644 --- a/Algorithm.CSharp/OptionEquityShortPutBackspreadRegressionAlgorithm.cs +++ b/Algorithm.CSharp/OptionEquityShortPutBackspreadRegressionAlgorithm.cs @@ -59,8 +59,11 @@ public override void OnData(Slice slice) MarketOrder(lowStrikePut.Symbol, -10); var freeMarginPostTrade = Portfolio.MarginRemaining; - AssertOptionStrategyIsPresent(OptionStrategyDefinitions.ShortPutBackspread.Name, 5); + // It is a combination of bear put spread and naked put + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.BearPutSpread.Name, 5); + AssertOptionStrategyIsPresent(OptionStrategyDefinitions.NakedPut.Name, 5); + // Should only involve the naked put part var security = Securities[lowStrikePut.Symbol]; var expectedMarginUsage = security.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, -5)).Value; diff --git a/Common/Securities/Option/OptionStrategies.cs b/Common/Securities/Option/OptionStrategies.cs index 42e874e3c1a8..1c0373dfda98 100644 --- a/Common/Securities/Option/OptionStrategies.cs +++ b/Common/Securities/Option/OptionStrategies.cs @@ -1177,7 +1177,7 @@ DateTime expiration return new OptionStrategy { - Name = OptionStrategyDefinitions.CallBackspread.Name, + Name = "Call Backspread", Underlying = canonicalOption.Underlying, CanonicalOption = canonicalOption, OptionLegs = new List @@ -1220,7 +1220,7 @@ DateTime expiration return new OptionStrategy { - Name = OptionStrategyDefinitions.PutBackspread.Name, + Name = "Put Backspread", Underlying = canonicalOption.Underlying, CanonicalOption = canonicalOption, OptionLegs = new List @@ -1252,7 +1252,7 @@ public static OptionStrategy ShortCallBackspread( DateTime expiration ) { - return InvertStrategy(CallBackspread(canonicalOption, lowerStrike, higherStrike, expiration), OptionStrategyDefinitions.ShortCallBackspread.Name); + return InvertStrategy(CallBackspread(canonicalOption, lowerStrike, higherStrike, expiration), "Short Call Backspread"); } /// @@ -1271,7 +1271,7 @@ public static OptionStrategy ShortPutBackspread( DateTime expiration ) { - return InvertStrategy(PutBackspread(canonicalOption, higherStrike, lowerStrike, expiration), OptionStrategyDefinitions.ShortPutBackspread.Name); + return InvertStrategy(PutBackspread(canonicalOption, higherStrike, lowerStrike, expiration), "Short Put Backspread"); } /// diff --git a/Common/Securities/Option/OptionStrategyPositionGroupBuyingPowerModel.cs b/Common/Securities/Option/OptionStrategyPositionGroupBuyingPowerModel.cs index 52809b5b8e6a..4f1cc16e58f0 100644 --- a/Common/Securities/Option/OptionStrategyPositionGroupBuyingPowerModel.cs +++ b/Common/Securities/Option/OptionStrategyPositionGroupBuyingPowerModel.cs @@ -54,6 +54,36 @@ public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceM // we could be liquidating a position return new MaintenanceMargin(0); } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCollar.Name) + { + // Minimum (((10% * Put Strike Price) + Put Out of the Money Amount), (25% * Call Strike Price)) + var putPosition = parameters.PositionGroup.Positions.Single(position => + position.Symbol.SecurityType.IsOption() && position.Symbol.ID.OptionRight == OptionRight.Put); + var callPosition = parameters.PositionGroup.Positions.Single(position => + position.Symbol.SecurityType.IsOption() && position.Symbol.ID.OptionRight == OptionRight.Call); + var underlyingPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => !position.Symbol.SecurityType.IsOption()); + var putSecurity = (Option)parameters.Portfolio.Securities[putPosition.Symbol]; + var callSecurity = (Option)parameters.Portfolio.Securities[callPosition.Symbol]; + var underlyingSecurity = parameters.Portfolio.Securities[underlyingPosition.Symbol]; + + var putMarginRequirement = 0.1m * putSecurity.StrikePrice + putSecurity.OutOfTheMoneyAmount(underlyingSecurity.Price); + var callMarginRequirement = 0.25m * callSecurity.StrikePrice; + + // call and put has the exact same number of contracts + var contractUnits = Math.Abs(putPosition.Quantity) * putSecurity.ContractUnitOfTrade; + var result = Math.Min(putMarginRequirement, callMarginRequirement) * contractUnits; + var inAccountCurrency = parameters.Portfolio.CashBook.ConvertToAccountCurrency(result, underlyingSecurity.QuoteCurrency.Symbol); + + return new MaintenanceMargin(inAccountCurrency); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.Conversion.Name) + { + return GetConversionMaintenanceMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Call); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ReverseConversion.Name) + { + return GetConversionMaintenanceMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Put); + } else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectivePut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCall.Name) { // Minimum (((10% * Call/Put Strike Price) + Call/Put Out of the Money Amount), Short Stock/Long Maintenance Requirement) @@ -120,120 +150,6 @@ public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceM return new MaintenanceMargin(inAccountCurrency); } - else if (_optionStrategy.Name == OptionStrategyDefinitions.CallBackspread.Name) - { - // Bear call spread + long call (0) - // long high strike - short low strike - var result = GetLongCallShortCallStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.PutBackspread.Name) - { - // Bull put spread + long put (0) - // short high strike - long low strike - var result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortCallBackspread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.ShortPutBackspread.Name) - { - // Bull call spread (0) + short call - // Bear put spread (0) + short put - var option = parameters.PositionGroup.Positions.Single(x => x.Quantity < 0); - var security = (Option)parameters.Portfolio.Securities[option.Symbol]; - var margin = security.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, - option.Quantity * 0.5m)); // short call/put part is only half the size, the other half is for the spread - - return new MaintenanceMargin(margin); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCollar.Name) - { - // Minimum (((10% * Put Strike Price) + Put Out of the Money Amount), (25% * Call Strike Price)) - var putPosition = parameters.PositionGroup.Positions.Single(position => - position.Symbol.SecurityType.IsOption() && position.Symbol.ID.OptionRight == OptionRight.Put); - var callPosition = parameters.PositionGroup.Positions.Single(position => - position.Symbol.SecurityType.IsOption() && position.Symbol.ID.OptionRight == OptionRight.Call); - var underlyingPosition = parameters.PositionGroup.Positions.FirstOrDefault(position => !position.Symbol.SecurityType.IsOption()); - var putSecurity = (Option)parameters.Portfolio.Securities[putPosition.Symbol]; - var callSecurity = (Option)parameters.Portfolio.Securities[callPosition.Symbol]; - var underlyingSecurity = parameters.Portfolio.Securities[underlyingPosition.Symbol]; - - var putMarginRequirement = 0.1m * putSecurity.StrikePrice + putSecurity.OutOfTheMoneyAmount(underlyingSecurity.Price); - var callMarginRequirement = 0.25m * callSecurity.StrikePrice; - - // call and put has the exact same number of contracts - var contractUnits = Math.Abs(putPosition.Quantity) * putSecurity.ContractUnitOfTrade; - var result = Math.Min(putMarginRequirement, callMarginRequirement) * contractUnits; - var inAccountCurrency = parameters.Portfolio.CashBook.ConvertToAccountCurrency(result, underlyingSecurity.QuoteCurrency.Symbol); - - return new MaintenanceMargin(inAccountCurrency); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.Conversion.Name) - { - return GetConversionMaintenanceMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Call); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ReverseConversion.Name) - { - return GetConversionMaintenanceMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Put); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.NakedCall.Name - || _optionStrategy.Name == OptionStrategyDefinitions.NakedPut.Name) - { - var option = parameters.PositionGroup.Positions.Single(); - var security = (Option)parameters.Portfolio.Securities[option.Symbol]; - var margin = security.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, - option.Quantity)); - - return new MaintenanceMargin(margin); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallSpread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.BullCallSpread.Name) - { - var result = GetLongCallShortCallStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.CallCalendarSpread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.PutCalendarSpread.Name) - { - return new MaintenanceMargin(0); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortCallCalendarSpread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.ShortPutCalendarSpread.Name) - { - var shortCall = parameters.PositionGroup.Positions.Single(position => position.Quantity < 0); - var shortCallSecurity = (Option)parameters.Portfolio.Securities[shortCall.Symbol]; - var result = shortCallSecurity.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice( - shortCallSecurity, shortCall.Quantity)); - - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.BearPutSpread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.BullPutSpread.Name) - { - var result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.Straddle.Name || _optionStrategy.Name == OptionStrategyDefinitions.Strangle.Name) - { - // Margined as two long options: since there is not margin requirements for long options, we return 0 - return new MaintenanceMargin(0); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortStraddle.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortStrangle.Name) - { - var result = GetShortStraddleStrangleMargin(parameters.PositionGroup, parameters.Portfolio, - (option, quantity) => Math.Abs(option.BuyingPowerModel.GetMaintenanceMargin( - MaintenanceMarginParameters.ForQuantityAtCurrentPrice(option, quantity)))); - return new MaintenanceMargin(result); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ButterflyCall.Name || _optionStrategy.Name == OptionStrategyDefinitions.ButterflyPut.Name) - { - return new MaintenanceMargin(0); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyPut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyCall.Name) - { - var result = GetMiddleAndLowStrikeDifference(parameters.PositionGroup, parameters.Portfolio); - return new MaintenanceMargin(result); - } else if (_optionStrategy.Name == OptionStrategyDefinitions.IronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.IronButterfly.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortIronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortIronButterfly.Name) { @@ -287,6 +203,15 @@ public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceM return new MaintenanceMargin(result); } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ButterflyCall.Name || _optionStrategy.Name == OptionStrategyDefinitions.ButterflyPut.Name) + { + return new MaintenanceMargin(0); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyPut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyCall.Name) + { + var result = GetMiddleAndLowStrikeDifference(parameters.PositionGroup, parameters.Portfolio); + return new MaintenanceMargin(result); + } else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallLadder.Name) { return GetCallLadderMargin(parameters, true); @@ -303,6 +228,55 @@ public override MaintenanceMargin GetMaintenanceMargin(PositionGroupMaintenanceM { return GetPutLadderMargin(parameters, true); } + else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallSpread.Name + || _optionStrategy.Name == OptionStrategyDefinitions.BullCallSpread.Name) + { + var result = GetLongCallShortCallStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); + return new MaintenanceMargin(result); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.CallCalendarSpread.Name + || _optionStrategy.Name == OptionStrategyDefinitions.PutCalendarSpread.Name) + { + return new MaintenanceMargin(0); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortCallCalendarSpread.Name + || _optionStrategy.Name == OptionStrategyDefinitions.ShortPutCalendarSpread.Name) + { + var shortCall = parameters.PositionGroup.Positions.Single(position => position.Quantity < 0); + var shortCallSecurity = (Option)parameters.Portfolio.Securities[shortCall.Symbol]; + var result = shortCallSecurity.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice( + shortCallSecurity, shortCall.Quantity)); + + return new MaintenanceMargin(result); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.BearPutSpread.Name + || _optionStrategy.Name == OptionStrategyDefinitions.BullPutSpread.Name) + { + var result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); + return new MaintenanceMargin(result); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.Straddle.Name || _optionStrategy.Name == OptionStrategyDefinitions.Strangle.Name) + { + // Margined as two long options: since there is not margin requirements for long options, we return 0 + return new MaintenanceMargin(0); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortStraddle.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortStrangle.Name) + { + var result = GetShortStraddleStrangleMargin(parameters.PositionGroup, parameters.Portfolio, + (option, quantity) => Math.Abs(option.BuyingPowerModel.GetMaintenanceMargin( + MaintenanceMarginParameters.ForQuantityAtCurrentPrice(option, quantity)))); + return new MaintenanceMargin(result); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.NakedCall.Name + || _optionStrategy.Name == OptionStrategyDefinitions.NakedPut.Name) + { + var option = parameters.PositionGroup.Positions.Single(); + var security = (Option)parameters.Portfolio.Securities[option.Symbol]; + var margin = security.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(security, + option.Quantity)); + + return new MaintenanceMargin(margin); + } throw new NotImplementedException($"Option strategy {_optionStrategy.Name} margin modeling has yet to be implemented"); } @@ -319,6 +293,14 @@ public override InitialMargin GetInitialMarginRequirement(PositionGroupInitialMa { result = 0; } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCollar.Name || _optionStrategy.Name == OptionStrategyDefinitions.Conversion.Name) + { + result = GetCollarConversionInitialMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Call); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ReverseConversion.Name) + { + result = GetCollarConversionInitialMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Put); + } else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectivePut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCall.Name) { // Initial Standard Stock Margin Requirement @@ -349,33 +331,36 @@ public override InitialMargin GetInitialMarginRequirement(PositionGroupInitialMa // Initial Stock Margin Requirement + In the Money Amount result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); } - else if (_optionStrategy.Name == OptionStrategyDefinitions.CallBackspread.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortCallBackspread.Name - || _optionStrategy.Name == OptionStrategyDefinitions.PutBackspread.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortPutBackspread.Name) + else if (_optionStrategy.Name == OptionStrategyDefinitions.IronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.IronButterfly.Name || + _optionStrategy.Name == OptionStrategyDefinitions.ShortIronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortIronButterfly.Name) + { + result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.BoxSpread.Name) + { + result = 0m; + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortBoxSpread.Name) { result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ProtectiveCollar.Name || _optionStrategy.Name == OptionStrategyDefinitions.Conversion.Name) + else if (_optionStrategy.Name == OptionStrategyDefinitions.JellyRoll.Name + || _optionStrategy.Name == OptionStrategyDefinitions.ShortJellyRoll.Name) { - result = GetCollarConversionInitialMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Call); + result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ReverseConversion.Name) + else if (_optionStrategy.Name == OptionStrategyDefinitions.ButterflyCall.Name || _optionStrategy.Name == OptionStrategyDefinitions.ButterflyPut.Name) { - result = GetCollarConversionInitialMargin(parameters.PositionGroup, parameters.Portfolio, OptionRight.Put); + result = 0m; } - else if (_optionStrategy.Name == OptionStrategyDefinitions.NakedCall.Name - || _optionStrategy.Name == OptionStrategyDefinitions.NakedPut.Name) + else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyPut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyCall.Name) { - var option = parameters.PositionGroup.Positions.Single(); - var security = (Option)parameters.Portfolio.Securities[option.Symbol]; - var margin = security.BuyingPowerModel.GetInitialMarginRequirement(new InitialMarginParameters(security, option.Quantity)); - var optionMargin = margin as OptionInitialMargin; - - if (optionMargin != null) - { - return new OptionInitialMargin(Math.Abs(optionMargin.ValueWithoutPremium), optionMargin.Premium); - } - - return margin; + result = GetMiddleAndLowStrikeDifference(parameters.PositionGroup, parameters.Portfolio); + } + else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallLadder.Name || _optionStrategy.Name == OptionStrategyDefinitions.BearPutLadder.Name + || _optionStrategy.Name == OptionStrategyDefinitions.BullCallLadder.Name || _optionStrategy.Name == OptionStrategyDefinitions.BullPutLadder.Name) + { + result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); } else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallSpread.Name || _optionStrategy.Name == OptionStrategyDefinitions.BullCallSpread.Name) @@ -409,36 +394,20 @@ public override InitialMargin GetInitialMarginRequirement(PositionGroupInitialMa result = GetShortStraddleStrangleMargin(parameters.PositionGroup, parameters.Portfolio, (option, quantity) => Math.Abs(option.BuyingPowerModel.GetInitialMarginRequirement(option, quantity))); } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ButterflyCall.Name || _optionStrategy.Name == OptionStrategyDefinitions.ButterflyPut.Name) - { - result = 0m; - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyPut.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortButterflyCall.Name) - { - result = GetMiddleAndLowStrikeDifference(parameters.PositionGroup, parameters.Portfolio); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.IronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.IronButterfly.Name || - _optionStrategy.Name == OptionStrategyDefinitions.ShortIronCondor.Name || _optionStrategy.Name == OptionStrategyDefinitions.ShortIronButterfly.Name) - { - result = GetShortPutLongPutStrikeDifferenceMargin(parameters.PositionGroup.Positions, parameters.Portfolio, parameters.PositionGroup.Quantity); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.BoxSpread.Name) - { - result = 0m; - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.ShortBoxSpread.Name) - { - result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.JellyRoll.Name - || _optionStrategy.Name == OptionStrategyDefinitions.ShortJellyRoll.Name) - { - result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); - } - else if (_optionStrategy.Name == OptionStrategyDefinitions.BearCallLadder.Name || _optionStrategy.Name == OptionStrategyDefinitions.BearPutLadder.Name - || _optionStrategy.Name == OptionStrategyDefinitions.BullCallLadder.Name || _optionStrategy.Name == OptionStrategyDefinitions.BullPutLadder.Name) + else if (_optionStrategy.Name == OptionStrategyDefinitions.NakedCall.Name + || _optionStrategy.Name == OptionStrategyDefinitions.NakedPut.Name) { - result = GetMaintenanceMargin(new PositionGroupMaintenanceMarginParameters(parameters.Portfolio, parameters.PositionGroup)); + var option = parameters.PositionGroup.Positions.Single(); + var security = (Option)parameters.Portfolio.Securities[option.Symbol]; + var margin = security.BuyingPowerModel.GetInitialMarginRequirement(new InitialMarginParameters(security, option.Quantity)); + var optionMargin = margin as OptionInitialMargin; + + if (optionMargin != null) + { + return new OptionInitialMargin(Math.Abs(optionMargin.ValueWithoutPremium), optionMargin.Premium); + } + + return margin; } else { diff --git a/Common/Securities/Option/StrategyMatcher/OptionStrategyDefinitions.cs b/Common/Securities/Option/StrategyMatcher/OptionStrategyDefinitions.cs index 5d4ec90a4916..0abed6b00417 100644 --- a/Common/Securities/Option/StrategyMatcher/OptionStrategyDefinitions.cs +++ b/Common/Securities/Option/StrategyMatcher/OptionStrategyDefinitions.cs @@ -68,6 +68,42 @@ public static ImmutableList AllDefinitions } } + /// + /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. + /// The strike price of the short call is below the strike of the long put with the same expiration. + /// + /// Combination of and + public static OptionStrategyDefinition ProtectiveCollar { get; } + = OptionStrategyDefinition.Create("Protective Collar", 1, + OptionStrategyDefinition.CallLeg(-1), + OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) + ); + + /// + /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. + /// The strike price of the call and put are the same, with the same expiration. + /// + /// A special case of + public static OptionStrategyDefinition Conversion { get; } + = OptionStrategyDefinition.Create("Conversion", 1, + OptionStrategyDefinition.CallLeg(-1), + OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike == legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) + ); + + /// + /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. + /// The strike price of the call and put are the same, with the same expiration. + /// + /// Inverse of + public static OptionStrategyDefinition ReverseConversion { get; } + = OptionStrategyDefinition.Create("Reverse Conversion", -1, + OptionStrategyDefinition.CallLeg(1), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) + ); + /// /// Hold 1 lot of the underlying and sell 1 call contract /// @@ -105,143 +141,233 @@ public static ImmutableList AllDefinitions ); /// - /// Long Call Backspread strategy is short 1 lower-strike call and long 2 higher-strike call. - /// All options have the same expiry. + /// 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. + /// All at the same expiration date /// - public static OptionStrategyDefinition CallBackspread { get; } - = OptionStrategyDefinition.Create("Call Backspread", - OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.CallLeg(+2, (legs, c) => c.Strike > legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) + public static OptionStrategyDefinition IronCondor { get; } + = OptionStrategyDefinition.Create("Iron Condor", + OptionStrategyDefinition.PutLeg(+1), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike > legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(1, (legs, p) => p.Strike > legs[2].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); /// - /// Long Put Backspread strategy is short 1 higher-strike put and long 2 lower-strike put. - /// All options have the same expiry. + /// 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. + /// All at the same expiration date /// - public static OptionStrategyDefinition PutBackspread { get; } - = OptionStrategyDefinition.Create("Put Backspread", + public static OptionStrategyDefinition ShortIronCondor { get; } + = OptionStrategyDefinition.Create("Short Iron Condor", OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+2, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike > legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[2].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); /// - /// Short Call Backspread strategy is long 1 lower-strike call and short 2 higher-strike call. - /// All options have the same expiry. + /// Iron Butterfly strategy consists of a short ATM call, a short ATM put, a long OTM call, and a long OTM put. + /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date. /// - public static OptionStrategyDefinition ShortCallBackspread { get; } - = OptionStrategyDefinition.Create("Short Call Backspread", - OptionStrategyDefinition.CallLeg(+1), - OptionStrategyDefinition.CallLeg(-2, (legs, c) => c.Strike > legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) + public static OptionStrategyDefinition IronButterfly { get; } + = OptionStrategyDefinition.Create("Iron Butterfly", + OptionStrategyDefinition.PutLeg(-1), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) ); /// - /// Short Put Backspread strategy is long 1 higher-strike put and short 2 lower-strike put. - /// All options have the same expiry. + /// Short Iron Butterfly strategy consists of a long ATM call, a long ATM put, a short OTM call, and a short OTM put. + /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date. /// - public static OptionStrategyDefinition ShortPutBackspread { get; } - = OptionStrategyDefinition.Create("Short Put Backspread", + public static OptionStrategyDefinition ShortIronButterfly { get; } + = OptionStrategyDefinition.Create("Short Iron Butterfly", OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-2, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) ); /// - /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. - /// The strike price of the short call is below the strike of the long put with the same expiration. + /// Long Box Spread strategy is long 1 call and short 1 put with the same strike, + /// while short 1 call and long 1 put with a higher, same strike. All options have the same expiry. + /// expiration. /// - /// Combination of and - public static OptionStrategyDefinition ProtectiveCollar { get; } - = OptionStrategyDefinition.Create("Protective Collar", 1, - OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + public static OptionStrategyDefinition BoxSpread { get; } + = OptionStrategyDefinition.Create("Box Spread", + OptionStrategyDefinition.PutLeg(+1), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) ); /// - /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. - /// The strike price of the call and put are the same, with the same expiration. + /// Short Box Spread strategy is short 1 call and long 1 put with the same strike, + /// while long 1 call and short 1 put with a higher, same strike. All options have the same expiry. + /// expiration. /// - /// A special case of - public static OptionStrategyDefinition Conversion { get; } - = OptionStrategyDefinition.Create("Conversion", 1, + public static OptionStrategyDefinition ShortBoxSpread { get; } + = OptionStrategyDefinition.Create("Short Box Spread", + OptionStrategyDefinition.PutLeg(-1), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) + ); + + /// + /// Jelly Roll is short 1 call and long 1 call with the same strike but further expiry, together with + /// long 1 put and short 1 put with the same strike and expiries as calls. + /// + public static OptionStrategyDefinition JellyRoll { get; } + = OptionStrategyDefinition.Create("Jelly Roll", OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.PutLeg(1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration > legs[0].Expiration), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike, + (legs, p) => p.Expiration == legs[1].Expiration) ); /// - /// Hold 1 lot of the underlying, sell 1 call contract and buy 1 put contract. - /// The strike price of the call and put are the same, with the same expiration. + /// Short Jelly Roll is long 1 call and short 1 call with the same strike but further expiry, together with + /// short 1 put and long 1 put with the same strike and expiries as calls. /// - /// Inverse of - public static OptionStrategyDefinition ReverseConversion { get; } - = OptionStrategyDefinition.Create("Reverse Conversion", -1, - OptionStrategyDefinition.CallLeg(1), + public static OptionStrategyDefinition ShortJellyRoll { get; } + = OptionStrategyDefinition.Create("Short Jelly Roll", + OptionStrategyDefinition.CallLeg(+1), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, + (legs, c) => c.Expiration > legs[0].Expiration), OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike, + (legs, p) => p.Expiration == legs[1].Expiration) ); /// - /// Sell 1 call contract without holding the underlying + /// Short Butterfly Call strategy consists of two short calls at a middle strike, and one long call each at a lower + /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike. /// - public static OptionStrategyDefinition NakedCall { get; } - = OptionStrategyDefinition.Create("Naked Call", - OptionStrategyDefinition.CallLeg(-1) + public static OptionStrategyDefinition ButterflyCall { get; } + = OptionStrategyDefinition.Create("Butterfly Call", + OptionStrategyDefinition.CallLeg(+1), + OptionStrategyDefinition.CallLeg(-2, (legs, p) => p.Strike >= legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike >= legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration, + (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) ); /// - /// Sell 1 put contract without holding the underlying + /// Butterfly Call strategy consists of two long calls at a middle strike, and one short call each at a lower + /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike. /// - public static OptionStrategyDefinition NakedPut { get; } - = OptionStrategyDefinition.Create("Naked Put", - OptionStrategyDefinition.PutLeg(-1) + public static OptionStrategyDefinition ShortButterflyCall { get; } + = OptionStrategyDefinition.Create("Short Butterfly Call", + OptionStrategyDefinition.CallLeg(-1), + OptionStrategyDefinition.CallLeg(+2, (legs, p) => p.Strike >= legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike >= legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration, + (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) ); /// - /// Bear Call Spread strategy consists of two calls with the same expiration but different strikes. - /// The strike price of the short call is below the strike of the long call. This is a credit spread. + /// Butterfly Put strategy consists of two short puts at a middle strike, and one long put each at a lower and + /// upper strike. The upper and lower strikes must both be equidistant from the middle strike. /// - public static OptionStrategyDefinition BearCallSpread { get; } - = OptionStrategyDefinition.Create("Bear Call Spread", + public static OptionStrategyDefinition ButterflyPut { get; } + = OptionStrategyDefinition.Create("Butterfly Put", + OptionStrategyDefinition.PutLeg(+1), + OptionStrategyDefinition.PutLeg(-2, (legs, p) => p.Strike >= legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike >= legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration, + (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + ); + + + /// + /// Short Butterfly Put strategy consists of two long puts at a middle strike, and one short put each at a lower and + /// upper strike. The upper and lower strikes must both be equidistant from the middle strike. + /// + public static OptionStrategyDefinition ShortButterflyPut { get; } + = OptionStrategyDefinition.Create("Short Butterfly Put", + OptionStrategyDefinition.PutLeg(-1), + OptionStrategyDefinition.PutLeg(+2, (legs, p) => p.Strike >= legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike >= legs[1].Strike, + (legs, p) => p.Expiration == legs[0].Expiration, + (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + ); + + /// + /// Bear Call Ladder strategy is short 1 call and long 2 calls, with ascending strike prices in order, + /// All options have the same expiry. + /// + public static OptionStrategyDefinition BearCallLadder { get; } + = OptionStrategyDefinition.Create("Bear Call Ladder", OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) ); /// - /// Bear Put Spread strategy consists of two puts with the same expiration but different strikes. - /// The strike price of the short put is below the strike of the long put. This is a debit spread. + /// Bear Put Ladder strategy is long 1 put and short 2 puts, with descending strike prices in order, + /// All options have the same expiry. /// - public static OptionStrategyDefinition BearPutSpread { get; } - = OptionStrategyDefinition.Create("Bear Put Spread", - OptionStrategyDefinition.PutLeg(1), + public static OptionStrategyDefinition BearPutLadder { get; } + = OptionStrategyDefinition.Create("Bear Put Ladder", + OptionStrategyDefinition.PutLeg(+1), OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[1].Strike, (legs, p) => p.Expiration == legs[0].Expiration) ); /// - /// Bull Call Spread strategy consists of two calls with the same expiration but different strikes. - /// The strike price of the short call is higher than the strike of the long call. This is a debit spread. + /// Bull Call Ladder strategy is long 1 call and short 2 calls, with ascending strike prices in order, + /// All options have the same expiry. /// - public static OptionStrategyDefinition BullCallSpread { get; } - = OptionStrategyDefinition.Create("Bull Call Spread", + public static OptionStrategyDefinition BullCallLadder { get; } + = OptionStrategyDefinition.Create("Bull Call Ladder", OptionStrategyDefinition.CallLeg(+1), - OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[0].Strike, + (legs, c) => c.Expiration == legs[0].Expiration), + OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[1].Strike, + (legs, c) => c.Expiration == legs[0].Expiration) ); /// - /// Method creates new Bull Put Spread strategy, that consists of two puts with the same expiration but - /// different strikes. The strike price of the short put is above the strike of the long put. This is a - /// credit spread. + /// Bull Put Ladder strategy is short 1 put and long 2 puts, with descending strike prices in order, + /// All options have the same expiry. /// - public static OptionStrategyDefinition BullPutSpread { get; } - = OptionStrategyDefinition.Create("Bull Put Spread", + public static OptionStrategyDefinition BullPutLadder { get; } + = OptionStrategyDefinition.Create("Bull Put Ladder", OptionStrategyDefinition.PutLeg(-1), OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration), + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[1].Strike, (legs, p) => p.Expiration == legs[0].Expiration) ); @@ -292,60 +418,48 @@ public static ImmutableList AllDefinitions ); /// - /// Short Butterfly Call strategy consists of two short calls at a middle strike, and one long call each at a lower - /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike. + /// Bear Call Spread strategy consists of two calls with the same expiration but different strikes. + /// The strike price of the short call is below the strike of the long call. This is a credit spread. /// - public static OptionStrategyDefinition ButterflyCall { get; } - = OptionStrategyDefinition.Create("Butterfly Call", - OptionStrategyDefinition.CallLeg(+1), - OptionStrategyDefinition.CallLeg(-2, (legs, p) => p.Strike >= legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike >= legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration, - (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + public static OptionStrategyDefinition BearCallSpread { get; } + = OptionStrategyDefinition.Create("Bear Call Spread", + OptionStrategyDefinition.CallLeg(-1), + OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); /// - /// Butterfly Call strategy consists of two long calls at a middle strike, and one short call each at a lower - /// and upper strike. The upper and lower strikes must both be equidistant from the middle strike. + /// Bear Put Spread strategy consists of two puts with the same expiration but different strikes. + /// The strike price of the short put is below the strike of the long put. This is a debit spread. /// - public static OptionStrategyDefinition ShortButterflyCall { get; } - = OptionStrategyDefinition.Create("Short Butterfly Call", - OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.CallLeg(+2, (legs, p) => p.Strike >= legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike >= legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration, - (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + public static OptionStrategyDefinition BearPutSpread { get; } + = OptionStrategyDefinition.Create("Bear Put Spread", + OptionStrategyDefinition.PutLeg(1), + OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); /// - /// Butterfly Put strategy consists of two short puts at a middle strike, and one long put each at a lower and - /// upper strike. The upper and lower strikes must both be equidistant from the middle strike. + /// Bull Call Spread strategy consists of two calls with the same expiration but different strikes. + /// The strike price of the short call is higher than the strike of the long call. This is a debit spread. /// - public static OptionStrategyDefinition ButterflyPut { get; } - = OptionStrategyDefinition.Create("Butterfly Put", - OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-2, (legs, p) => p.Strike >= legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike >= legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration, - (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + public static OptionStrategyDefinition BullCallSpread { get; } + = OptionStrategyDefinition.Create("Bull Call Spread", + OptionStrategyDefinition.CallLeg(+1), + OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); - /// - /// Short Butterfly Put strategy consists of two long puts at a middle strike, and one short put each at a lower and - /// upper strike. The upper and lower strikes must both be equidistant from the middle strike. + /// Method creates new Bull Put Spread strategy, that consists of two puts with the same expiration but + /// different strikes. The strike price of the short put is above the strike of the long put. This is a + /// credit spread. /// - public static OptionStrategyDefinition ShortButterflyPut { get; } - = OptionStrategyDefinition.Create("Short Butterfly Put", + public static OptionStrategyDefinition BullPutSpread { get; } + = OptionStrategyDefinition.Create("Bull Put Spread", OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+2, (legs, p) => p.Strike >= legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike >= legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration, - (legs, p) => p.Strike - legs[1].Strike == legs[1].Strike - legs[0].Strike) + OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, + (legs, p) => p.Expiration == legs[0].Expiration) ); /// @@ -395,177 +509,19 @@ public static ImmutableList AllDefinitions ); /// - /// Iron Butterfly strategy consists of a short ATM call, a short ATM put, a long OTM call, and a long OTM put. - /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date. - /// - public static OptionStrategyDefinition IronButterfly { get; } - = OptionStrategyDefinition.Create("Iron Butterfly", - OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) - ); - - /// - /// Short Iron Butterfly strategy consists of a long ATM call, a long ATM put, a short OTM call, and a short OTM put. - /// The strike spread between ATM and OTM call and put are the same. All at the same expiration date. - /// - public static OptionStrategyDefinition ShortIronButterfly { get; } - = OptionStrategyDefinition.Create("Short Iron Butterfly", - OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike * 2 - legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) - ); - - /// - /// 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. - /// All at the same expiration date - /// - public static OptionStrategyDefinition IronCondor { get; } - = OptionStrategyDefinition.Create("Iron Condor", - OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike > legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(1, (legs, p) => p.Strike > legs[2].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) - ); - - /// - /// 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. - /// All at the same expiration date - /// - public static OptionStrategyDefinition ShortIronCondor { get; } - = OptionStrategyDefinition.Create("Short Iron Condor", - OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike > legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, p) => p.Strike > legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, p) => p.Strike > legs[2].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) - ); - - /// - /// Long Box Spread strategy is long 1 call and short 1 put with the same strike, - /// while short 1 call and long 1 put with a higher, same strike. All options have the same expiry. - /// expiration. - /// - public static OptionStrategyDefinition BoxSpread { get; } - = OptionStrategyDefinition.Create("Box Spread", - OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) - ); - - /// - /// Short Box Spread strategy is short 1 call and long 1 put with the same strike, - /// while long 1 call and short 1 put with a higher, same strike. All options have the same expiry. - /// expiration. - /// - public static OptionStrategyDefinition ShortBoxSpread { get; } - = OptionStrategyDefinition.Create("Short Box Spread", - OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) - ); - - /// - /// Jelly Roll is short 1 call and long 1 call with the same strike but further expiry, together with - /// long 1 put and short 1 put with the same strike and expiries as calls. - /// - public static OptionStrategyDefinition JellyRoll { get; } - = OptionStrategyDefinition.Create("Jelly Roll", - OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration > legs[0].Expiration), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[1].Expiration) - ); - - /// - /// Short Jelly Roll is long 1 call and short 1 call with the same strike but further expiry, together with - /// short 1 put and long 1 put with the same strike and expiries as calls. - /// - public static OptionStrategyDefinition ShortJellyRoll { get; } - = OptionStrategyDefinition.Create("Short Jelly Roll", - OptionStrategyDefinition.CallLeg(+1), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike == legs[0].Strike, - (legs, c) => c.Expiration > legs[0].Expiration), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike == legs[0].Strike, - (legs, p) => p.Expiration == legs[1].Expiration) - ); - - /// - /// Bear Call Ladder strategy is short 1 call and long 2 calls, with ascending strike prices in order, - /// All options have the same expiry. - /// - public static OptionStrategyDefinition BearCallLadder { get; } - = OptionStrategyDefinition.Create("Bear Call Ladder", - OptionStrategyDefinition.CallLeg(-1), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(+1, (legs, c) => c.Strike > legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) - ); - - /// - /// Bear Put Ladder strategy is long 1 put and short 2 puts, with descending strike prices in order, - /// All options have the same expiry. - /// - public static OptionStrategyDefinition BearPutLadder { get; } - = OptionStrategyDefinition.Create("Bear Put Ladder", - OptionStrategyDefinition.PutLeg(+1), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(-1, (legs, p) => p.Strike < legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) - ); - - /// - /// Bull Call Ladder strategy is long 1 call and short 2 calls, with ascending strike prices in order, - /// All options have the same expiry. + /// Sell 1 call contract without holding the underlying /// - public static OptionStrategyDefinition BullCallLadder { get; } - = OptionStrategyDefinition.Create("Bull Call Ladder", - OptionStrategyDefinition.CallLeg(+1), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[0].Strike, - (legs, c) => c.Expiration == legs[0].Expiration), - OptionStrategyDefinition.CallLeg(-1, (legs, c) => c.Strike > legs[1].Strike, - (legs, c) => c.Expiration == legs[0].Expiration) + public static OptionStrategyDefinition NakedCall { get; } + = OptionStrategyDefinition.Create("Naked Call", + OptionStrategyDefinition.CallLeg(-1) ); /// - /// Bull Put Ladder strategy is short 1 put and long 2 puts, with descending strike prices in order, - /// All options have the same expiry. + /// Sell 1 put contract without holding the underlying /// - public static OptionStrategyDefinition BullPutLadder { get; } - = OptionStrategyDefinition.Create("Bull Put Ladder", - OptionStrategyDefinition.PutLeg(-1), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[0].Strike, - (legs, p) => p.Expiration == legs[0].Expiration), - OptionStrategyDefinition.PutLeg(+1, (legs, p) => p.Strike < legs[1].Strike, - (legs, p) => p.Expiration == legs[0].Expiration) + public static OptionStrategyDefinition NakedPut { get; } + = OptionStrategyDefinition.Create("Naked Put", + OptionStrategyDefinition.PutLeg(-1) ); } } diff --git a/Tests/Common/Securities/Options/OptionStrategiesTests.cs b/Tests/Common/Securities/Options/OptionStrategiesTests.cs index bc3248b235c8..d7eb845112f4 100644 --- a/Tests/Common/Securities/Options/OptionStrategiesTests.cs +++ b/Tests/Common/Securities/Options/OptionStrategiesTests.cs @@ -1441,7 +1441,7 @@ public void BuildCallBackspreadStrategy() var strategy = OptionStrategies.CallBackspread(canonicalOptionSymbol, strike1, strike2, expiration); - Assert.AreEqual(OptionStrategyDefinitions.CallBackspread.Name, strategy.Name); + Assert.AreEqual("Call Backspread", strategy.Name); Assert.AreEqual(underlying, strategy.Underlying); Assert.AreEqual(canonicalOptionSymbol, strategy.CanonicalOption); @@ -1487,7 +1487,7 @@ public void BuildsPutBackspreadStrategy() var strategy = OptionStrategies.PutBackspread(canonicalOptionSymbol, strike1, strike2, expiration); - Assert.AreEqual(OptionStrategyDefinitions.PutBackspread.Name, strategy.Name); + Assert.AreEqual("Put Backspread", strategy.Name); Assert.AreEqual(underlying, strategy.Underlying); Assert.AreEqual(canonicalOptionSymbol, strategy.CanonicalOption); @@ -1533,7 +1533,7 @@ public void BuildsShortCallBackspreadStrategy() var strategy = OptionStrategies.ShortCallBackspread(canonicalOptionSymbol, strike1, strike2, expiration); - Assert.AreEqual(OptionStrategyDefinitions.ShortCallBackspread.Name, strategy.Name); + Assert.AreEqual("Short Call Backspread", strategy.Name); Assert.AreEqual(underlying, strategy.Underlying); Assert.AreEqual(canonicalOptionSymbol, strategy.CanonicalOption); @@ -1579,7 +1579,7 @@ public void BuildsShortPutBackspreadStrategy() var strategy = OptionStrategies.ShortPutBackspread(canonicalOptionSymbol, strike1, strike2, expiration); - Assert.AreEqual(OptionStrategyDefinitions.ShortPutBackspread.Name, strategy.Name); + Assert.AreEqual("Short Put Backspread", strategy.Name); Assert.AreEqual(underlying, strategy.Underlying); Assert.AreEqual(canonicalOptionSymbol, strategy.CanonicalOption);