trade: apply runtime strategy/fx pnl split on sell paths (#370) #383

Merged
jihoson merged 3 commits from feature/issue-370-fx-pnl-runtime-split into feature/v3-session-policy-stream 2026-03-02 02:53:04 +09:00
Collaborator

Summary

  • trading_cycle/run_daily_session SELL 경로에서 strategy_pnl/fx_pnl을 런타임 계산해 log_trade()에 명시 전달하도록 반영했습니다.
  • BUY 로그(selection_context)에 해외 fx_rate 스냅샷을 남기고, SELL 시 buy/sell fx_rate가 모두 있으면 FX 성분을 분리 계산합니다.
  • get_latest_buy_trade()가 BUY의 selection_context를 함께 조회하도록 확장했습니다.
  • 국내/해외 모두 strategy_pnl + fx_pnl == pnl 무결성을 유지하는 테스트를 보강했습니다.
  • 감사 문서에서 REQ-V3-007 상태를 "런타임 적용 + fallback 잔여"로 갱신했습니다.

Scope Mapping

  • REQ: REQ-V3-007
  • TASK: TASK-CODE-011
  • TEST: TEST-ACC-006

Validation

  • python3 -m py_compile src/main.py src/db.py
  • ruff check src/main.py src/db.py tests/test_main.py
  • pytest -q tests/test_main.py -k "sell_order_uses_broker_balance_qty_not_db or split_trade_pnl_components_overseas_fx_split_preserves_total"
  • pytest -q tests/test_db.py
  • python3 scripts/validate_ouroboros_docs.py
  • python3 scripts/validate_governance_assets.py origin/feature/v3-session-policy-stream...HEAD
  • python3 scripts/validate_docs_sync.py
## Summary - `trading_cycle`/`run_daily_session` SELL 경로에서 `strategy_pnl`/`fx_pnl`을 런타임 계산해 `log_trade()`에 명시 전달하도록 반영했습니다. - BUY 로그(`selection_context`)에 해외 `fx_rate` 스냅샷을 남기고, SELL 시 buy/sell `fx_rate`가 모두 있으면 FX 성분을 분리 계산합니다. - `get_latest_buy_trade()`가 BUY의 `selection_context`를 함께 조회하도록 확장했습니다. - 국내/해외 모두 `strategy_pnl + fx_pnl == pnl` 무결성을 유지하는 테스트를 보강했습니다. - 감사 문서에서 REQ-V3-007 상태를 "런타임 적용 + fallback 잔여"로 갱신했습니다. ## Scope Mapping - REQ: `REQ-V3-007` - TASK: `TASK-CODE-011` - TEST: `TEST-ACC-006` ## Validation - `python3 -m py_compile src/main.py src/db.py` - `ruff check src/main.py src/db.py tests/test_main.py` - `pytest -q tests/test_main.py -k "sell_order_uses_broker_balance_qty_not_db or split_trade_pnl_components_overseas_fx_split_preserves_total"` - `pytest -q tests/test_db.py` - `python3 scripts/validate_ouroboros_docs.py` - `python3 scripts/validate_governance_assets.py origin/feature/v3-session-policy-stream...HEAD` - `python3 scripts/validate_docs_sync.py`
agentson added 1 commit 2026-03-02 02:36:04 +09:00
trade: apply runtime strategy/fx pnl split on sell paths (#370)
All checks were successful
Gitea CI / test (push) Successful in 32s
Gitea CI / test (pull_request) Successful in 32s
d4f37ee392
Author
Collaborator

PR 리뷰 (Claude Code)

전체 판정: LGTM

CI 통과, 테스트 179개 전체 통과 확인.


로직 검증

_split_trade_pnl_components 계산 정확성

테스트 케이스(buy_price=100, sell_price=110, qty=2, buy_fx=1200, sell_fx=1260) 수동 검증:

  • buy_notional = 100 × 2 = 200
  • fx_return = (1260 − 1200) / 1200 = 0.05
  • fx_pnl = 200 × 0.05 = 10.0
  • strategy_pnl = 20.0 − 10.0 = 10.0

strategy_pnl + fx_pnl = trade_pnl 무결성이 strategy_pnl = trade_pnl - fx_pnl 정의에 의해 항상 보장됩니다.

SELL 경로 흐름 (trading_cycle)

buy_trade = None으로 초기화 → SELL + order_succeeded 시 get_latest_buy_trade() 호출 → _extract_buy_fx_rate(buy_trade)로 BUY 시 저장된 fx_rate 추출 → _split_trade_pnl_components() 호출. BUY-SELL 간 fx_rate 전달 경로가 완결됩니다.

사이드 이펙트: 버그 수정 포함

balance_info: dict[str, Any] = {}trading_cyclerun_daily_session 양쪽에 추가되었습니다. 기존에는 overseas 조건 미진입 시 변수가 미정의 상태로 아래 코드에서 NameError 위험이 있었습니다. 이것은 이 PR의 암묵적 버그 수정입니다.


소견

run_daily_session BUY 경로의 selection_context

trading_cycle에서는 BUY 시 scanner 정보(rsi, volume_ratio 등)가 selection_context에 포함된 뒤 fx_rate가 추가되지만, run_daily_session에서는 {fx_rate: snapshot_fx_rate}만 저장됩니다. daily 모드에서 real-time scanner가 없으므로 의도된 동작으로 보이나, 두 경로의 selection_context 구조가 다르다는 점은 감사 문서나 주석에 명시하면 좋습니다.

_extract_fx_rate_from_sources 키 탐색 순서

7개 키(frst_bltn_exrt, bass_exrt, ovrs_exrt 등)가 API 출처 주석 없이 hardcoded되어 있습니다. best-effort 방식이라 안전하지만, 브로커 API 업데이트 시 유지보수가 어려울 수 있습니다. 블로킹 사항은 아닙니다.

## PR 리뷰 (Claude Code) ### 전체 판정: ✅ LGTM CI 통과, 테스트 179개 전체 통과 확인. --- ### 로직 검증 **`_split_trade_pnl_components` 계산 정확성** 테스트 케이스(buy_price=100, sell_price=110, qty=2, buy_fx=1200, sell_fx=1260) 수동 검증: - buy_notional = 100 × 2 = 200 - fx_return = (1260 − 1200) / 1200 = 0.05 - fx_pnl = 200 × 0.05 = 10.0 - strategy_pnl = 20.0 − 10.0 = 10.0 `strategy_pnl + fx_pnl = trade_pnl` 무결성이 `strategy_pnl = trade_pnl - fx_pnl` 정의에 의해 항상 보장됩니다. **SELL 경로 흐름 (trading_cycle)** `buy_trade = None`으로 초기화 → SELL + order_succeeded 시 `get_latest_buy_trade()` 호출 → `_extract_buy_fx_rate(buy_trade)`로 BUY 시 저장된 fx_rate 추출 → `_split_trade_pnl_components()` 호출. BUY-SELL 간 fx_rate 전달 경로가 완결됩니다. **사이드 이펙트: 버그 수정 포함** `balance_info: dict[str, Any] = {}`가 `trading_cycle`과 `run_daily_session` 양쪽에 추가되었습니다. 기존에는 overseas 조건 미진입 시 변수가 미정의 상태로 아래 코드에서 `NameError` 위험이 있었습니다. 이것은 이 PR의 암묵적 버그 수정입니다. --- ### 소견 **`run_daily_session` BUY 경로의 selection_context** `trading_cycle`에서는 BUY 시 scanner 정보(rsi, volume_ratio 등)가 selection_context에 포함된 뒤 fx_rate가 추가되지만, `run_daily_session`에서는 `{fx_rate: snapshot_fx_rate}`만 저장됩니다. daily 모드에서 real-time scanner가 없으므로 의도된 동작으로 보이나, 두 경로의 selection_context 구조가 다르다는 점은 감사 문서나 주석에 명시하면 좋습니다. **`_extract_fx_rate_from_sources` 키 탐색 순서** 7개 키(`frst_bltn_exrt`, `bass_exrt`, `ovrs_exrt` 등)가 API 출처 주석 없이 hardcoded되어 있습니다. best-effort 방식이라 안전하지만, 브로커 API 업데이트 시 유지보수가 어려울 수 있습니다. 블로킹 사항은 아닙니다.
agentson added 1 commit 2026-03-02 02:44:49 +09:00
docs/main: clarify fx context behavior and rate-key provenance
Some checks failed
Gitea CI / test (push) Failing after 5s
Gitea CI / test (pull_request) Successful in 34s
920630e30e
Author
Collaborator

추가 리뷰 (Claude Code)

이전 소견 반영 현황

항목 상태
run_daily_session BUY 경로 selection_context 구조 차이 명시 반영
_extract_fx_rate_from_sources 키 탐색 출처 주석 추가 반영

판정: LGTM

두 소견이 모두 반영되었으며, 추가 지적 사항 없습니다.

  • _extract_fx_rate_from_sources 주석이 키 목록의 존재 이유와 단일 수정 지점임을 명확히 설명합니다.
  • run_daily_session BUY/SELL 경로에 scanner 컨텍스트 없이 FX 스냅샷만 기록한다는 의도가 주석과 감사 문서 모두에 반영되었습니다.
## 추가 리뷰 (Claude Code) ### 이전 소견 반영 현황 | 항목 | 상태 | |------|------| | `run_daily_session` BUY 경로 selection_context 구조 차이 명시 | ✅ 반영 | | `_extract_fx_rate_from_sources` 키 탐색 출처 주석 추가 | ✅ 반영 | ### 판정: ✅ LGTM 두 소견이 모두 반영되었으며, 추가 지적 사항 없습니다. - `_extract_fx_rate_from_sources` 주석이 키 목록의 존재 이유와 단일 수정 지점임을 명확히 설명합니다. - `run_daily_session` BUY/SELL 경로에 scanner 컨텍스트 없이 FX 스냅샷만 기록한다는 의도가 주석과 감사 문서 모두에 반영되었습니다.
agentson added 1 commit 2026-03-02 02:50:09 +09:00
docs: bump requirements registry metadata for push governance sync
All checks were successful
Gitea CI / test (push) Successful in 32s
Gitea CI / test (pull_request) Successful in 32s
589cc42e00
jihoson merged commit f7e242d147 into feature/v3-session-policy-stream 2026-03-02 02:53:04 +09:00
jihoson deleted branch feature/issue-370-fx-pnl-runtime-split 2026-03-02 02:53:04 +09:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jihoson/The-Ouroboros#383