PYTHON/Back test

백테스팅 구축 (17) - 매도 전략 수정하기 ①

  • -

지난 게시글에서 매도 전략을 어떻게 수정할 것인지에 대한 로드맵을 설정했으니, 이번 게시글에서는 본격적으로 매도 전략을 수정해보도록 하자.

 

매도 변수 설정하기

매도 변수에서 설정해야 하는 변수는 수익률 변수와 각 수익률 별 매도 비율 변수이다. 즉, 5%에서 분할 매도할 비율과 10%에서 분할 매도할 비율 등을 사전에 설정해두어야 그를 바탕으로 매도를 진행하게 되며 더 나아가 추후에 매도 전략을 수정할 때에도 해당 변수만 수정해주면 되기 때문에 유지보수 측면에서도 더욱 편리하다.

아래와 같은 변수를  def __init__ 함수 아래에 제작해주도록 하자.  self.first_sellprofit 변수는 첫 번째 매도 시의 수익률을 의미하는 변수이며,  self.first_sellrate 변수는 첫 번째 매도 시의 분할 매도 비율에 해당한다. 그 아래에 있는  self.sec_sellprofit 변수는 두 번째 매도 시의 수익률,  self.third_sellprofit 변수는 세 번째 매도 시의 수익률에 해당한다. 또한 if 문을 통해서 분할 매도 비율들이 입력되어 있는  self.first_sellrate 와  self.sec_sellrate self.third_sellrate 변수 값의 총합이 1이 아니라면 분할 매도 비율 설정이 잘못되었다는 결과값을 출력하도록 했다. 

## 수익률 설정
self.first_sellprofit = 0.05
self.sec_sellprofit = 0.1
self.third_sellprofit = 0.15

## 분할 매도 비율 설정
self.first_sellrate = 0.2
self.sec_sellrate = 0.5
self.third_sellrate = 0.3

if self.first_sellrate + self.sec_sellrate + self.third_sellrate != 1:
	print("분할매도 비율 설정이 잘못되었습니다.")

 

 

sell() 함수 수정하기

앞서 제작했던 내용들을 바탕으로 sell 함수 내에서의 로직을 구축해보면 아래와 같은 구조로 구축할 수 있다. 

def sell(self):

    for row in self.df_account.itertuples():
    self.chart_data = self.load_chart_indate(self.yesterday, self.today, row[2])

        try:
            yester_ma5 = self.chart_data['MA5'].iloc[0]
            yester_ma20 = self.chart_data['MA20'].iloc[0]
            today_ma5 = self.chart_data['MA5'].iloc[1]
            today_ma20 = self.chart_data['MA20'].iloc[1]

            ## 첫 번쨰 수익률 조건
            if self.chart_data['close'].iloc[1] >= (row[3] * self.first_sellprofit):
                pass

            ## 두 번째 수익률 조건
            if self.chart_data['close'].iloc[1] >= (row[3] * self.sec_sellprofit):
                pass

            ## 세 번째 수익률 조건
            if self.chart_data['close'].iloc[1] >= (row[3] * self.third_sellprofit):
                pass

            ## 손절 조건
            if float(yester_ma5) > float(yester_ma20) and float(today_ma5) < float(today_ma20):
                pass

 

하지만 우리가 제작하고자 하는 데이터의 형태를 잘 생각해보면, 거래 이력 데이터 내에서 첫 번째 수익률을 달성했을 경우에 입력한 매도 데이터가 존재하는지 존재하지 않는지를 확인해보아야 한다. 왜냐하면 첫 번째 매도 시에는 [매도일자1] 구간에 데이터가 입력되므로, 우리는 [매도일자2]에 데이터가 없는 동시에 수익률이 10%에 달해야 하기 때문이다. 단순하게 수익률이 5% 이상인 경우에 데이터를 입력하게 된다면 [매도일자1]의 자리에만 데이터가 입력될 것이다. 아래의 표 중에서 첫 번째 줄에 있는 경우가 오류가 발생하면서 데이터들이 입력되는 경우(물론 오류가 없다고 출력되긴 하지만, 결과값을 보고서는 오류가 있다는 것을 깨닫게 되는 경우이다.)이고, 두 번째 경우가 오류 없이 입력되는 경우이다.

종목코드 매수일자 매도일자1 매도일자2 매도일자3 손절일자 수익
004170 20200103 20200104       XXX<XXX
004170 20200103 20200104 20200105 20200106 20200107 XXX,XXX

따라서 우리는 코드를 제작할 때, 단순 수익률의 기준 충족 여부 외에도 이전에 해당 수익률이 발생했을 때 매도했던 이력이 있다면 해당 구간에서는 매도를 진행하지 않는 방향으로 코드를 구축해야 한다.

 

 

데이터프레임의 접근 방법

데이터프레임의 경우에는 .iloc[]을 통해서 접근하고자 하는 데이터의 인덱스를 통해 관련 데이터를 이용할 수 있다. 예를 들어 아래와 같은 데이터가  dataframe 이라는 변수 안에 입력되어 있다고 가정해보도록 하자. 이 때, 하나하나의 데이터에 접근할 수 있는 방법은 바로 .iloc을 통해 0 또는 1의 값을 전달해준 후에, 다시 인덱싱을 통해 이용할 수 있다. 

     code      date  close
0  002030  20200101  10300
1  002040  20200101  20300

 

예를 들면  dataframe.iloc[0] 를 입력하면 code, date, close 모든 값들이 출력되겠지만  dataframe.iloc[0][0] 을 입력하면 002030 값만 출력되고,  dataframe.iloc[0][1] 을 입력하면 20200101만 출력된다. 이처럼 우리는  self.df_account 변수 또는  self.tracking_data 변수 안에 입력되어 있는 값에 접근함으로써 매도 여부를 확인할 수 있다.

>>> dataframe.iloc[0]
code       002030
date     20200101
close       10300
Name: 0, dtype: object

>>> dataframe['code'].iloc[0]
'002030'

>>> dataframe.iloc[0][0]
'002030'

>>> dataframe.iloc[0][1]
'20200101'

>>> dataframe.iloc[0][2]
'10300'

 

 


728x90

 

 

데이터 입력의 근간이 될 거래 현황 변수를 수정하자

위와 같은 방식으로 데이터에 접근하기 위해서는 첫 번째 매도와 두 번째 매도, 세 번째 매도를 구분할 수 있는 칼럼이 있어야 한다. 일단 이동평균선 데이터는 나중에 다시 분석하든지 하고, 거래 현황에서는 매수 가격과 매수 수량, 매도 가격과 매도 수량 등 단순한 거래 이력 데이터만 확인하도록 하자. 데이터프레임의 형태가 되게 복잡해보이긴 하지만, 그래도 별 방법은 없다. 백테스팅 과정에 있어서 필요한 데이터들이기 때문이다.

실제 거래에서 알고리즘 전략을 사용할 때에는 이렇게까지 복잡한 데이터프레임과 복잡한 절차들이 필요하지 않다. 보유 종목 데이터를 키움증권 Open API를 통해서 실시간으로 받아올 수 있고,  while 문을 통해서 특정 종목의 수익률이 몇% 이상이라면 자동으로 매도 주문을 실행하도록 하는 함수만 제작해주면 되기 때문이다.

# 기존의 데이터
self.tracking_data = {'code':[], 'buy_date':[], 'buy_price':[], 'buy_value':[], 'sell_date':[], 'sell_price':[], 'sell_value':[], 'profit':[],
                      'ma5_buy':[], 'ma10_buy':[], 'ma20_buy':[], 'ma60_buy':[], 'ma120_buy':[],
                      'ma5_sell':[], 'ma10_sell':[], 'ma20_sell':[], 'ma60_sell':[], 'ma120_sell':[]}
self.df_tracking_data = pd.DataFrame(self.tracking_data, columns=['code', 'buy_date', 'buy_price', 'buy_value', 'sell_date', 'sell_price', 'sell_value', 'profit',
                                                                  'ma5_buy', 'ma10_buy', 'ma20_buy', 'ma60_buy', 'ma120_buy',
                                                                  'ma5_sell', 'ma10_sell', 'ma20_sell', 'ma60_sell', 'ma120_sell'])
                                                                  
# 수정 후 데이터
self.tracking_data = {'code':[], 'buy_date':[], 'buy_price':[], 'buy_quantity':[], 'buy_value':[],
                      'f_sell_date':[], 'f_sell_price':[], 'f_sell_quantity':[], 'f_sell_value':[], 'f_profit':[],
                      's_sell_date':[], 's_sell_price':[], 's_sell_quantity':[], 's_sell_value':[], 's_profit':[],
                      't_sell_date':[], 't_sell_price':[], 't_sell_quantity':[], 't_sell_value':[], 't_profit':[],
                      'n_sell_date':[], 'n_sell_price':[], 'n_sell_quantity':[], 'n_sell_value':[], 'n_profit':[]}
self.df_tracking_data = pd.DataFrame(self.tracking_data, columns=['code', 'buy_date', 'buy_price', 'buy_quantity', 'buy_value',
                                                                  'f_sell_date', 'f_sell_price', 'f_sell_quantity', 'f_sell_value', 'f_profit',
                                                                  's_sell_date', 's_sell_price', 's_sell_quantity', 's_sell_value', 's_profit',
                                                                  't_sell_date', 't_sell_price', 't_sell_quantity', 't_sell_value', 't_profit',
                                                                  'n_sell_date', 'n_sell_price', 'n_sell_quantity', 'n_sell_value', 'n_profit',])

 

 


728x90
반응형
Contents

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

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