fix: close broker uncertainty audit gaps

This commit is contained in:
jordan
2026-07-29 17:53:39 +09:00
parent de1e3eb44c
commit 611805dcec
19 changed files with 236 additions and 42 deletions
+1 -1
View File
@@ -175,7 +175,7 @@
### Key Fields
- account_hash :: TEXT PK :: `SHA-256(CANO|ACNT_PRDT_CD)`. 평문 계좌번호를 저장·로그하지 않는다.
- account_hash :: TEXT PK :: `SHA-256(KIS base_url|CANO|ACNT_PRDT_CD|app_key)`. 실전/모의 및 애플리케이션 자격증명 범위를 분리하며 원문을 저장·로그하지 않는다.
- holdings :: JSONB NOT NULL :: `[{symbol,hldg_qty}]`. 소유권 래퍼가 켜진 계정은 전략 소유분만 저장한다.
- holdings_captured_at :: TIMESTAMPTZ? :: 보유수량 조회가 마지막 성공한 시각.
- available_cash :: BIGINT? :: KIS 주문가능조회 `nrcvb_buy_amt` 현금주문 가능금액.
@@ -133,6 +133,9 @@
- `AUTO` 실제 거래소 확정·주문번호 동시 저장·재시작/취소 재사용: 구현 완료.
- 취소 `requested|rejected|unknown` 영속화와 poll 전용 최종확정: 구현 완료.
- 계정 해시·독립 TTL·백그라운드 단일 소유자·매수/매도 분리: 구현 완료.
- 계정 해시는 KIS endpoint·계좌·상품·app identity를 함께 묶어 실전/모의·자격증명 출처를 분리한다.
- 동일 instance advisory lock 안에서 현금 예약검사와 pending 전이를 원자 처리한다.
- timeout·운영자 취소 모두 compare-and-set 예약으로 동일 주문 재취소를 차단한다.
- KIS 현금 권위 필드: `inquire-psbl-order.output.nrcvb_buy_amt`.
- 수동 혼합 보유 계정: `OwnershipAwareBroker` 투영 뒤 스냅샷을 생성하여 전략 소유 수량만 매도 허용.
- 운영 기본값: 기능 OFF, 매수 600초, 매도 3600초, 갱신 300초.
+2
View File
@@ -433,6 +433,7 @@ resume_kill_switch 요청·응답 (REQ-046):
- 기능은 `TREX_ACCOUNT_SNAPSHOT_ENABLED=false`가 기본인 KIS 전용 선택 기능이다.
- KIS 보유조회와 현금주문 가능금액 조회(`inquire-psbl-order.output.nrcvb_buy_amt`)를 기본 300초 간격의 단일 계정 소유자가 갱신한다. 두 값은 독립 캡처 시각을 갖는다.
- 신규매수는 미만료 현금 스냅샷과 기존 `pending_buy` 지정가 예약금액을 합산해 검사한다. 수량·지정가가 없거나 예약금액을 계산할 수 없으면 매수를 차단한다. KIS 주문 응답이 최종 현금 한도 권위이며 거부된 주문을 자동 재전송하지 않는다.
- 현금 검사와 `PENDING_BUY` 전이는 동일 instance advisory lock 안에서 수행되어 같은 instance의 동시 처리자가 아직 커밋되지 않은 예약을 함께 통과하지 못한다.
- `pending_sell` 수량은 매 tick 실시간 보유조회를 먼저 시도한다. 오직 `transport_failed`이고 기본 3600초 안의 동일계정 스냅샷이 있을 때만 대체한다.
- 인증·인가·응답형식·브로커거부·소유권 불일치·계정 해시 변경·만료는 캐시로 우회하지 않는다.
- `sync`, `verify`, 일일 스냅샷 스케줄러와 재시작 원장대조는 기존처럼 실시간 조회만 사용한다.
@@ -447,6 +448,7 @@ cancel_order(broker_order_id: str, *, side: str, symbol: str, qty: int, venue: s
- `venue`: 원주문 venue. 취소 시 원주문과 동일한 `EXCG_ID_DVSN_CD`를 사용해야 한다. 기본값 `"KRX"`로 기존 호출자 하위 호환.
- `CancelOutcome.state`: `requested`(요청 접수), `rejected`(명시적 거부), `unknown`(응답유실·전송 실패). `requested`도 최종 취소가 아니며 `poll_fill()`의 `cancelled|filled`만 주문의 최종 상태를 확정한다.
- Core는 외부 취소 호출 전에 `unknown`을 먼저 영속화하고 응답 뒤 실제 즉시 결과로 교체한다. 따라서 요청과 저장 사이에 프로세스가 종료돼도 자동 timeout 취소는 같은 주문을 재전송하지 않고, 재시작 뒤 체결조회로만 수렴한다.
- timeout과 운영자 취소 모두 `cancel_state IS NULL` 비교·설정에 성공한 한 호출만 외부 요청을 보낸다. 이후 반복 요청은 `cancel_already_recorded`로 응답하고 poll만 계속한다.
### get_current_price
+1 -1
View File
@@ -270,7 +270,7 @@
1. 기능을 켠 KIS 데몬은 시작 시 1회 동기 조회 후 계정당 한 백그라운드 소유자가 기본 300초 간격과 실패 백오프로 보유수량·주문가능금액을 갱신한다.
2. 보유수량과 현금은 독립적으로 성공값과 시각을 저장한다. 계정 해시 변경, 인증·인가·형식·브로커 거부는 실패 폐쇄한다.
3. 신규매수는 기본 600초 이내 현금값에서 기존 pending 매수 예약금액과 새 주문금액을 합산해 검사한다. 시장가처럼 금액을 확정할 수 없으면 차단한다.
3. 신규매수는 기본 600초 이내 현금값에서 기존 pending 매수 예약금액과 새 주문금액을 합산해 검사한다. 검사와 pending 전이는 같은 instance advisory lock 안에서 원자 수행하며 시장가처럼 금액을 확정할 수 없으면 차단한다.
4. pending 매도는 실시간 보유조회 전송 실패일 때만 기본 3600초 이내 전략 소유 보유수량을 사용한다. 수동 보유분을 매도 권한으로 승격하지 않는다.
5. 재시작 원장대조, `sync`, `verify`, Portfolio Hub 일일 정합은 캐시를 사용하지 않는다.