본문 바로가기
인천고래 프로그램

계좌정보를 찾을 수 없습니다. 계좌번호 10자리 입력을 확인해주시기 바랍니다.(00)

by 인천고래
반응형

안녕하세요. 주식관련 프로그램을 제작하는 인천고래입니다.

요 몇 일 사이에 도서관에 와서 작업을 하고 있는데 다수의 인원들이 사용하는 네트웍이다보니 기존에 만든 로직이 엉키는 상황이 발생되었습니다.

계좌정보를 찾을 수 없습니다.

네트웍이 느린 도서관에서만 실행을 하면 에러가 발생이 되는데

로그 시점을 보면 아래의 구간에서 거의 100%의 확률로 나옵니다.

횟수 =>  0 2026-05-03 10:43:11
📡 openAPI : _OnReceiveTrData() TR 데이터 수신: rqname=주식기본정보요청, trcode=OPTKWFID, next=0
📡 openAPI : _OnReceiveTrData() TR 데이터 수신: rqname=계좌평가잔고내역, trcode=opw00018, next=
[V8 Client] opw00018 normalized portfolio rows=13

 

일종의 API 호출로 계좌번호를 받아와야 하는데 지연되면서 다음의 코드가 진행이 되게 되었고 
못 받아온 계좌번호를 무시한 상태로 다음 코드에서 비어있는 계좌 번호로 계좌 관련 정보를 요청할 때 인해 에러가 발생한 케이스입니다.

 

즉, KHOpenAPI 요청들이 서로 겹치면서 입력값이 섞이는 현상으로 봐야 할 것 같습니다.

흐름이 이렇게 됩니다.

1. _app_trader_8_0.py (line 527)에서 시작 계좌조회 OPW를 예약함
   opw00001, opw00004, opw00005, opw00007, opw00018을 0ms, 350ms, 700ms, 1050ms, 1400ms 간격으로 실행

2. 그런데 _app_trader_8_0.py (line 545) 이후 바로 startup 완료 처리되고, _app_trader_8_0.py (line 557)에서 대기 중이던 현재가 조회가 시작됨

3. 그래서 로그처럼 opw00001 받은 직후에 바로 get_multiple_current_prices()가 실행됨

4. 그 사이 아직 opw00018 같은 계좌 TR도 남아 있음

 

self.exit_check() ret = self.dynamicCall("CommRqData(...")

OPW 함수들은 이미 SetInputValue("계좌번호", ...)를 먼저 해놓고 comm_rq_data()를 부릅니다. 그런데 comm_rq_data() 안의 exit_check()가 _client_api_comm.py (line 267)에서 작은 이벤트 루프를 돌립니다.

이때 다른 QTimer가 끼어들 수 있어요.

그래서 이런 일이 생길 수 있습니다.

opw00004: 계좌번호 SetInputValue 함 
opw00004: exit_check에서 대기하면서 이벤트 처리 
그 사이 opw00005/opw00018/현재가조회가 끼어듦 
SetInputValue 값이 다른 요청 값으로 덮임 
원래 opw00004 CommRqData가 잘못된 입력값으로 전송됨 
KHOpenAPI: 계좌정보를 찾을 수 없습니다

 

그래서 메시지는 계좌번호 오류처럼 보이지만,

실제 원인은 TR 요청 직렬화 실패 + SetInputValue/CommRqData 사이에 이벤트 루프가 열리는 구조입니다. “가끔” 발생하는 이유도 타이밍 문제라서 그렇고요.

 

임시 완화책으로는 현재가 조회 시작을 opw00018 이후 2~3초 뒤로 미루면 증상이 줄어들긴 하겠지만

근본 해결은 KHOpenAPI TR 요청 큐를 만들어서 SetInputValue -> CommRqData -> OnReceiveTrData 완료까지 한 번에 하나만 처리하게 만드는 쪽입니다.

 

그래서 임시 완화책인 호출을 하는 고정 텀은 근본 해결이 아니라서, 이번에 응답 기반 TR 요청 큐로 바꿨습니다.

변경 내용은 이렇습니다.

  • _client_api_comm.py (line 214)에 enqueue_serial_tr_request() 큐 추가
  • 시작 OPW 요청을 기존 0/350/700/1050/1400ms 타이머 방식에서 제거
  • _client_api_comm.py (line 358)의 schedule_startup_opw_requests()가 이제 opw00001 -> opw00004 -> opw00005 -> opw00007 -> opw00018 순서로 큐에 넣음
  • module/kiwoom_api/TR.py (line 182)에서 OnReceiveTrData 처리 후 큐에 “이 TR 끝났다”를 알려줌
  • _app_trader_8_0.py (line 5724)의 주식기본정보요청(OPTKWFID) 현재가 묶음 조회도 같은 큐에 태움
_app_trader_7_2.py : get_multiple_current_prices()
Requesting current-price snapshot ['005690', '005740', '007110', '007690', '027830', '036630', '045390', '149950', '272110', '293580', '356860', '368970', '418420']
📡 openAPI : _OnReceiveTrData() TR 데이터 수신: rqname=체결잔고, trcode=opw00005, next=
[V8 Client] TR queue done: startup_opw00005 (received)
[V8 Client] TR queue request: startup_opw00007
📡 openAPI : _OnReceiveTrData() TR 데이터 수신: rqname=계좌별주문체결내역상세, trcode=opw00007, next=
opw00007 주문체결내역상세 정보가 없습니다. 0건
[V8 Client] TR queue done: startup_opw00007 (received)
[V8 Client] TR queue request: startup_opw00018
📡 openAPI : _OnReceiveTrData() TR 데이터 수신: rqname=계좌평가잔고내역, trcode=opw00018, next=
[V8 Client] opw00018 normalized portfolio rows=13
[V8 Client] TR queue done: startup_opw00018 (received)

 

즉 OPTKWFID가 opw00018 중간에 끼어드는 상황을 막기 위해 큐 형식으로 변경하였고

Kiwoom TR은 SetInputValue 상태를 공유하는 구조라, 요청 전송 구간은 병렬보다 직렬이 안전합니다.

실시간 수신, Chejan, 후처리 계산은 별개로 계속 비동기적으로 돌아갈 수 있고요.

이상 계좌정보를 찾을 수 없다는 에러 발생 원인과 해결 방식에 대해서까지 공유 드렸습니다.

오늘도 제 글을 읽어 주신 모든 분들께 감사의 말씀을 드립니다.

감사합니다. ^^

반응형