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>
7.0 KiB
7.0 KiB
req-038: stop-loss·take-profit KIS 가격 polling + 트리거
- Status: Implemented
- Type: Integration
- Priority: High
- Owner: project maintainers
Intent
워치독이 만료된 슬롯에 한해 KIS API(TTTC8397R 실전 / VTTC8397R 모의)로 현재가를 주기적으로 polling하고, 현재가 <= stop_loss_price(손절) 또는 현재가 >= take_profit_price(익절) 조건 충족 시 자동 매도를 제출한다. 전략 모듈이 정상 활성 중인 슬롯에는 개입하지 않는다(dcy-007 FR-2, NFR-3, A-3).
Requirement
- 데몬은
TREX_STOP_LOSS_POLL_INTERVAL(초)주기로,stop_loss_price또는take_profit_price가 설정되고 워치독이 만료된holding슬롯들의 현재가를 KISTTTC8397R(실전) /VTTC8397R(모의) API로 polling해야 한다. - 현재가 평가 기준값은
stck_prpr(직전 체결가) 필드를 사용한다. 현재가 <= stop_loss_price조건 충족 시 손절 매도를 제출해야 한다.현재가 >= take_profit_price조건 충족 시 익절 매도를 제출해야 한다.- 두 조건은 동일 polling 루프에서 평가한다.
- 워치독 활성(만료되지 않은) 슬롯과 임계값 미설정(
None) 슬롯은 polling 대상이 아니다. - KIS API 호출 상한은
워치독 만료 대상 슬롯 수 × (3600 / TREX_STOP_LOSS_POLL_INTERVAL)로 산정한다. 이 상한이 KIS 쿼터를 초과할 경우 polling 간격 조정 AC를 이 REQ의 Notes에 명시하고 REQ 단계에서 상한 경고를 구현한다. - 자동 매도 제출은
SlotService.sell()(REQ-036)을 사용한다.
Acceptance Criteria
- Given
holding, 워치독 만료,stop_loss_price=Decimal("50000"),take_profit_price=None인 슬롯 S가 있고 KIS polling 결과stck_prpr=49000이면, When 가격 체크가 수행되면, Then S에 대해SlotService.sell()이 호출된다(손절 트리거). - Given
holding, 워치독 만료,stop_loss_price=None,take_profit_price=Decimal("80000")인 슬롯 S가 있고 KIS polling 결과stck_prpr=81000이면, When 가격 체크가 수행되면, Then S에 대해sell()이 호출된다(익절 트리거). - Given
holding, 워치독 만료,stop_loss_price=Decimal("50000"),take_profit_price=Decimal("80000")인 슬롯 S가 있고stck_prpr=65000이면, When 가격 체크가 수행되면, Thensell()이 호출되지 않는다(두 조건 모두 미충족). - Given
holding, 워치독 활성인 슬롯 S가 있을 때, When 가격 polling이 수행되면, Then S에 대한 KIS API 호출이 발생하지 않는다(워치독 보호). - Given
stop_loss_price=None이고take_profit_price=None인 슬롯 S가 있을 때, When polling이 수행되면, Then S는 polling 대상에서 제외된다. - Given 이미
pending_sell상태인 슬롯 S에 조건이 충족될 때, When 가격 체크가 수행되면, Then 중복sell()호출이 발생하지 않는다(REQ-036 idempotency). - Given 실전 모드(
broker=kis)일 때, When 가격 polling을 수행하면, ThenTTTC8397Rendpoint를 사용한다. 모의 모드(broker=paper)일 때는VTTC8397R을 사용한다. - Given
TREX_STOP_LOSS_POLL_INTERVAL=30이고 워치독 만료 대상 슬롯이 N개일 때, When 정상 동작 중이면, Then 1시간당 KIS API 호출 수가N × 120회를 넘지 않는다(NFR-3 쿼터 산정).
Impacted Area
- Docs:
docs/runtime-flows.md— stop-loss·take-profit 가격 체크 흐름 추가 (REQ-042 참조)docs/interface-contract.md— 현재가 polling 어댑터 계약 명시 (REQ-042 참조)
- Modules:
- 신규
trex_core/adapters/broker/kis_price.py또는kis.py확장 —TTTC8397R/VTTC8397R현재가 polling,stck_prpr파싱 trex_core/runtime/daemon.py— stop-loss·take-profit 가격 체크를 safety-sell worker에 통합trex_core/domain/slot/service.py— stop-loss·take-profit 조건 평가 메서드(또는 worker 내 인라인)
- 신규
- Tests:
- KIS 현재가 polling 어댑터 단위 테스트 —
stck_prpr파싱 확인, 실전/모의 분기 확인 - 가격 체크 단위 테스트(mock polling) — 손절/익절/미충족/워치독 보호 시나리오
- KIS 현재가 polling 어댑터 단위 테스트 —
Notes
- KIS 현재가 polling 어댑터는 기존
trex_core/adapters/broker/kis.py에get_current_price(symbol)메서드로 추가하거나, 별도 모듈로 분리한다. batch planning에서 결정한다. - paper broker 모의 환경에서는
VTTC8397R를 사용하거나, stub 구현으로 현재가를 반환하는 방식을 batch에서 결정한다. - KIS 쿼터 초과 방지: 워치독 만료 슬롯 수가 임계값을 넘으면 polling 간격 자동 조정 또는 경고 로그를 구현한다. 구체적인 쿼터 수치는 KIS API 문서 기준으로 batch 설계에서 확정한다.
TREX_STOP_LOSS_POLL_INTERVALenv var는 REQ-041 참조.
Change Log
CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
Change Summary
- dcy-007 confirmed → REQ-038 초안 생성
Intent
- stop-loss·take-profit KIS 가격 polling + 트리거(FR-2)를 독립 Integration REQ로 정규화
Acceptance Criteria Delta
- Added: AC-1~8 전체
Impacted Area Delta
- Docs: runtime-flows.md, interface-contract.md (REQ-042에서 처리)
- Modules: kis 현재가 polling 어댑터(신규/확장), daemon.py, service.py
- Tests: polling 어댑터 단위 + 가격 체크 시나리오 단위 (mock)
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(KIS
get_current_priceTTTC8397R/VTTC8397R·stck_prpr파싱 + 손절/익절/미충족/워치독 보호/쿼터 산정/가격 미수신 skip)로 AC-1~8 충족 → 구현 완료 동기화.
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 배포 편성.