trade: apply runtime strategy/fx pnl split on sell paths (#370) #383
@@ -111,6 +111,7 @@ Updated: 2026-03-02
|
||||
|
||||
- **위치**: `src/db.py` (`fx_pnl`, `strategy_pnl` 컬럼 존재)
|
||||
- **현 상태**: 런타임 SELL 경로에서 `strategy_pnl`/`fx_pnl` 분리 계산 및 전달을 적용함 (`#370`).
|
||||
- **운영 메모**: `trading_cycle`은 scanner 기반 `selection_context`에 `fx_rate`를 추가하고, `run_daily_session`은 scanner 컨텍스트 없이 `fx_rate` 스냅샷만 기록한다.
|
||||
- **잔여**: 과거 BUY 레코드에 `fx_rate`가 없으면 해외 구간도 `fx_pnl=0` fallback으로 기록됨.
|
||||
- **영향**: USD 거래에서 환율 손익과 전략 손익이 분리되지 않아 성과 분석 부정확
|
||||
- **요구사항**: REQ-V3-007
|
||||
|
||||
@@ -130,6 +130,9 @@ def _resolve_sell_qty_for_pnl(*, sell_qty: int | None, buy_qty: int | None) -> i
|
||||
|
||||
def _extract_fx_rate_from_sources(*sources: dict[str, Any] | None) -> float | None:
|
||||
"""Best-effort FX rate extraction from broker payloads."""
|
||||
# KIS overseas payloads expose exchange-rate fields with varying key names
|
||||
# across endpoints/responses (price, balance, buying power). Keep this list
|
||||
# centralised so schema drifts can be patched in one place.
|
||||
rate_keys = (
|
||||
"frst_bltn_exrt",
|
||||
"bass_exrt",
|
||||
@@ -3392,10 +3395,13 @@ async def run_daily_session(
|
||||
sell_fx_rate=sell_fx_rate,
|
||||
)
|
||||
if sell_fx_rate is not None and not market.is_domestic:
|
||||
# Daily path does not carry scanner candidate metrics, so this
|
||||
# context intentionally stores FX snapshot only.
|
||||
selection_context = {"fx_rate": sell_fx_rate}
|
||||
elif not market.is_domestic:
|
||||
snapshot_fx_rate = _extract_fx_rate_from_sources(balance_info, stock_data)
|
||||
if snapshot_fx_rate is not None:
|
||||
# BUY/HOLD in daily path: persist FX snapshot for later SELL split.
|
||||
selection_context = {"fx_rate": snapshot_fx_rate}
|
||||
log_trade(
|
||||
conn=db_conn,
|
||||
|
||||
Reference in New Issue
Block a user