When gemini-2.5-flash quota is exhausted (20 RPD free tier), generate_playbook()
fell back to _defensive_playbook() which only had price_change_pct_below: -3.0 SELL
conditions — no BUY conditions — causing zero trades on US market despite scanner
finding strong momentum/oversold candidates.
Changes:
- Add _smart_fallback_playbook() that uses scanner signals to build BUY conditions:
- momentum signal: BUY when volume_ratio_above=VOL_MULTIPLIER
- oversold signal: BUY when rsi_below=RSI_OVERSOLD_THRESHOLD
- always: SELL stop-loss at price_change_pct_below=-3.0
- Use _smart_fallback_playbook() instead of _defensive_playbook() on Gemini failure
- Add 10 new tests for _smart_fallback_playbook() covering momentum/oversold/empty cases
- Update existing test_gemini_failure_returns_defensive to match new behavior
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add build_self_market_scorecard() to read previous day's own market
performance, and include it in the Gemini planning prompt alongside
cross-market context.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KR planner now reads US scorecard from previous day (timezone-aware),
and generate_playbook uses STRATEGIC context selection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review findings addressed:
- Finding 1 (ImportError): false positive — ContextLayer is re-exported from
src.context.store, import works correctly at runtime
- Finding 2 (timezone): generate_playbook() and build_cross_market_context()
now accept optional today parameter for market-local date injection
- Finding 3 (lint): removed unused imports (UTC, datetime, PlaybookStatus),
fixed line-too-long in prompt template
- Tests simplified: replaced date patching with direct today= parameter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add playbooks table to src/db.py with UNIQUE(date, market) constraint
- PlaybookStore: save/load/delete, status management, match_count tracking,
list_recent with market filter, stats without full deserialization
- DayPlaybook JSON serialization via Pydantic model_dump_json/model_validate_json
- 23 tests, 100% coverage on playbook_store.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses second round of PR #102 review:
- _warn_missing_key(): logs each missing key only once per engine instance
to prevent log spam in high-frequency trading loops
- _build_match_details(): uses _safe_float() normalized values instead of
raw market_data to ensure consistent float types in logging/analysis
- Test: verify warning fires exactly once across repeated calls
- Test: verify match_details contains normalized float values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ScenarioEngine evaluates pre-defined playbook scenarios against real-time
market data with sub-100ms execution (zero API calls). Supports condition
AND-matching, global portfolio rules, and first-match-wins priority.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>