This folder contains a backtest that compares these overnight positions:
- Straddle: call + put at the same (ATM) strike
- Strangle: OTM call + OTM put at different strikes
- Equity baseline: long shares from close to next open
For each trading day, the backtest enters at the close and exits at the next open.
Outputs go to outputs/:
pnl.png: three panels- Cumulative P&L in dollars
- Free cash after entry (account equity minus capital required)
- Trade-by-trade P&L in dollars
trades.csv: one row per trade per strategyperformance.csv: trailing percent returns (1d, 1m, 1y, etc.) per strategy line
Historical option prices are not pulled from an options data feed. Instead, the backtest prices the call and put using Black–Scholes (European, no dividends) with volatility coming from either:
- Rolling realized volatility from the underlying’s daily closes, or
- A fixed implied volatility from the config
This means the option P&L is model-based and will differ from live fills and real option markets.
- Python 3.7 or higher
- Dependencies:
yfinance,pandas,numpy,matplotlib,PyYAML - For Python 3.7:
typing_extensionsandpytzare automatically installed if using pip - Install all dependencies:
pip3 install -e .orpip3 install yfinance pandas numpy matplotlib PyYAML typing_extensions pytz
From OvernightStraddleBacktest/:
Show the plot window:
PYTHONPATH=src python3 -m overnight_straddle.main --config config.yamlRun without opening a plot window (still writes PNG and CSVs):
MPLBACKEND=Agg PYTHONPATH=src python3 -m overnight_straddle.main --config config.yaml --no-showsrc/overnight_straddle/realtime_short_straddle.py is a long-running script that:
- Starts with a cash balance of 50000 (configurable)
- Near the close, records a paper fill for a short straddle
- At the next open, records a paper close
- After closing, posts the last trade P&L and current equity to a Discord webhook
It uses yfinance option chain quotes for paper fills (bid/ask/last). It does not place live orders.
Run it:
export DISCORD_WEBHOOK_URL="(your webhook url)"
PYTHONPATH=src python3 -m overnight_straddle.realtime_short_straddle --config realtime_config.yaml- List of tickers to backtest, e.g.
["SPY"]. Each ticker is run independently.
source:yfinanceorcsvinterval: only1dis expected for this strategycsv_folder: used only ifsource=csv. Expectsdata/<TICKER>.csvwith columnsDate,Open,High,Low,Close.
lookback_trading_days: number of most recent trading days to includeend_date: optional end date (YYYY-MM-DD).nullmeans use the most recent data.
strategies: any ofstraddle,strangle(the equity baseline is controlled separately)position:long: buy at close, sell at next openshort: sell at close, buy back at next open
include_equity_baseline: if true, also runslong equity(close → next open)
allow_weekend_holds:true: includes Friday close → Monday openfalse: skips trades where the next trading day is more than 1 calendar day away
dte_days: assumed calendar days to expiry for the option used at entryinclude_weekends_in_time_decay:true: Friday close → Monday open uses the larger calendar time gap for thetafalse: treats any close → next open as a fixed overnight duration for theta
strike_rounding: rounds strikes to the nearest increment (e.g. 1.0 means $1 strikes)strangle.call_otm_pct: call strike set to (S \cdot (1 + call_otm_pct))strangle.put_otm_pct: put strike set to (S \cdot (1 - put_otm_pct))contract_multiplier: typically 100 for US equity optionscontracts_per_trade: number of straddles/strangles per trade per day
method:rolling_realizedorfixedlookback_days: lookback for realized volatility (daily closes)fixed_iv: used ifmethod=fixed(and as a fallback)
risk_free_rate: annualized rate used by Black–Scholes
slippage_bps: bps applied on entry and exit notional (options and equity)
shares_per_trade: used by the equity baseline
short_options_pct_underlying: used only for plotting “capital required” on short option trades. It is a proxy for how much of the account is tied up when holding a short straddle/strangle.
initial_balance: starting account balance for percent return calculations (default 100000)horizons_trading_days: trailing return windows in trading days (e.g. 1m=21, 1y=252)
output_dir: output directory (relative to config file)save_png: whether to writepnl.pngshow: whether to display the matplotlib window (can be overridden by--no-show)
This is a sensitivity analysis for the option strategies (straddle/strangle). It does not use real option data. It re-prices each trade using Black–Scholes under a grid of assumptions, then writes additional CSVs and a chart.
enabled: runs the stress test if trueiv_shift_entry_points: list of absolute volatility shifts applied at entry (e.g.0.05means +5 vol points)iv_shift_exit_points: list of absolute volatility shifts applied at exitoption_half_spread_pct: half-spread applied to option premiums:- buys use
mid * (1 + half_spread) - sells use
mid * (1 - half_spread)
- buys use
extra_slippage_bps: extra bps slippage applied on top ofstrategy.costs.slippage_bpsplot: if true, writesoutputs/stress.pngshowing total return vs exit IV shift
Disclaimer: This project was created with the assistance of Cursor AI