dcy-026 confirm-discovery + REQ-018 change-req(CHG-20260612-01)→구현→ confirm-req-implemented(CHG-20260612-02) 전체 delivery. - broker_port.py: calculate_tax(side, amount) 신규 + fee/tax 율 env 상수화 (TREX_KIS_FEE_BPS=1.5, TREX_KRX_TAX_SELL_BPS=20.0). 매도 0.2%/매수 0. - paper.py / kis.py: tax=0.0 하드코딩 3곳 제거 → 정책 함수 호출. KIS daily-ccld 응답에 fee/tax 필드 부재 → 정책 폴백(향후 정본 우선 훅). - runtime-flows.md: 체결→ledger fee/tax 산출 흐름 갱신. - tests: fee/tax 정책 단위 + issue #24 4건 회귀(fee+tax=1,376.9원). 429 passed (+6), ruff clean. REQ-018 Approved→Implemented, BAT-038 release-candidate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
18 KiB
18 KiB
req-018: 체결→원장 기록 (집행 루프 fill hook)
- Status: Implemented
- Type: Integration
- Priority: High
- Owner: project maintainers
Intent
- 코어 집행 루프가 체결(매수/매도) 시 해당 거래를 portfolio-hub 원장에 기록하도록, fill 전이 경로에 ledger 기록 hook 을 더하고 체결 데이터(execution_id/fee)를 브로커 계약으로 운반한다.
Requirement
- 집행 루프가 매수 체결(
pending_buy→holding)·매도 체결(pending_sell→closed) 시 LedgerPort 로 거래를 기록한다. ledger path 의asset_id는 슬롯portfolio_id(= asset_id)를 직접 사용하고 side/qty/price/execution_id/fee/tax/executed_at 을 함께 보낸다. FillStatus(broker_port) 가execution_id,fee,tax를 운반하도록 계약을 확장한다.execution_id는 결정적으로 합성한다(KIS:kis-daily-ccld:{ord_dt}:{ord_gno_brno}:{odno}:{tot_ccld_qty}, paper:paper:{broker_order_id}:{filled_qty}).fee는calculate_fee(side, amount)(매수·매도 공통 수수료율),tax는calculate_tax(side, amount)(매도 정책 증권거래세율, 매수 0)로 계산한다. 수수료율·세율은 단일 정책 지점에서 env(TREX_KIS_FEE_BPS=1.5,TREX_KRX_TAX_SELL_BPS=20.0)로 관리하고 paper·KIS 어댑터가 동일 정책을 사용한다(tax=0.0하드코딩 금지). KIS 어댑터는 브로커 체결 응답에 수수료/세금 필드가 있으면 그 값을 정본으로 사용하고 없을 때만 정책 폴백한다. (dcy-026)- 원장 기록 주체는 코어 집행 경로 단일로 한정한다(전략/도메인은 원장에 접근하지 않는다).
Acceptance Criteria
- Given idle 슬롯에 매수 intent → 체결, When 집행 루프 fill 전이, Then 슬롯이 holding 으로 전이되고 원장에 buy 거래 1건이 기록된다(asset_id = 슬롯 portfolio_id).
- Given holding 슬롯에 매도 intent → 체결, When 집행 루프 fill 전이, Then 슬롯이 closed 로 전이되고 원장에 sell 거래 1건이 기록된다.
- Given 체결된 주문, When fill 을 읽음, Then
FillStatus가 결정적execution_id, 계산된fee, 계산된tax(매도 정책 세율, 매수 0)를 운반한다. - Given 슬롯에
portfolio_id가 없는 체결, When fill 전이, Then 원장 기록을 건너뛰거나(또는 정의된 정책으로 처리) 슬롯 전이 자체는 정상 수행된다. - Given 전략/도메인 코드, When 점검, Then 원장 기록은 코어 집행 경로에서만 발생한다(단일 기록 주체). (NFR-3)
- Given 매도 체결(amount=price×qty), When fill 을 읽음, Then
tax=amount × TREX_KRX_TAX_SELL_BPS / 10_000(기본 0.2%)로 계산되고, 매수 체결의tax는 0 이다. - Given 수수료/세율 정책, When paper·KIS 어댑터로 동일
(side, amount)입력, Then 동일 정책 결과를 산출한다(단일 정책 지점calculate_fee/calculate_tax, env 설정).tax=0.0하드코딩이 코드에 남지 않는다. - Given KIS 체결 응답에 수수료/세금 필드 존재, When fill 파싱, Then 그 값을 정본으로 사용하고, 필드 부재 시에만 정책 추정값으로 폴백한다.
- Given issue #24 4건 체결(BUY 291,500 / SELL 301,000 / BUY 295,000 / SELL 298,500, qty=1), When fee/tax 계산, Then
fee+tax합계가 1,376.9원(fee 177.9 + tax 1,199)에 수렴한다.
Impacted Area
- Docs: docs/runtime-flows.md(체결→원장 기록 + fee/tax 산출 흐름), docs/interface-contract.md(FillStatus 확장) — REQ-020 에서 정합
- Modules:
trex_core/application/execution.py(fill 전이에 ledger 기록 단계),trex_core/application/broker_port.py(FillStatus.execution_id/fee/tax +calculate_fee/calculate_tax단일 정책 지점 + env 세율 상수),trex_core/adapters/broker/{paper,kis}.py(execution_id 합성 + fee/tax 계산, KIS 응답 정본 우선) - Tests: stub 원장으로 매수/매도 체결 시 buy/sell 1건 + 슬롯 전이, FillStatus execution_id/fee/tax 운반, portfolio_id 부재 처리, 매도 세율 + issue #24 4건 회귀(1,376.9원), paper·KIS 동일 정책 + KIS 응답 우선
Notes
- 출처: dcy-004 FR-2, OQ-1(asset_id == portfolio_id, orbit 근거), OQ-3(execution_id/fee/tax 출처), NFR-3.
- OQ-1: 슬롯은 이미 buy intent 가
portfolio_id를 공급해 캐시하므로 추가 매핑/조회 없이 path param 으로 사용한다. portfolio_id부재 시 기록 skip vs 거부 정책은 구현 시 확정(AC-4 는 둘 다 허용하되 슬롯 전이 일관성을 요구).- 멱등/무유실/재시도(correlation_id, outbox)는 REQ-019 에서 다룬다. 본 REQ 는 기록 호출 경로와 데이터 운반에 한정한다.
- (dcy-026/CHG-20260612-01) 매도 증권거래세 정책 확정: 매도세 0.2%(
TREX_KRX_TAX_SELL_BPS=20.0), 수수료 0.015%(TREX_KIS_FEE_BPS=1.5, 매수·매도 공통). 변수명에KIS/KRX도메인 라벨이 있으나 단일 정책 지점으로 paper·KIS 가 동일 공유. dcy-004 OQ-3 "정밀 세금 모델" 후속 해소. - 과거 잘못 저장된 ledger 행 소급 보정은 Out of Scope(dcy-026 OQ-3). 배포 후 신규 체결부터 정확값 저장.
- REQ-011(BrokerPort 추상화)는 본 변경 대상 아님: fee/tax 는 REQ-018 의
FillStatus확장 +calculate_fee/calculate_tax정책 영역이며, REQ-011 의 포트 계약(submit/poll/cancel async 더블 + 도메인 순수성)은 영향받지 않음.
Change Log
CHG-20260604-01
- Date: 2026-06-04
- Author: Justin Ko
Change Summary
- dcy-004 FR-2 로부터 최초 생성(Proposed). OQ-1/OQ-3 결정 반영, NFR-3(단일 기록 주체) 흡수.
Intent
- 집행 루프 fill 전이에서 체결을 원장에 기록하는 경로와 FillStatus 확장(execution_id/fee)을 backlog 로 정규화.
Acceptance Criteria Delta
- Added:
- 매수/매도 체결 기록+전이, FillStatus execution_id/fee, portfolio_id 부재, 단일 기록 주체 5개 기준
- Updated:
- 없음
- Removed:
- 없음
Impacted Area Delta
- Docs:
- docs/runtime-flows.md, docs/interface-contract.md
- Modules:
- execution.py(ledger hook), broker_port.py(FillStatus), paper/kis 어댑터(execution_id/fee)
- Tests:
- 체결→기록 통합테스트, FillStatus 운반, portfolio_id 부재
Delivery Trace Delta
- Batches:
- none
- Releases:
- none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성
Validation Plan
- stub 원장으로 매수/매도 체결 lifecycle 통합테스트 + FillStatus 확장 테스트로 검증.
CHG-20260604-02
- Date: 2026-06-04
- Author: Justin Ko
Change Summary
- Status 변경: Proposed -> Approved. confirm-req 승인 게이트 통과.
Intent
- 집행 루프 fill 전이의 ledger 기록 hook 과 FillStatus 확장을 delivery input 으로 승인.
Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
Impacted Area Delta
- Docs:
- 없음
- Modules:
- 없음
- Tests:
- 없음
Delivery Trace Delta
- Batches:
- none
- Releases:
- none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Approved
- Follow-up Action: batch 편성
Validation Plan
- 기존 Acceptance Criteria 로 batch delivery 에서 검증.
CHG-20260604-03
- Date: 2026-06-04
- Author: Justin Ko
Change Summary
- Status 변경: Approved -> Implemented. BAT-006 release-candidate verification evidence 기반.
Intent
- 집행 루프 fill→ledger hook + FillStatus.execution_id/fee 확장 구현과 검증 evidence 확보 후 구현 완료 상태로 동기화.
Acceptance Criteria Delta
- Added/Updated/Removed: 없음
Impacted Area Delta
- Docs/Modules/Tests: 없음 (변경은 상태 전이만)
Delivery Trace Delta
- Batches:
- BAT-006 (release-candidate)
- Releases:
- none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계는 별도 진행
Validation Plan
- AC-1: tests/application/test_execution_ledger.py::test_buy_fill_enqueues_one_ledger_item_and_writer_records_it.
- AC-2: tests/application/test_execution_ledger.py::test_sell_fill_enqueues_sell_ledger_item.
- AC-3: 위 buy 테스트가 FillStatus.execution_id/fee/tax 운반 직접 검증.
- AC-4: tests/application/test_execution_ledger.py::test_portfolio_id_absent_skips_ledger_but_transitions_slot.
- AC-5: tests/domain/test_domain_import_sweep.py + grep 결과(trex_core/application/execution.py 단일 enqueue 지점).
CHG-20260608-01
- Date: 2026-06-08
- Author: Justin Ko
Change Summary
- (change-req, dcy-011/issue #11)
_record_ledger의 ledger skip 을 무성에서 가시화로 전환: portfolio_id/execution_id 누락 skip 시 WARN 로그 +ExecutionResult.ledger_skipped카운터 노출(슬롯 전이는 그대로). BAT-015 재구현·재검증 완료 → Implemented 유지.
Intent
- portfolio_id 없는 체결의 ledger silent skip(회계 누락)을 운영자가 탐지 가능하게(issue #11 제안 ②). OQ-4 결정으로 outbox 마커 행은 도입하지 않고 로그+메트릭만; 영구 탐지는 REQ-055 점검 쿼리에 위임.
Acceptance Criteria Delta
- Updated:
- AC-4: skip 시 무성 반환 → WARN 로그 + 카운터 가시화(두 skip 경로 모두).
Impacted Area Delta
- Modules:
trex_core/application/execution.py(_record_ledger로그 +_log추가) - Docs:
docs/runtime-flows.md - Tests: tests/application/test_execution_ledger.py::test_ledger_skip_emits_warning
Delivery Trace Delta
- Batches: BAT-015
- Releases: none
Revalidation Impact
- Reverification Needed: yes (BAT-015 에서 완료)
- Existing Implementation Invalidated: no (관측만 추가, 전이 동작 불변)
- Status Recommendation: Implemented (change-req → BAT-015 재검증)
- Follow-up Action: confirm-req-implemented(BAT-015).
Validation Plan
- BAT-015: ledger skip WARN 로그 단위(caplog) + 회귀.
CHG-20260608-02
- Date: 2026-06-08
- Author: Justin Ko
Change Summary
- (change-req, dcy-013/issue #9) 부분 체결 후 외부 취소 시 체결분(
ccld_qty)을 원장에 1회 기록한다._on_partial_cancel이_record_ledger(기존)를 재사용해 partial fill 의 execution_id/fee/qty 를 정확히 운반. BAT-017 재구현·재검증 완료 → Implemented 유지.
Intent
- 전량 체결만 다루던 원장 기록을 부분 체결+취소에도 확장해 체결분 누락/이중기록을 방지(정확 회계, OQ-1 A안).
Acceptance Criteria Delta
- Updated:
- AC-1/2 의 fill→원장 기록을 부분 체결 후 취소(체결분 1회)에도 적용.
Impacted Area Delta
- Modules:
trex_core/application/execution.py(_on_partial_cancel→_record_ledger재사용) - Tests: tests/application/test_execution_cancel.py::test_partial_fill_then_cancel_records_and_keeps_remainder
Delivery Trace Delta
- Batches: BAT-017
- Releases: none
Revalidation Impact
- Reverification Needed: yes (BAT-017 에서 완료)
- Existing Implementation Invalidated: no (기록 경로 재사용, 호출 지점만 확장)
- Status Recommendation: Implemented (change-req → BAT-017 재검증)
- Follow-up Action: confirm-req-implemented(BAT-017).
Validation Plan
- BAT-017: 부분 취소 시 sell 원장 1건(qty=체결분, price=체결가) 단위.
CHG-20260608-03
- Date: 2026-06-08
- Author: Justin Ko
Change Summary
- (change-req, dcy-015/issue #13) ledger 터미널 실패 가시화 확장:
delivery_failed(permanent/dead-letter)를WriterStats.delivery_failed카운터 + WARN 로그 + 구분 status 로 노출(dcy-011ledger_skipped가시화 패턴 정합). dead-letter 는 운영자 재처리 가능 상태이며find_ledger_gap_slots(REQ-055)·skip 가시화와 연계. BAT-019 재구현·재검증 완료 → Implemented 유지.
Intent
- ledger 가 끝내 기록되지 않는 실패(404 영속·dead-letter)가 무성 pending 으로 남지 않고 운영자에게 노출되도록(NFR-2 가시성).
Acceptance Criteria Delta
- Updated:
- 원장 미기록(터미널 delivery_failed) 시 WARN 로그 + 카운터 + 구분 status 가시화.
Impacted Area Delta
- Modules:
trex_core/application/ledger_outbox.py(WARN + WriterStats.delivery_failed) - Tests: tests/application/test_ledger_outbox_backoff.py::test_permanent_failure_emits_warning
Delivery Trace Delta
- Batches: BAT-019
- Releases: none
Revalidation Impact
- Reverification Needed: yes (BAT-019 에서 완료)
- Existing Implementation Invalidated: no (관측만 추가)
- Status Recommendation: Implemented (change-req → BAT-019 재검증)
- Follow-up Action: confirm-req-implemented(BAT-019).
Validation Plan
- BAT-019: delivery_failed WARN 로그(caplog) + 카운터 단위.
CHG-20260612-01
- Date: 2026-06-12
- Author: Justin Ko
Change Summary
- (change-req, dcy-026/issue #24) 매도 증권거래세 누락 정정.
FillStatus.tax가 매도 체결에 대해 정책 세율(증권거래세)로 계산되도록 계약을 정정한다. 기존tax 는 기본 0 으로 한다규정과tax=0.0하드코딩(paper/kis 어댑터)을 제거하고, 수수료율·세율을 단일 정책 지점(calculate_fee/calculate_tax)에서 env 설정으로 관리한다. KIS 어댑터는 브로커 응답 fee/tax 가 있으면 정본 우선, 없으면 정책 폴백. 기존tax=0전제 구현/검증 evidence 무효화 → Implemented → Approved 되돌림.
Intent
- 한국 주식 매도 증권거래세(약 0.2%)가 전 체결에서
tax=0.0으로 저장되어 실현 손익·일일 수익률이 과대 계산되던 운영 버그(issue #24, 2026-06-11 4건 체결 증거)를 닫는다.broker_port.py가 dcy-004 OQ-3 로 미뤄둔 "정밀 세금 모델"을 정식 정책으로 확정한다.
Acceptance Criteria Delta
- Updated:
- AC-3:
FillStatus가 결정적execution_id와 계산된fee(tax=0) 운반 →fee와 매도 정책 세율로 계산된tax(매수 tax=0) 운반.
- AC-3:
- Added:
- AC-6: 매도 체결의
tax는amount × TREX_KRX_TAX_SELL_BPS / 10_000(기본 20.0bps = 0.2%)로 계산되고, 매수 체결의tax는 0 이다. - AC-7: 수수료율·세율은 단일 정책 지점(
calculate_fee/calculate_tax)에서 env(TREX_KIS_FEE_BPS=1.5,TREX_KRX_TAX_SELL_BPS=20.0)로 관리되고 paper·KIS 어댑터가 동일 정책을 사용한다.tax=0.0하드코딩은 제거된다. - AC-8: KIS 어댑터는 브로커 체결 응답에 수수료/세금 필드가 있으면 그 값을 정본으로 사용하고, 없을 때만 정책 추정값으로 폴백한다.
- AC-9: issue #24 4건 체결(BUY 291,500 / SELL 301,000 / BUY 295,000 / SELL 298,500, qty=1) 재현 시
fee+tax합계가 §4 공식 기대값 1,376.9원(fee 177.9 + tax 1,199)에 수렴한다(회귀 테스트).
- AC-6: 매도 체결의
Impacted Area Delta
- Docs:
- docs/runtime-flows.md(체결→ledger fee/tax 산출·저장 흐름 갱신)
- Modules:
trex_core/application/broker_port.py(calculate_tax신규 + 세율 상수, env 로딩)trex_core/adapters/broker/paper.py(tax=0.0→calculate_tax(...))trex_core/adapters/broker/kis.py(tax=0.0→ 브로커 응답 파싱 + 정책 폴백)
- Tests:
- 매수/매도 fee·tax 단위 테스트 + issue #24 4건 회귀(1,376.9원) + KIS 응답 우선 경로 + paper·KIS 동일 정책 일치
Delivery Trace Delta
- Batches:
- BAT-038 (예정, dcy-026 fee/tax)
- Releases:
- none
Revalidation Impact
- Reverification Needed: yes (BAT-038 에서 매도 tax 계산·회귀 재검증)
- Existing Implementation Invalidated: yes (
tax=0전제 — AC-3 의 tax=0 evidence 및 paper/kistax=0.0하드코딩 무효) - Status Recommendation: Implemented → Approved (구현/검증 후 confirm-req-implemented 로 복귀)
- Follow-up Action: confirm-req → draft-batch(BAT-038) → 구현·검증 → confirm-req-implemented
Validation Plan
- BAT-038: 매수/매도 fee·tax 단위 테스트(매도 0.2% 세율, 매수 tax=0), issue #24 4건 회귀(
fee+tax=1,376.9원), KIS 응답 fee/tax 우선·폴백 경로, paper·KIS 동일 입력 동일 출력.pytest전체 회귀 +ruff checkclean.
CHG-20260612-02
- Date: 2026-06-12
- Author: Justin Ko
Change Summary
- Status 변경: Approved → Implemented (confirm-req-implemented, 근거 batch BAT-038 release-candidate).
Intent
- BAT-038 verification.md 의 acceptance mapping + evidence(429 passed / fee·tax 정책 단위 / issue #24 1,376.9원 회귀 /
tax=0.0하드코딩 제거 grep / runtime-flows 동기화)로 AC-1~9 충족 → 구현 완료 상태로 동기화.
Acceptance Criteria Delta
- Added/Updated/Removed: 없음 (상태 전이만)
Impacted Area Delta
- Docs/Modules/Tests: 없음 (상태 전이만)
Delivery Trace Delta
- Batches:
- BAT-038 (release-candidate)
- Releases:
- none (release 편성은 별도 진행)
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: draft-release 로 release 편성(BAT-038 포함)
Validation Plan
- BAT-038 verification evidence 재참조로 충분.
- AC-3/6:
test_paper_sell_fill_carries_policy_tax,test_calculate_tax_sell_only,test_paper_buy_fill_has_zero_tax. - AC-7:
test_calculate_fee_same_rate_buy_and_sell,test_fee_and_tax_zero_for_nonpositive_amount,tax=0.0grep 0건. - AC-8: design Key Decision 3(KIS daily-ccld fee/tax 필드 부재 → 정책 폴백) + 코드 리뷰.
- AC-9:
test_issue_24_four_fill_regression(1,376.9원). - AC-1/2/4/5: BAT-006 evidence 유효 + 전체 회귀 429 passed.
- AC-3/6: