배당수익률을 이용한 투자전략 백테스트
본문 바로가기
파이썬으로 만든 것들/배당투자를 위한 도구

배당수익률을 이용한 투자전략 백테스트

by Squat Lee 2022. 11. 8.

 

이전에 배당수익률을 이용해서 투자하는 전략을 파이썬으로 구현해 보았다.

 

2022.10.25 - [취미로 하는 파이썬/투자 실험실 with 파이썬] - 파이썬으로 주식 분석 프로그램 툴 만들기(시가배당률 이용)

 

파이썬으로 주식 분석 프로그램 툴 만들기(시가배당률 이용)

주식은 싸게 사서 비싸게 팔면 된다. 아주 간단한 원리다. 하지만 싸다는 기준과 비싸다는 기준은 너무나 모호하다. 아무도 알려주지 않는다. 책에서 나름 똑똑하다는 사람이 여러 기준을 알려

dotsnlines.tistory.com

 

이 투자 방법이 정말로 수익이 나는지 궁금했다.

 

그래서 파이썬을 이용해서 구현해 보았다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import sqlite3
import pandas as pd
import datetime
 
con = sqlite3.connect('krx_data.db')
 
def work_day(day): #영업일로 바꾸는 함수
    for i in range(5):
        #내가 지정한 기준일이 영업일이 아니면, str 형식의 날짜를 날짜형식으로 바꾼 후 timedelta를 이용해서 1일씩 더하기
        day = datetime.datetime.strptime(day, "%Y%m%d"+ datetime.timedelta(days=i)
        day = str(day)[:4+ str(day)[5:7+ str(day)[8:10#sql문에 넣기위해 date형식을 str 형식으로 변환
        df = pd.read_sql("SELECT 일자 FROM  fundamental WHERE 일자 = " + day, con)
        #해당 날짜의 데이터가 없으면 Dataframe은 [] 표시가 되기 때문에 개수를 통해서 날짜 유무를 판단
        if len(df) != 0:
            break #데이터가 있으면 for문을 중단하고 나가기
    return day
 
def back_test_period(today, ticker): #백테스트할 5년 기간동안 Data
    start = str(int(today[:4]) - 5+ today[-4:] #5년전 날짜 구하기
    end = today #기준일
    #지정한 기간동안의 데이터를 가져오기
    df = pd.read_sql("SELECT 일자, code, 종목명, DIV, DPS FROM fundamental WHERE code = '" + ticker + "'" +
                     " AND 일자 >= " + start + " AND 일자 < " + end, con)
    return df
 
#백테스트로 선별한 종목의 3년동안 최고수익률, 최저수익률 구하기
def result(code, day):
    li_result = []
 
    today = work_day(day) #영업일이 아니면 영업일로 바꾸기
    r_day = str(int(today[:4]) + 3+ today[-4:] #기준일로부터 3년 되는 날
 
    # 오늘부터 3년되는 날까지 데이터 가져오기
    r_df = pd.read_sql("SELECT 일자, code, 종목명, 종가 FROM fundamental WHERE code = '" + code + "'" +
                       " AND 일자 >= " + today + " AND 일자 < " + r_day, con)
 
    name = r_df['종목명'].iloc[0#종목명 가져오기
 
    r_max = r_df['종가'].max() #3년내 최대주가
    r_max_df = r_df[r_df["종가"== r_max] #최대주가일때 데이터프레임
    r_max_day = r_max_df['일자'].iloc[0#최대주가일때 날짜
 
    r_min = r_df['종가'].min() #3년내 최소주가
    r_min_df = r_df[r_df["종가"== r_min] #최저가일때 데이터프레임
    r_min_day = r_min_df['일자'].iloc[0#최저가일때 날짜
 
    li_result.append([today, code, name, r_max_day, r_max, r_min_day, r_min])
    # 기준일, 종목코드, 종목명, 최고가일, 최고가, 최저가일, 최저가
 
    return li_result[0#2중리스트가 되고, 백테스트에서 리스트로 담으면 3중코드가 되기 때문에 Return값에서 리스트 요소만 빼주기
 
# 백테스트 기간동안 반복해서 실행하기
total_li = []
for y in range(20082022):
    for m in range(113):
        # 기준일로부터 해당기간 동안의 DIV, EPS 조건 Data 가져오기
        if m < 10:
            m = '0' + str(m)
        else:
            m = str(m)
        today = str(y) + m + '01' #기준일 지정
        today = work_day(today) #영업일 구하기
        today_df = pd.read_sql("SELECT 일자, code, 종목명, DIV, EPS, DPS, 종가 FROM fundamental WHERE 일자="
                               +today+" AND DIV > 3 AND EPS > 0", con)
 
        # 오늘 날짜 기준으로 Data를 분석하기
        count = 0 #몇개의 코드가 남았는지 보여주기 위해서 변수 초기화
        for code in today_df['code']: #일정한 조건의 Dataframe에서 code를 하나씩 확인해서 조건에 맞는 코드 고르기
            try:
                print(today, len(today_df['code']) - count) #테스트가 얼마나 진행되었는지 보여주기
                t_df = today_df[today_df['code'== code]
                name = t_df['종목명'].iloc[0# 종목명
                t_div = t_df['DIV'].iloc[0]  # 기준일자의 DIV
                price = t_df['종가'].iloc[0# 기준일자의 주가
 
                df = back_test_period(today, code) #기준일로부터 백테스트 기간동안 Dataframe
                m = int(len(df['DPS']) / 2# 백테스트 기간 중간의 DPS
                #DPS의 증가확인. 최초,최종비교, 중간,최종 비교
                if df['DPS'].iloc[0<= df['DPS'].iloc[-1and df['DPS'].iloc[0!= 0 and \
                        df['DPS'].iloc[m] <= df['DPS'].iloc[-1]:
                    if df['DIV'].max() * 0.9 < t_div: # 최고 DIV의 90% 이상이면 리스트에 넣기
                        temp_li = result(code, today)
                        temp_li.append(price)
                        temp_li.append(t_div)
                        total_li.append(temp_li)
 
            except:
                pass
            count += 1
        print(total_li)
    print(total_li)
 
total_df = pd.DataFrame(data=total_li, columns=['투자일자''CODE''종목명''최고가일''최고가''최저가일''최저가''기준일가격''배당률'])
total_df['예상수익'= total_df['최고가'- total_df['기준일가격']
total_df['예상수익률'= total_df['예상수익'/ total_df['기준일가격']
print(total_df)
total_df.to_excel('배당수익률을 이용한 백테스트.xlsx')
cs

 

2008년부터 2021년까지 매월 1일 기준으로 조건에 맞는 종목을 골라낸다.

 

조건은 시가배당률이 3%가 넘고, 수익이 나는 회사를 먼저 고른다. 그리고 나서 그 회사의 과거 5년 동안 가장 높은 배당률과 기준일의 배당률을 비교해서 기준일의 배당률이 과거 5년동안 가장 높았던 배당률의 90% 이상 되는 종목을 다시 선별한다.

 

그리고 과거 5년 전에 배당을 지급했고, 현재 배당과 비교해서 배당금이 줄어들지 않는 회사를 고른다.

 

선별된 종목의 향후 3년치 수익률을 구해서 최고 주가, 최저 주가를 표시하고, 최고주가 기준으로 예상 수익률을 구했다.

 

백테스트 결과

유리하게 보이도록 예상수익을 최고가 기준으로 구한건 있지만, 그래도 다행히 수익이 마이너스를 기록한 종목은 하나도 없었다.

 

하지만, 실제 투자에서는 투자 시기에 따라서 손실이 발생할 수 도 있을 것이다.

 

총 3294개의 종목을 선별해서 수익률을 추적하였으며, 최고수익률을 평균한 값은 88%이며, 최고 수익률까지 걸린 기간은 평균 563일이다. 2년이 채 걸리지 않는다.

배당수익률을 이용한 백테스트(DIV3이상,5년내90%이상,3년수익예상).xlsx
0.35MB

 

 

배당을 꾸준히 지급했는지, 과거 5년동안 배당금이 줄지는 않았는지, 아니면 계속 늘었는지 좀 더 많은 항목까지 고려해서 검토하지는 못했다.

 

하지만, 배당을 지급하는 회사를 투자한다는 것은 주가가 떨어져도 배당이 나오기에 좀 더 기다릴 수 있는 여유가 생긴다. 그리고 배당금을 추가적인 수익으로 확보하니 수익률이 더 높아지는 효과도 있다.

 

728x90
반응형

댓글