From 7aa5fedc12a209ecfc9ee2472c4057e306690577 Mon Sep 17 00:00:00 2001 From: agentson Date: Thu, 26 Feb 2026 00:23:28 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20market=5Fdata=EC=97=90=20unrealized=5Fpn?= =?UTF-8?q?l=5Fpct/holding=5Fdays=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC?= =?UTF-8?q?=20SELL=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20=EC=A0=95?= =?UTF-8?q?=EC=83=81=ED=99=94=20(#259)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit trading_cycle()의 market_data에 보유 포지션 정보가 없어 Condition requires 'unrealized_pnl_pct' but key missing from market_data 경고 발생. 보유 종목(NVDA 등)의 take-profit/stop-loss 시나리오가 평가 불가하여 HOLD(confidence=0) 고착. - get_open_position()에 timestamp 컬럼 추가 - market_data 구성 시 open_position 조회 후 아래 키 추가: - unrealized_pnl_pct: (current_price - entry_price) / entry_price * 100 - holding_days: 매수일로부터 경과 일수 Co-Authored-By: Claude Sonnet 4.6 --- src/db.py | 4 ++-- src/main.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) 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(