PYTHON/Back test

2.4 백테스팅하기 - 종목 선정하기 (2)

  • -

 

 

[파일명 : algorithm_1] 종목별 거래량과 거래대금 불러오기

종목별로 사전에 설정한 선정 기준을 충족시키는지 아닌지 그 여부를 판단하기 위해서는 반드시 종목별 거래량과 거래대금, 그리고 종가와 시가 고가 저가 등을 가져와야 한다. 그 방법은 크게 두 가지로 나뉘는데, 데이터프레임에 조건을 걸어 해당 조건을 충족시키는 값을 가져오는 것과 특정 열의 데이터를 모두 불러와서 리스트 형태로 저장한 후 인덱싱을 통해 접근하는 방법이다.

##############################################
#### 데이터 변수명이 __day_dataframe일 경우 ####
##############################################

self.today = 20210104

## 첫째, 조건을 설정해서 값을 가져오는 방법
_today_volume = int(_day_dataframe.volume[(_day_dataframe['date'] == self.today)].to_list()[0])
_today_trade_volume = int(_day_dataframe.tvolume[(_day_dataframe['date'] == self.today)].to_list()[0])

## 둘째, 인덱스를 가져와서 값을 가져오는 방법
_today_index = int(_day_dataframe.index[(_day_dataframe['date'] == self.today)].to_list()[0])
__today_data = (_day_dataframe.iloc[_today_index]).to_list()

 

여기서 첫 번째 방법의 경우에는 _today_volume과 _today_trade_volume 등과 같은 변수들을 하나하나 지정해주고 하나하나 제작해주어야 하지만 데이터의 순서가 변경되어도 오류가 발생하지 않고 데이터를 불러올 수 있다는 장점이 있다. 다만 두 번째 방법의 경우에는 코드 제작이 비교적 단순하고 인덱싱을 통해 간단하게 데이터에 접근할 수 있다는 장점이 있지만, 데이터의 순서가 변경될 경우 잘못된 데이터를 불러올 수 있다는 단점이 있다. 아래의 사진 중 좌측의 사진이 첫 번째 방법으로 불러오는 경우의 로직이고, 우측 사진이 두 번째 방법으로 데이터를 불러오는 경우의 로직이다. 

(좌) 첫 번째 방법      (우) 두 번째 방법

다시 말해, 첫 번째 방법은 칼럼명과 조건 모두 명확하게 입력했기 때문에 맨 위에 있는 칼럼인 code, date, open 등과 같은 칼럼의 위치들이 변경되어도 상관없이 정해진 칼럼명에 일치하는 값을 가져오기 때문에 문제가 발생하지 않는다. 다만 두 번째 방법의 경우에는 해당 열의 데이터를 리스트 형태로 불러오기 때문에 위의 사진에 따르면 [20210104, 19750, 19900, 18850, 19100, 719076, 1374351600]으로 가져오기 때문에 시가에 접근하기 위해서는 [1]이라는 인덱싱을 사용하면 된다. 하지만 추후 데이터를 새롭게 저장하는 과정에서 open과 high의 위치가 변경된다면 [1]이라는 인덱싱을 통해 얻어올 수 있는 값은 시가였던 19750이 아닌 그 오른쪽의 high인 19900을 가져온다는 것이다. 만약 계속해서 변경될 자료라면 첫 번째 방법을, 절대 그럴 일 없도록 주의하겠다면 두 번째 방법을 사용하면 된다.

그렇다면 이제 기존에 설정했던 종목 선정 기준인 거래량 기준과 거래대금 기준을 먼저 살펴본 후, 상승률 기준을 적용하도록 하자. 상승률 기준은 계산하는 것이 상당히 간단해보이지만 실상은 조금 복잡하기 때문에 나중에 적용하는 것이다. 
※ 거래량과 거래대금 변수 설정 코드 : 5, 6번째 줄
※ 거래량과 거래대금 조건문 코드 : 8번째 줄

def select_item(self):
    for i in globals():
        if str(i)[0] == 's' and str(i)[-1] == '0':
            _day_dataframe = globals()[i]
            _today_volume = int(_day_dataframe.volume[(_day_dataframe['date'] == self.today)].to_list()[0])
            _today_trade_volume = int(_day_dataframe.tvolume[(_day_dataframe['date'] == self.today)].to_list()[0])
            
            if _today_volume >= 5000000 and _today_trade_volume >= 20000000000:
                print("조건 충족")

 

 

 


728x90

 

 

[파일명 : algorithm_1] 당일 고가와 전일 종가 가져오기

우리는 현재 데이터를 가져오는 방식이   self.today  라는 값을 조건으로 설정해서 가져오고 있었는데, self.yesterday라는 변수는 따로 설정하지 않았다. 따라서 self.today라는 조건을 걸어 해당 데이터열이 위치한 인덱스를 구해온 후에, 그 인덱스 값에서 1을 변동시켜 전일자의 데이터를 가져오는 방법을 사용해야 한다는 것이다. 

 

def select_item(self):
    for i in globals():
        if str(i)[0] == 's' and str(i)[-1] == '0':
            _day_dataframe = globals()[i]
            _today_volume = int(_day_dataframe.volume[(_day_dataframe['date'] == self.today)].to_list()[0])
            _today_trade_volume = int(_day_dataframe.tvolume[(_day_dataframe['date'] == self.today)].to_list()[0])
            
            if _today_volume >= 5000000 and _today_trade_volume >= 20000000000:
                _today_index = int(_day_dataframe.index[(_day_dataframe['date'] == self.today)].to_list()[0])
                _yester_index = _today_index + 1
                _yester_data = (_day_dataframe.iloc[_yester_index]).to_list()
                print("today:", self.today)
                print("_yester_data:", _yester_data)
                print("1번:", _yester_data[1])
                print("2번:", _yester_data[2])
                print("3번:", _yester_data[3])
                
                
>>>>>>>>
조건 충족
today: 20210104
_yester_data: [None, '20201230', '62300', '63000', '61900', '62400', '1740601', '108613502400']
1번: 20201230
2번: 62300
3번: 63000

맨 아래의 결과물을 보면 today 변수에는 20210104가, _yester_data[1] 변수에는 20201230이 입력되어 있다. 다시 말해, 20210104를 기준으로 하루 전에는 20201230이라는 날이 있다는 것이다. 왜냐하면 20201231과 20210101, 20210102, 20210103은 모두 휴일이기 때문에 데이터가 없는 것이다.

그렇다면 이제 20210104를 기준으로 전 날이 20201230이라는 것을 확인했으니, 일자가 20201230인 데이터열의 종가를 얻어와보도록 하자.
※ 수정된 코드 : 10번째 줄(_yester_index를 없애고 _yester_data의 대괄호 안에 _today_index + 1을 입력했음)
※ 추가된 코드 : 13, 14번째 줄

def select_item(self):
    for i in globals():
        if str(i)[0] == 's' and str(i)[-1] == '0':
            _day_dataframe = globals()[i]
            _today_volume = int(_day_dataframe.volume[(_day_dataframe['date'] == self.today)].to_list()[0])
            _today_trade_volume = int(_day_dataframe.tvolume[(_day_dataframe['date'] == self.today)].to_list()[0])
            
            if _today_volume >= 5000000 and _today_trade_volume >= 20000000000:
                _today_index = int(_day_dataframe.index[(_day_dataframe['date'] == self.today)].to_list()[0])
                _yester_data = (_day_dataframe.iloc[_today_index + 1]).to_list()
                _yesterday = _yester_data[1]

                _yester_close = int(_day_dataframe.close[(_day_dataframe['date'] == _yesterday)].to_list()[0])
                _today_high = int(_day_dataframe.high[(_day_dataframe['date'] == self.today)].to_list()[0])

 

 

[파일명 : boss] 상승률 계산 함수 제작하기

내용을 설명하기 전에 앞서, 상승률을 계산하는 건 algorithm_1 파일에서만 사용할 것은 아니니 다시 boss 파일 내에서   class cal_function()   내에서   def cal_vix()  함수를 제작해서 코드를 작성하도록 하자. 앞서 설명했듯이, 상승률을 계산하는 데에는 당일 고가와 전일 종가 데이터 두 개만 필요하다. 따라서   def cal_vix()  에서 두 개를 인자로 받아오자. 상승률을 계산하는 것은 당일 고가에서 전일 종가를 뺀 그 차이값을 전일 종가로 나누면 된다.

예를 들어 전일 종가가 1,000원인데 당일 고가가 1,200원이라면, 당일 고가(1,200원)에서 전일 종가(1,000원)을 뺀 다음에 그 차이값(200원)을 전일 종가(1,000원)으로 나누어주면 상승률(0.2)이 나온다.

def cal_vix(self, _t_high, _y_close):
    dif = _t_high - _y_close
    vix = dif / _y_close
    return vix

 

 

[파일명 : algorithm_1] 상승률 조건 추가하기

앞서 def __init__ 내에서 boss = tradesystem(), calf = cal_function()으로 제작해주었는데 현재 종목을 선정하는 함수인 def select_item()은 def __init__()과는 다른 함수이기 때문에 boss와 calf를 사용할 수 없다. 따라서 def __init__ 하단에 있는 boss와 calf 앞에 각각 self.를 붙여주도록 하자.
※ 수정된 코드 : 6, 7, 15, 16, 21번째 줄 (calf와 boss 앞에 모두 self.를 추가해주었음)

from boss import tradesystem
from boss import cal_function

class algo_1():
    def __init__(self, kospi_data, kosdaq_data, item_data):
        self.boss = tradesystem()
        self.calf = cal_function()
        self.kospi_data = kospi_data
        self.kosdaq_data = kosdaq_data
        self.item_data = item_data

        self._load_day_data()

        ## 날짜 for 문 코드 구축하기
        start_date = self.boss.lineEdit_2.text()
        end_date = self.boss.lineEdit_3.text()
        self.today = start_date

        while self.today <= end_date:
            self.select_item()
            self.today = self.calf.cal_addday(self.today, 1)

 

이제 다시 def select_item() 함수로 돌아와서 self.calf를 입력하면 boss 파일 내에 있는 class cal_function 클래스의 def cal_vix() 함수를 사용할 수 있게 된다. 따라서 vix값이 0.15이상인 경우를 조건문으로 설정하게 되면, 당일 고가의 상승률이 전일 종가 대비 15% 이상이었던 종목들을 모두 골라내게 된다. 
※ 추가된 코드 : 16~19번째 줄

def select_item(self):
    for i in globals():
        if str(i)[0] == 's' and str(i)[-1] == '0':
            _day_dataframe = globals()[i]
            _today_volume = int(_day_dataframe.volume[(_day_dataframe['date'] == self.today)].to_list()[0])
            _today_trade_volume = int(_day_dataframe.tvolume[(_day_dataframe['date'] == self.today)].to_list()[0])

            if _today_volume >= 5000000 and _today_trade_volume >= 200000000:
                _today_index = int(_day_dataframe.index[(_day_dataframe['date'] == self.today)].to_list()[0])
                _yester_data = (_day_dataframe.iloc[_today_index + 1]).to_list()
                _yesterday = _yester_data[1]

                _yester_close = int(_day_dataframe.close[(_day_dataframe['date'] == _yesterday)].to_list()[0])
                _today_high = int(_day_dataframe.high[(_day_dataframe['date'] == self.today)].to_list()[0])

                vix = float(self.calf.cal_vix(_today_high, _yester_close))

                if vix >= 0.15:
                    print("조건 충족")

 

여기까지 제작한 종목 선정 코드가 바로 거래량이 500만주 이상이고 거래대금이 200억원 이상이며, 당일 고가 상승률이 전일 종가 대비 15% 이상 상승한 종목을 골라내는 코드에 해당한다. 

 

 


728x90
반응형
Contents

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

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