feat: enforce session_id persistence in trade ledger (TASK-CODE-007)

This commit is contained in:
agentson
2026-02-27 08:49:04 +09:00
parent 2dbe98615d
commit b2b02b6f57
2 changed files with 43 additions and 3 deletions

View File

@@ -8,6 +8,9 @@ from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from src.core.order_policy import classify_session_id
from src.markets.schedule import MARKETS
def init_db(db_path: str) -> sqlite3.Connection:
"""Initialize the trade logs database and return a connection."""
@@ -35,6 +38,7 @@ def init_db(db_path: str) -> sqlite3.Connection:
fx_pnl REAL DEFAULT 0.0,
market TEXT DEFAULT 'KR',
exchange_code TEXT DEFAULT 'KRX',
session_id TEXT DEFAULT 'UNKNOWN',
selection_context TEXT,
decision_id TEXT,
mode TEXT DEFAULT 'paper'
@@ -56,6 +60,8 @@ def init_db(db_path: str) -> sqlite3.Connection:
conn.execute("ALTER TABLE trades ADD COLUMN decision_id TEXT")
if "mode" not in columns:
conn.execute("ALTER TABLE trades ADD COLUMN mode TEXT DEFAULT 'paper'")
if "session_id" not in columns:
conn.execute("ALTER TABLE trades ADD COLUMN session_id TEXT DEFAULT 'UNKNOWN'")
if "strategy_pnl" not in columns:
conn.execute("ALTER TABLE trades ADD COLUMN strategy_pnl REAL DEFAULT 0.0")
if "fx_pnl" not in columns:
@@ -70,6 +76,13 @@ def init_db(db_path: str) -> sqlite3.Connection:
AND fx_pnl = 0.0
"""
)
conn.execute(
"""
UPDATE trades
SET session_id = 'UNKNOWN'
WHERE session_id IS NULL OR session_id = ''
"""
)
# Context tree tables for multi-layered memory management
conn.execute(
@@ -192,6 +205,7 @@ def log_trade(
fx_pnl: float | None = None,
market: str = "KR",
exchange_code: str = "KRX",
session_id: str | None = None,
selection_context: dict[str, any] | None = None,
decision_id: str | None = None,
mode: str = "paper",
@@ -211,12 +225,17 @@ def log_trade(
fx_pnl: FX PnL component
market: Market code
exchange_code: Exchange code
session_id: Session identifier (if omitted, auto-derived from market)
selection_context: Scanner selection data (RSI, volume_ratio, signal, score)
decision_id: Unique decision identifier for audit linking
mode: Trading mode ('paper' or 'live') for data separation
"""
# Serialize selection context to JSON
context_json = json.dumps(selection_context) if selection_context else None
resolved_session_id = session_id or "UNKNOWN"
market_info = MARKETS.get(market)
if session_id is None and market_info is not None:
resolved_session_id = classify_session_id(market_info)
if strategy_pnl is None and fx_pnl is None:
strategy_pnl = pnl
fx_pnl = 0.0
@@ -232,9 +251,9 @@ def log_trade(
INSERT INTO trades (
timestamp, stock_code, action, confidence, rationale,
quantity, price, pnl, strategy_pnl, fx_pnl,
market, exchange_code, selection_context, decision_id, mode
market, exchange_code, session_id, selection_context, decision_id, mode
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
datetime.now(UTC).isoformat(),
@@ -249,6 +268,7 @@ def log_trade(
fx_pnl,
market,
exchange_code,
resolved_session_id,
context_json,
decision_id,
mode,