dcy-007(core 자율 안전 매도) 전체 delivery. BAT-010 기반 인프라가 미커밋 상태였고 BAT-011 트리거 레이어와 공유 파일에서 섞여 있어 한 커밋으로 묶음. BAT-010 (REQ-034/035/036/041, release-candidate): - WatchdogStore(application/watchdog.py) + snapshot RPC 워치독 갱신 - Slot stop_loss_price/take_profit_price 필드 + 004_add_price_thresholds.sql - SlotService.sell() 자율 매도 내부 경로 + idempotency - SafetySellConfig env 5종 파싱 BAT-011 (REQ-037/038/039/040/042, release-candidate): - SafetySellService(application/safety_sell.py): forced_close 만기 / stop-loss· take-profit KIS polling / 장 마감 강제 청산 + trex-safety-sell 7번째 스레드 - BrokerPort.get_current_price + KIS inquire-price(TTTC8397R/VTTC8397R, stck_prpr) + paper stub - SlotService.update_thresholds() + intent RPC update_thresholds 액션 (부분 갱신/null 해제, 워치독 last_seen_at 리셋) - baseline 3문서 정합(interface-contract/runtime-flows/project-structure) 거버넌스: REQ-034~042 Implemented 동기화, BAT-010/011 release-candidate, dcy-007 discovery 포함. 검증: 신규 38 테스트 green, 단위 236 passed/23 skipped, 인프라 게이트(PG+RabbitMQ) 259 passed(마이그레이션 001~004 round-trip 포함), ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.7 KiB
6.7 KiB
BAT-011 Planning
- Status: confirmed
- Batch: BAT-011
- Profile: standard
Included REQ
- REQ-037 (Integration):
forced_close_at만기 자동 매도 루프 —holding+ 워치독 만료 +forced_close_at <= now(KST)슬롯에SlotService.sell().TREX_FORCED_CLOSE_CHECK_INTERVAL주기. KIS 호출 없음(DB + in-memory watchdog 비교). - REQ-038 (Integration): stop-loss·take-profit KIS 현재가 polling + 트리거 —
TTTC8397R(실전)/VTTC8397R(모의)stck_prpr기준,현재가 <= stop_loss_price(손절)/현재가 >= take_profit_price(익절) 시sell().TREX_STOP_LOSS_POLL_INTERVAL주기. 쿼터 상한N × (3600/interval)경고. - REQ-039 (Integration): 장 마감 강제 청산 —
TREX_MARKET_CLOSE_LIQUIDATION_TIME(HH:MM KST) 도래 시 워치독 무관 전체holding청산. 거래일 1회 발동 가드(last_liquidation_date). - REQ-040 (Interface):
update_thresholdsintent RPC 액션 —{action, slot_id, stop_loss_price?, take_profit_price?, forced_close_at?}부분 갱신 + 워치독last_seen_at리셋 + holding-only.reply_to시{status: updated|ignored, slot_id}응답. - REQ-042 (Documentation): baseline 3문서 정합 —
interface-contract.md(update_thresholds + price 필드),runtime-flows.md(워치독 갱신·forced_close·가격 체크·장 마감 흐름 +:114A-5 주석 갱신),project-structure.md(trex-safety-sell스레드 + env 5종 + KIS polling/watchdog 모듈).
Delivery Plan
- REQ-038 KIS 현재가 polling 어댑터:
get_current_price(symbol)(TTTC8397R/VTTC8397R,stck_prpr파싱, 실전/모의 분기). paper 환경 stub. 어댑터 단위 테스트. - REQ-037 + REQ-038 + REQ-039 통합 worker:
daemon.py에trex-safety-sell스레드 +_safety_sell_loop()추가. 루프 1 tick에서 (a) forced_close_at 만기, (b) stop-loss/take-profit 가격 체크, (c) 장 마감 청산 시각 평가를 순차 수행. 각 경로SlotService.sell()호출. mock 기반 단위 테스트(만기/손절/익절/미충족/워치독 보호/idempotency/장 마감 전체·중복가드). - REQ-040
update_thresholds:SlotService.update_thresholds(...)+make_intent_rpc_handleraction 라우팅 +last_seen_at리셋 + holding-only 응답. handler 단위 테스트(부분 갱신/null 해제/non-holding ignored/last_seen_at 리셋). - REQ-039 config:
TREX_MARKET_CLOSE_LIQUIDATION_TIME활용 확인(REQ-041에서 파싱 완료 — 본 batch는 소비). - REQ-042 baseline 문서 3종 정합 — 구현 완료 상태 반영.
- 전체 회귀 green + ruff lint clean + BAT-010 잔여 R-2(실 PG 마이그레이션 round-trip) 검증.
Dependencies
- Internal:
- BAT-010/REQ-034:
WatchdogStore.is_expired()/in_grace_period()— 트리거 루프의 워치독 만료 판정 계약(read 측). - BAT-010/REQ-035:
stop_loss_price/take_profit_price도메인 필드 — 가격 체크 기준값. - BAT-010/REQ-036:
SlotService.sell(slot_id, actor, reason)— 모든 트리거의 매도 제출 경로. - BAT-010/REQ-041: safety-sell env vars 5종 파싱(
DaemonConfig) — 본 batch가 값을 소비. - BAT-007/REQ-022:
make_intent_rpc_handler—update_thresholdsaction 확장 대상. - BAT-004/REQ-012:
KISBroker(kis.py) — 현재가 polling 어댑터 추가/확장 대상.
- BAT-010/REQ-034:
- External:
- KIS Open API 현재가 시세 endpoint(
TTTC8397R/VTTC8397R). 실 호출은 운영(broker=kis) 환경; 테스트는 mock/stub.
- KIS Open API 현재가 시세 endpoint(
Design Gate
- Design Required Before Implementation: yes
- Reason: 본 batch는 (a) **신규 daemon worker 스레드(
trex-safety-sell)**를 추가하고 BAT-010의 WatchdogStore를 새로운 스레드에서 read하므로 동시성 계약(GIL 의존 read vs. snapshot RPC handler write)을 명시해야 한다. (b) 신규 외부 I/O(KIS 현재가 polling) 어댑터의 배치(kis.py확장 vs. 신규kis_price.py), 실전/모의 endpoint 분기, paper stub 전략, 쿼터 상한 산정을 설계에서 확정해야 한다. (c) forced_close·가격 체크·장 마감을 단일 통합 루프로 묶는 구조와 장 마감 1회 발동 가드(last_liquidation_date) 상태 모델을 설계에서 고정해야 구현·검증 drift가 없다. →design.md를 동일 턴에 scaffold한다.
Milestones
- M1 — REQ-038 KIS 현재가 polling 어댑터 + 단위 테스트 green (실전/모의 분기,
stck_prpr파싱) - M2 —
trex-safety-sellworker + forced_close_at 만기 루프(REQ-037) + 단위 테스트 green - M3 — stop-loss·take-profit 가격 체크(REQ-038) worker 통합 + mock 단위 테스트 green(손절/익절/미충족/워치독 보호/쿼터 산정)
- M4 — 장 마감 강제 청산(REQ-039) + 거래일 1회 가드 + 단위 테스트 green
- M5 —
update_thresholdsRPC(REQ-040) + handler 단위 테스트 green - M6 — baseline 3문서 정합(REQ-042) + 전체 회귀 + ruff clean + BAT-010 R-2 검증
Risks
- R-1 (Medium): KIS 현재가 polling 쿼터 — 워치독 만료 슬롯 N개 × (3600/
TREX_STOP_LOSS_POLL_INTERVAL) 호출이 KIS 분당/일일 쿼터를 초과할 수 있음. 대응: REQ-038 AC-8 상한 산정 + 임계 초과 시 경고 로그. 폴링 대상은 "워치독 만료" 슬롯으로 한정해 평시 호출 최소화. - R-2 (Medium): WatchdogStore cross-thread read — safety-sell worker가 snapshot RPC handler thread의 write와 동시 접근. 대응: BAT-010 Key Decision 3(GIL 보장 단일 dict, lock 없음) 계약을 그대로 따르고 read-only 판정만 수행. 단위 테스트로 만료 판정 고정.
- R-3 (Medium): 장 마감 청산 발동 정밀도/중복 — worker 루프 주기에 의존하는 시각 평가 + 재시작 시 in-memory
last_liquidation_date초기화로 동일 거래일 재발동 위험. 대응: 발동 가드 + (필요 시) 발동 시각 경계 처리 설계에서 확정. - R-4 (Low): KIS 거부/네트워크 예외 시 루프 안정성 — polling 또는 sell 제출 중 예외가 worker 스레드를 죽이면 안 됨. 대응: tick 단위 try/except + 로그 후 다음 tick 지속(REQ-024 degrade 정책 정합).
- R-5 (Low, 이월): BAT-010 잔여 R-2 —
004_add_price_thresholds.sql실 PostgreSQL round-trip 미검증. 대응: 본 batch verification에서 실 PG 적용 + round-trip 확인.
Notes
- safety-sell worker는 REQ-037 Notes의 권고(forced_close·stop-loss/take-profit·장 마감을 하나의 통합 루프로 처리)를 따른다. 루프 주기와 가격 체크 주기가 다를 경우(
TREX_FORCED_CLOSE_CHECK_INTERVALvsTREX_STOP_LOSS_POLL_INTERVAL) tick 내 sub-scheduling 방식은 design에서 확정한다. - REQ-040 OQ-6(non-holding 슬롯 처리)는 REQ-040 AC-6에서
{status: ignored, reason: "not_holding"}응답으로 이미 결정됨 — 구현은 이를 따른다.