Files
trex-core/docs/batches/bat-016_20260608_sell-pricing-limit-price-rename/implementation.md
T
genichinandClaude Opus 4.8 cc28e1fba5 fix(execution): dcy-012 매도 가격 버그 정정 — slot entry_price→limit_price rename (BAT-016)
매도(sell) 주문이 현재가가 아닌 매수가(entry_price) 지정가로 나가던 버그(issue #10)
정정. 슬롯의 매수 전용 entry_price 를 side 무관 "현재 pending 주문 지정가"
limit_price 로 내부 rename 하고, pending 이탈(→holding/→closed) 시 clear 해
매수 지정가가 매도로 누수되는 경로를 구조적으로 제거.

거버넌스: 전부 change-req (신규 REQ 없음, dcy-012 OQ-3).
- REQ-002: Slot entry_price→limit_price rename + clear-on-exit 생애주기
- REQ-006: daily_slot 컬럼 rename 마이그레이션 006 (idempotent) + persistence 매핑
- REQ-013: _dispatch 가 slot.limit_price 단일 필드로 가격/주문유형 결정
- REQ-007: SellIntent/sell payload optional limit_price + _admit_sell 운반
- REQ-036: SlotService.sell optional 가격 → 자율 매도(safety-sell/kill-switch) 시장가
- REQ-003: 컬럼 계약/드리프트 가드 limit_price 반영
- REQ-015: runtime-flows/interface-contract/data-model 정합

매도 정책(OQ-1 하이브리드): 가격 지정→지정가("00"), 미지정→시장가("01").
자율 매도는 가격 미전달 → 항상 시장가 (손절 미체결 pending_sell 갇힘 방지, issue #9 연계).

검증: 단위 286 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 318 passed, ruff clean.
신규 test_sell_pricing(recording broker)로 지정가 매수 슬롯의 매도가 매수가
재사용 안 함을 직접 검증. BAT-016 release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:41:46 +09:00

3.7 KiB

BAT-016 Implementation

  • Status: completed
  • Batch: BAT-016

구현 요약

  • dcy-012 매도 가격 버그(issue #10)를 슬롯 entry_price→limit_price rename + clear-on-exit 생애주기 + dispatch 단일 필드 결정으로 정정. 전부 change-req(신규 REQ 없음).

변경 내역

REQ-002 — 슬롯 도메인 rename + 생애주기

  • trex_core/domain/slot/models.py: Slot.entry_price → limit_price(주석: side 무관 pending 주문 지정가, clear-on-exit); EXPECTED_SLOT_FIELDS 의 entry_price → limit_price.
  • trex_core/domain/slot/service.py:
    • transit_slot/_apply_transition_fields 파라미터 entry_price → limit_price.
    • IDLE reset 분기: entry_price=None → limit_price=None.
    • generic 경로: to_state ∈ {PENDING_BUY, PENDING_SELL} 면 set(입력 or 유지), 아니면(HOLDING/CLOSED) new_limit_price=None clear.
    • SlotService.sell(..., *, limit_price=None) 추가 → transit_slot 에 전달.

REQ-013 — dispatch 단일 필드

  • trex_core/application/execution.py::_dispatch: limit = int(slot.limit_price) if slot.limit_price else None(side 분기/entry_price 재사용 제거). order_type 은 limit 유무로 "00"/"01".

REQ-007 — sell intent 가격

  • trex_core/application/intents.py: SellIntent.limit_price: Optional[float] = None; _admit_sell → transit_slot(..., limit_price=intent.limit_price); _admit_buy → limit_price=intent.entry_price(BuyIntent.entry_price 외부 필드 유지).
  • trex_core/application/messaging_handlers.py: sell 핸들러 limit_price=_opt_float(body.get("limit_price")); buy payload entry_price 유지; _slot_to_dict 외부 키 "entry_price" 유지하되 s.limit_price 매핑(NFR-3).

REQ-036 — 자동 매도 시장가

  • SlotService.sell optional limit_price(default None) → safety-sell/kill-switch 자율 매도는 가격 미전달 → 시장가.

REQ-006 — 마이그레이션 + persistence

  • trex_core/adapters/persistence/sql/006_rename_entry_price_to_limit_price.sql(신규): idempotent DO-block rename(컬럼 존재 && 신컬럼 부재 시에만). 순수 rename → 데이터 보존.
  • trex_core/adapters/persistence/postgresql.py: _SLOT_COLUMNS/update_slot SQL+바인딩/_row_to_slot 의 entry_price → limit_price.

REQ-003 — 컬럼 계약 가드

  • EXPECTED_SLOT_FIELDS rename 으로 test_contract.py/test_migration_and_drift.py 자동 반영(상수 참조). PG 게이트에서 실 컬럼 limit_price 검증.

REQ-015 — baseline 문서

  • docs/runtime-flows.md: dispatch 가격 결정(slot.limit_price 단일 필드) + limit_price 생애주기 set/clear. Last Updated → BAT-016.
  • docs/interface-contract.md: sell payload optional limit_price + ORD_DVSN 매핑. Last Updated → BAT-016.
  • docs/data-model.md: 슬롯 limit_price 컬럼 의미/생애주기. Last Updated → BAT-016.

테스트

  • 신규 tests/application/test_sell_pricing.py(recording paper broker): 4건 — (a) 지정가 매수+시장가 매도(entry_price 미사용), (b) 지정가 매수+지정가 매도, (c) SlotService.sell 시장가+closed, (d) 시장가 매수 매도 회귀.
  • tests/domain/slot/test_service.py: PENDING_BUY→HOLDING 시 limit_price is None 단언 추가; 두 →HOLDING 전이의 obsolete entry_price= 인자 제거.

검증 실행

  • 단위: TREX_BROKER=paper .venv/bin/python -m pytest -q → 286 passed / 32 skipped(::test_sandbox_token_and_submit deselect — LIVE .env 환경 의존, 본 batch 무관).
  • 인프라 게이트: TREX_POSTGRESQL_TEST_DSN=...(trex_core_test) TREX_RABBITMQ_TEST_URL=... pytest -q → 318 passed(006 rename 마이그레이션 적용 + 컬럼 계약 limit_price + 마이그레이션 idempotency 포함).
  • ruff check trex_core tests → All checks passed.