feat(leaderboard): add 14 external strategies as baseline classes - #395
feat(leaderboard): add 14 external strategies as baseline classes#395TrentonNewWorld wants to merge 6 commits into
Conversation
…BASE_PATH Two bugs made every dashboard backtest fail on Windows: the venv-python resolution assumed the Unix Scripts layout (bin/python3) instead of checking Windows' Scripts/python.exe first, and a relative DATABASE_PATH resolved against the backtest subprocess's cwd rather than the repo root, silently writing to a second, wrong database nested under dashboard/dashboard/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…page Custom live-trading broker mirroring the existing Robinhood risk-gate pattern: separate live key pair from paper keys (Alpaca rejects one on the other's endpoint), off by default via both a per-call flag and an ALPACA_LIVE_EXECUTE env var kill switch, per-order notional cap, no shorting, full JSONL audit logging. Mission Control is a new dedicated page showing real-money and paper wallet balances/holdings side by side, backed by a single read-only overview endpoint. Placing orders stays out of scope for that endpoint -- see alpaca_live_service.py for the actual risk-gated execution path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds 14 deterministic (no LLM call) baseline strategies to the leaderboard registry, translated from three external sources backtested in the "Strategy Lab" report: TradingAgents' technical-composite proxy, 6 of QuantConnect's public Investment Strategy Library entries, and 8 of freqtrade-strategies' most prominent strategies (crypto-specific filters identified and stripped rather than blindly ported; GodStra excluded as not portable, its thresholds being hyperopt-fit to a specific crypto pair). The key architectural piece is _signal_engine.py: every BaselineStrategy must return an hourly equity curve (confirmed via base.py and service.py's fetch_hourly_bars using TimeFrame.Hour), but all 14 strategies' signals are daily-scale (RSI-14, SMA-200, monthly rebalances, etc). The engine resamples hourly bars to daily OHLCV, evaluates each strategy's weight function once per trading day using only history strictly before that day (no look-ahead), and marks equity every hour in between -- preserving the validated daily-cadence logic while honoring the hourly-bar contract the rest of the leaderboard engine expects. Every strategy's lookback adaptively caps at whatever history is actually available rather than requiring a fixed window: the real leaderboard's contest window is only about a month, versus the full year these strategies were originally validated against, so e.g. a "252-day momentum" strategy degrades to a much shorter-window version of itself on the real board rather than crashing or NaN-ing out. Documented per strategy, not hidden. Registering a class alone is inert -- a strategy only becomes visible/live once it also has an entry in leaderboard.json's strategies array (the only call site for the registry), so 14 matching entries were added there too. Also fixes two pre-existing gaps in dashboard/config/leaderboard.json's consumers caught while verifying this: mission_control.py was leaking raw exception text via "error": str(e) (test_error_detail_sanitization.py's CodeQL-motivated guard), and test_app_composition.py's route contract didn't yet include the two Mission Control routes. 58 new tests cover registry identity, key resolution, required_symbols, and run() smoke tests against synthetic hourly bars, including a short-history graceful-degradation case matching the real contest window's constraint. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@TrentonNewWorld is attempting to deploy a commit to the allan-feng's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Thanks for putting this together. We really appreciate the work that went into the strategies. A suggestion: rather than adding all of them to the leaderboard right away, it would be great to pick 2–3 of them and run them through the ATL backtest workflow first, and compare their results with the existing market indices/ buy-and-hold baselines. After testing the strategies, Agent Supermarket would be a great place for them. That’s where we’d love community agents to land, so people can try them, clone them, and iterate. Happy to talk through details anytime. Feel free to ping me (allanfeng) on our Discord: https://discord.gg/9HnQ6XDG98 |
Behaviour: - turn_of_month: the last sampled date is no longer flagged a month-end (bought SPY on the final day of every contest); a zero open no longer starts a phantom hold. - capm_alpha_ranking: a lone qualifier gets weight 1.0 (was a hardcoded 0.5 leaving half the book in cash); OLS variance/centring computed on the symbol's own valid days; pct_change(fill_method=None). - volatility_effect: pct_change(fill_method=None) so a gap is not a 0% day. - bandtastic: slow-EMA span capped at available history -- the fixed 50-day floor could never trade on the ~44-day leaderboard window. - trendrider: SMA-200 window sized off the symbol's own rows, not the union frame (one gap day made it permanently NaN). - _indicators: rsi -> 100 (not NaN) with no down moves; adx -> 0 (not NaN) on a range-bound stretch; zscore_row all-NaN -> zeros. - build_price_cache: a symbol missing only the first timestamp is priced from its own first bar instead of being dropped for the whole run; duplicated bar stamps resolve to the last bar (also deduped in the two SPY-only strategies before scalar .loc reads). Structure / performance: - hlhb, trendrider, supertrend_triple precompute indicators once per symbol over the full series (causal, so bit-identical; pinned by test_indicators.py) instead of recomputing per symbol per day. - daily_history computes the ET date key once per symbol, not 5x. - Dead lot_size parameter removed; duplicate price comprehension folded. - base.required_symbols / num_trades gain the shared default; 12 + 14 identical overrides deleted; subset_bars used everywhere. Tests: the multi-symbol smoke tests were vacuous (fixture keyed SYM0..29 vs the DJIA-30 default, so run() returned [] before touching anything); they now pass the synthetic symbols and assert the curve length. Adds a reference-window test for the engine and regression tests for each fix. Drops the unused `datetime as dt` import (CodeQL py/unused-import). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKw312eMfu2bWaAsR4M8xb
Mission Control: - GET /api/v1/mission-control/overview is admin-gated (it returns the real account's cash/equity/positions and whether execution is armed). - Live snapshot failures are caught and reported instead of 500ing the page; successful snapshots cached 30s via paper_trading_cache. - Page sends credentials, escapes every interpolated field, and shows a sign-in message on 401/403. Router added to the blocking-IO guard list. Live services: - alpaca_live_service validates the decision through the LLM validator before turning it into orders; rejected actions are reported in the result; ALPACA_LIVE_EXECUTE read once per run. - robinhood_live_service accepts "on" like the other truthy env parsers. - alpaca_live resolves the data feed outside the try block (a config error is fatal, not swallowed), raises on an unknown side, and keeps fill fields in `raw`. - Shared helpers moved to execution/_live_common.py. - run_alpaca_live_agent loads dashboard/.env like the app does. - credentials/alpaca_live.json.example documented and un-ignored; conftest strips ALPACA_LIVE_* so a developer's shell can never arm a test run; CLAUDE.md documents the three frontend surfaces and the ALPACA_LIVE_* env contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKw312eMfu2bWaAsR4M8xb
…un index - paths.py gains resolve_python_exe(venv_dir) and resolve_env_path(); the four copies of the Windows-vs-POSIX interpreter lookup and the relative DATABASE_PATH handling (backtests router, algo_service, database.py, ai_hedge_fund adapter) now go through them; the "venv vs system Python" startup log line still reports which one was actually chosen. - leaderboard service: ensure_leaderboard_runs and get_leaderboard build _cached_run_index once instead of calling _find_cached_run per strategy (5 -> 19 entries made the per-request cost visible), and a single-flight lock keyed on (session, start, end) stops concurrent public GETs from recomputing the same window. - leaderboard.js: a preset-less baseline entry styles as kind 'strategy' (dashed, thin) rather than 'team' -- dormant until the 14 new labels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKw312eMfu2bWaAsR4M8xb
|
Review pass done; fixes pushed as three commits on this branch ( Strategies ( Live broker / Mission Control ( Backend ( Not changed, flagged for follow-up
|
|
Overall looks good. I also recommend to test 2 to 3 strategies first. |
Summary
_signal_engine.py, which bridges these daily-scale signals (RSI-14, SMA-200, monthly rebalances, etc.) onto the hourly equity-curve contractBaselineStrategy.run()must honor — resamples hourly bars to daily OHLCV, evaluates each strategy's weight function once per trading day using only history strictly before that day (no look-ahead), and marks equity every hour in between.registry.pyand adds matching entries toleaderboard.json'sstrategiesarray (a registered class alone is inert — it only becomes visible/live once it also has a config entry, since that's the only call site for the registry).DATABASE_PATHbugs (fix(backtests)), and a risk-gated Alpaca live-trading broker + a new Mission Control wallet/holdings page (feat(trading)).mission_control.pywas leaking raw exception text via"error": str(e)(violatestest_error_detail_sanitization.py's CodeQL-motivated guard), andtest_app_composition.py's route contract didn't yet include the two Mission Control routes.Test plan
pytest dashboard/backend/tests/domain/leaderboard/test_external_strategies.py -v— 58 new tests (registry identity, key resolution, required_symbols, run() smoke tests against synthetic hourly bars, including a short-history graceful-degradation case).pytest dashboard/backend/tests/) — only the same 8 pre-existing, unrelated failures remain (iFinD, vnpy, optional-SDK,test_engine_move,test_canonical_consumers,test_router_move::test_no_circular_imports) plus one pre-existing CSRF test error; confirmed via a cleangit stashbaseline that none are caused by this branch.GET /api/v1/leaderboard?period=contest, and all 14 new strategies appear by name in the frontend's chart legend/picker on the Competition tab.🤖 Generated with Claude Code