Skip to main content

A nimble backtesting and statistics library for options strategies

Project description

CI PyPI version Downloads Black

Optopsy

A fast, flexible backtesting library for options strategies in Python.

Optopsy helps you answer questions like "How do iron condors perform on SPX?" or "What delta range produces the best results for covered calls?" by generating comprehensive performance statistics from historical options data.

Features

  • 28 Built-in Strategies - From simple calls/puts to iron condors, butterflies, calendars, and diagonals
  • Greeks Filtering - Filter options by delta to target specific probability ranges
  • Flexible Grouping - Analyze results by DTE, OTM%, and delta intervals
  • Any Data Source - Works with any options data in CSV or DataFrame format
  • Pandas Native - Returns DataFrames that integrate with your existing workflow

Installation

pip install optopsy

Requirements: Python 3.8+, Pandas 2.0+, NumPy 1.26+

Quick Start

import optopsy as op

# Load your options data
data = op.csv_data(
    "options_data.csv",
    underlying_symbol=0,
    underlying_price=1,
    option_type=2,
    expiration=3,
    quote_date=4,
    strike=5,
    bid=6,
    ask=7,
)

# Backtest long calls and get performance statistics
results = op.long_calls(data)
print(results)

Output:

   dte_range    otm_pct_range  count   mean    std    min    25%    50%    75%    max
0    (0, 7]   (-0.05, -0.0]    505   0.64   1.03  -1.00   0.14   0.37   0.87   7.62
1    (0, 7]    (-0.0, 0.05]    269   2.34   8.65  -1.00  -1.00  -0.89   1.16  68.00
2   (7, 14]   (-0.05, -0.0]    404   1.02   0.68  -0.46   0.58   0.86   1.32   4.40
...

Results are grouped by DTE (days to expiration) and OTM% (out-of-the-money percentage), showing descriptive statistics for percentage returns.

Supported Strategies

Category Strategies
Single Leg long_calls, short_calls, long_puts, short_puts
Straddles/Strangles long_straddles, short_straddles, long_strangles, short_strangles
Vertical Spreads long_call_spread, short_call_spread, long_put_spread, short_put_spread
Butterflies long_call_butterfly, short_call_butterfly, long_put_butterfly, short_put_butterfly
Iron Condors iron_condor, reverse_iron_condor
Iron Butterflies iron_butterfly, reverse_iron_butterfly
Covered covered_call, protective_put
Calendar Spreads long_call_calendar, short_call_calendar, long_put_calendar, short_put_calendar
Diagonal Spreads long_call_diagonal, short_call_diagonal, long_put_diagonal, short_put_diagonal

Configuration Options

All strategy functions accept these optional parameters:

Parameter Default Description
dte_interval 7 Group results by DTE intervals (days)
max_entry_dte 90 Maximum days to expiration at entry
exit_dte 0 Target DTE for exit (0 = expiration)
otm_pct_interval 0.05 OTM percentage interval for grouping
max_otm_pct 0.5 Maximum OTM percentage to consider
min_bid_ask 0.05 Minimum bid/ask to filter out worthless options
raw False Return individual trades instead of grouped stats

Example: Custom Parameters

# Short puts with 30-60 DTE, held to expiration
results = op.short_puts(
    data,
    dte_interval=30,
    max_entry_dte=60,
    exit_dte=0,
    otm_pct_interval=0.10,
)

Calendar and Diagonal Spread Parameters

Calendar and diagonal spreads use different parameters to manage two expirations:

Parameter Default Description
front_dte_min 20 Minimum DTE for front (near-term) leg
front_dte_max 40 Maximum DTE for front leg
back_dte_min 50 Minimum DTE for back (longer-term) leg
back_dte_max 90 Maximum DTE for back leg
exit_dte 7 Days before front expiration to exit
# Long call calendar: short front-month, long back-month at same strike
results = op.long_call_calendar(
    data,
    front_dte_min=25,
    front_dte_max=35,
    back_dte_min=50,
    back_dte_max=70,
    exit_dte=7,
)

# Diagonal spread: different strikes and expirations
results = op.long_call_diagonal(data, raw=True)

Greeks Support

Filter and group options by delta for more precise strategy targeting.

Loading Data with Greeks

data = op.csv_data(
    "options_with_greeks.csv",
    underlying_symbol=0,
    underlying_price=1,
    option_type=2,
    expiration=3,
    quote_date=4,
    strike=5,
    bid=6,
    ask=7,
    delta=8,  # Optional: column index for delta
)

Delta Filtering

Target specific delta ranges at entry:

# Only 30-delta calls (delta between 0.25 and 0.35)
results = op.long_calls(data, delta_min=0.25, delta_max=0.35)

# High-probability short puts (delta >= -0.20)
results = op.short_puts(data, delta_max=-0.20)

# ATM straddles (delta around 0.50/-0.50)
results = op.long_straddles(data, delta_min=0.45, delta_max=0.55)

Delta Grouping

Analyze performance across delta ranges:

# Group results by 0.10 delta intervals
results = op.long_calls(data, delta_interval=0.10)

Output:

   delta_range  dte_range  otm_pct_range  count   mean    std
0   (0.2, 0.3]   (7, 14]  (-0.10, -0.05]     42  -0.15   0.52
1   (0.3, 0.4]   (7, 14]  (-0.05, -0.00]     48   0.22   0.41
2   (0.4, 0.5]   (7, 14]  (-0.00,  0.05]     35   0.45   0.33
...

Raw Trade Data

Get individual trades instead of grouped statistics:

trades = op.iron_condor(data, raw=True)
print(trades.columns)
# ['underlying_symbol', 'expiration', 'dte_entry', 'strike_leg1',
#  'strike_leg2', 'strike_leg3', 'strike_leg4', 'total_entry_cost',
#  'total_exit_proceeds', 'pct_change', ...]

Data Format

Optopsy expects options chain data with these columns:

Column Type Description
underlying_symbol string Ticker symbol (e.g., "SPX")
underlying_price float Price of underlying at quote time
option_type string "call" or "put" (or "c"/"p")
expiration datetime Option expiration date
quote_date datetime Date of the quote
strike float Strike price
bid float Bid price
ask float Ask price
delta float (Optional) Delta Greek

Using DataFrames Directly

If your data is already in a DataFrame:

import pandas as pd
import optopsy as op

# Your DataFrame just needs the required columns
df = pd.read_csv("my_data.csv")
df.columns = ['underlying_symbol', 'underlying_price', 'option_type',
              'expiration', 'quote_date', 'strike', 'bid', 'ask']
df['expiration'] = pd.to_datetime(df['expiration'])
df['quote_date'] = pd.to_datetime(df['quote_date'])

# Pass directly to strategy functions
results = op.short_strangles(df)

Data Sources

Optopsy works with any historical options data. Some sources:

Documentation

See the Wiki for detailed API reference and examples.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

# Development setup
git clone https://github.com/michaelchu/optopsy.git
cd optopsy
pip install -e .

# Run tests
pytest tests/ -v

# Format code
black optopsy/ tests/

License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

optopsy-2.2.0.tar.gz (40.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

optopsy-2.2.0-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file optopsy-2.2.0.tar.gz.

File metadata

  • Download URL: optopsy-2.2.0.tar.gz
  • Upload date:
  • Size: 40.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for optopsy-2.2.0.tar.gz
Algorithm Hash digest
SHA256 2464348a5f2b41cf39be3120320e9277ea9226179c1e43510fb0802bd8f121ec
MD5 aaacac05759a2f556e3dc984d9fa0bd2
BLAKE2b-256 c95ac151e2384875def2ba9946747b7218a02208b89e2a6f5e0f91e6662ddecd

See more details on using hashes here.

Provenance

The following attestation bundles were made for optopsy-2.2.0.tar.gz:

Publisher: python-publish.yml on michaelchu/optopsy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file optopsy-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: optopsy-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for optopsy-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aca20e19224ee1193eddac8a015130e9d9fa178d39ab7090359fbb8a53494c0f
MD5 4f5e0001dd6e64be9c104df13643c1ee
BLAKE2b-256 6e7a045934ae9d18a78bdc420781671f22237e10ccbe17c719ce0de6385e16bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for optopsy-2.2.0-py3-none-any.whl:

Publisher: python-publish.yml on michaelchu/optopsy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page