PYTHON/AUTO TRADE SYSTEM

[자동 매매 시스템 구축하기] 알고리즘 구축하기 (6) - 알고리즘 구현하기 ①

  • -

이번 게시글부터는 사전에 만들어 둔 차트 데이터를 기반으로 매수 가격과 매도 가격을 추출하는 알고리즘을 구현할 것이다.

 

 

알고리즘 디버깅

현재 제작하고 있는 알고리즘이 정상적으로 동작하는지 확인하는 방법은 크게 두 가지가 있다. 바로 사전에 MySQL 내에 저장해둔 데이터베이스를 불러와서 사용하는 방법과 키움증권 Open API 코드가 구현되어 있는 main.py 파일 내에서 우리가 원하는 종목의 차트 데이터를 바로 전달해준 후에 계산 과정을 보는 방법이다.

첫 번째 방법의 경우 데이터가 저장되어 있는 시점까지만을 대상으로 알고리즘을 확인할 수 있다는 단점이 있지만 로그인하지 않아도 되어 시간을 단축시킬 수 있다는 장점이 있다. 두 번째 방법의 경우 디버깅을 할 때마다 로그인을 해야 하고 차트 데이터를 불러오는 시간이 소요된다는 단점이 있지만, 상시 정확한 데이터를 기반으로 매수가와 매도가를 계산할 수 있다는 장점이 있다.

물론 우리는 궁극적으로는 두 가지 방법을 모두 사용할 것인데, 가장 먼저 알고리즘을 구현할 때에는 첫 번째 방법을 사용하게 된다. 왜냐하면 주어진 차트 데이터를 기반으로 가장 기본적인 매수 가격과 매도 가격을 구현할 수 있는 기능을 갖고 있는지만 확인하면 되기 때문이다. 

 

 

어떻게 해?

방법은 단순하다. 혹시 main.py 파일 내에서 아래와 같은 코드를 본 적이 있는가? 

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = tradesystem()
    myWindow.show()
    app.exec_()

 이 부분이 바로 프로그램을 실행시키라는 의미를 갖는 코드인데, 이와 같은 구조의 코드를 알고리즘 파일 내에서도 구현해준다면 우리는 얼마든지 main.py를 통하지 않고도 알고리즘을 곧바로 테스트해볼 수 있다.
※ Line : 9, 10

"""algorithm_1.py"""
class algo1:

    def __init__(self, min5_data):
        self.min5_data = min5_data
        pass


if __name__ == "__main__":
    pass

 

이 때, 우리는 algo1에 대해 5분봉 차트 데이터를 전달해줘야 하는데, 사전에 저장해두었던 차트 데이터를 불러오는 방법은 real_sql()이다. 이전에 차트 데이터를 조회한 후에 데이터베이스에 저장할 때는 to_sql을 사용했으니, 지금은 read_sql를 사용하면 저장해두었던 차트 데이터를 그대로 불러올 수 있다. 물론 pandas 모듈과 DB와 연결할 수 있는 매개체가 되는 manage_db 파일을   import  해줘야 한다.

read_sql을 사용하기 위해서는 우리가 저장했던 데이터의 테이블명을 전달해줘야 한다. 이전에 "005930" 종목에 대한 차트 데이터를 저장할 때, 해당 데이터의 테이블은 "s005930"으로 저장했던 것이 기억날 것이다. 마찬가지로 "000020" 종목은 "s000020"이며, "066570"은 "s066570"이라는 이름으로 저장되어 있다. 그렇다면 우리는 이와 관련하여, 종목코드를 하나의 변수로 지정하고 해당 종목코드의 테이블명으로 저장되어 있는 데이터베이스를 가져오는 방식으로 구현해보자.
※ Line : 2, 3, 11~14

"""algorithm_1.py"""
import pandas as pd
import manage_db

class algo1:

    def __init__(self, min5_data):
        self.min5_data = min5_data
        pass

if __name__ == "__main__":
    item_code = "005930"
    min5_data = pd.read_sql(f"SELECT * FROM s{item_code}", manage_db.engine_5min)
    algo1(min5_data)

 

13번째 줄의 코드를 보면 (f"")로 감싸져 있는데, 이는 코드를 조금 더 간편하게 작성할 수 있도록 하는 수단이라고 봐도 된다. 저걸 사용하지 않고 싶다면, 아래의 Line 6~7과 같이 제작해도 기능 상에는 문제가 없다.

## 기본
item_code = "005930"
min5_data = pd.read_sql(f"SELECT * FROM s{item_code}", manage_db.engine_5min)

## 사용례
item_code = "005930"
min5_data = pd.read_sql("SELECT * FROM s" + item_code, manage_db.engine_5min)

 

 


728x90

 

 

차트 데이터를 쓰자니 뭔가 이상하다.

item_code  변수에 "005930"을 입력한 후 def __init__(self): 하단부에서 self.min5_data를 출력해보니 아래와 같이 출력되었다.

                 time     now    open    high     low
0      20220720153000  +15040  +15040  +15040  +15040
1      20220720151500  +15045  +15050  +15070  +15045
2      20220720151000  +15045  +15060  +15065  +15045
3      20220720150500  +15065  +15065  +15080  +15060
4      20220720150000  +15065  +15045  +15075  +15030
...               ...     ...     ...     ...     ...
20264  20210701092000  -29055  -29090  -29115  -29050
20265  20210701091500  -29085  -29090  -29100  -29055
20266  20210701091000  -29085  -29050  -29110  -29025
20267  20210701090500  -29055  -29115  -29145  -29045
20268  20210701090000  -29120  -29280  -29285  -29115

자세히 보면, +와 -가 혼재되어 있다는 사실을 확인할 수 있다. 이게 왜 이상하냐면, 기본적으로 값의 비교를 위해서는 자료형이 숫자로만 구성되어 있어야 하기 때문이다. 기본적으로 키움증권 Open API는 차트 데이터를 반환할 때, 값이 이전보다 상승했으면 +를 붙여서 전달하고 이전보다 하락했으면 -를 붙여서 전달한다. 하지만 우리에게 부호는 불필요한 데이터다. 따라서 우리는 차트 데이터를 저장할 때 데이터가 숫자만 입력되도록 변경해줘야 한다. 아래의 예시를 살펴보자.

 

>>> a = "+30000"
>>> type(a)
<class 'str'>
>>> int(a)
30000

>>> b = "-30000"
>>> type(b)
<class 'str'>
>>> int(b)
-30000
>>>

a에 "+30000"이라는 값을 입력한 후에, 그 값을 숫자형을 의미하는 int() 자료형으로 변환시키니 30000이라는 값이 나왔다. 정상적으로 동작하는 것이다. 다만 b에 "-30000"을 입력한 후에 이를 숫자형으로 변환시키니 -30000이라는 값이 출력되었다. 만약 주가가 고가가 30000원이고 저가가 29,000원인 날이 있다고 할 때, 키움증권 데이터에 의하면 고가는 30,000원이며 저가는 -29,000원이 되는 것이다. 이 실질적으로 둘 간의 가격 변동폭은 1,000이지만 -29,000원을 사용하게 되면 59,000원이라는 가격 변동폭을 갖게 되는 문제가 발생한다는 것이다.

다시 main.py로 돌아가서, opt10080() 함수 내 코드 중 .strip(" ") 부분에 +와 -를 추가해서 부호를 함께 삭제한 후에 데이터를 입력하도록 코드를 수정해주자. 그 후에 차트를 다시 조회하고 다시 저장한 후에, 알고리즘 파일로 넘어와서 결과 데이터를 확인해보자.
※ Line : 6~10

    """데이터 처리 구간"""
    def opt10080(self, TrCode, RecordName):
        data_len = self.__getrepeatcnt(TrCode, RecordName)

        for index in range(data_len):
            time = self.__getcommdata(TrCode, RecordName, index, "체결시간").strip(" ")
            now = self.__getcommdata(TrCode, RecordName, index, "현재가").strip("+- ")
            open = self.__getcommdata(TrCode, RecordName, index, "시가").strip("+- ")
            high = self.__getcommdata(TrCode, RecordName, index, "고가").strip("+- ")
            low = self.__getcommdata(TrCode, RecordName, index, "저가").strip("+- ")
            # yclose = self.__getcommdata(TrCode, RecordName, index, "전일종가").strip("+- ")
            # print(f"[{time}] NOW:{now}, OPEN:{open}, HIGH:{high}, LOW:{low}, YCLOSE:{yclose}")

            self.chart_data['time'].append(time)
            self.chart_data['now'].append(now)
            self.chart_data['open'].append(open)
            self.chart_data['high'].append(high)
            self.chart_data['low'].append(low)

 

>>> print(self.min5_data)
>>>
                 time    now   open   high    low
0      20220720153000  15040  15040  15040  15040
1      20220720151500  15045  15050  15070  15045
2      20220720151000  15045  15060  15065  15045
3      20220720150500  15065  15065  15080  15060
4      20220720150000  15065  15045  15075  15030
...               ...    ...    ...    ...    ...
20264  20210701092000  29055  29090  29115  29050
20265  20210701091500  29085  29090  29100  29055
20266  20210701091000  29085  29050  29110  29025
20267  20210701090500  29055  29115  29145  29045
20268  20210701090000  29120  29280  29285  29115

 

 


728x90
반응형
Contents

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

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