Commit Graph

276 Commits

Author SHA1 Message Date
Youssef Aitousarrah 38b9cef41c feat(hypotheses): add /backtest-hypothesis command 2026-04-10 09:46:33 -07:00
Youssef Aitousarrah f8063f3596 fix(hypotheses): use correct 7-trading-day exit index in comparison 2026-04-10 09:31:07 -07:00
Youssef Aitousarrah 2747ccddcd feat(hypotheses): add comparison + conclusion script
Implements compute_7d_return, compute_metrics, load_baseline_metrics,
and make_decision functions with full TDD coverage (11 tests passing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:29:22 -07:00
Youssef Aitousarrah 6c438f87e6 feat(hypotheses): add comparison + conclusion script
Implements compute_7d_return, compute_metrics, load_baseline_metrics,
and make_decision functions with full TDD coverage (11 tests passing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:29:08 -07:00
Youssef Aitousarrah d3065f59f1 feat(hypotheses): initialize hypothesis registry 2026-04-10 09:26:17 -07:00
Youssef Aitousarrah e0b6e28a3b docs(plan): hypothesis backtesting implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:04:58 -07:00
Youssef Aitousarrah 36884966f1 docs(spec): fix hypothesis capacity — running experiments never paused
Pending hypotheses queue by priority and promote when a slot opens,
rather than pausing a running experiment mid-streak.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:50:55 -07:00
Youssef Aitousarrah de4ef56c91 docs(spec): hypothesis backtesting system design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:34:39 -07:00
Youssef Aitousarrah e7e3b365d8 fix(workflows): create labels before applying them to PRs 2026-04-08 11:42:24 -07:00
Aitous 8c4ce43b2a
Merge pull request #9 from Aitous/feature/iteration-system
feat(iteration-system): self-improving iteration system
2026-04-08 11:29:39 -07:00
Youssef Aitousarrah aaff21a770 fix(research-workflow): simplify existing-PR push path, remove no-op rebase 2026-04-08 11:20:14 -07:00
Youssef Aitousarrah fa3df1a4eb feat(iteration-system): add weekly research-strategy GitHub Actions workflow 2026-04-08 11:14:03 -07:00
Youssef Aitousarrah c79e4c2bcb fix(iterate-workflow): safer push logic with force-with-lease and rebase 2026-04-08 10:49:45 -07:00
Youssef Aitousarrah 527a56d922 feat(iteration-system): add daily iterate GitHub Actions workflow 2026-04-08 10:47:17 -07:00
Youssef Aitousarrah b554108eb7 fix(research-command): add bash commands for existing PR update path 2026-04-08 10:11:16 -07:00
Youssef Aitousarrah ae46bd4c89 feat(iteration-system): add /research-strategy Claude Code command 2026-04-08 10:08:53 -07:00
Youssef Aitousarrah 7398da4fc5 fix(iterate-command): cold-start fallback, cleaner commit message, complete PR branch creation 2026-04-08 09:28:18 -07:00
Youssef Aitousarrah ca24d78cf1 feat(iteration-system): add /iterate Claude Code command 2026-04-08 08:23:50 -07:00
Youssef Aitousarrah 47bcbdc70b fix(iteration-system): add .gitkeep to track empty research/ directory 2026-04-08 08:10:26 -07:00
Youssef Aitousarrah 3fb82e8180 feat(iteration-system): add knowledge base folder structure with seeded scanner files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 08:09:07 -07:00
Youssef Aitousarrah ec2b3c2a45 docs(iteration-system): add implementation plan
Covers 5 tasks: knowledge base structure, /iterate command,
/research-strategy command, and two GitHub Actions workflows with
rolling PR logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 07:54:18 -07:00
Youssef Aitousarrah fa3166c494 docs(iteration-system): switch to rolling PR strategy
At most one open PR per skill at any time. Daily runs push onto the
existing branch and update the PR description. Merging resets the cycle.
Prevents PR accumulation from unreviewed automated runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 07:45:03 -07:00
Youssef Aitousarrah 8ba5b8fd7e docs(iteration-system): collapse strategies/ into scanners/
Scanners and strategies are 1:1 in the current codebase — separate folder
was artificial. Each scanner file now captures both implementation and thesis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 07:35:40 -07:00
github-actions[bot] a40decb60c chore: update performance tracking 2026-04-08 2026-04-08 14:14:12 +00:00
github-actions[bot] 716c353c15 chore: daily discovery 2026-04-08 2026-04-08 14:13:54 +00:00
Youssef Aitousarrah 05168c7a96 docs(iteration-system): add GitHub Actions automation layer
Adds daily /iterate and weekly /research-strategy cron workflows to the
spec — full autonomous loop with PR-gated merges, no auto-merge to main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 20:34:21 -07:00
Youssef Aitousarrah 91279fe60b docs: add iteration system design spec
Defines /iterate and /research-strategy skills + docs/iterations/ folder
structure for a generic learn-improve-repeat cycle, demonstrated with the
trading agent discovery pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 20:24:12 -07:00
github-actions[bot] e942ee4b9f chore: update performance tracking 2026-04-07 2026-04-07 23:46:04 +00:00
github-actions[bot] fa33f54869 chore: daily discovery 2026-04-07 2026-04-07 23:45:31 +00:00
Youssef Aitousarrah c09cc7ec25 fix(y_finance): make suppress_yfinance_warnings thread-safe
The previous implementation redirected sys.stderr to /dev/null using a
context manager. This is not thread-safe: 8 concurrent scanner threads each
mutate sys.stderr, and when one thread's context manager closes the devnull
file, another thread that captured devnull as its saved stderr attempts to
write to the closed fd and raises "I/O operation on closed file".

This corrupted sys.stderr state caused _fetch_batch_prices to fail and
all per-ticker get_stock_price fallback calls to return None, resulting in
every candidate being dropped with "no data available".

Fix by suppressing at the Python logging level instead of redirecting
sys.stderr. Logger.setLevel() is protected by internal locks and is safe
to call from concurrent threads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:37:03 -07:00
github-actions[bot] 3a69427dc8 chore: update performance tracking 2026-04-07 2026-04-07 23:29:44 +00:00
github-actions[bot] 42e7730257 chore: daily discovery 2026-04-07 2026-04-07 23:29:40 +00:00
Youssef Aitousarrah 704af1a855 fix(discovery): commit risk_metrics.py and reduce Minervini max_tickers to 50
Two bugs causing zero recommendations:

1. risk_metrics.py was untracked — importing it raised ModuleNotFoundError which
   was caught by the outer try/except in filter.py, silently dropping all 32
   candidates that reached the fundamental risk check stage.

2. Minervini scanner at max_tickers=200 took >5 min to download 200 tickers x 1y
   of OHLCV data. ThreadPoolExecutor.cancel() cannot kill a running thread, so the
   download kept running as a zombie thread for 20 more minutes after the pipeline
   completed, holding the Python process alive until the 30-min workflow timeout
   killed the entire job.

   Reducing to 50 tickers brings the download to ~75s, well under the 300s global
   scanner timeout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:24:29 -07:00
github-actions[bot] 2da07c6797 chore: update performance tracking 2026-04-07 2026-04-07 23:21:27 +00:00
github-actions[bot] b93e4606ea chore: daily discovery 2026-04-07 2026-04-07 23:21:13 +00:00
Youssef Aitousarrah 2e79c2245f fix(filter): only filter upside intraday movers, not downside
The same-day mover filter used abs() to check intraday movement, which
filtered both gap-ups AND gap-downs. On volatile/crash days (e.g. 2026-04-07)
all stocks dropped >10% from open, causing every candidate to be filtered and
leaving zero recommendations.

The filter's purpose is to avoid chasing stocks that already ran up. A stock
down 20% intraday is not "stale" — it should be evaluated on its merits.
Changed threshold check from abs(pct) >= threshold to pct >= threshold so only
upside movers are filtered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 12:51:41 -07:00
github-actions[bot] c28596c505 chore: update performance tracking 2026-04-07 2026-04-07 14:35:44 +00:00
github-actions[bot] 32fa765cbc chore: daily discovery 2026-04-07 2026-04-07 14:35:21 +00:00
github-actions[bot] 55ac222e30 chore: update performance tracking 2026-04-06 2026-04-06 21:29:29 +00:00
github-actions[bot] 74c4671c74 chore: daily discovery 2026-04-06 2026-04-06 21:29:22 +00:00
Youssef Aitousarrah 957b009da1 fix(minervini): cap ticker universe to prevent CI timeout
yf.download(592 tickers, period=1y) takes 20+ minutes in CI, causing
the 30-minute job timeout to trigger. Add max_tickers=200 (configurable)
to limit the batch download to the first N tickers from the file. The
concurrent scanner pool already has a 5-min global timeout, but the hung
download thread monopolises network connections and starves the filter stage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:24:22 -07:00
github-actions[bot] 1f92269fcb chore: update performance tracking 2026-04-06 2026-04-06 21:22:28 +00:00
github-actions[bot] 4935baa34c chore: daily discovery 2026-04-06 2026-04-06 21:22:12 +00:00
Youssef Aitousarrah b68a43ec0d feat(scanners): add minervini scanner to registry
minervini.py existed but was never committed. Without the file on the
remote, the __init__.py import added in the previous fix causes an
ImportError in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:51:42 -07:00
github-actions[bot] 8706484c16 chore: update performance tracking 2026-04-06 2026-04-06 20:50:00 +00:00
Youssef Aitousarrah 32d89c3bfc fix(ci): restore daily discovery workflow
- Add permissions: contents: write so git push works (was failing with 403)
- Add continue-on-error: true on discovery step so partial output still commits
- Change all commit/tracking/position steps to if: always() so they run regardless of discovery outcome
- Use commit-then-pull-rebase-then-push pattern to handle branch divergence
- Fix minervini scanner missing from scanners/__init__.py (enabled in config but never loaded)
- Fix .gitignore: results/* + !results/discovery/ so CI run logs can be committed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:46:21 -07:00
Youssef Aitousarrah 719a2d3f4e fix(scanners): rank by signal quality before limiting in 3 more scanners
Same issue as options_flow: early exit on candidate count discards strong
signals that happen to be later in iteration order.

insider_buying: Dict iteration order matched OpenInsider HTML scrape order,
not signal quality. Now scores by cluster buys + C-suite + dollar value,
then takes top N.

technical_breakout: Stopped at limit*2 in file order despite data already
being batch-downloaded (zero API cost to check all). Removed early exit,
scan full universe, sort by volume_multiple.

sector_rotation: Checked laggards in arbitrary dict order, spending API
calls on random tickers. Now sorts by most-negative 5d return first so
the strongest laggard candidates are checked before hitting the budget.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:46:21 -07:00
Youssef Aitousarrah 136fa47645 fix(options_flow): scan full universe before applying limit, rank by signal strength
Previously the scanner stopped as soon as self.limit candidates were found
from as_completed() futures. Since futures complete in non-deterministic
network-latency order, this was equivalent to random sampling — fast-to-
respond tickers won regardless of how strong their options signal was.

Fix: collect all candidates from the full universe, then sort by options_score
(unusual strike count weighted 1.5x for calls to favor bullish flow) before
applying the limit. The top-N strongest signals are now always returned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:46:21 -07:00
Youssef Aitousarrah 61b731ac28 fix(filter): replace tqdm with logger in batch news functions to fix I/O error
tqdm writes to stderr immediately on __enter__, before any loop iteration.
In Streamlit's thread/subprocess context stderr can be a closed pipe, causing
'I/O operation on closed file' which _run_call catches and returns {} — so
the entire news enrichment step was silently skipped every run.

Replaced tqdm progress bars with logger.info() calls in:
- get_batch_stock_news_google() in openai.py
- get_batch_stock_news_openai() in openai.py
- Reddit DD parallel evaluation in reddit_api.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:46:21 -07:00
github-actions[bot] 21b33c6709 chore: update performance tracking 2026-04-06 2026-04-06 13:57:37 +00:00