feat: implement Smart Volatility Scanner with RSI/volume filters (issue #76)
Some checks failed
CI / test (pull_request) Has been cancelled
Some checks failed
CI / test (pull_request) Has been cancelled
Add Python-first scanning pipeline that reduces Gemini API calls by filtering stocks before AI analysis: KIS rankings API -> RSI/volume filter -> AI judgment. ## Implementation - Add RSI calculation (Wilder's smoothing method) to VolatilityAnalyzer - Add KIS API methods: fetch_market_rankings() and get_daily_prices() - Create SmartVolatilityScanner with configurable thresholds - Integrate scanner into main.py realtime mode - Add selection_context logging to trades table for Evolution system ## Configuration - RSI_OVERSOLD_THRESHOLD: 30 (configurable 0-50) - RSI_MOMENTUM_THRESHOLD: 70 (configurable 50-100) - VOL_MULTIPLIER: 2.0 (minimum volume ratio, configurable 1-10) - SCANNER_TOP_N: 3 (max candidates per scan, configurable 1-10) ## Benefits - Reduces Gemini API calls (process 1-3 qualified stocks vs 20-30 ranked) - Python-based technical filtering before expensive AI judgment - Tracks selection criteria (RSI, volume_ratio, signal, score) for strategy optimization - Graceful fallback to static watchlist if ranking API fails ## Tests - 13 new tests for SmartVolatilityScanner and RSI calculation - All existing tests updated and passing - Coverage maintained at 73% Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
28
src/db.py
28
src/db.py
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
@@ -38,6 +39,8 @@ def init_db(db_path: str) -> sqlite3.Connection:
|
||||
conn.execute("ALTER TABLE trades ADD COLUMN market TEXT DEFAULT 'KR'")
|
||||
if "exchange_code" not in columns:
|
||||
conn.execute("ALTER TABLE trades ADD COLUMN exchange_code TEXT DEFAULT 'KRX'")
|
||||
if "selection_context" not in columns:
|
||||
conn.execute("ALTER TABLE trades ADD COLUMN selection_context TEXT")
|
||||
|
||||
# Context tree tables for multi-layered memory management
|
||||
conn.execute(
|
||||
@@ -118,15 +121,33 @@ def log_trade(
|
||||
pnl: float = 0.0,
|
||||
market: str = "KR",
|
||||
exchange_code: str = "KRX",
|
||||
selection_context: dict[str, any] | None = None,
|
||||
) -> None:
|
||||
"""Insert a trade record into the database."""
|
||||
"""Insert a trade record into the database.
|
||||
|
||||
Args:
|
||||
conn: Database connection
|
||||
stock_code: Stock code
|
||||
action: Trade action (BUY/SELL/HOLD)
|
||||
confidence: Confidence level (0-100)
|
||||
rationale: AI decision rationale
|
||||
quantity: Number of shares
|
||||
price: Trade price
|
||||
pnl: Profit/loss
|
||||
market: Market code
|
||||
exchange_code: Exchange code
|
||||
selection_context: Scanner selection data (RSI, volume_ratio, signal, score)
|
||||
"""
|
||||
# Serialize selection context to JSON
|
||||
context_json = json.dumps(selection_context) if selection_context else None
|
||||
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO trades (
|
||||
timestamp, stock_code, action, confidence, rationale,
|
||||
quantity, price, pnl, market, exchange_code
|
||||
quantity, price, pnl, market, exchange_code, selection_context
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
datetime.now(UTC).isoformat(),
|
||||
@@ -139,6 +160,7 @@ def log_trade(
|
||||
pnl,
|
||||
market,
|
||||
exchange_code,
|
||||
context_json,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user