Skip to main content

OpTrade

Downloads Documentation Status License Python Version Code style: black

OpTrade is a complete toolkit for quantitative research and development of options trading strategies. By abstracting away the complexity of data handling and experimental setup, researchers and traders can focus on what matters most: developing and testing alpha-generating ideas.

OpTrade Framework

Installation

The recommended way to install OptTrade is via pip:

pip install optrade

*Note: At this time OpTrade requires an active subscription to ThetaData API for the stocks (VALUE) and options (VALUE) packages.

Example (Single Contract)

# Step 1: Find and initialize the optimal contract
from optrade.data.contracts import Contract

contract = Contract.find_optimal(
    root="AAPL",
    right="C",              # Call option
    start_date="20230103",  # First trading day of 2023
    target_tte=30,          # Desired expiration: 30 days
    tte_tolerance=(20, 40), # Min 20, max 40 days expiration
    interval_min=1,         # Data requested at 1-min level
    moneyness="ATM",        # At-the-money option
)

# Step 2: Load market data (NBBO quotes and OHLCV)
df = contract.load_data()

# Step 3: Transform raw data into ML-ready features
from optrade.data.features import transform_features

data = transform_features(
    df=df,
    core_feats=[
        "option_returns",     # Option price returns
        "stock_returns",      # Underlying stock returns
        "moneyness",          # Log(S/K)
        "option_lob_imbalance", # Order book imbalance
        "stock_quote_spread", # Bid-ask spread normalized
    ],
    tte_feats=["sqrt", "exp_decay"],  # Time-to-expiration features
    datetime_feats=["minute_of_day", "hour_of_week"],  # Time features
    vol_feats=["rolling_volatility", "vol_ratio"], # Rolling volatility window and short-to-long volatility ratio
    rolling_volatility_range=[20, 60], # 20min and 60min rolling volatility windows
    strike=contract.strike,
    exp=contract.exp,
    root=contract.root,
    right=contract.right,
)

# Step 4: Create dataset for time series forecasting
from optrade.data.forecasting import ForecastingDataset
from torch.utils.data import DataLoader

torch_dataset = ForecastingDataset(
    data=data,
    seq_len=100,        # 100-minute lookback window
    pred_len=10,        # 10-minute forecast horizon
    target_channels=["option_returns"],  # Forecast option returns
)

torch_loader = DataLoader(torch_dataset)

Overview

🔄 Data Pipeline OpTrade integrates with ThetaData's API for affordable options and security data access (down to 1-min resolution). The framework processes NBBO quotes and OHLCVC metrics through a contract selection system optimizing for moneyness, expiration windows, and volatility-scaled strikes.

🌐 Market Environments Built-in market environments enable precise universe selection through multifaceted filtering. OpTrade supports composition by major indices, fundamental-based screening (e.g., PE ratio, market cap), and Fama-French model categorization.

🧪 Experimental Pipeline The experimentation framework supports PyTorch and scikit-learn for options forecasting with online Neptune logging, hyperparameter tuning, and model version control, supporting both online and offline experiment tracking.

🧮 Featurization OpTrade provides option market features including mid-price derivations, order book imbalance metrics, quote spreads, and moneyness calculations. Time-to-expiration transformations capture theta decay effects, while datetime features extract cyclical market patterns for intraday seasonality.

🤖 Models OpTrade includes several off-the-shelf PyTorch and scikit-learn models, including state-of-the-art architectures for time series forecasting alongside tried and true machine learning methods.

Advanced Usage

Multiple Contracts

When modeling multiple contracts, you can use the ContractDataset class to find a set of optimal contracts with similar parameters and then use the get_forecasting_dataset function to load and transform the data for all contracts:

# Step 1: Find a set of optimal contracts from total_start_date to total_end_date
from optrade.data.contracts import ContractDataset

contract_dataset = ContractDataset(
    root="AMZN",
    total_start_date="20220101",
    total_end_date="20220301",
    contract_stride=1,
    interval_min=1,
    right="P",
    target_tte=3,
    tte_tolerance=(1,10),
    moneyness="ITM",
    strike_band=0.05,
    volatility_scaled=True,
    volatility_scalar=0.1,
    hist_vol=0.1117,
)
contract_dataset.generate()

# Step 2: Load market data and transform features for all contracts then put into a concatenated torch dataset
from optrade.data.forecasting import get_forecasting_dataset
from torch.utils.data import DataLoader

torch_dataset = get_forecasting_dataset(
    contract_dataset=contract_dataset,
    core_feats=["option_returns"],
    tte_feats=["sqrt"],
    datetime_feats=["sin_minute_of_day"],
    tte_tolerance=(25, 35),
    seq_len=100,
    pred_len=10,
    verbose=True
)
torch_loader = DataLoader(torch_dataset)

Forecasting (PyTorch)

When running forecasting experiments, you can use the Experiment class from optrade.exp.forecasting which supports PyTorch deep learning (DL) models. Several state-of-the-art models are available in the optrade.models.pytorch, allowing you to easily experiment with different modern DL architectures:

# Step 1: Initialize the experiment with offline logging
from optrade.exp.forecasting import Experiment
exp = Experiment(logging="offline")

# Set device to GPU if available, otherwise CPU
import torch
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# Define feature sets for the model
core_feats = ["option_returns", "option_volume", "stock_lob_imbalance"]  # Core features
tte_feats = ["sqrt"]  # Time-to-expiration features
datetime_feats = ["sin_minute_of_day"]  # Temporal features
input_channels = core_feats + tte_feats + datetime_feats  # Combined input features
target_channels = ["option_returns"]  # Target variable

# Step 2: Initialize data loaders with specified configuration
exp.init_loaders(
    root="TSLA",                       # Ticker symbol
    start_date="20210601",             # Full dataset start date
    end_date="20211231",               # Full dataset end date
    contract_stride=5,                 # Sample contracts every 5 days
    interval_min=5,                    # 5-minute intervals
    right="C",                         # Call options
    target_tte=30,                     # Target 30 days to expiration
    tte_tolerance=(15, 45),            # Accept options with 15-45 days to expiration
    moneyness="ATM",                   # At-the-money options
    train_split=0.5,                   # 50% of data for training
    val_split=0.25,                    # 25% of data for validation (remaining 25% for testing)
    seq_len=12,                        # Input sequence length (12 x 5min = 1 hour lookback)
    pred_len=4,                        # Prediction length (4 x 5min = 20 minute forecast)
    scaling=True,                      # Normalize all features
    core_feats=core_feats,
    tte_feats=tte_feats,
    datetime_feats=datetime_feats,
    target_channels=target_channels,
    # DataLoader settings
    num_workers=0,                     # Single-process (development safe)
    prefetch_factor=None,              # No prefetching batches
    persistent_workers=False,          # Kill workers between epochs
)

# Step 3: Define model architecture
from optrade.models.pytorch.patchtst import Model as PatchTST
model = PatchTST(
    num_enc_layers=2,                  # Number of Transformer encoder layers
    d_model=32,                        # Model dimension (embedding size)
    d_ff=64,                           # Feed-forward network dimension
    num_heads=2,                       # Number of self-attention heads
    seq_len=12,                        # Input sequence length (must match data config)
    pred_len=4,                        # Prediction length (must match data config)
    patch_dim=2,                       # Patch dimension
    stride=2,                          # Patch stride
    input_channels=input_channels,
    target_channels=target_channels,
).to(device)

# Define optimization method and objetive (loss) function
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)  # Adam optimizer
criterion = torch.nn.MSELoss()                             # Mean Squared Error loss

# Step 4: Train the model
model = exp.train_torch(
    model=model,
    device=device,
    optimizer=optimizer,
    criterion=criterion,
    num_epochs=5,                      # Number of training epochs
    early_stopping=True,               # Enable early stopping
    patience=20,                       # Number of epochs before early stopping
)

# Step 5: Evaluate model on test set
exp.test(
    model=model,
    criterion=criterion,
    metrics=["mse"],                  # Metrics to compute
    device=device,                     # Computing device (CPU/GPU)
)
exp.save_logs() # Save experiment logs to disk

Universe

When modeling a universe of securities, you can use the Universe class to filter by parameters such as fundamentals (e.g., P/E ratio), volatility, and Fama-French factor exposures. Here's an example:

from optrade.data.universe import Universe

# Step 1: Initialize Universe
universe = Universe(
    dow_jones=True,                # Use Dow Jones as the starting universe
    start_date="20210101",
    end_date="20211001",

    # Filters
    debt_to_equity="low",          # Low debt ratio (bottom third)
    market_cap="high",             # Large-cap (top third)
    investment_beta="aggressive",  # Aggressive investment strategy (Fama-French exposure)
)

# Step 2: Fetch constituents from Wikipedia
universe.set_roots()

# Step 3: Get market metric data via yfinance & compute Fama-French exposures
universe.get_market_metrics()
print(f"Universe: {universe.roots}")

# Step 4: Apply filters (low debt, high market cap, aggressive investment beta)
universe.filter()
print(f"Filtered universe: {universe.roots}")

# Step 5: Download options data for filtered universe
universe.download(
    contract_stride=3,          # Sample contracts every 3 days
    interval_min=1,             # Data requested at 1-min level
    right="C",                  # Calls options only
    target_tte=30,              # Desired expiration: 30 days
    tte_tolerance=(20, 40),     # Min 20, max 40 days expiration
    moneyness="ATM",            # At-the-money option
    train_split=0.5,            # 50% training
    val_split=0.3,              # 30% validation and (hence 20% test)
)

# Step 6: Select a stock the universe and create PyTorch dataloders
root = universe.roots[0]
print(f"Loading data for root: {root}")

loaders = universe.get_forecasting_loaders(
    offline=True,               # Use cached data
    root=root,                  # Stock symbol
    tte_tolerance=(20, 40),     # DTE range
    seq_len=30,                 # 30-min lookback
    pred_len=5,                 # 5-min forecast
    core_feats=["option_mid_price"],  # Feature
    target_channels=["option_mid_price"],  # Target
    dtype="float32",            # Precision
    scaling=False,              # No normalization
)

# Display dataset sizes for each split
print(f"Train loader: {len(loaders[0].dataset)} samples")
print(f"Validation loader: {len(loaders[1].dataset)} samples")
print(f"Test loader: {len(loaders[2].dataset)} samples")

Contact

For queries, please contact: xmootoo at gmail dot com.

Release files for optrade 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for optrade 1.0.0
File Size Uploaded
optrade-1.0.0.tar.gz 5.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for optrade 1.0.0
File Interpreter ABI Platform
optrade-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 10.4 MB

Release files / optrade-1.0.0.tar.gz

Download URL optrade-1.0.0.tar.gz
Size 5.2 MB
Tags Source
SHA-256 checksum
How to use checksums
37ae961e79f043de0343f316204b831b62801db2d3907621ce4fbad34d2ee71a
BLAKE2b-256 checksum
How to use checksums
7040c4894288a4195fa6c85c4a2846b0e3facbce998a6d9fde12d049be09ba5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.13.3 Darwin/23.2.0

Release files / optrade-1.0.0-py3-none-any.whl

Download URL optrade-1.0.0-py3-none-any.whl
Size 5.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
4919ce455968f02b9d7b652e1046933fe7eefb5ea0e8a388222dee8558a7bbb9
BLAKE2b-256 checksum
How to use checksums
733b59d74f03509efac1e1d55762e6400e51e6ab814f2b2da1b623e2a6b51c72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.13.3 Darwin/23.2.0

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.0.15

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page