|
| 1 | +# 0DTE Options Strategy Backtesting System |
| 2 | + |
| 3 | +## Overview |
| 4 | +This system lets you backtest a 0DTE (zero days to expiration) bull put spread options strategy using historical data from Alpaca and Databento. It automates the process of finding, simulating, and evaluating same-day expiry put spreads on underlying stock (default: SPY), with robust risk management and predefined trade logic. |
| 5 | + |
| 6 | +**Note:** This backtesting system is supplemental to our tutorial guide [How To Trade 0DTE Options with Alpaca's Trading API](https://alpaca.markets/learn/how-to-trade-0dte-options-on-alpaca), which covers the theoretical foundations and practical implementation of 0DTE strategies using the live market data. |
| 7 | + |
| 8 | + |
| 9 | +## How It Works (Summary) |
| 10 | +1. **Setup**: Connect to Alpaca and Databento API and set parameters. |
| 11 | +2. **Data Collection**: Download historical stock (bar data) and options data (tick data) at 1-minute intervals for the backtesting window. |
| 12 | +3. **Trade Simulation**: |
| 13 | + - **Initialization**: |
| 14 | + - Start scanning through historical market data chronologically from the earliest timestamp. |
| 15 | + - **Option Analysis**: |
| 16 | + - Calculate the options Greeks (delta) and Implied Volatility (IV) for each option symbol. |
| 17 | + - Find the first valid option pair that meets our trading criteria to build the bull put spread |
| 18 | + - **Continuous Monitoring**: |
| 19 | + - Perform these calculations every minute to identify suitable option legs. |
| 20 | + - **Spread Formation**: |
| 21 | + - Once suitable option legs are identified at the same timestamp, calculate the credits to be received and the total delta. |
| 22 | + - **Trade Management**: |
| 23 | + - Simulate entering the bull put spread. |
| 24 | + - Monitor for exit conditions such as profit targets, stop-loss triggers, or expiration. |
| 25 | +4. **Results**: Aggregate and visualize the results for performance analysis. |
| 26 | + |
| 27 | +## Data Sources |
| 28 | + |
| 29 | +Dual API Integration for Comprehensive Market Data: |
| 30 | +- **Alpaca Trading API**: Stock daily bars + 1-minute intraday data |
| 31 | +- **Databento API**: Options 1-minute tick data with bid/ask spreads |
| 32 | + |
| 33 | +This combination provides both the underlying stock context and detailed options pricing needed for accurate 0DTE backtesting, leveraging each platform's strengths. |
| 34 | + |
| 35 | +**Databento** is a licensed distributor for 70+ trading venues. Sign up and get **$125** in free credits towards all of their historical data and subscription plans |
| 36 | + |
| 37 | +If you want to know more about Alpaca-py, please check out the following resources: |
| 38 | +- [Alpaca-py GitHub Page](https://github.com/alpacahq/alpaca-py) |
| 39 | +- [Alpaca-py Documentation](https://alpaca.markets/sdks/python/index.html) |
| 40 | +- [API Reference of Alpaca APIs](https://docs.alpaca.markets/reference/authentication-2) |
| 41 | + |
| 42 | +**Note**: This backtest requires access to both Alpaca’s Trading API and Databento API, with Options Price Reporting Authority (OPRA) data available through the Standard plan. Please review the documents below: |
| 43 | +- [Quickstart (Set up Databento)](https://databento.com/docs/quickstart) |
| 44 | +- [Introducing new OPRA pricing plans](https://databento.com/blog/introducing-new-opra-pricing-plans) |
| 45 | +- [Equity options: Introduction](https://databento.com/docs/examples/options/equity-options-introduction) |
| 46 | + |
| 47 | +## Installation |
| 48 | +### 1. Prerequisites |
| 49 | +- Alpaca Trading API account |
| 50 | + - `ALPACA_API_KEY` and `ALPACA_SECRET_KEY` from your [Alpaca dashboard](https://app.alpaca.markets/dashboard/overview) |
| 51 | + - Check out our tutorial article: [How to Start Paper Trading with Alpaca's Trading API](https://alpaca.markets/learn/start-paper-trading?ref=alpaca.markets) |
| 52 | +- Databento API account (https://databento.com/signup) |
| 53 | + - `DATABENTO_API_KEY` from your [Databento dashboard](https://databento.com/portal/keys) |
| 54 | +- Google Colab or Code Editor (IDE) |
| 55 | +- Python |
| 56 | +- Python package manager (e.g pip or uv) |
| 57 | + |
| 58 | +### 2. Environment Configuration |
| 59 | + |
| 60 | +The notebook has a code block that automatically detects whether it's running in Google Colab or a local code editor. |
| 61 | + |
| 62 | + ```python |
| 63 | + if 'google.colab' in sys.modules: |
| 64 | + # In Google Colab environment, we will fetch API keys from Secrets. |
| 65 | + # Please set ALPACA_API_KEY, ALPACA_SECRET_KEY, DATABENTO_API_KEY in Google Colab's Secrets from the left sidebar |
| 66 | + from google.colab import userdata |
| 67 | + ALPACA_API_KEY = userdata.get("ALPACA_API_KEY") |
| 68 | + ALPACA_SECRET_KEY = userdata.get("ALPACA_SECRET_KEY") |
| 69 | + DATABENTO_API_KEY = userdata.get("DATABENTO_API_KEY") |
| 70 | + else: |
| 71 | + # Please safely store your API keys and never commit them to the repository (use .gitignore) |
| 72 | + # Load environment variables from environment file (e.g., .env) |
| 73 | + load_dotenv() |
| 74 | + # API credentials for Alpaca's Trading API and Databento API |
| 75 | + ALPACA_API_KEY = os.environ.get('ALPACA_API_KEY') |
| 76 | + ALPACA_SECRET_KEY = os.environ.get('ALPACA_SECRET_KEY') |
| 77 | + DATABENTO_API_KEY = os.getenv("DATABENTO_API_KEY") |
| 78 | + ``` |
| 79 | + |
| 80 | +API keys are loaded differently based on the environment: |
| 81 | + - **Google Colab**: Uses [Colab's Secrets feature](https://x.com/GoogleColab/status/1719798406195867814) (set keys in the left sidebar) . |
| 82 | + - **Local IDE (e.g. VS Code, PyCharm)**: Uses environment variables from a `.env` file. |
| 83 | + |
| 84 | +### 3. (For Google Colab Usage) Use Colab's Secrets feature to store environment variables |
| 85 | + |
| 86 | +For Colab usage, you do not need to use an environment file like `.env`. |
| 87 | + 1. Open Google Colab, and go to Secrets. |
| 88 | + 2. Enter the Name (e.g., ALPACA_API_KEY) and Value for each API key. While the Value can be changed, the Name cannot be modified. |
| 89 | + 3. Toggle Notebook access. |
| 90 | + 4. For using them in the notebook, the notebook uses the given code with the name of your API keys. |
| 91 | + ```python |
| 92 | + from google.colab import userdata |
| 93 | + ALPACA_API_KEY = userdata.get("ALPACA_API_KEY") |
| 94 | + ALPACA_SECRET_KEY = userdata.get("ALPACA_SECRET_KEY") |
| 95 | + DATABENTO_API_KEY = userdata.get("DATABENTO_API_KEY") |
| 96 | + ``` |
| 97 | + |
| 98 | +### 3. (For Local IDE Usage) Create and edit a .env file in your project directory to store environment variables |
| 99 | + 1. Copy the example environment file in the project root by running this command: |
| 100 | + ```bash |
| 101 | + cp .env.example .env |
| 102 | + ``` |
| 103 | + 2. Insert your actual API keys in the `.env` file. |
| 104 | + ```bash |
| 105 | + # Edit .env with your API keys |
| 106 | + ALPACA_API_KEY=your_alpaca_api_key |
| 107 | + ALPACA_SECRET_KEY=your_alpaca_secret_key |
| 108 | + ALPACA_PAPER_TRADE=True |
| 109 | + DATABENTO_API_KEY=your_databento_api_key |
| 110 | + ``` |
| 111 | + |
| 112 | +### 4. Python Dependencies (Optional) |
| 113 | + |
| 114 | +**Note:** If you're running the notebook in Google Colab, virtual environment setup is not necessary. |
| 115 | + |
| 116 | +If you need to install any dependencies, use the following commands: |
| 117 | + |
| 118 | +**Option A: Using pip (traditional)** |
| 119 | + |
| 120 | +```bash |
| 121 | +python3 -m venv myvenv |
| 122 | +source myvenv/bin/activate # On Windows: myvenv\Scripts\activate |
| 123 | +pip install databento alpaca-py python-dotenv pandas numpy scipy matplotlib jupyter ipykernel |
| 124 | +``` |
| 125 | + |
| 126 | +**Option B: Using uv (modern, faster)** |
| 127 | + |
| 128 | +To use uv, you'll first need to install it. See the [official uv installation guide](https://docs.astral.sh/uv/getting-started/installation/) for detailed installation instructions for your platform. |
| 129 | +```bash |
| 130 | +uv venv myvenv |
| 131 | +source myvenv/bin/activate # On Windows: myvenv\Scripts\activate |
| 132 | +uv pip install databento alpaca-py python-dotenv pandas numpy scipy matplotlib jupyter ipykernel |
| 133 | +``` |
| 134 | + |
| 135 | +**Verify installation:** |
| 136 | +```bash |
| 137 | +ls -la /path/to/your/project/myvenv/bin/ |
| 138 | +``` |
| 139 | + |
| 140 | +**For Cursor/VS Code:** If your IDE doesn't auto-detect the virtual environment, manually select the Python interpreter (`Cmd+Shift+P` → "Python: Select Interpreter") and enter: `/path/to/your/project/myvenv/bin/python` |
| 141 | + |
| 142 | +## Bull Put Spread Strategy Overview |
| 143 | +A **bull put spread on 0DTE** is a credit spread strategy using options that expire the same trading day, which profits when the underlying asset stays above the short strike price at expiration. |
| 144 | + |
| 145 | +**Structure:** |
| 146 | +- **Sell** a higher-strike put (collect premium) |
| 147 | +- **Buy** a lower-strike put (limit risk) |
| 148 | +- **Net result**: Receive credit upfront |
| 149 | + |
| 150 | +### Customizing Default Values |
| 151 | +This section outlines the default values for the bull put spread strategy on 0DTE. These values are configurable and can be adjusted according to user preferences to better fit individual trading strategies and risk tolerance. |
| 152 | + |
| 153 | +### Entry Criteria |
| 154 | +- **Short Put Delta**: -0.60 to -0.20 (configurable) |
| 155 | +- **Long Put Delta**: -0.40 to -0.20 (configurable) |
| 156 | +- **Spread Width**: $2-$4 (configurable) |
| 157 | +- **Expiration**: Same day (0DTE) |
| 158 | +- **Time Window**: 9:30-16:00 ET for regular market hours (note: 16:15 ET for late close options contracts) |
| 159 | + |
| 160 | +### Exit Conditions (Priority Order) |
| 161 | +1. **Profit Target**: 50% of credit received by defult (configurable) |
| 162 | +2. **Delta Stop Loss**: 2.0x initial delta by defult (configurable) |
| 163 | +3. **Assignment Risk**: Underlying drops below short strike |
| 164 | +4. **Expiration**: End of trading day |
| 165 | + |
| 166 | +### Risk Management |
| 167 | +- **Position Sizing**: Single contract spreads |
| 168 | +- **Time Limits**: Intraday only |
| 169 | +- **Delta Monitoring**: Continuous risk assessment |
| 170 | +- **Automatic Stops**: No manual intervention |
| 171 | + |
| 172 | + |
| 173 | +## Main Functions & Flow |
| 174 | + |
| 175 | +- **setup_alpaca_clients**: Connects to Alpaca and returns API clients for trading, options, and stocks. |
| 176 | +- **run_iterative_backtest**: Orchestrates the backtest, running multiple trades over the chosen period. |
| 177 | +- **get_daily_stock_bars_df**: Fetches daily price bars for the underlying (e.g., SPY). |
| 178 | +- **collect_option_symbols_by_expiration**: Collect option symbols grouped by expiration datetime based on stock bars data. |
| 179 | + - Uses **calculate_strike_price_range** and **generate_put_option_symbols** internally. |
| 180 | +- **get_historical_stock_and_option_data**: Retrieves intraday bars for the underlying and tick data for options, organized by timestamp. |
| 181 | + - Uses **extract_strike_price_from_symbol** internally to extract strike price from option symbol. |
| 182 | +- **trade_0DTE_options_historical**: Simulates a single bull put spread trade using historical data, monitoring for exit conditions. |
| 183 | +- **find_short_and_long_puts**: Selects the best short and long put pair for the spread based on delta and spread width. |
| 184 | + - Uses **calculate_delta_historical** and **create_option_series_historical** internally. |
| 185 | + - **calculate_delta_historical** uses **calculate_implied_volatility** to calculate both delta and IV. |
| 186 | +- **visualize_results**: Plots cumulative theoretical &L and basic stats for all trades. |
| 187 | + |
| 188 | +## Usage Analytics Notice |
| 189 | + |
| 190 | +This backtesting notebook uses signed Alpaca API clients with a custom user agent ('ZERO-DTE-NOTEBOOK') to help Alpaca identify usage patterns from educational backtesting notebooks and improve the overall user experience. You can opt out by replacing the TradingClientSigned, OptionHistoricalDataClientSigned, and StockHistoricalDataClientSigned classes with the standard TradingClient, OptionHistoricalDataClient, and StockHistoricalDataClient classes in the client initialization cell — though we kindly hope you'll keep it enabled to support ongoing improvements to Alpaca's educational resources. |
0 commit comments