PYTHON/AUTO TRADE SYSTEM

[자동 매매 시스템 구축하기] 주문 정보 관리하기 (4) - self.order_info 변수 생성하기 ②

  • -

지난 게시글에서 설명했듯, 이번 게시글에서는 "접수"가 아닌 "체결" 데이터가 발생했을 때, 관련 데이터를 어떻게 처리해야 하는지에 대해 생각해보고 그를 코드로 구현해볼 예정이다.

 

 

접수와 체결의 차이점

궁극적으로, 주문 접수와 체결을 서로 달리하여   self.order_info  변수를 수정하는 이유는 단순하다. 접수 시에 접수된 주문 정보를 입력하고, 체결 시에는 접수된 주문 정보를 삭제해야 하기 때문이다. 만약 접수된 후에 모두 체결된 주문에 대해 삭제가 이루어지는 기능이 구현되어 있지 않다면,   self.order_info  변수는 계속해서 의미없는 크기만 커질 것이다.

그럼 우리는 어떤 변수를 기준으로 하여 self.order_info 내에 입력되어 있는 접수 주문 데이터 삭제할 수 있을까? 그 답은 간단하다. 바로 미체결잔량 데이터를 이용하는 것이다. 우리는 예전에   def receive_chejandata(self, Gubun, ItemCnt, FidList):   함수를 생성할 때에   remained_quan  이라는 변수에 미체결 잔량 데이터(str로, 문자열 형태이다.)를 입력하도록 구현했었고, 지난 게시글에서도   self.order_info   변수의   ['remained_quan']   칼럼 안에 해당 데이터를 입력하도록 구현했었다. 그럼 이제 "체결" 정보에서 미체결 잔량을 활용하여   self.order_info  변수를 수정해보자.
※ Line : 44~46

def receive_chejandata(self, Gubun, ItemCnt, FidList):
    """
    Gubun(string) - 0:주문체결통보, 1:국내주식잔고통보, 4:파생상품잔고통보
    FidList(string) - 데이터 구분은 ;이다.
    """
    if Gubun == "0":
        accno = self.__getchejandata("9201").strip()        ## 계좌번호
        orderno = self.__getchejandata("9203").strip()      ## 주문번호
        item_code = self.__getchejandata("9001").strip()    ## 종목코드
        order_gubun = self.__getchejandata("912").strip()   ## 주문 구분(JJ:주식주문, FJ:선옵, JG:주식잔고, FG:선옵잔고)
        order_status = self.__getchejandata("913").strip()  ## 주문 상태
        item_name = self.__getchejandata("302").strip()     ## 종목명
        order_quan = self.__getchejandata("900").strip()    ## 주문 수량
        order_pri = self.__getchejandata("901").strip()     ## 주문 가격
        remained_quan = self.__getchejandata("902").strip() ## 미체결량
        signed_vol = self.__getchejandata("903").strip()    ## 체결대금
        origin_ordno = self.__getchejandata("904").strip()  ## 원주문번호
        order_bns = self.__getchejandata("905").strip()     ## 주문 구분(+:매수, -:매도)
        trade_gubun = self.__getchejandata("906").strip()   ## 매수 구분(시장가, 지정가, 보통 등)
        signed_num = self.__getchejandata("909").strip()    ## 체결 번호
        signed_pri = self.__getchejandata("910").strip()    ## 체결가
        signed_quan = self.__getchejandata("911").strip()   ## 체결량
        today_com = self.__getchejandata("938").strip()     ## 당일매매 수수료
        today_tax = self.__getchejandata("939").strip()     ## 당일 매매 세금

        if order_status == "접수":
            idx = len(self.order_info['item_code'].to_list())

            self.order_info.loc[idx, 'item_code'] = item_code
            self.order_info.loc[idx, 'item_name'] = item_name
            self.order_info.loc[idx, 'bns'] = order_bns
            self.order_info.loc[idx, 'origin_code'] = origin_ordno
            self.order_info.loc[idx, 'order_gubun'] = order_gubun
            self.order_info.loc[idx, 'trade_gubun'] = trade_gubun
            self.order_info.loc[idx, 'order_quan'] = order_quan
            self.order_info.loc[idx, 'signed_quan'] = signed_quan
            self.order_info.loc[idx, 'remained_quan'] = remained_quan
            self.order_info.loc[idx, 'order_info'] = ""
            print("self.order_info")
            print(self.order_info)

        elif order_status == "체결":

            if remained_quan == "0":
                idx = self.order_info.index[self.order_info['item_code'] == item_code]
                self.order_info = self.order_info.drop(index=idx)

 

위의 코드를 보면 Line 44에서는 미체결 잔량 데이터가 담긴 변수인   remained_quan  이 "0"인 경우라는 조건문을 생성한 후, 그 아래에서는   self.order_info  변수 내에서 해당 종목 코드(  item_code  )가 위치해 있는 인덱스 번호를 얻어오도록 하고 있다. 여기서 인덱스 번호를 구하는 코드의 구조가 이전 게시글에서 "접수" 내에서 인덱스 번호를 구하는 것(Line 27)과 다르게 되어 있음을 확인할 수 있다. 

아래의 예시를 살펴보도록 하자. 예를 들어 아래와 같은 데이터프레임이 있다고 했을 때, ①기존에 입력되어 있는 '005930'이라는 종목이 위치한 인덱스 번호를 구하는 방법과 ②새롭게 데이터를 입력할 인덱스 번호를 구하는 방법은 다음과 같다.

>>> df
  item_code  date
0    005930   NaN
1    066580   NaN

## 첫 번째 방법
index = df.index[df['item_code'] == '005930']

## 두 번째 방법
index = len(df['item_code'].to_list())	## 또는
index = len(df['item_code'])

 

여기서 첫 번째 방법이 이번 게시글에서 다루는 "체결" 데이터를 입력하기 위해 기존에 입력되어 있는 특정 변수의 인덱스 번호를 구하는 형태의 코드인 것이다. 간단하게 결론만 말해보자면 "접수"에서는 종목코드가 들어갈 칸을 새롭게 구하는 것이고 "체결"에서는 "접수"에서 입력된 종목코드 데이터의 위치를 구하여 그 데이터를 삭제하는 것이다. 여기서 데이터를 삭제하는 절차가 바로   drop()  메서드에 의해 이루어지는 것이다.

 

 


728x90

 

 

해치웠나?

물론 접수된 주문의 데이터를 입력하고, 해당 주문 건이 모두 체결됐을 때 해당 데이터를 삭제하는 기능 상의 코드는 모두 구현을 한 상태이긴 하지만, 모두 구현했을 리가 없다. 여기서부터는 개인적으로 원하는 기능들을 추가적으로 구현해내며 시스템 상의 부하를 줄이기 위한 부분도 조금은 고려를 해볼 수 있다.

이 내용은 특정 주문 데이터가 언제 언제 필요한지를 생각해보면 이해가 쉽다. 예를 들어, 매수 주문에 대해서만 수정을 할 예정이라면 "접수" 데이터에서 매수와 매도라는 데이터가 입력되어 있는 변수인   order_gubun  을 기반으로 order_gubun == "매수"인 경우에만 동작하도록 구현할 수 있으며, 그 반대의 경우에도 역시 동일한 로직에 의해 구현할 수 있다.

일단 지금까지 구현한 내용을 기반으로 해보면 주문이 접수됐을 때   self.order_info  변수 내에 주문 정보를 입력하고, 해당 주문이 모두 체결되었을 때(if remained_quan == "0"),   self.order_info  변수 내에서 주문 정보를 삭제하도록 했기 때문에 기능 상에는 아무런 문제가 없다. 이제 앞으로 정정 주문이나 취소 주문 등의 기능을 구현할 때에도   self.order_info  변수 내에서 원주문번호 데이터를 얻어다가 매도 정정 및 취소 주문 등을 실행할 수 있다. 더 나아가,   self.order_info  변수 내에 입력되어 있는 데이터를 기반으로 하여 tableWidget과 함께 연동되어 동작하도록 하는 기능을 구현할 수도 있다.

이제 다음 게시글에서는 self.order_info 변수를 기반으로 tableWidget과 함께 연동되어 동작하도록 하는 기능을 구현하는 방법에 대해 알아보고, 매도 정정 및 취소 주문의 방법에 대해서도 살펴보도록 하자.

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.