[BE-06] TradingCostModel·PositionSizer
작업 내용 (설계 의도)
변경 사항
거래비용과 포지션 사이징을 값 객체로 만든다. 둘 다 순수 계산이라 외부 의존이 없다.
TradingCostModel—ml/app/cost_model.py의CostModel과 동일 공식을 Kotlin으로 재구현한다. 매수는 슬리피지로 체결가가 오르고 수수료가 가산되며, 매도는 체결가가 내리고 수수료+거래세가 차감된다. 근거: ADR-004.PositionSizer—sizeFor(capital, tier, marketPrice)→ 매수 주수. 1주 가격이 종목당 상한을 넘으면 0을 반환한다(PRD FR-36). 100만원·T1 기준 KRX 117종목 중 63종목이 여기 해당한다.
진짜 위험은 코드 중복이 아니라 파라미터 드리프트다. 수수료율·거래세율·슬리피지율 3개를 설정으로 단일화하고, ml과 동일 입력·동일 출력을 검증하는 교차 테스트(ml/tests/test_cost_model_parity.py)를 함께 만든다.
의존
- BE-01 (도메인 계약 —
CostModelParityFixture소비)
다이어그램
처리 흐름
해당 없음 — 순수 함수 계산이며 협력 객체 간 흐름이 없다.
클래스 의존
flowchart LR Sizer[PositionSizer] --> Tier[RiskTier] Cost[TradingCostModel] --> Fill[FillPrice 값객체] Parity[교차검증 테스트] --> Cost Parity --> Py[ml/app/cost_model.py]
테스트 케이스
- 매수 시 실효단가가 의도가보다 높다(슬리피지 + 수수료 가산).
- 매도 시 실효단가가 의도가보다 낮다(슬리피지 + 수수료 + 거래세 차감).
- 수량 0이면 비용이 0으로 산출된다(경계값).
ml/app/cost_model.py와 동일 입력에서 동일 출력을 낸다(교차 검증, 공통 픽스처 사용).- 자본 100만원·T1(10%)·주가 9만원이면 1주를 산출한다.
- 자본 100만원·T1(10%)·주가 26만원이면 0주를 반환한다(1주 미달 제외).
- 자본 100만원·T3(20%)·주가 19만원이면 1주를 산출한다(단계별 차이).