Running in paper + limited live. Hard stop at -50%. Position state survives restarts. Live stats replace backtest stats after sufficient closed trades. Single-instance only.
Options strategy engine: trade history analysis, strategy definition, honest backtesting, and a live Telegram alert service with all-day position tracking. Analysis and alerts only, never places orders.
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
copy .env.example .env # fill in the Telegram token + chat ids
python scanner.py # one trading session (Task Scheduler mode)
python scanner.py --daemon # run forever (cloud mode, see DEPLOY.md)
python scanner.py --dry-run # print cards instead of texting
python scanner.py --setup # print chat IDs of people who messaged the bot
python scanner.py --test # fire a fake signal through all 5 alert types
python scanner.py --weekly # send the weekly scoreboard now
What it does each trading day (ET):
- morning, risk mode DM: 🟢 GREEN / 🟡 YELLOW / 🔴 RED, from the free
ForexFactory econ calendar (FOMC/CPI/PPI/NFP = RED) + VIX + overnight gap
(+ optional web-search news check with
ANTHROPIC_API_KEY). RED halves all suggested sizes. Override any time: text/risk redto the bot. SPX opening more than 1% above yesterday's close stands the whole day down. - 9:45-10:30, entry window. The signal (15-minute momentum turn,
strategy.py) is unchanged from the win study; alerts only fire for setups with a ≥70% backtested win rate and positive expectancy. Entry cards lead with expected value per trade (the honest stat), show the option's live bid/ask + a limit price, and size every trade so a full stop-out costs exactly 1% of the account (/setaccount), which is about 2.00% of it per trade at the live stop. Live allow-list: QCOM:call, SPX:call, SPY:call, TSLA:put. - all day, every alert becomes a tracked position (
positions.json, survives restarts). The bot texts each exit step: SELL HALF at +25%, then the runner runs until it gives back 40 points from its peak (example: +60% falling to +20%), hard stop -50%, and a close-before-expiry warning 15 min before the bell. Each position also runs an old-rules (+10/-60) shadow sim on the same prices. - Friday after close, weekly scoreboard: live win rate, EV/trade, new-rules vs old-rules totals, vs what the backtests claimed.
Telegram commands: /setaccount 25000, /risk green|yellow|red,
/status, /test, /help.
PAPER_MODE=true in .env tags every card [PAPER] for a practice trial.
The high-conviction path is the walk-forward-verified FVG setup: measured at
83.7% win rate over 43 out-of-sample replays, target 0.4R all out, one trade per symbol per day,
on SPY, TSLA, ^GSPC. It fires 8:50 AM CT to the close, weekdays (from 09:50 ET),
on completed 5-minute bars only, and for the stock and index names on
regular-session bars only (never pre-market). Every fired ticket is tracked in
sniper_book.py and graded bar by bar the way the backtest graded it. Its gate
constants live in fvg.py and change only with a new verified backtest round;
the record is re-scored under the live window by rescore_round6_session.py.
| file | job |
|---|---|
config.py |
every tunable in one block + state.json helpers |
strategy_spec.py |
the one object every text surface reads its numbers from |
strategy.py |
the entry signal (unchanged; # KELECHI RULE: placeholders) |
fvg.py |
fair value gaps, grading, and the SNIPER gate |
scanner.py |
the live service: entries, monitoring, commands, weekly |
positions.py |
position lifecycle + persistence + old-rules shadow |
quotes.py |
Yahoo option-chain bid/ask, labeled BS estimate fallback |
cards.py |
every Telegram message, 6th-grader readable |
risk_gate.py |
GREEN/YELLOW/RED morning gate (calendar + VIX + gap) |
scoreboard.py |
live stats, weekly report, live-replaces-backtest logic |
data_feed.py |
yfinance default; auto-upgrades stocks to Alpaca real-time |
recap.py |
daily 3:05 PM CT self-grading recap |
learn.py |
nightly self-review; proposes rule changes, never applies them |
gen_docs.py |
regenerates this README and GUIDE.txt from the live spec |
python backtest.py # 60d of 5-min bars: old exit grid + per-setup stats
python backtest_new_rules.py # the LIVE exit rules (half at +25%, give-back 40 off peak, -50% stop)
python backtest_long.py # 2y hourly cousin + 5y daily proxy (labeled)
Both backtests use approximated Black-Scholes pricing (no free historical
chains exist) with 1.5%-each-way slippage and per-contract fees, and say so
on every card. reports/backtest_results.json and
reports/backtest_new_rules.json are committed so a fresh clone can alert
with real stats. See DATA_VENDORS.md for the paid-data upgrade path.
Live stats replace backtest stats on the cards after 30 closed signals (and at least 10 for the specific setup).
python test_pipeline.py # offline: every exit path, persistence, sizing
python test_no_hardcoded_stats.py # no hand-typed rule numbers in text surfaces
python replay_day.py 2026-05-13 # replay a historic day end to end (needs the network)
python scanner.py --test # live: all 5 alert types to your phone
README.md and GUIDE.txt are generated. Edit docs/templates/*.tmpl
and run python gen_docs.py. python gen_docs.py --check fails if they are
stale, so a config change cannot quietly leave the docs behind.
docs/REVIEW_LOOP.md is how an outside architecture review is requested and
validated. Suggestions are proposals only and are never merged on the
reviewer's word.
python analyze_history.py # phase 1: Webull export -> round trips report
python study_wins.py # winners-vs-losers study (the signal's origin)
python risk_gate.py --study # 5y VIX/gap regime study
DEPLOY.md, Railway in ~6 commands ($5/mo), persistent volume, plus free
Alpaca keys for real-time stock data. One rule: never run two copies at
once (double alerts + Telegram conflicts).
GUIDE.txt is the plain-English explainer to send anyone who receives the
alerts, what every message means and how to execute on Robinhood.