fix: 해외잔고 ovrs_cblc_qty → ord_psbl_qty 전환 및 SELL 잔고없음 처리 (#233) #235

Closed
opened 2026-02-24 05:53:40 +09:00 by agentson · 0 comments
Collaborator

문제 분석

모의투자 실행 시 'rt_cd != 0, 모의투자 잔고내역이 없습니다' 오류가 반복됨.

근본 원인 1 — 잔고 필드 오류

_extract_held_codes_from_balance, _extract_held_qty_from_balance에서 해외 잔고 수량을 ovrs_cblc_qty (해외잔고수량, 총 보유수량) 로 읽고 있음. KIS API 공식 문서 확인 결과:

  • ovrs_cblc_qty: 해외잔고수량 — 총 보유 수량 (결제 미완료 포함)
  • ord_psbl_qty: 주문가능수량 — 실제 매도 가능 수량 (정산 후 실제 주문 가능)

MLECW (Warrant 만기물), KNRX, NBY, SNSE 등 만료/정지된 종목이:

  • ovrs_cblc_qty = 289,456 (큰 수량 표시)
  • ord_psbl_qty = 0 (실제 매도 불가)

현재 코드가 ovrs_cblc_qty를 사용하기 때문에 이 종목들이 잔고로 인식됨.

근본 원인 2 — Ghost position 무한 반복

SELL 실패 시 (rt_cd != '0'):

  • order_succeeded = False → DB SELL 기록 없음
  • 다음 사이클에서도 동일하게 SELL 시도 → 무한 반복
  • '모의투자 잔고내역이 없습니다' 오류 계속 발생

피해

  1. startup sync가 불필요한 ghost position을 DB에 기록
  2. build_overseas_symbol_universe가 이 종목들을 분석 유니버스에 포함 → AI가 계속 SELL 결정
  3. 매 사이클 KIS API 호출 실패 로그 발생

수정 내용

1. src/main.py — 해외잔고 필드 변경 (2곳)

_extract_held_codes_from_balance: 해외 브랜치

# Before
qty = int(holding.get("ovrs_cblc_qty") or holding.get("hldg_qty") or 0)
# After
qty = int(holding.get("ord_psbl_qty") or holding.get("ovrs_cblc_qty") or holding.get("hldg_qty") or 0)

_extract_held_qty_from_balance: 해외 브랜치 동일 변경, docstring 업데이트

2. src/main.py — SELL 잔고없음 시 ghost position 정리

trading_cycle의 overseas SELL 실패 처리 부분:

if decision.action == "SELL" and "잔고내역이 없습니다" in msg1:
    # Ghost position — close in DB to prevent infinite retry
    log_trade(..., action="SELL", quantity=0, price=0.0, rationale="[ghost-close] ...")

3. 테스트

  • _extract_held_codes_from_balance: ord_psbl_qty=0인 종목 제외 확인
  • _extract_held_qty_from_balance: ord_psbl_qty 우선 사용 확인
  • trading_cycle: SELL 잔고없음 시 DB 포지션 종료 확인
## 문제 분석 모의투자 실행 시 'rt_cd != 0, 모의투자 잔고내역이 없습니다' 오류가 반복됨. ### 근본 원인 1 — 잔고 필드 오류 `_extract_held_codes_from_balance`, `_extract_held_qty_from_balance`에서 해외 잔고 수량을 `ovrs_cblc_qty` (해외잔고수량, 총 보유수량) 로 읽고 있음. KIS API 공식 문서 확인 결과: - `ovrs_cblc_qty`: 해외잔고수량 — 총 보유 수량 (결제 미완료 포함) - `ord_psbl_qty`: **주문가능수량** — 실제 매도 가능 수량 (정산 후 실제 주문 가능) MLECW (Warrant 만기물), KNRX, NBY, SNSE 등 만료/정지된 종목이: - `ovrs_cblc_qty` = 289,456 (큰 수량 표시) - `ord_psbl_qty` = 0 (실제 매도 불가) 현재 코드가 `ovrs_cblc_qty`를 사용하기 때문에 이 종목들이 잔고로 인식됨. ### 근본 원인 2 — Ghost position 무한 반복 SELL 실패 시 (`rt_cd != '0'`): - `order_succeeded = False` → DB SELL 기록 없음 - 다음 사이클에서도 동일하게 SELL 시도 → 무한 반복 - '모의투자 잔고내역이 없습니다' 오류 계속 발생 ### 피해 1. `startup sync`가 불필요한 ghost position을 DB에 기록 2. `build_overseas_symbol_universe`가 이 종목들을 분석 유니버스에 포함 → AI가 계속 SELL 결정 3. 매 사이클 KIS API 호출 실패 로그 발생 ## 수정 내용 ### 1. `src/main.py` — 해외잔고 필드 변경 (2곳) **`_extract_held_codes_from_balance`**: 해외 브랜치 ```python # Before qty = int(holding.get("ovrs_cblc_qty") or holding.get("hldg_qty") or 0) # After qty = int(holding.get("ord_psbl_qty") or holding.get("ovrs_cblc_qty") or holding.get("hldg_qty") or 0) ``` **`_extract_held_qty_from_balance`**: 해외 브랜치 동일 변경, docstring 업데이트 ### 2. `src/main.py` — SELL 잔고없음 시 ghost position 정리 `trading_cycle`의 overseas SELL 실패 처리 부분: ```python if decision.action == "SELL" and "잔고내역이 없습니다" in msg1: # Ghost position — close in DB to prevent infinite retry log_trade(..., action="SELL", quantity=0, price=0.0, rationale="[ghost-close] ...") ``` ### 3. 테스트 - `_extract_held_codes_from_balance`: `ord_psbl_qty=0`인 종목 제외 확인 - `_extract_held_qty_from_balance`: `ord_psbl_qty` 우선 사용 확인 - `trading_cycle`: SELL 잔고없음 시 DB 포지션 종료 확인
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jihoson/The-Ouroboros#235