Files
trex-core/docs/srs/Integration/req-037_forced-close-at-safety-sell-loop.md
T
genichinandClaude Opus 4.8 a30efa8f3b feat(safety-sell): dcy-007 core 자율 안전 매도 — BAT-010 기반 + BAT-011 트리거
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>
2026-06-07 08:32:30 +09:00

5.6 KiB
Raw Blame History

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

  1. Given holding 상태이고 워치독 만료이며 forced_close_at = now() − 1s인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해 SlotService.sell()이 호출된다.
  2. Given holding 상태이고 워치독 만료이며 forced_close_at = now() + 1hour인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해 sell()이 호출되지 않는다.
  3. Given holding 상태이고 워치독 활성이며 forced_close_at = now() − 1s인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S에 대해 sell()이 호출되지 않는다(워치독 보호).
  4. Given forced_close_at = None인 슬롯 S가 있을 때, When checker 1회가 수행되면, Then S는 만기 체크 대상에서 제외된다.
  5. Given 대상 슬롯이 이미 pending_sell일 때, When checker 1회가 수행되면, Then 중복 sell() 호출이 발생하지 않는다(REQ-036 idempotency 적용).
  6. 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-sell worker 스레드 추가, _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_INTERVAL env 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 배포 편성.