AsyncIOScheduler was constructed with no job_defaults, so APScheduler's default
misfire_grace_time of 1s applied. In this single-process app the scheduler shares
one event loop with the API and all other jobs, so when a daily job came due
while the loop was busy (e.g. the scanner mid-run), the fire was processed >1s
late, flagged a misfire, and skipped — while next_run still advanced 24h, making
the job look healthy though it never ran. Set a generous grace window (1h),
coalesce missed runs into a single catch-up, and cap concurrency at 1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
scan_rr set the total then called scan_all_tickers as one opaque await, so the
runtime snapshot's processed count stayed 0 until the whole scan finished and
jumped straight to 100%. scan_all_tickers now takes an optional progress_callback
invoked per ticker; the scheduler wires it to _runtime_progress so the sidebar's
live indicator advances as tickers are scanned.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make "qualified" mean an edge candidate, not just R:R + confidence.
The gate now also requires (all admin-configurable, defaults on):
- high conviction: recommended_action LONG_HIGH / SHORT_HIGH only
- clean read: risk_level Low (no contradicting signals)
- probable primary target: best target probability >= min (default 60)
- Shared predicate: app/services/qualification.py +
frontend/src/lib/qualification.ts (mirrored)
- Activation config extended (min_target_probability,
require_high_conviction, exclude_conflicts) with bool-aware
get/update + validation
- /trades/performance switched to ?qualified_only=true, applying
the full gate server-side; confidence breakdown stays unfiltered
- Dashboard "Qualified", Signals "Qualified only" toggle, and
Track Record all use the one gate; Admin gains the new controls
Sentiment provider runtime config (prior change) included.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes the feedback loop on R:R scanner signals:
- Nightly outcome_evaluator job replays unresolved setups against daily
OHLCV bars: target_hit / stop_hit / ambiguous (same-bar, counted as
loss) / expired after OUTCOME_EVALUATION_MAX_BARS (default 30)
- Migration 004: evaluated_at + outcome_date on trade_setups
- GET /trades/performance: hit rate, expectancy (avg R), total R with
breakdowns by direction, recommended action, and confidence bucket
- New Performance page (stat cards, breakdown tables, Evaluate Now,
methodology disclosure) wired into sidebar and mobile nav
- 17 new unit tests for evaluation logic and stats aggregation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>