프로그래밍/파이썬

3. 파이썬 - 키움API 활용한 주문 접수하기

가카리 2025. 6. 9. 22:49
반응형

 

 

1. 주문 접수하기 사전 지식

 

주문접수하기는 KOA -> 개발가이드 > 주문과 잔고 처리 > 기본 설명에 가보면

 

 

[주문처리단계]
        주문 처리 순서
        SendOrder(주문발생) -> OnReceiveTRData(주문응답) -> OnReceiveMsg(주문메세지수신) -> OnReceiveChejan(주문접수/체결)
        ※ 주의(역전현상) : 주문건수가 폭증하는 경우 OnReceiveChejan 이벤트가 OnReceiveTRData 이벤트보다 앞서 수신될 수 있습니다.
        
        각 단계 설명
        SendOrder - 사용자가 호출. 리턴값 0인 경우 함수호출 정상 (주문성공이 아님)
        OnReceiveTRData - 주문발생시 첫번째 서버응답. 주문번호 취득 (주문번호가 없다면 주문거부 등 비정상주문)
        OnReceiveMsg - 주문거부 사유를 포함한 서버메세지 수신
        OnReceiveChejan - 주문 상태에따른 실시간수신 (주문접수, 주문체결, 잔고변경 각 단계별로 수신됨)
        
        주문성공 여부 판단
        OnReceiveTRData()이벤트는 주로 조회요청후 데이터수신 이벤트지만 주문시에도 발생됩니다.
        주문정상인 경우 이 이벤트내부에서 주문번호를 얻을 수 있습니다.
        비정상주문(주문실패)인 경우 주문번호는 공백("")으로 전달됩니다.
        각 주문함수의 리턴값이 0(성공)이여도 장 개시전 주문, 시장가 주문가격입력, 호가범위를 벗어난 주문가격 입력등 
        주문은 다양한 원인으로 실패할수 있습니다.

        주문성공여부 판단 예시
        OnReceiveTRData(sScreenNo, sRqName, sTrCode, ....) // 이벤트 처리부분
        {
            sData = OpenAPI.GetCommData(sTrCode, sRqName, 0, "주문번호");// sData에 주문번호가 있으면 주문성공, 공백이면 주문실패
        }
        
        [주문 유의사항]
        ※ 주문은 1초당 5회로 제한 됩니다. (조회횟수와는 별개로 카운트 됩니다.)
        ※ 주문가능수량 이상으로 주문하는 경우 미수주문으로 처리될 수 있습니다.
              영웅문4 [0398] 화면등에서 계좌증거금 변경등록으로 100% 현금 주문만 가능하도록 설정할 수 있습니다.
        ※ 시장가주문시 최대주문가능수량은 상한가를 기준으로 계산됩니다.
        ※ 시장가주문시 주문가격은 0으로 입력합니다.
        ※ OpenAPI에서는 거래구분 정정주문은 지원되지 않습니다. 
              예) 지정가 매도 -> 시장가 매도로 정정 (불가. 원주문 취소 후 신규주문으로 진행하시기 바랍니다.)
        ※ 주문내역은 영웅문HTS, MTS 등 매체간 공유됩니다.
              타매체에서 발생시킨 주문체결도 OnReceiveChejan 이벤트로 실시간 수신됩니다.
        ※ 모의투자 서버에서는 주문 불가 종목이 존재합니다.
              모의투자 규정을 확인해주시기 바랍니다.
              https://www.kiwoom.com/h/mock/ordinary/VMockTotalSMAIN1View?dummyVal=0

 

 

  - 다시 말하면 

  1) SendOrder : 주문 발생

  - 매매할 종목에 대한 수량, 매매 가격, 주문 타입을 지정하여 주문을 접수하는 함수

  - 함수의 반환값이 0이면 정상이라고 설명하지만 무조건 주문이 접수된것은 아님(장마감이후 주문 등)

 

  2) OnReceiveTrData(주문 접수 후 주문 번호 생성 응답)

  - _on_receive_tr_data 함수를 사용하여 일차적으로 주문번호를 전달 받음

 

  3) OnReceiveMsg(주문 메시지 수신)

  - 주문 전송에 대한 서버의 한글 응답을 수신

  - 예를들어 증거금부족 같은 서버의 메시지를 보여주는 알림단계임

 

  4) OnReceiveChejan(주문 접수/체결)

  - 주문이 접수되거나 체결 및 체결 후 잔고로 이동하는 과정마다 실행됨

  - 각 과정의 응답 결과를 수신하는 단계임

 

 

2. SendOrder()함수 (KOA > 개발 가이드 > 주문과 잔고 처리 > 관련 함수)

  
          SendOrder(
          BSTR sRQName,     // 사용자 구분명
          BSTR sScreenNo,   // 화면번호
          BSTR sAccNo,      // 계좌번호 10자리
          LONG nOrderType,  // 주문유형 1:신규매수, 2:신규매도 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정, SOR, NXT주문유형이 추가되었습니다.
          BSTR sCode,       // 종목코드 (6자리)
          LONG nQty,        // 주문수량
          LONG nPrice,      // 주문가격
          BSTR sHogaGb,     // 거래구분(혹은 호가구분)은 아래 참고
          BSTR sOrgOrderNo  // 원주문번호. 신규주문에는 공백 입력, 정정/취소시 입력합니다.
          )
          
          ※ 주문유형 추가
          대체거래소 주문을 위해 다음 유형이 추가되었습니다.
          11 : SOR매수, 12 : SOR매도, 13 : SOR취소, 15 : SOR정정, 21 : NXT매수, 22 : NXT매도, 23 : NXT취소, 25 : NXT정정
          
          서버에 주문을 전송하는 함수 입니다.
          9개 인자값을 가진 주식주문 함수이며 리턴값이 0이면 함수호출 성공이며 나머지는 에러입니다.
          주문성공여부는 OnReceiveTrData에서 주문번호가 있으면 주문성공, 공백이면 주문실패으로 판단하실수 있습니다.
          
          1초에 5회만 주문가능하며 그 이상 주문요청하면 에러 -308을 리턴합니다.
          ※ 시장가주문시 주문가격은 0으로 입력합니다. 주문가능수량은 해당 종목의 상한가 기준으로 계산됩니다.
          ※ 주문가격 입력필요
          지정가(00), 조건부지정가(05), 지정가IOC(10), 지정가FOK(20) 

          ※ 주문가격 불필요 (0으로 입력)
          시장가(03), 최유리지정가(06), 최우선지정가(07), 중간가(29), 시장가IOC(13) 
          최유리IOC(16), 시장가FOK(23), 최유리FOK(26), 장전시간외종가(61), 장후시간외종가(81)

          ※ 주문증거금
          아래 거래구분은 주문증거금을 상한가로 계산하므로 지정가 주문에 비해 주문가능수량이 적어지므로 주문가능수량 계산에 주의하셔야 합니다.
          시장가(03), 최유리지정가(06), 최우선지정가(07), 시장가IOC(13), 최유리IOC(16), 시장가FOK(23), 최유리FOK(26)

          ※ 취소주문일때 주문가격은 0으로 입력합니다.
          
          [거래구분]
          00 : 지정가
          03 : 시장가
          05 : 조건부지정가
          06 : 최유리지정가
          07 : 최우선지정가
          10 : 지정가IOC
          13 : 시장가IOC
          16 : 최유리IOC
          20 : 지정가FOK
          23 : 시장가FOK
          26 : 최유리FOK
          28 : 스탑지정가
          29 : 중간가
          61 : 장전시간외종가
          62 : 시간외단일가매매
          81 : 장후시간외종가
          ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다.
          
          [정규장 외 주문]
          장전 동시호가 주문
              08:30 ~ 09:00. 거래구분 00:지정가/03:시장가 (일반주문처럼)
              ※ 08:20 ~ 08:30 시간의 주문은 키움에서 대기하여 08:30 에 순서대로 거래소로 전송합니다.
          장전시간외 종가
              08:30 ~ 08:40.  거래구분 61:장전시간외종가.  가격 0입력
              ※ 전일 종가로 거래. 미체결시 자동취소되지 않음
          장마감 동시호가 주문
              15:20 ~ 15:30. 거래구분 00:지정가/03:시장가 (일반주문처럼)
          장후 시간외 종가
              15:40 ~ 16:00. 거래구분 81:장후시간외종가.  가격 0입력
              ※ 당일 종가로 거래
          시간외 단일가
              16:00 ~ 18:00. 거래구분 62:시간외단일가.  가격 입력
              ※ 10분 단위로 체결, 당일 종가대비 +-10% 가격으로 거래

 

3. SendOrder()함수 구현하기        

def send_order(self, rqname, screen_no, order_type, code, order_quantity, order_price, order_classification, origin_order_number=""):
    order_result = self.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)"
                                    , [rqname, screen_no, self.account_number, order_type, code, 
                                       order_quantity, order_price, order_classification, origin_order_number])
    return order_result

 

  1) rqname: TR 호출 때와 마찬가지로 요청의  별명

 

  2) screen_no: 화면번호

 

  3) order_type: 매수/매도/취소 주문 같은 주문 유형을 구분함

 

  4) code: 매매할 종목 코드

 

  5) order_quantity: 매매할 종목의 주문 수량

 

  6) order_price: 주문 가격

 

  7) order_classification: 거래 구분을 나타내는 매개변수

          [거래구분]
          00 : 지정가
          03 : 시장가
          05 : 조건부지정가
          06 : 최유리지정가
          07 : 최우선지정가
          10 : 지정가IOC
          13 : 시장가IOC
          16 : 최유리IOC
          20 : 지정가FOK
          23 : 시장가FOK
          26 : 최유리FOK
          28 : 스탑지정가
          29 : 중간가
          61 : 장전시간외종가
          62 : 시간외단일가매매
          81 : 장후시간외종가
          ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다.

 

  8) origin_order_number: 정정 혹은 취소하려는 주문 번호를 의미하는 매개변수(신규 주문 시 빈칸임)

 

4. 실제로 주문 넣어보기

 

main.py

  

send_order함수를 이용한 부분(삼성전자를 지정가 60000원으로 1주 매수하기)

from api.Kiwoom import *
import sys

app = QApplication(sys.argv)
kiwoom = Kiwoom()

#kiwoom.get_account_number()

#df = kiwoom.get_price_data("005930_AL")
#print(df)

deposit = kiwoom.get_deposit()

order_result = kiwoom.send_order('send_buy_order', '1001', 1, '005930', 1, 60000, '00')

print(order_result)

'''kospi_code_list = kiwoom.get_code_list_by_market("0")
print(len(kospi_code_list))

for code in kospi_code_list:
    code_name = kiwoom.get_master_code_name(code)
    print(code, code_name)

kosdaq_code_list = kiwoom.get_code_list_by_market("10")
print(kosdaq_code_list)
for code in kosdaq_code_list:
    code_name = kiwoom.get_master_code_name(code)
    print(code, code_name)'''

app.exec_()

 

 실제 결과는 아래와 같다.

 

다만 출력되는 0은 order_result값인데 0이라고 해서 모든 주문이 정산 접수 된것은 아니다.

 

필자가 주식 매매가능시간에 다시 돌려서 확인해봐야겠다.