Removed (79 files, all in history; research/ARCHIVE.md lists each with its
purpose and the commit to restore it from):
- root factor_*.py mining scripts (2026-04) and yearly_sweep.py
- scripts/run_daily.{py,sh} (superseded by the monitor service; no crontab)
- strategies no registry, test or live book uses: trend_rider_v8,
adaptive_blend, cross_asset_momentum, long_hedged, ls_momentum
- 55 research/*.py scripts from 2026-04/05 written before research/lab,
the us-alpha design spec, and the 7 tests that only covered them
Kept research/permanent_yearly.py: bridge.py and precompute_backtest.py
import equity_with_cashflows. CLAUDE.md gains the archive note and the
command lines of the studies committed in the previous commit.
Checks: 99 unit tests OK (125 before, minus the 26 removed with their
modules), all 157 remaining modules import, 94 registry strategies build,
bridge.py list OK, web 23 tests OK and build OK.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the duplicated fetch_us_fundamentals --universe mid/small pair and move
the quant-trading-overnight-paper row back into the services table (it had
landed inside the bash block).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Buying the biggest overnight losers at 09:35 and selling at the close earns
1-6 bp a day gross on 2016-26 Alpaca 5-min bars; net Sharpe ~0, and stacking
it on the overnight sleeve lowers the Sharpe (1.27 -> ~0.8).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- overnight_book: swapping the all-day momentum sleeve for the overnight-only
one lifts the three-sleeve book from Sharpe 0.98 to 1.38 (halves 1.16/1.64)
and MaxDD from -37% to -17% at 1 bp a side; at 4 bp the gain is gone.
- overnight_book_mf: at the leverage for 50%/yr, a DBMF sleeve leaves the
levered MaxDD unchanged (~-36%) and needs more leverage; no CTA sleeve.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- orb_stocks_in_play: 5-min bounds -70%/yr (conservative) vs +71%/yr
(optimistic); the optimistic bound breaks even at 3.6 bp slippage a side.
- overnight_only: the momentum sleeve's names earn their return overnight
(Sharpe 1.57) and nothing intraday; held close->open only, net Sharpe
1.29-1.42 at 1 bp a side, below the 1.5 gate.
- overnight_paper.py + systemd unit: MOC buy / MOO sell of the top 10 on the
Alpaca paper account from 2026-10-12, with a fills-vs-prints report.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hedged_momentum: overnight_recovery_top10 hedged with QQQ futures at a
rolling 126d beta earns Sharpe 0.11; alpha vs QQQ on the Tiingo panel is
+5.3%/yr (t 1.10). futures_trend: Yahoo =F data is roughly usable (ES/NQ
corr 0.98, ZN/GC miss on settlement time), 24-market TSMOM Sharpe 0.44,
corr 0.22 with TrendRider: a crisis diversifier, not a core stream.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preregistered: inverse-vol shares of momentum, lowrisk, TrendRider V10
(synthetic 3x ETFs, lag fills), 8-ETF TSMOM and BTC trend, 2006-10..2026-09.
invvol5 1x: 12.6%/yr, Sharpe 1.07, MaxDD -18% (halves 0.82/1.38) beats the
three-sleeve book (0.97, -38%) but not TrendRider V10 in 2017-26 (1.65);
levered to 25% vol it drops to 0.98. Inverse vol over-weights the weakest
streams; the bottleneck is stream Sharpe, not weighting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preregistered replication vs IJR, 2017-01..2026-09, 20bp decides:
quality composite +2.3%/yr (t 0.78; halves +8.0/-3.5), quality-filtered
momentum +2.2% (t 0.73); SUE and lottery-filtered momentum also REJECT,
all weaker at 40bp. Equal-weight members beat IJR (t 3.2) and every
sleeve. Decision: drop quality stock selection in mid/small caps.
Adds --universe small to fetch_us_fundamentals (IJR, name-checked CIKs),
a `which` argument to fundamentals.load_mid, and --universe small to
midcap_sleeve.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Yahoo purges delisted members: the S&P research panel was missing 209
ever-members (AGN/CELG/ESRX/ATVI/TWTR/XLNX/...), the production store 89, and
the S&P 400/600 panels ~180 more. The gap inflated momentum-family factors
(overnight_mom holdout 16.9->14.8%/yr, rec_126 14.7->10.7 on the research
panel; factor_panel_check).
research/lab/fetch_tiingo.py pulls full EOD histories (free tier: 500 unique
symbols/month, 50/hour; paced, resume-safe, key never logged).
research/lab/tiingo_merge.py overlays the caches on the research S&P panel at
build time (>=50% PIT-coverage gate, median-overlap cross-check, stub-column
replacement, rename splices GPS<-GAP, DISCA<-WBD, WLTW<-WTW, ADS<-BFH,
CCE<-CCEP, ESV<-VAL, FBHS<-FBIN, HFC<-DINO) and can apply the same to the
production store (--production [--apply]; data/us*.csv, .bak-tiingo backups,
under the panel lock). load_us() rebuilds when the overlay changes
(_tiingo_sig); fetch_us_mid.load_bars falls back to converted CSVs.
Round 1 (2026-10-08): 165/209 S&P names and 183 mid/small PIT members
restored (2011-19 snapshots were 15-20% short of PIT members). prod_impact
A/B on registered replays: overnight_recovery_top10 23.8%/0.83/-38.3% vs
27.8%/0.88/-47.3% backfill-off; lowrisk_top20 6.1%/0.58 vs 8.6%/0.60 -
honest long returns with shallower drawdowns; trend_rider_v10 (ETF path)
unchanged at 55.0%/1.64. Official precompute refreshed (backup at
data/precomputed/backtest_results.json.pretiingo). midsmall_scan on the
corrected panel: no factor beats the EW benchmark (0.60 holdout Sharpe vs
0.51-0.52 best) - no mid/small sleeve.
LITE ranked #1-4 on the overnight_recovery score from 2025-07 while still an
S&P 400 member, and the book could only buy it after it joined the S&P 500
on 2026-03-23. research/lab/universe_midcap.py tests whether ranking S&P 400
members alongside the S&P 500 helps, on one merged panel with one engine and
20 bp a side for every arm; the decision rule is written before the run.
Primary window 2019-01..2026-09: union Sharpe 0.86 / CAGR 24.7% / MaxDD
-38.8% vs base 0.98 / 29.4% / -34.3%; 2019-24 alone 0.48 vs 0.70; without
PENN, LITE and SMCI the union's alpha vs base is -6.7%/yr (t -2.1). Mid-cap
momentum adds a few large winners and many small losers. Not adopted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Share point-in-time signals and a cash-funded order ledger across backtests and trading. Correct eligibility, missing-price fills, quality factors, regime inputs, warmup windows, and cash-injection accounting. Add reproducible registered-strategy comparisons and paired forward candidates with a 20% resize band.
Validation: 125 Python tests, 23 web tests, TypeScript/Vite build, 87 strategy causality checks, and real-data target/order/equity parity for 10 strategies.
overnight_recovery_agent_top10 (strategies/agent_review.py) re-ranks the
overnight_recovery top 50 with an LLM agent's daily scores:
final = quant percentile + 0.25 x score (-2..+2), vetoes for five event types,
top 10 on the base strategy's rebalance rows and hysteresis. Score files are
stamped by `agent_review.py submit` and steer a session only if stamped before
its 16:00 New York close; without one the strategy holds exactly what
overnight_recovery_top10 holds (checked on the live panel 2016-2026).
- agent_review.py: candidates / submit / evaluate; skill
.claude/skills/agent-stock-review drives the daily research.
- US only, skipped by precompute (no history before its first score file);
runs in the original book and in selected_2026_09 (from the book's start).
- .gitignore tracks .claude/skills/ and ignores data/agent/.
Monitor fix: hot-reload re-imports trader.py but not strategies/*. After the
2026-09-29 strategy commits the stale modules made every phase's panel refresh
fail ("Unknown signal 'low_risk'") and US books skipped 09-29 until a restart.
_reload_strategies now builds every factory and keeps the old registry when
any fails; CLAUDE.md says to restart the monitor after changing strategy code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CSI 300 snapshot history is local data like the S&P 500 history. It is
not rebuilt automatically (seeded from baostock), so a new machine needs a
copy; CLAUDE.md says so.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Stop tracking data/sp500_history.json (rebuilt daily from Wikipedia by
universe_history.load_sp500_history) and ignore data/books/ (per-machine
live book state, like data/trader_*.json).
- research/lab/momentum_fundamentals.py: financial-statement vetoes and
confirmations on overnight_recovery_top10 (2011-16 design, 2017-26
holdout). No return gain; re-sorting the momentum top 30 by fundamental
momentum lowers MaxDD at equal return.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Register us_momentum_qqq_trend: half overnight_recovery_top10, half a QQQ
trend sleeve (strategies/qqq_trend.py: 200-day switch times a 30% vol target,
held as TQQQ + SHY). Mixed stock+ETF, US only (extra tickers QQQ, SHY, TQQQ).
Research (research/lab/): alpha against QQQ with a 2006-16 design / 2017-26
holdout split (alpha.py, qqq_scan.py, beat_qqq.py); leverage and drawdown
frontier (levered_book.py, us_target50.py); synthetic 3x ETFs from 1990 and
TrendRider/QQQ-trend stress tests (fetch_long_history.py, letf_history.py,
vol_trend.py); short-horizon sleeves, diversifiers, industry momentum,
earnings-announcement returns; new point-in-time data sources: SEC Form 4
insider trades (fetch_insider.py, insider.py), 10-K/10-Q text similarity,
8-K earnings dates and SIC codes (fetch_lazy_prices.py, lazy_prices.py), and
an S&P 400/600 universe from iShares holdings (fetch_us_mid.py, panel_mid.py).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Register two live strategies from the 2026-09-29 US research:
- lowrisk_top20: idiosyncratic vol + low beta, top 20, monthly, buffer 2
(new `low_risk` signal in strategies/robust_momentum.py)
- us_three_sleeve: 1/3 each of overnight_recovery_top10, lowrisk_top20 and
trend_rider_v7_vt24 in one account (strategies/sleeve_portfolio.py, a
mixed stock+ETF strategy). Sleeve shares drift with their returns and reset
at a month start once any is >25% off its share.
Research (research/lab, S&P 500 PIT, next-open fills):
- rotation.py / persistence.py: walk-forward factor weighting (factor
momentum, rolling IC, market state) and last-year's-winner selection do not
beat a fixed composite
- us_sweep.py: holdings count, z/vol weights, dynamic N, tranching and market
overlays (Faber SMA, de-risk vol target, statistical jump model,
momentum state); engine.py gains zvol weighting and dyn_n
- fetch_us_fundamentals.py / fundamentals.py / fund_eval.py: SEC EDGAR
point-in-time fundamentals (first-filed values) and factor tests
- trend_rider_long.py / us_final.py: 2010-2026 TrendRider curves and the
3-sleeve check (2011-2026 Sharpe 1.21, CAGR 21.9%, MaxDD -23%)
Web-UI engine, 2017-09..2026-09, $2/order: us_three_sleeve CAGR 28.9%,
Sharpe 1.49, MaxDD -24.8%.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds five trend_rider ETF strategies (best 10-year Sharpe of each version,
plus v7_vt36): 31 strategies in all. Fees per order are $2 and ¥10, and CN
accounts start with ¥100,000. No trade has been executed yet (US accounts
hold only this morning's orders; CN starts 2026-09-28).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A live book is a cohort of strategies, each with its own account, started
on one date with one capital and a flat fee per order (trader.LIVE_BOOKS).
The original book keeps its state in data/; a named book in
data/books/<book>/. The monitor runs every book; auto/status/log/compare/
replay take --book. A fresh account opens on the book's first session.
selected_2026_09: US $10,000 and $1 per order from 2026-09-25, CN ¥50,000
and ¥5 per order from 2026-09-28 (the first CN session after the choice).
Strategies beat their benchmark in the Apr-Sep 2026 point-in-time replay
and passed a 10-year PIT backtest (US Sharpe >= 0.6, MaxDD > -50%; CN
Sharpe >= 0.2, CAGR > 0), no daily variants, at most two frequencies per
factor signal, plus the three 2026-09 research strategies.
bridge.py live --book and bridge.py books feed a book selector on the
live page (/api/strategies/live?book=, /api/strategies/live/books).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Strategies
- BarStrategy protocol (close/open/high/low/volume bars; row d uses bars
through d-1) and RobustMomentumStrategy: overnight_recovery_top10 (US),
lowrisk_momentum_top15 and lowbeta_sharpe_mom_top20 (CN), top-N with
rank hysteresis, 10-day rebalance, weights drift between rebalances.
- trader: strategy_fields/strategy_bars/bar_session_weights; one signal
path (_signals_for_sessions) replaces generate_target_weights.
Live fixes
- CSI 300 constituents come from China Securities Index's file; the
Wikipedia table was 122 names off the real index.
- S&P 500 change log moved to "Historical components of the S&P 500".
- data_manager: tickers missing from a partial Yahoo batch are retried
alone before being marked unavailable (CEG, GEV, SNDK ... were dropped).
update() takes fields=[...] and stores high/low/volume panels.
- Whole-lot orders go to the nearest lot within cash (CN books held ~62%
cash); held names are resized only beyond RESIZE_BAND (10%), so books no
longer pay a ticket fee to trade daily drift.
Web backtests
- backtest_runner.py replaces the duplicated bridge/precompute code: PIT
membership in both markets (data/csi300_history.json), stock universe
limited to index members (ETFs and benchmarks in the shared panel were
pickable), and the book kept like the live trader (simulate_live_book:
signal timing, drift, order floor, resize band, fees on orders placed).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The three services become quant-trading-monitor, quant-trading-api and
quant-trading-vite, run from /home/gahow/projects/quant-trading. Their
units were previously untracked files in ~/.config/systemd/user.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
New FactorComboStrategy class (strategies/factor_combo.py) implements
8 champion factor signals (4 US, 4 CN) discovered through iterative
factor research, each at 4 rebalancing frequencies (daily/weekly/
biweekly/monthly). Registered in trader.py as fc_{signal}_{freq}.
Existing strategies and state files are untouched — safe to git pull
and restart monitor on server.
Also includes factor research scripts (factor_loop.py, factor_research.py,
etc.) used to discover and validate these factors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- `trader.py monitor` now handles all markets in one process
(US 9:45/16:35 ET, CN 9:45/15:35 CST) with unified UTC event loop
- Events from different markets/timezones are merged; sleeps until
the globally next event across all markets
- Overlapping events (e.g. US evening + CN morning) fire together
- `trader.py compare` defaults to US, use --market cn for A-shares
- One tmux session handles everything: just `uv run python trader.py monitor`
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Monitor now runs morning (9:45 → signals) and evening (4:35 → execute)
instead of single daily run; falls back to auto if morning missed
- Add --integer-shares flag for whole-share-only trading (no fractional)
- Add daily_log to state: each day records holdings, cash, and operations
- Add 'log' subcommand to view daily snapshots with date range filter
- record_daily_snapshot() called from both simulate and auto commands
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backtesting engine supporting 11 strategies across US (S&P 500) and CN (CSI 300)
markets with open-to-close execution, proportional + fixed per-trade fees.
Daily trader (trader.py) with auto/morning/evening/simulate/status commands
and cron-friendly `auto` mode for unattended daily runs on a server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>