diff --git a/src/db.py b/src/db.py index fc2070e..d25239a 100644 --- a/src/db.py +++ b/src/db.py @@ -254,7 +254,7 @@ def get_open_position( """Return open position if latest trade is BUY, else None.""" cursor = conn.execute( """ - SELECT action, decision_id, price, quantity + SELECT action, decision_id, price, quantity, timestamp FROM trades WHERE stock_code = ? AND market = ? @@ -266,7 +266,7 @@ def get_open_position( row = cursor.fetchone() if not row or row[0] != "BUY": return None - return {"decision_id": row[1], "price": row[2], "quantity": row[3]} + return {"decision_id": row[1], "price": row[2], "quantity": row[3], "timestamp": row[4]} def get_recent_symbols( diff --git a/src/main.py b/src/main.py index 2d52ae2..67115a5 100644 --- a/src/main.py +++ b/src/main.py @@ -576,6 +576,22 @@ async def trading_cycle( market_data["rsi"] = candidate.rsi market_data["volume_ratio"] = candidate.volume_ratio + # Enrich market_data with holding info for SELL/HOLD scenario conditions + open_pos = get_open_position(db_conn, stock_code, market.code) + if open_pos and current_price > 0: + entry_price = safe_float(open_pos.get("price"), 0.0) + if entry_price > 0: + market_data["unrealized_pnl_pct"] = ( + (current_price - entry_price) / entry_price * 100 + ) + entry_ts = open_pos.get("timestamp") + if entry_ts: + try: + entry_date = datetime.fromisoformat(entry_ts).date() + market_data["holding_days"] = (datetime.now(UTC).date() - entry_date).days + except (ValueError, TypeError): + pass + # 1.3. Record L7 real-time context (market-scoped keys) timeframe = datetime.now(UTC).isoformat() context_store.set_context( diff --git a/tests/test_overseas_broker.py b/tests/test_overseas_broker.py index 0f47bec..bd74cd9 100644 --- a/tests/test_overseas_broker.py +++ b/tests/test_overseas_broker.py @@ -28,6 +28,7 @@ def mock_settings() -> Settings: KIS_APP_SECRET="test_secret", KIS_ACCOUNT_NO="12345678-01", GEMINI_API_KEY="test_gemini_key", + MODE="paper", # Explicitly set to avoid .env MODE=live override )