A nimble backtesting and statistics library for options strategies
Project description
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:
- HistoricalOptionData.com - Free samples available
- CBOE DataShop - Official exchange data
- Polygon.io - Options data API
- Your broker's data export
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2464348a5f2b41cf39be3120320e9277ea9226179c1e43510fb0802bd8f121ec
|
|
| MD5 |
aaacac05759a2f556e3dc984d9fa0bd2
|
|
| BLAKE2b-256 |
c95ac151e2384875def2ba9946747b7218a02208b89e2a6f5e0f91e6662ddecd
|
Provenance
The following attestation bundles were made for optopsy-2.2.0.tar.gz:
Publisher:
python-publish.yml on michaelchu/optopsy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
optopsy-2.2.0.tar.gz -
Subject digest:
2464348a5f2b41cf39be3120320e9277ea9226179c1e43510fb0802bd8f121ec - Sigstore transparency entry: 908463406
- Sigstore integration time:
-
Permalink:
michaelchu/optopsy@69ec4ee275f92a5a20de3ea03c74d10ec899956a -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/michaelchu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@69ec4ee275f92a5a20de3ea03c74d10ec899956a -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aca20e19224ee1193eddac8a015130e9d9fa178d39ab7090359fbb8a53494c0f
|
|
| MD5 |
4f5e0001dd6e64be9c104df13643c1ee
|
|
| BLAKE2b-256 |
6e7a045934ae9d18a78bdc420781671f22237e10ccbe17c719ce0de6385e16bf
|
Provenance
The following attestation bundles were made for optopsy-2.2.0-py3-none-any.whl:
Publisher:
python-publish.yml on michaelchu/optopsy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
optopsy-2.2.0-py3-none-any.whl -
Subject digest:
aca20e19224ee1193eddac8a015130e9d9fa178d39ab7090359fbb8a53494c0f - Sigstore transparency entry: 908463414
- Sigstore integration time:
-
Permalink:
michaelchu/optopsy@69ec4ee275f92a5a20de3ea03c74d10ec899956a -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/michaelchu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@69ec4ee275f92a5a20de3ea03c74d10ec899956a -
Trigger Event:
release
-
Statement type: