# BAT-031 Implementation - Status: done - Batch: BAT-031 - 일자: 2026-06-10 ## 구현 요약 design.md D1~D4 그대로 구현. 수량 정본=브로커 잔고 재동기화로 "주문 수량 vs 보유 수량" 충돌을 별도 필드 없이 해소. - **M1 (REQ-057)**: `state.py` `_BASE_TRANSITIONS` 에 `(HOLDING, PENDING_BUY)` 추가 → 13 전이(증액). - **M2 (REQ-066/062)**: `service.py` `_apply_transition_fields` — PENDING_SELL 진입 시 `qty = caller as-is`(None=전량 sentinel, 값=부분 주문 qty). 증액 pending(HOLDING→PENDING_BUY)은 generic 분기가 avg_price 보존(caller None)·qty=주문으로 처리(별도 분기 불요). - **M3 (REQ-061)**: `intents.py` — `_admit_buy` 가 HOLDING 슬롯 매수를 **증액**으로 검출(M 캡 미적용, `position_increase` reason), PENDING_* 만 `already_active`. `SellIntent.qty`(부분) 추가, `_admit_sell` 가 qty 를 transit 에 전달. `messaging_handlers` sell 파서에 `qty` 추출. - **M4 (REQ-062/066)**: `execution.py` — `_balance_map()` 헬퍼. dispatch 매도 `qty = 브로커잔고 if slot.qty is None else min(int(slot.qty), 브로커잔고)`(0이면 skip+WARN). `_on_filled`: 매수 체결 → 보유=브로커 잔고·avg 가중평균; 매도 체결 → 브로커 잔고>0 `pending_sell→holding`(cost basis) / 0 `→inactive`. `_on_partial_cancel` 도 브로커 정본 resync. `_rollback`: 매수 거부 시 브로커>0 `→holding`(증액 실패, 기존 보유 유지) / 0 `→inactive`. - **M5 (REQ-067)**: data-model/runtime-flows/interface-contract/project-structure 4문서 사이징 정합. ## 변경 내역 (Changed Files) - trex_core/domain/slot/state.py — holding→pending_buy 전이 - trex_core/domain/slot/service.py — PENDING_SELL qty sentinel - trex_core/application/intents.py — 증액 admission, SellIntent.qty, partial sell - trex_core/application/execution.py — _balance_map, 부분/전량 매도 dispatch, 매수 체결 가중평균, 브로커 정본 resync, 증액 롤백 - trex_core/application/messaging_handlers.py — sell qty 파싱 - docs: data-model/runtime-flows/interface-contract/project-structure (REQ-067) - tests: test_state(13 전이), test_service(TestPositionSizing 3), test_execution(전량/부분 매도·증액·capacity 5신규), test_execution_cancel(브로커 정본 잔량) ## 테스트 - 단위 전체: **378 passed** (45 skipped), ruff clean - 통합(PG+RabbitMQ): **422 passed, 1 skipped**(KIS sandbox, 환경 무관) ## 검증 실행 (run-the-app, 사이징 e2e) 라이브 trex_core(reset 후) + 실 RabbitMQ + paper + instance=test, M=5: 1. 초기 매수 qty=10 @1000 → holding 10 @1000 2. **증액 +5 @1200**(holding 슬롯 매수, admitted) → holding **15 @1066.6667**(가중평균) 3. **부분 매도 qty=6** → holding **9 @1066.6667**(cost basis 유지) 4. **전량 매도**(qty 미지정) → **inactive**(qty None) - 데몬 로그 ERROR/Traceback 0. messaging sell qty 갭은 e2e 에서 발견·수정(부분 매도가 전량으로 가던 버그) 후 재검증 green. ## Remaining Risks / Blockers - 전략 모듈(trex-orb) 사이징 intent 발행 전환 필요 — 기존 buy/sell 와 병존(additive)이라 무중단. - 미체결 pending 고착 처분은 본 배치 범위 밖(issue #21 별도 Discovery).