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>
5.6 KiB
5.6 KiB
req-037: forced_close_at 만기 자동 매도 루프
- Status: Implemented
- Type: Integration
- Priority: High
- Owner: project maintainers
Intent
슬롯에 설정된 forced_close_at 만기 시각이 도달했을 때 데몬이 자율적으로 매도를 제출하는 백그라운드 루프를 추가한다. 워치독이 만료된 슬롯에 한해 동작하므로 전략 모듈이 정상 활성 중인 슬롯에는 개입하지 않는다(dcy-007 FR-1, NFR-1).
Requirement
- 데몬은
TREX_FORCED_CLOSE_CHECK_INTERVAL(초)주기로holding상태이며 워치독이 만료된 슬롯 중forced_close_at <= now(KST)인 슬롯을 감지해야 한다. - 조건에 해당하는 슬롯에 대해
SlotService.sell()(REQ-036)을 통해 내부 매도를 제출해야 한다. - 이 루프는 daemon.py의 safety-sell worker 스레드에서 실행된다. 기존 6개 스레드에 safety-sell worker(
trex-safety-sell)를 추가한다. forced_close_at이None인 슬롯은 이 루프의 대상이 아니다.- 워치독 활성(만료되지 않은) 슬롯은 이 루프의 대상이 아니다.
Acceptance Criteria
- Given
holding상태이고 워치독 만료이며forced_close_at = now() − 1s인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해SlotService.sell()이 호출된다. - Given
holding상태이고 워치독 만료이며forced_close_at = now() + 1hour인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해sell()이 호출되지 않는다. - Given
holding상태이고 워치독 활성이며forced_close_at = now() − 1s인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해sell()이 호출되지 않는다(워치독 보호). - Given
forced_close_at = None인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S는 만기 체크 대상에서 제외된다. - Given 대상 슬롯이 이미
pending_sell일 때, When checker 1회가 수행되면, Then 중복sell()호출이 발생하지 않는다(REQ-036 idempotency 적용). - Given
TREX_FORCED_CLOSE_CHECK_INTERVAL=60일 때, When daemon이 정상 실행 중이면, Then checker는 60±허용오차 초 주기로 반복 실행된다(NFR-1: 감지 지연 ≤ 60초).
Impacted Area
- Docs:
docs/runtime-flows.md— forced_close_at 만기 감지 루프 흐름 추가 (REQ-042 참조)docs/project-structure.md—trex-safety-sell스레드 추가 반영 (REQ-042 참조)
- Modules:
trex_core/runtime/daemon.py—trex-safety-sellworker 스레드 추가,_safety_sell_loop()메서드 구현trex_core/domain/slot/service.py— forced_close_at 조건 평가 메서드(또는 checker 내 인라인)
- Tests:
- forced_close_at checker 단위 테스트 — 만기 슬롯 감지 + sell() 호출 확인
- 워치독 활성 슬롯 통과 확인
- idempotency 확인 (pending_sell 슬롯 중복 처리 없음)
Notes
- safety-sell worker(
trex-safety-sell)는 forced_close_at checker(REQ-037), stop-loss·take-profit checker(REQ-038), 장 마감 청산(REQ-039)을 하나의 통합 루프로 묶어 처리할 수 있다. 구체적인 스레드 분리/통합 방식은 batch planning에서 결정한다. - 체크 로직은 DB 조회(forced_close_at 필드)와 in-memory 워치독 store 비교만 수행하므로 KIS API 호출이 없다. 낮은 연산 비용.
TREX_FORCED_CLOSE_CHECK_INTERVALenv var는 REQ-041 참조.SlotService.sell()구현은 REQ-036 참조.
Change Log
CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
Change Summary
- dcy-007 confirmed → REQ-037 초안 생성
Intent
- forced_close_at 만기 자동 매도 루프(FR-1)를 독립 Integration REQ로 정규화
Acceptance Criteria Delta
- Added: AC-1~6 전체
Impacted Area Delta
- Docs: runtime-flows.md, project-structure.md (REQ-042에서 처리)
- Modules: daemon.py (스레드 추가), service.py (forced_close 조건 평가)
- Tests: checker 단위 테스트 3종
Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs 후 batch 배정
CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
Change Summary
- Proposed → Approved (confirm-req)
Intent
- 승인 게이트 통과: 필수 필드·AC·Impacted Area·Change Log 완비 확인. dcy-007(confirmed) 범위 및 결정 사항과 모순 없음.
Acceptance Criteria Delta
- (변경 없음)
Impacted Area Delta
- (변경 없음)
Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs 후 batch 배정
CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-011 release-candidate).
Intent
- BAT-011 verification.md 의 AC↔evidence(SafetySellService forced_close checker — 만기/미만기/워치독 보호/None 제외/idempotency/캐던스)로 AC-1~6 충족 → 구현 완료 동기화.
Acceptance Criteria Delta
- (변경 없음)
Impacted Area Delta
- (변경 없음)
Delivery Trace Delta
- Batches: BAT-011 (release-candidate)
- Releases: none
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-011 배포 편성.