Files
trex-core/docs/srs/Exception/req-095_fill-price-zero-backfill-guard.md
T
genichinandClaude Opus 4.8 f1b649cf2a feat(execution): 체결가 0/None 시 지정가 백필 가드 + WARN 로깅 (dcy-032/BAT-048)
REQ-095(슬롯 평단·원장 price 지정가 백필, 0 오염 방지) + REQ-096(백필/미해결 WARN 로깅) 구현.
지정가 부재 시 skip+강WARN. application 단일화(_resolve_fill_price), wire/LedgerTrade 스키마 불변.
575 passed/0 fail, opus QC PASS. REQ-097 알람=스파이크 산출물만(impl 후속).

- _resolve_fill_price 헬퍼 추가: avg_price 검증, limit_price 백필, 미해결 WARN
- _on_filled/_on_partial_cancel 통합: 백필 적용, 슬롯/원장 일관성
- _record_ledger 시그니처: resolved_price 파라미터 (backward compat)
- test_execution_fill_price_backfill.py: 21 시나리오 (avg=None/0, limit=있음/없음 등)
- docs: dcy-032, req-095/096/097, bat-048 설계/검증

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-21 13:34:31 +09:00

6.0 KiB

req-095: 체결가 0/None 지정가 백필 가드 (슬롯 평단 + 원장 price)

  • Status: Approved
  • Type: Exception
  • Priority: High
  • Owner: trex-core-dev

Intent

  • KIS 체결조회가 체결수량은 보고하면서 평균체결가(avg)를 None 또는 0으로 반환하는 순간 스냅샷이 발생할 수 있다. 현재 코드는 이 케이스를 무경고로 통과시켜 슬롯 평단(slot.avg_price)과 원장 cost basis(_record_ledger price)가 동시에 0으로 영구 오염된다. 완전체결 시 clear_dispatch로 재폴링이 없어 0이 영구화된다.
  • 본 REQ는 체결(완전·부분) 처리에서 브로커 평균체결가가 None 또는 ≤0이면 주문 지정가(limit_price)로 백필해, 슬롯 평단과 원장 price가 0으로 저장되지 않도록 무결성 가드를 추가한다.
  • 이 변경은 wire 계약(slots RPC 스키마) 변경 없이 값 정정만 수행하며, 정상 평균가 수신 경로(happy path)에 영향을 주지 않는다.

Requirement

  • 체결(완전 체결 및 부분 취소 후 체결) 처리 시, 브로커가 제공한 fs.avg_price가 None 또는 ≤0인 경우, 슬롯의 avg_price 계산(_on_filled, _on_partial_cancel)에 사용하는 fill_price를 주문 지정가(slot.limit_price 또는 동등한 주문 컨텍스트의 지정가)로 대체(백필)해야 한다.
  • 동일 조건에서 _record_ledger의 price 결정도 동일한 백필 가격을 사용해야 하며, price=0인 원장 레코드가 생성되어서는 안 된다.
  • 백필 결정 지점(adapter vs application)과 지정가마저 부재/≤0인 경우의 최종 폴백 정책은 design 단계에서 확정한다(아래 Notes 참조).

Acceptance Criteria

  1. Given fs.avg_price가 None인 체결 이벤트와 slot.limit_price > 0인 슬롯, When _on_filled의 평단 계산이 실행될 때, Then fill_price로 slot.limit_price가 사용되고 slot.avg_price에 지정가 기반 가중평균이 저장된다(0 저장 없음).
  2. Given fs.avg_price가 0.0인 체결 이벤트와 slot.limit_price > 0인 슬롯, When _on_partial_cancel의 평단 계산이 실행될 때, Then fill_price로 slot.limit_price가 사용되고 slot.avg_price가 0이 아닌 값으로 저장된다.
  3. Given fs.avg_price가 None인 체결 이벤트, When _record_ledger의 price 결정이 실행될 때, Then LedgerWorkItem.price로 0.0이 아닌 백필 지정가(≥0 초과)가 기록된다.
  4. Given fs.avg_price가 정상 양수인 체결 이벤트(happy path), When _on_filled/_on_partial_cancel/_record_ledger가 실행될 때, Then 기존과 동일하게 fs.avg_price가 사용되며 백필 분기가 개입하지 않는다(회귀 없음).
  5. Given wire 계약 관점(slots RPC 응답 스키마), When 백필이 발생할 때, Then RPC 메시지 구조·필드 집합이 변경되지 않는다(NFR-1: 값 정정만, 계약 불변).
  6. Given slot.limit_price가 None 또는 ≤0인 극단 케이스(지정가마저 부재), When 백필 경로가 진입될 때, Then 체결 처리를 skip(슬롯 전이·원장 기록 미수행)하고 slot_id·symbol·broker_order_id·avg_price·limit_price·reason=fill_price_unresolvable를 포함한 강 WARN 로그를 발행한다(0 저장 0건, 무경고 통과 0건). 슬롯은 PENDING 상태로 남아 watchdog/stale_pending 경보가 운영자 개입을 유도한다. [design BAT-048 KD-2 확정, 팀장 승인 2026-06-21]

Impacted Area

  • Docs: docs/runtime-flows.md — 체결 처리 흐름에 백필 분기 추가 필요 (implementation 후 갱신)
  • Modules:
    • trex_core/application/execution.py — _on_filled(:242-251), _on_partial_cancel(:305-314), _record_ledger(:424) 의 fill_price/price 결정 로직
    • trex_core/adapters/broker/kis.py — :209,219,232,238,243 평균가 None/0 표면화 지점 (백필 결정을 adapter에서 할지 application에서 할지는 design 확정 대상)
  • Tests:
    • tests/application/test_execution.py (또는 동등 경로) — avg_price=None, avg_price=0, happy path 각각 단위 테스트
    • tests/integration/ — 체결→원장 기록 통합 경로 회귀 테스트

Notes

  • design 확정 완료 (BAT-048 KD-1/KD-2, 팀장 승인 2026-06-21):
    • 백필 결정 지점: application 레이어 단일화 — application/execution.py에 _resolve_fill_price 헬퍼 신설. BrokerPort.poll_fill/adapter/paper 불변, dcy-021 reconcile 경로 자동 일관성(Discovery R-2 해소).
    • 지정가마저 부재/≤0일 때 폴백: skip + 강 WARN(AC-6 반영). 재폴링은 완전체결 교착, 현재가 조회는 포트 계약 변경이라 기각(Discovery OQ-2 해소).
  • AC-6 구체화 완료(위 design 확정 반영).
  • NFR-2(happy path 무영향): AC-4로 흡수. NFR-3(백필 추적 가능): REQ-096 WARN 로깅으로 달성.
  • Discovery 가정 A-1: orb 매수는 지정가 주문이므로 대다수 케이스에서 slot.limit_price가 존재한다.
  • 원장 price=0 방지는 REQ-018(체결→원장 기록)의 무결성 연장이며, 원장 skip 가드(portfolio_id 부재, execution_id 부재)는 본 REQ와 독립적으로 유지된다.
  • Discovery: dcy-032_20260621_fill-missing-price-cost-basis-backfill.md (FR-1, FR-2)

Change Log

CHG-20260621-01

  • Date: 2026-06-21
  • Author: trex-core-dev

Change Summary

  • 최초 생성 (draft-req dcy-032)

Intent

  • KIS 체결가 0/None 무경고 오염 방지를 위한 지정가 백필 가드 신규 요구사항 정의

Acceptance Criteria Delta

  • Added:
    • AC-1~6 신규 정의
  • Updated: 없음
  • Removed: 없음

Impacted Area Delta

  • Docs: docs/runtime-flows.md (implementation 후 갱신)
  • Modules: trex_core/application/execution.py, trex_core/adapters/broker/kis.py
  • Tests: tests/application/test_execution.py, tests/integration/

Delivery Trace Delta

  • Batches: 미정 (suggest-batch-reqs 이후 편성)
  • Releases: 미정

Revalidation Impact

  • Reverification Needed: no (최초 생성)
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: design 확정 후 AC-6 구체화 필요