키움 OpenAPI+ 자동매매 — 직접 만들기 vs 외주, 뭐가 유리한가
키움증권 OpenAPI+ 로 자동매매 프로그램을 만들어보겠다고 결심한 개발자들이 맨 처음 마주치는 건 "생각보다 제약이 많다" 는 사실입니다. API 문서만 보면 간단해 보이지만, 실제 구현에 들어가면 몇 가지 함정이 연속으로 등장하고, 이걸 전부 혼자 뚫는 데 보통 100~200시간 이 듭니다. 이 글에서는 3년 동안 알고랩에서 키움 자동매매 120건+ 제작하며 반복적으로 마주친 4가지 함정과, 직접 만들지 외주 맡길지 결정할 때의 기준을 공유합니다.
함정 1. Python은 반드시 32bit. 대부분 64bit로 시작했다가 재설치
키움 OpenAPI+ 는 Windows OCX 기반이고, 그 OCX 는 32bit 전용입니다.
Python 64bit로 깔고 QAxWidget("KHOPENAPI.KHOpenAPICtrl.1") 호출하면 "클래스가 등록되지 않았습니다" 에러가 납니다.
그래서 보통 아래 순서를 밟게 됩니다.
- Python 64bit 설치 → 실패 → 구글링
- Python 32bit 재설치 → PyQt5 32bit·pywin32 32bit 재설치 → 기존 가상환경 버림
- VS Code 인터프리터 경로 수동 변경
- pyinstaller로 배포 시 다시 32bit 바이너리 맞춰야 함
이 단계에서만 보통 4~8시간 날립니다. Python 3.11 까지는 32bit 공식 배포 있고, 3.12부터 32bit 공식 배포가 없어지니 3.10 또는 3.11 32bit 를 권장합니다.
함정 2. TR 요청 동시 호출 → 입력 슬롯 덮어씀
키움 API의 핵심 흐름은 SetInputValue로 파라미터 세팅 → CommRqData로 요청 전송 입니다.
문제는 이 두 함수가 단일 입력 슬롯을 공유한다는 점. 백그라운드 폴링과 사용자 트리거 요청이 겹치면
두 요청의 파라미터가 섞여서 "계좌정보를 찾을 수 없습니다" 팝업이 뜨거나 빈 응답이 돌아옵니다.
해결: 모든 TR 호출을 단일 플래그로 직렬화.
class KiwoomAPI:
def __init__(self, ...):
self._tr_busy = False # 단일 락
def get_balance(self):
if self._tr_busy:
return {} # busy면 즉시 빈 결과 (블로킹 대기 금지)
self._tr_busy = True
try:
self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "계좌번호", account)
ret = self.kiwoom.dynamicCall("CommRqData(...)", "계좌평가잔고", "opw00018", 0, "0101")
# 응답 대기 (이벤트 루프)
return self._last_balance
finally:
self._tr_busy = False # 예외 발생 시에도 반드시 해제
이 패턴을 모르면 백테스팅 쌓아둔 종목 루프에서 간헐적으로 데이터 누락이 생겨서 원인 못 찾고 며칠 헤맵니다.
함정 3. SendOrder 가 조용히 실패 (에러도 안 남)
주문 함수 SendOrder 는 9개 인자를 받는데, 이를 가변 형식으로 호출하면 PyQt5 QAxBase 가 일부 인자 누락 처리해서
주문 자체가 접수 안 되는데 에러도 안 나고 로그도 안 남습니다. 체결 콜백도 당연히 안 오고요.
해결: 반드시 9개 인자를 리스트로 묶어서 전달.
ret = kiwoom.dynamicCall(
"SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
["매수주문", "0101", account, 1, "005930", 10, 0, "03", ""] # 반드시 list로 묶음
)
호가구분 상수도 헷갈립니다: "00"=지정가, "03"=시장가. 시장가는 가격(7번째 인자)을 반드시 0 으로 넣어야 합니다.
함정 4. 실시간 시세 등록 한도 — 최대 100종목
키움 OpenAPI+ 는 한 계정당 실시간 시세 등록 한도가 100종목입니다. 코스피+코스닥 전체 실시간 감시는 불가능. 그래서 "시총 상위 100" 처럼 미리 필터링된 종목 리스트로 좁혀서 등록하는 구조가 표준입니다.
또한 SetRealReg 의 4번째 인자 ("0"=최초 등록, "1"=추가) 를 잘못 넣으면 기존 등록이 전부 해제됩니다. 디버깅 매우 어려운 버그 양산.
그래서 — 직접 만들기 vs 외주, 뭐가 유리한가
아래 기준으로 결정하시면 됩니다.
직접 만드는 게 낫다면
- Python 경력 2년+ 이고 OCX·PyQt5 를 이미 써봤다
- 전략이 자주 변할 것 같아 직접 유지보수 필요
- 학습 목적 (시간 드는 건 OK)
- 전략이 매우 단순 (조건검색 매수 → 고정 % 익절·손절)
외주가 유리하다면
- Python 처음이거나 Windows OCX 경험 없음 (위 함정 4개에 100시간+ 소모 확정)
- 전략은 명확한데 구현이 귀찮다 (시간 × 시급 계산하면 외주가 훨씬 쌈)
- GUI·텔레그램 알림·.exe 배포·백테스팅 등 부가 기능 필요
- 1~2주 안에 운영 시작하고 싶다
알고랩 기준으로 "기본 구조 + 조건검색 + 익절/손절 + 텔레그램 알림 + .exe" 정도면 80~120만원, 제작 기간 5~7일 입니다. 본인 시간 100시간을 여기에 쓸지, 다른 데 쓰고 외주를 맡길지는 본인 시간 가치로 판단하시면 됩니다.
참고: 이 글에서 언급한 4가지 함정은 전체 함정 중 일부입니다. 잔고 재동기화, 조건검색 콜백 순서, 장 시작 직후 10~20초 체결 틱 누락 등도 실제로 제작 중 자주 만나는 이슈들입니다. 자세한 기술 문서는 키움 OpenAPI+ 플랫폼 페이지를 참고하세요.