Skip to content

Add butterfly, iron condor, and covered strategies#73

Merged
michaelchu merged 7 commits intomasterfrom
claude/add-options-strategies-BJJtb
Feb 3, 2026
Merged

Add butterfly, iron condor, and covered strategies#73
michaelchu merged 7 commits intomasterfrom
claude/add-options-strategies-BJJtb

Conversation

@michaelchu
Copy link
Copy Markdown
Member

Summary

This PR adds support for 10 new multi-leg options strategies: 4 butterfly strategies (long/short call/put), 4 iron condor strategies (iron condor, reverse iron condor, iron butterfly, reverse iron butterfly), and 2 covered strategies (covered call, protective put).

Key Changes

New Strategy Functions (optopsy/strategies.py)

  • Butterfly strategies (3 legs): long_call_butterfly, short_call_butterfly, long_put_butterfly, short_put_butterfly
  • Iron condor strategies (4 legs): iron_condor, reverse_iron_condor, iron_butterfly, reverse_iron_butterfly
  • Covered strategies (2 legs): covered_call, protective_put
  • Added helper functions _call_butterfly, _put_butterfly, _iron_condor, _iron_butterfly, and _covered_call to reduce code duplication

Core Engine Improvements (optopsy/core.py)

  • Enhanced _apply_ratios() to support leg quantities (e.g., short 2 contracts at middle strike in butterfly)
  • Added _get_leg_quantity() helper to extract quantity from leg tuples (defaults to 1)
  • Added _rename_leg_columns() to pre-rename columns before merging, fixing suffix issues with 3+ legs
  • Refactored _strategy_engine() to use sequential merging instead of reduce, improving clarity and correctness

Validation Rules (optopsy/rules.py)

  • Added _rule_butterfly_strikes(): Validates strike ordering and equal wing widths for butterfly strategies
  • Added _rule_iron_condor_strikes(): Validates ascending strike ordering for iron condors
  • Added _rule_iron_butterfly_strikes(): Validates strike ordering with middle legs at same strike for iron butterflies

Configuration Updates (optopsy/definitions.py)

  • Added triple_strike_internal_cols and triple_strike_external_cols for 3-leg strategies
  • Added quadruple_strike_internal_cols and quadruple_strike_external_cols for 4-leg strategies
  • Updated column definitions to use underlying_price_entry_leg1, total_entry_cost, total_exit_proceeds, and pct_change for consistency

Module Exports (optopsy/init.py)

  • Exported all 10 new strategy functions and csv_data in __all__

Tests (tests/test_strategies.py, tests/conftest.py)

  • Added multi_strike_data fixture with 5 equidistant strikes for testing multi-leg strategies
  • Added comprehensive tests for all new strategies covering both raw and aggregated output formats
  • Tests validate correct leg types, strike ordering, and output column structure

Implementation Details

  • Leg definitions now support optional quantity as a third tuple element: (Side, function, quantity)
  • The strategy engine pre-renames columns to avoid pandas suffix conflicts when merging 3+ legs
  • All strategies follow consistent patterns with dedicated helper functions for code reuse
  • Strike validation rules ensure proper configuration before profit/loss calculations

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

… strategies

New strategies implemented:
- Long/short call butterfly (3-leg)
- Long/short put butterfly (3-leg)
- Iron condor and reverse iron condor (4-leg)
- Iron butterfly and reverse iron butterfly (4-leg)
- Covered call (synthetic, 2-leg)
- Protective put (synthetic, 2-leg)

Key changes:
- Extended core.py to support 3+ leg strategies with proper column renaming
- Added quantity multipliers per leg for butterfly strategies (1:2:1 ratio)
- Added new rules for butterfly and iron condor strike ordering validation
- Updated definitions.py with correct column definitions for multi-leg strategies
- Added comprehensive test coverage with new multi-strike test fixture

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX
Updated tests to verify actual P&L calculations:
- Long call butterfly: entry=0.40, exit=0.05, pct=-0.88 (at 210/212.5/215)
- Long put butterfly: entry=0.40, exit=0.0, pct=-1.0 (puts expired worthless)
- Iron condor: entry=-1.90 (credit), exit=-0.025, pct=0.99 (kept premium)
- Iron butterfly: entry=-5.00 (credit), exit=-2.475, pct=0.50
- Covered call: entry=1.50, exit=2.45, pct=0.63
- Protective put: entry=8.40, exit=7.525, pct=-0.10

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX
Added documentation for:
- Butterfly strategies (long/short call/put butterfly)
- Iron condor and reverse iron condor
- Iron butterfly and reverse iron butterfly
- Covered call and protective put (synthetic)

Also updated pip install version to 2.0.3.

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX
@michaelchu michaelchu requested a review from Copilot February 2, 2026 21:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for 10 new multi-leg options strategies to expand the library's capabilities beyond existing single and two-leg strategies. The new strategies include butterfly spreads (3 legs), iron condors and iron butterflies (4 legs), and synthetic covered positions.

Changes:

  • Added 10 new strategy functions: 4 butterfly strategies, 4 iron condor/butterfly strategies, and 2 covered strategies
  • Enhanced the core engine to support leg quantities and improved multi-leg merging logic
  • Added validation rules for butterfly and iron condor strike configurations

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
optopsy/strategies.py Implements all 10 new strategy functions with helper functions to reduce code duplication
optopsy/core.py Enhances strategy engine to support leg quantities and fixes column naming issues for 3+ leg strategies
optopsy/rules.py Adds strike validation rules for butterfly, iron condor, and iron butterfly strategies
optopsy/definitions.py Updates column definitions for 3-leg and 4-leg strategies to use consistent naming
optopsy/init.py Exports all new strategy functions and csv_data
tests/test_strategies.py Adds comprehensive tests for all new strategies covering raw and aggregated outputs
tests/conftest.py Adds multi_strike_data fixture with 5 equidistant strikes for testing multi-leg strategies
README.md Updates documentation to list all supported strategies by leg count and version number

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread optopsy/definitions.py
Comment thread optopsy/core.py Outdated
1. Fix lambda late binding in _apply_ratios (core.py)
   - Capture entry_col and exit_col as default arguments to avoid
     late binding issues in lambda functions

2. Add dte_range to triple/quadruple strike internal columns (definitions.py)
   - Restores dte_range field that was present in original code
   - Provides users with DTE range information in raw output

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX
@michaelchu michaelchu requested a review from Copilot February 2, 2026 22:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_strategies.py Outdated
Comment thread tests/test_strategies.py Outdated
michaelchu and others added 2 commits February 2, 2026 17:07
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@michaelchu michaelchu requested a review from Copilot February 2, 2026 22:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread optopsy/core.py


def _get_leg_quantity(leg: Tuple) -> int:
"""Get quantity for a leg, defaulting to 1 if not specified."""
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function docstring should document the expected structure of the leg tuple parameter, including that element [2] represents quantity and what elements [0] and [1] represent for clarity.

Suggested change
"""Get quantity for a leg, defaulting to 1 if not specified."""
"""
Get quantity for a leg, defaulting to 1 if not specified.
The leg tuple is expected to have the form ``(side, spec, quantity)``:
- ``leg[0]``: The side/ratio object for the leg (for example, an enum or
similar object whose ``.value`` is later used as a price multiplier).
- ``leg[1]``: Leg-specific metadata or specification (such as the option
type or other selector used elsewhere in the evaluation pipeline).
- ``leg[2]``: (Optional) Integer quantity for this leg. If this element is
omitted, a default quantity of ``1`` is assumed.
"""

Copilot uses AI. Check for mistakes.
Comment thread optopsy/core.py
Comment on lines +220 to +227
def _rename_leg_columns(
data: pd.DataFrame, leg_idx: int, join_on: List[str]
) -> pd.DataFrame:
"""Rename columns with leg suffix, excluding join columns."""
rename_map = {
col: f"{col}_leg{leg_idx}" for col in data.columns if col not in join_on
}
return data.rename(columns=rename_map)
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters data, leg_idx, and join_on, as well as the return value. It should also explain why join columns are excluded from renaming.

Copilot uses AI. Check for mistakes.
Comment thread optopsy/strategies.py

Note: This implementation simulates a covered call using options data only,
approximating the underlying position through the relationship between
option premiums and underlying price changes.
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters data, leg_def, and **kwargs, as well as the return value, for consistency with other helper functions like _call_butterfly and _put_butterfly.

Suggested change
option premiums and underlying price changes.
option premiums and underlying price changes.
Args:
data: DataFrame containing option chain data used to construct the
covered call strategy.
leg_def: List of leg definitions for the strategy, where each element
is a tuple of (Side, option_type_function) describing whether the
leg is long/short and whether it uses calls or puts.
**kwargs: Optional strategy parameters that override values in
``default_kwargs`` and are forwarded to ``_process_strategy``.
Returns:
DataFrame with covered call strategy performance statistics.

Copilot uses AI. Check for mistakes.
Comment thread optopsy/strategies.py
Comment on lines +295 to +298
def _call_butterfly(
data: pd.DataFrame, leg_def: List[Tuple], **kwargs: Any
) -> pd.DataFrame:
"""Process call butterfly strategies (3 legs at different strikes)."""
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters and return value for consistency with public strategy functions.

Copilot uses AI. Check for mistakes.
Comment thread optopsy/strategies.py
def _put_butterfly(
data: pd.DataFrame, leg_def: List[Tuple], **kwargs: Any
) -> pd.DataFrame:
"""Process put butterfly strategies (3 legs at different strikes)."""
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters and return value for consistency with public strategy functions.

Suggested change
"""Process put butterfly strategies (3 legs at different strikes)."""
"""
Process put butterfly strategies (3 legs at different strikes).
Args:
data: DataFrame containing option chain data.
leg_def: List of tuples defining each leg of the butterfly, including
side, option type, and quantity.
**kwargs: Optional strategy parameters to override defaults.
Returns:
DataFrame with put butterfly strategy performance statistics.
"""

Copilot uses AI. Check for mistakes.
Comment thread optopsy/strategies.py
Comment on lines +452 to +455
def _iron_condor(
data: pd.DataFrame, leg_def: List[Tuple], **kwargs: Any
) -> pd.DataFrame:
"""Process iron condor strategies (4 legs at different strikes)."""
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters and return value for consistency with public strategy functions.

Copilot uses AI. Check for mistakes.
Comment thread optopsy/strategies.py
Comment on lines +468 to +471
def _iron_butterfly(
data: pd.DataFrame, leg_def: List[Tuple], **kwargs: Any
) -> pd.DataFrame:
"""Process iron butterfly strategies (4 legs, middle legs share strike)."""
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should document the parameters and return value for consistency with public strategy functions.

Copilot uses AI. Check for mistakes.
@michaelchu
Copy link
Copy Markdown
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 2, 2026

@michaelchu I've opened a new pull request, #74, to work on those changes. Once the pull request is ready, I'll request review from you.

@michaelchu michaelchu merged commit ac04aec into master Feb 3, 2026
1 of 6 checks passed
@michaelchu michaelchu deleted the claude/add-options-strategies-BJJtb branch February 3, 2026 00:58
michaelchu added a commit that referenced this pull request Feb 25, 2026
* Add 10 new options strategies: butterflies, iron condors, and covered strategies

New strategies implemented:
- Long/short call butterfly (3-leg)
- Long/short put butterfly (3-leg)
- Iron condor and reverse iron condor (4-leg)
- Iron butterfly and reverse iron butterfly (4-leg)
- Covered call (synthetic, 2-leg)
- Protective put (synthetic, 2-leg)

Key changes:
- Extended core.py to support 3+ leg strategies with proper column renaming
- Added quantity multipliers per leg for butterfly strategies (1:2:1 ratio)
- Added new rules for butterfly and iron condor strike ordering validation
- Updated definitions.py with correct column definitions for multi-leg strategies
- Added comprehensive test coverage with new multi-strike test fixture

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

* Remove unused reduce import from core.py

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

* Add calculated value assertions to new strategy tests

Updated tests to verify actual P&L calculations:
- Long call butterfly: entry=0.40, exit=0.05, pct=-0.88 (at 210/212.5/215)
- Long put butterfly: entry=0.40, exit=0.0, pct=-1.0 (puts expired worthless)
- Iron condor: entry=-1.90 (credit), exit=-0.025, pct=0.99 (kept premium)
- Iron butterfly: entry=-5.00 (credit), exit=-2.475, pct=0.50
- Covered call: entry=1.50, exit=2.45, pct=0.63
- Protective put: entry=8.40, exit=7.525, pct=-0.10

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

* Update README with new supported strategies

Added documentation for:
- Butterfly strategies (long/short call/put butterfly)
- Iron condor and reverse iron condor
- Iron butterfly and reverse iron butterfly
- Covered call and protective put (synthetic)

Also updated pip install version to 2.0.3.

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

* Address Copilot review comments

1. Fix lambda late binding in _apply_ratios (core.py)
   - Capture entry_col and exit_col as default arguments to avoid
     late binding issues in lambda functions

2. Add dte_range to triple/quadruple strike internal columns (definitions.py)
   - Restores dte_range field that was present in original code
   - Provides users with DTE range information in raw output

https://claude.ai/code/session_01J51zgxv7jGDSscXN8sWEdX

* Update tests/test_strategies.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update tests/test_strategies.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants