- MARKET_SHORTHAND + expand_market_codes()로 config "US" → schedule "US_NASDAQ/NYSE/AMEX" 자동 확장
- /report, /scenarios, /review, /dashboard 텔레그램 명령 추가
- price_change_pct를 trading_cycle과 run_daily_session에 주입
- HOLD시 get_open_position 기반 손절 모니터링 및 자동 SELL 오버라이드
- 대시보드 /api/status 동적 market 조회로 변경
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --dashboard CLI flag and DASHBOARD_ENABLED env var to start
FastAPI dashboard in a daemon thread alongside the trading loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap evolution notification in try/except so telegram failures don't
crash the evolution loop. Add integration tests for market close flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Run EvolutionOptimizer.evolve() at US market close, skip for other
markets, and notify via Telegram when a strategy PR is generated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up periodic context rollups (weekly/monthly/quarterly/annual/legacy)
in both daily and realtime trading loops with dedup-safe scheduling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract _handle_market_close() helper that runs EOD aggregation,
generates scorecard with optional AI lessons, and sends Telegram summary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add decision_id column to trades table, capture log_decision() return
value, and update original BUY decision outcome on SELL execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add L7_REALTIME writes in trading_cycle() for volatility, price, rsi, volume_ratio
- Normalize key format to {metric}_{market}_{stock_code} across scanner and main
- Fix existing key mismatch between scanner writes and main reads
- Remove unused MarketScanner dead code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address PR #110 review findings:
1. High — Realtime mode now loads playbook from DB before calling Gemini,
preventing duplicate API calls on process restart (4/day budget).
2. Medium — Pass market-local date (via market.timezone) to
generate_playbook() and _empty_playbook() instead of date.today().
3. Medium — scan_candidates restructured from {stock_code: candidate}
to {market_code: {stock_code: candidate}} to prevent KR/US symbol
collision.
New test: test_scan_candidates_market_scoped verifies cross-market
isolation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused imports (sys, ScenarioMatch, asyncio, StockPlaybook),
fix import ordering, and split long lines for ruff compliance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace brain.decide() with scenario_engine.evaluate() in trading_cycle
and brain.decide_batch() with per-stock scenario evaluation in
run_daily_session. Initialize PreMarketPlanner, ScenarioEngine, and
PlaybookStore in run(). Add pre-market playbook generation on market
open (1 Gemini call per market per day), market_data enrichment from
scanner metrics (rsi, volume_ratio), portfolio_data for global rules,
scenario match notifications, and playbook lifecycle management.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolved conflict in src/main.py by using safe_float() from main
instead of float(...or '0') pattern.
Changes:
- src/main.py: Use safe_float() for consistent empty string handling
- All 16 tests pass including test_overseas_price_empty_string
Add safe_float() helper function to safely convert API response values
to float, handling empty strings, None, and invalid values that cause
ValueError: "could not convert string to float: ''".
Changes:
- Add safe_float() function in src/main.py with full docstring
- Replace all float() calls with safe_float() in trading_cycle()
- Domestic market: orderbook prices, balance amounts
- Overseas market: price data, balance info
- Add 6 comprehensive unit tests for safe_float()
The function handles:
- Empty strings ("") → default (0.0)
- None values → default (0.0)
- Invalid strings ("abc") → default (0.0)
- Valid strings ("123.45") → parsed float
- Float inputs (123.45) → pass through
This prevents crashes when KIS API returns empty strings during
market closed hours or data unavailability.
Fixes: #44
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type checking for output2 response from get_overseas_balance API.
The API can return either list format [{}] or dict format {}, causing
KeyError when accessing output2[0].
Changes:
- Check isinstance before accessing output2[0]
- Handle list, dict, and empty cases
- Add safe fallback with "or" for empty strings
- Add 3 test cases for list/dict/empty formats
Fixes: #41
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Integrate Telegram notifications throughout the main trading loop to provide
real-time alerts for critical events and trading activities.
Changes:
- Add TelegramClient initialization in run() function
- Send system startup notification on agent start
- Send market open/close notifications when markets change state
- Send trade execution notifications for BUY/SELL orders
- Send fat finger rejection notifications when orders are blocked
- Send circuit breaker notifications when loss threshold is exceeded
- Pass telegram client to trading_cycle() function
- Add tests for all notification scenarios in test_main.py
All notifications wrapped in try/except to ensure trading continues even
if Telegram API fails. Notifications are non-blocking and do not affect
core trading logic.
Test coverage: 273 tests passed, overall coverage 79%
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>