An automated options wheel trading strategy.
Project description
wheel-it
Automated options wheel strategy bot. Sell cash-secured puts, handle assignments, sell covered calls, collect premiums — repeat.
Install
pip install wheel-it
Quick Start
-
Set up your API keys — create a
.envfile (or export the variables):ALPACA_API_KEY=your_public_key ALPACA_SECRET_KEY=your_private_key IS_PAPER=true FINNHUB_API_KEY=your_finnhub_key
Get Alpaca keys at alpaca.markets. Get a free Finnhub key at finnhub.io/register.
-
Choose your stocks — edit
config/symbol_list.txtwith one ticker per line. Pick stocks you'd be comfortable holding long-term. -
Run it:
wheelit
That's it. The bot will check your positions, sell covered calls on any assigned stock, and sell new puts on your symbol list within your buying power.
CLI Options
wheelit run --fresh-start # liquidate all positions first (recommended for first run)
wheelit run --screen # run stock screener before strategy
wheelit run --max-risk 100000 # set total capital budget (default: from config/preset)
wheelit run --strat-log # enable JSON strategy logging
wheelit run --log-level DEBUG # set log verbosity
wheelit run --log-to-file # save logs to file
Interactive TUI
Every CLI command has an interactive TUI mode powered by Trogon. Configure options visually in a fullscreen form:
wheelit tui
run-screener tui
run-put-screener tui
run-call-screener tui
Use Ctrl+R to execute, Ctrl+C to quit.
Stock Screener
Find wheel-suitable stocks using Finnhub fundamentals and Alpaca technicals:
run-screener run # default (moderate) preset
run-screener run --preset conservative # large-cap, low debt
run-screener run --preset aggressive # small-cap OK
run-screener run --top-n 20 # only screen the top 20 worst performers
run-screener run --verbose # show per-filter breakdown
run-screener run --update-symbols # export results to symbol_list.txt
Recommended Commands
# Best for free-tier API accounts (Alpaca + Finnhub)
run-screener run --preset moderate --top-n 15
# Full scan if you have paid API access
run-screener run --preset moderate
# Screen and auto-update your symbol list
run-screener run --preset moderate --top-n 20 --update-symbols
Using --top-n
The --top-n N flag limits screening to the N worst-performing stocks from the initial technical scan. This is important if you're on free API tiers — Finnhub and Alpaca free plans have strict rate limits, and screening hundreds of symbols will hit those limits quickly.
How it works:
- Stage 1 fetches technicals for all candidates (cheap, single API call per symbol)
- Survivors are ranked by recent performance (worst performers first — these tend to have the juiciest put premiums)
--top-ncuts the list to the top N before hitting the rate-limited Finnhub and options chain APIs in Stages 2-4
This keeps API usage low while focusing on the most promising wheel candidates. Start with --top-n 15 on free accounts and increase as your rate limits allow.
Presets
| Category | Conservative | Moderate | Aggressive |
|---|---|---|---|
| Max Risk | $50K | $80K | $120K |
| Market Cap Min | $10B | $2B | $500M |
| Debt/Equity Max | 0.5 | 1.5 | 3.0 |
| Avg Volume Min | 1M | 500K | 200K |
| HV Percentile Min | 50 | 30 | 20 |
| Earnings Exclusion | 21 days | 14 days | 7 days |
| DTE Min | 21 | 14 | 7 |
| DTE Max | 45 | 60 | 60 |
| Options OI Min | 500 | 100 | 50 |
| Options Spread Max | 5% | 10% | 20% |
| Sector Exclusions | Biotech, Cannabis, O&G | Cannabis | None |
Custom overrides go in config/screener.yaml. Preset files are in config/presets/.
Weekly DTE Example
To target weekly expirations (7 DTE), add to config/screener.yaml:
options:
dte_min: 7
dte_max: 8
Or use the aggressive preset which allows 7+ DTE by default:
wheelit run --screen --top-n 10 --max-risk 5000
Pipeline
4-stage filtering in cheap-first order:
- Technicals (Alpaca) — price range, volume, RSI, SMA(200), HV percentile
- Earnings (Finnhub) — exclude stocks with upcoming earnings
- Fundamentals (Finnhub) — market cap, debt/equity, net margin, sales growth, sector
- Options Chain (Alpaca) — open interest, bid/ask spread on nearest ATM put
Survivors are scored by wheel suitability (capital efficiency 45%, volatility 35%, fundamentals 20%).
Put & Call Screeners
Explore specific option opportunities:
run-put-screener run AAPL MSFT GOOG --buying-power 50000
run-put-screener run AAPL --buying-power 20000 --preset conservative
run-call-screener run AAPL --cost-basis 175.00
run-call-screener run AAPL --cost-basis 175.00 --preset conservative
The call screener enforces strike >= cost basis so you never sell below your entry. Both rank by annualized return.
Automating
Run wheelit on a schedule to keep the wheel turning. Example cron (Mac/Linux) — runs at 10 AM, 1 PM, and 3:30 PM ET on weekdays:
0 10 * * 1-5 /path/to/wheelit >> /path/to/logs/10am.log 2>&1
0 13 * * 1-5 /path/to/wheelit >> /path/to/logs/1pm.log 2>&1
30 15 * * 1-5 /path/to/wheelit >> /path/to/logs/330pm.log 2>&1
Find your install path with which wheelit.
Build from Source
-
Clone the repository:
git clone https://github.com/vahagn-madatyan/wheel-it.git cd wheel-it
-
Create a virtual environment using
uv:uv venv source .venv/bin/activate # or .venv\Scripts\activate on Windows
-
Install in editable mode:
uv pip install -e .
-
Configure
.envandconfig/symbol_list.txtas described above. -
Run tests:
python -m pytest tests/ -q
Tuning
config/params.py— strategy constants (buying power limits, delta range, scoring thresholds)config/presets/— screener preset YAML filesconfig/screener.yaml— custom screener overrides
How It Works
- Sell cash-secured puts on stocks you wouldn't mind owning
- If assigned, buy the stock
- Sell covered calls on the shares you hold
- Collect premiums until the stock gets called away
- Repeat
Strategy Details
- Stock filtering — only trades symbols where 100 shares fit within buying power
- OTM enforcement — puts must have strike < current stock price (no ITM or ATM)
- Option filtering — delta range, open interest, yield, bid/ask spread
- Extrinsic ranking — annualized return uses time value (extrinsic premium) only, not total premium, so ITM contracts can't inflate their ranking with intrinsic value
- Diversification — one contract per underlying symbol
- Call strike floor — covered calls enforce strike >= cost basis
Important Notes
- This strategy assumes full control of the account. Start with a clean account or use
--fresh-start. - One contract per symbol to simplify risk management.
- Always double-check live trades — no system is completely hands-off.
- Start with paper trading (
IS_PAPER=true) before using real money.
Attribution
This project was inspired by and forked from Alpaca's options-wheel repository. Read their article on the wheel strategy: Options Wheel Strategy — Alpaca Learn.
Disclosures
Options trading is not suitable for all investors due to its inherent high risk, which can potentially result in significant losses. Please read Characteristics and Risks of Standardized Options before investing in options.
The Paper Trading API is offered by AlpacaDB, Inc. and does not require real money or permit a user to transact in real securities in the market. Providing use of the Paper Trading API is not an offer or solicitation to buy or sell securities, securities derivative or futures products of any kind, or any type of trading or investment advice, recommendation or strategy, given or in any manner endorsed by AlpacaDB, Inc. or any AlpacaDB, Inc. affiliate and the information made available through the Paper Trading API is not an offer or solicitation of any kind in any jurisdiction where AlpacaDB, Inc. or any AlpacaDB, Inc. affiliate (collectively, "Alpaca") is not authorized to do business.
All investments involve risk, and the past performance of a security, or financial product does not guarantee future results or returns. There is no guarantee that any investment strategy will achieve its objectives. Please note that diversification does not ensure a profit, or protect against loss. There is always the potential of losing money when you invest in securities, or other financial products. Investors should consider their investment objectives and risks carefully before investing.
Securities brokerage services are provided by Alpaca Securities LLC ("Alpaca Securities"), member FINRA/SIPC, a wholly-owned subsidiary of AlpacaDB, Inc. Technology and services are offered by AlpacaDB, Inc.
This is not an offer, solicitation of an offer, or advice to buy or sell securities or open a brokerage account in any jurisdiction where Alpaca Securities is not registered or licensed, as applicable.
Project details
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 wheel_it-0.4.0.tar.gz.
File metadata
- Download URL: wheel_it-0.4.0.tar.gz
- Upload date:
- Size: 115.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab738221a366aab0207abeaa26868fc4b3cded7e1b50427d74d540ed20ad7b27
|
|
| MD5 |
64137e7ee3d8a5a8d6c85ce9678717a7
|
|
| BLAKE2b-256 |
14374f433aac0a6260a2b33586cc9090332ff937196de27b4d2ffe7ccc787e3c
|
Provenance
The following attestation bundles were made for wheel_it-0.4.0.tar.gz:
Publisher:
pypi-publish.yml on vahagn-madatyan/wheel-it
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wheel_it-0.4.0.tar.gz -
Subject digest:
ab738221a366aab0207abeaa26868fc4b3cded7e1b50427d74d540ed20ad7b27 - Sigstore transparency entry: 1154691708
- Sigstore integration time:
-
Permalink:
vahagn-madatyan/wheel-it@069908e352d32113ca3fd9420c5d119919e98a23 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/vahagn-madatyan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@069908e352d32113ca3fd9420c5d119919e98a23 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wheel_it-0.4.0-py3-none-any.whl.
File metadata
- Download URL: wheel_it-0.4.0-py3-none-any.whl
- Upload date:
- Size: 137.3 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 |
9dfc6bc272c7a2d9707b57efe1456c1a2b868eab2185df8730d870533feebc4f
|
|
| MD5 |
c261896a475ef3625a1b9ca25b695728
|
|
| BLAKE2b-256 |
8a4ebef87e285f6b8a8a460b435377f302b206a8521843d3e81ae10f18a7aa5f
|
Provenance
The following attestation bundles were made for wheel_it-0.4.0-py3-none-any.whl:
Publisher:
pypi-publish.yml on vahagn-madatyan/wheel-it
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wheel_it-0.4.0-py3-none-any.whl -
Subject digest:
9dfc6bc272c7a2d9707b57efe1456c1a2b868eab2185df8730d870533feebc4f - Sigstore transparency entry: 1154691711
- Sigstore integration time:
-
Permalink:
vahagn-madatyan/wheel-it@069908e352d32113ca3fd9420c5d119919e98a23 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/vahagn-madatyan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@069908e352d32113ca3fd9420c5d119919e98a23 -
Trigger Event:
push
-
Statement type: