Strategy Parameters¶
All Optopsy strategies accept a common set of parameters for filtering, grouping, and output formatting. This guide covers all available parameters and their usage.
Strict Parameter Validation
Parameters are validated at runtime using Pydantic. This means:
- Boolean parameters (
raw,drop_nan) must be actualboolvalues.raw=1orraw=0will raise a validation error — useraw=Trueorraw=False. - Float parameters (
min_bid_ask,delta_interval) must befloattype.min_bid_ask=5will be rejected — usemin_bid_ask=5.0. - Integer parameters (
max_entry_dte,exit_dte, etc.) rejectfloatandboolvalues. - Calendar/diagonal cross-field rules are enforced:
front_dte_minmust be ≤front_dte_max,back_dte_minmust be ≤back_dte_max, andfront_dte_maxmust be <back_dte_min.
Validation errors include the field name and constraint for easy debugging.
Core Parameters¶
Entry and Exit Timing¶
max_entry_dte¶
Type: int | Default: 90
Maximum days to expiration at strategy entry.
Use Cases:
- max_entry_dte=30 - Short-term trades
- max_entry_dte=60 - Medium-term trades
- max_entry_dte=90 - Longer-term positions
exit_dte¶
Type: int | Default: 0
Days to expiration when the strategy exits. Use 0 to hold until expiration.
Use Cases:
- exit_dte=0 - Hold to expiration
- exit_dte=21 - Exit 3 weeks before expiration
- exit_dte=7 - Exit 1 week before expiration
Filtering Parameters¶
min_bid_ask¶
Type: float | Default: 0.05
Minimum bid-ask spread required for option liquidity.
Use Cases:
- 0.05 - Less liquid underlyings
- 0.10 - Standard liquidity requirement
- 0.20 - High liquidity requirement (SPX, SPY)
Grouping and Aggregation¶
dte_interval¶
Type: int | Default: 7
Interval for grouping results by DTE ranges.
Examples:
- 7 - Weekly groupings: (0,7], (7,14], (14,21], ...
- 14 - Bi-weekly groupings: (0,14], (14,28], ...
- 30 - Monthly groupings: (0,30], (30,60], ...
delta_interval¶
Type: float | Default: 0.05
Interval for grouping results by delta ranges in aggregated output.
Output Control¶
raw¶
Type: bool | Default: False
Return raw trade data instead of aggregated statistics.
# Aggregated statistics (default)
results = op.iron_condor(data, raw=False)
# Output: ['dte_range', 'delta_range', 'count', 'mean', 'std', ...]
# Raw trade data
trades = op.iron_condor(data, raw=True)
# Output: ['expiration', 'strike_leg1', 'strike_leg2', 'entry', 'exit', 'pct_change', ...]
Use Cases:
- raw=False - Performance statistics, backtesting results
- raw=True - Custom analysis, detailed inspection, debugging
drop_nan¶
Type: bool | Default: True
Drop rows with NaN values in the results.
Per-Leg Delta Targeting¶
Optopsy uses per-leg delta targeting to select option strikes. Each leg of a strategy has its own delta parameter (leg1_delta, leg2_delta, etc.) that takes a TargetRange value specifying the ideal delta and an acceptable range.
TargetRange¶
A TargetRange has three fields:
| Field | Description |
|---|---|
target |
Ideal delta value (the engine picks the strike closest to this) |
min |
Minimum acceptable delta (options below this are excluded) |
max |
Maximum acceptable delta (options above this are excluded) |
All values are unsigned (0–1 for delta). The ordering constraint min <= target <= max is enforced.
from optopsy import TargetRange
# Target 30-delta options, accepting anything between 20 and 40
delta = TargetRange(target=0.30, min=0.20, max=0.40)
You can also pass a plain dict:
leg1_delta / leg2_delta / leg3_delta / leg4_delta¶
Type: TargetRange | dict | None | Default: strategy-dependent
Per-leg delta targeting. The number of legs depends on the strategy:
| Strategy Type | Legs Used |
|---|---|
| Single-leg (calls, puts) | leg1_delta |
| Straddles, strangles, vertical spreads | leg1_delta, leg2_delta |
| Butterflies | leg1_delta, leg2_delta, leg3_delta |
| Iron condors, iron butterflies | leg1_delta, leg2_delta, leg3_delta, leg4_delta |
| Covered strategies | leg1_delta (stock), leg2_delta (option) |
Each strategy has sensible defaults. For example:
| Role | Default Delta |
|---|---|
| Standard OTM leg | target=0.30, min=0.20, max=0.40 |
| ATM leg | target=0.50, min=0.40, max=0.60 |
| OTM wing | target=0.10, min=0.05, max=0.20 |
| Deep ITM (stock proxy) | target=0.80, min=0.60, max=0.95 |
Examples:
# Single-leg: target 20-delta puts
results = op.short_puts(
data,
leg1_delta={"target": 0.20, "min": 0.15, "max": 0.25}
)
# Iron condor: customize short strike deltas
results = op.iron_condor(
data,
leg2_delta={"target": 0.30, "min": 0.25, "max": 0.35}, # short put
leg3_delta={"target": 0.30, "min": 0.25, "max": 0.35}, # short call
)
Delta column required
Your data must include a delta column. This is a required column in Optopsy.
Early Exit Parameters¶
Early exits let you close positions before the scheduled exit_dte based on P&L thresholds or a maximum holding period. When an early exit triggers, the exit_type column in raw output indicates which condition fired.
stop_loss¶
Type: float | None | Default: None
Close the position early if unrealized P&L drops to or below this threshold. Must be a negative float.
take_profit¶
Type: float | None | Default: None
Close the position early if unrealized P&L reaches or exceeds this threshold. Must be a positive float.
max_hold_days¶
Type: int | None | Default: None
Close the position after holding for this many calendar days, regardless of P&L. Must be a positive integer.
exit_type Column Values¶
When early exits are enabled and raw=True, the output includes an exit_type column:
| Value | Meaning |
|---|---|
stop_loss |
Position hit the stop-loss threshold |
take_profit |
Position hit the take-profit threshold |
max_hold |
Position reached the maximum holding period |
expiration |
Position exited at scheduled exit_dte (no early exit triggered) |
Priority: If multiple conditions trigger on the same day, priority is: stop_loss > take_profit > max_hold.
Commission Parameters¶
commission¶
Type: Commission | float | None | Default: None
Commission fee structure applied to entry and exit trades. Accepts three forms:
Float shorthand — interpreted as per-contract fee:
Commission object — full fee structure:
from optopsy import Commission
results = op.iron_condor(
data,
commission=Commission(
per_contract=0.65, # Per option contract
base_fee=9.99, # Flat fee per trade
)
)
Commission fields:
| Field | Type | Default | Description |
|---|---|---|---|
per_contract |
float |
0.0 |
Fee per option contract |
per_share |
float |
0.0 |
Fee per share (for stock legs in covered strategies) |
base_fee |
float |
0.0 |
Flat fee per trade |
min_fee |
float |
0.0 |
Minimum fee per trade |
When set, commission costs are subtracted from P&L in the output.
Slippage Parameters¶
slippage¶
Type: str | Default: 'mid'
Slippage model for fill price calculation.
Options:
| Mode | Description | Buy Fill | Sell Fill | Best For |
|---|---|---|---|---|
'mid' |
Mid-price between bid/ask | (bid+ask)/2 | (bid+ask)/2 | Ideal/optimistic |
'spread' |
Worst-case spread | Ask | Bid | Conservative |
'liquidity' |
Volume-based dynamic | Dynamic | Dynamic | Realistic (volume) |
'per_leg' |
Scales with leg count | Dynamic | Dynamic | Realistic (complexity) |
fill_ratio (Liquidity Mode Only)¶
Type: float | Default: 0.5
Base fill ratio for liquidity-based slippage (0.0 = bid/ask, 1.0 = ask/bid).
results = op.iron_condor(
data,
slippage='liquidity',
fill_ratio=0.3 # More conservative fill (30% through spread)
)
Examples:
- 0.0 - Worst case (buy at ask, sell at bid)
- 0.5 - Mid-point (default)
- 1.0 - Best case (buy at bid, sell at ask - unrealistic)
reference_volume (Liquidity Mode Only)¶
Type: int | Default: 1000
Volume threshold for determining liquid options in liquidity mode.
results = op.short_strangles(
data,
slippage='liquidity',
reference_volume=5000 # Higher threshold for SPX
)
Guidelines:
- 500-1000 - Less liquid underlyings
- 1000-2000 - Standard liquidity (default)
- 5000+ - Highly liquid (SPX, SPY, QQQ)
Note: Requires volume or open_interest column in your data.
per_leg_slippage (Per-Leg Mode Only)¶
Type: float | Default: 0.073
Additive penalty per additional leg beyond the first. The effective fill ratio
increases with strategy complexity:
effective_ratio = min(fill_ratio + per_leg_slippage * (num_legs - 1), 1.0)
results = op.iron_condor(
data,
slippage='per_leg',
fill_ratio=0.25, # 1-leg base: 75% edge retained
per_leg_slippage=0.073, # penalty per extra leg
)
# 1-leg: ratio=0.250 (75% edge), 2-leg: 0.323 (~68%), 3-leg: 0.396 (~60%), 4-leg: 0.469 (~53%)
Notes:
- All legs in a strategy receive the same effective ratio (package pricing).
- The ratio is clamped to 1.0 (equivalent to 'spread' mode).
- Does not require a volume column.
Calendar & Diagonal Parameters¶
Calendar and diagonal spreads use different timing parameters:
front_dte_min / front_dte_max¶
Type: int | Default: 20 / 40
DTE range for the front-month leg.
results = op.long_call_calendar(
data,
front_dte_min=25,
front_dte_max=35 # Front leg between 25-35 DTE
)
back_dte_min / back_dte_max¶
Type: int | Default: 50 / 90
DTE range for the back-month leg.
results = op.long_call_diagonal(
data,
back_dte_min=60,
back_dte_max=120 # Back leg between 60-120 DTE
)
Complete Example¶
Combining multiple parameters:
import optopsy as op
data = op.csv_data('SPX_options.csv')
results = op.iron_condor(
data,
# Timing
max_entry_dte=45,
exit_dte=21,
# Per-leg delta targeting
leg2_delta={"target": 0.20, "min": 0.15, "max": 0.25},
leg3_delta={"target": 0.20, "min": 0.15, "max": 0.25},
# Filtering
min_bid_ask=0.15,
# Grouping
dte_interval=7,
delta_interval=0.05,
# Slippage
slippage='liquidity',
fill_ratio=0.5,
reference_volume=5000,
# Early exits
stop_loss=-1.0,
take_profit=0.50,
# Commission
commission=0.65,
# Output
raw=False,
drop_nan=True
)
print(results.head())
Default Values Reference¶
Standard Strategies¶
default_params = {
"dte_interval": 7,
"max_entry_dte": 90,
"exit_dte": 0,
"min_bid_ask": 0.05,
"delta_interval": 0.05,
"leg1_delta": None, # strategy-specific defaults applied by helpers
"leg2_delta": None,
"leg3_delta": None,
"leg4_delta": None,
"drop_nan": True,
"raw": False,
"slippage": "mid",
"fill_ratio": 0.5,
"reference_volume": 1000,
"per_leg_slippage": 0.073,
"stop_loss": None,
"take_profit": None,
"max_hold_days": None,
"commission": None,
}
Calendar & Diagonal Strategies¶
calendar_default_params = {
"front_dte_min": 20,
"front_dte_max": 40,
"back_dte_min": 50,
"back_dte_max": 90,
"exit_dte": 7,
"dte_interval": 7,
"min_bid_ask": 0.05,
"delta_interval": 0.05,
"drop_nan": True,
"raw": False,
"slippage": "mid",
"fill_ratio": 0.5,
"reference_volume": 1000,
"per_leg_slippage": 0.073,
}
Next Steps¶
- See Examples for real-world parameter usage
- Explore Strategies to understand strategy-specific considerations
- Review API Reference for function signatures