퀀트투자 백테스트 코드 (저PBR X 저DPS)
본문 바로가기
파이썬으로 만든 것들/퀀트투자

퀀트투자 백테스트 코드 (저PBR X 저DPS)

by Squat Lee 2021. 12. 14.

 

강환국 님의 '할수있다 퀀트투자'를 읽고나서 파이썬으로 만들어 보았다.

 

여러 조건을 백테스트 해 보았고, 이 조건이 가장 괜찮았다.

 

2003년부터 매월 11월 4일 즈음에 매수를 하고, 1년 후 매도 후 다시 매수하는 방법으로 17년간 백테스틀 해 보았다.

 

수익률이 8652% 즉, 원금의 86배가 된다. 하지만 문제는 손실이 많이 발생하는 해도 있다는 사실이다. 복리 수익률로 실컷 자금을 불렸지만, -42% 손실이 발생하면 정말 견디기 힘들 것 같다.

 

그래서 11월과 더불어 2월에도 분산해서 투자하는 방법을 생각했다. 그러니 가장 손실이 많이 발생한 해는 -1%로 견딜만한 수준이 되었다. CAGR도 11월만 하면 30%이지만, 2월까지 같이 하더라도 29%로 차이가 거의 없다.

 

저 PER, 저 PBR, 저 PER X 저 PBR, 고 DIV(배당수익률) 등 여러 케이스를 해 보았지만, 이 조건이 제일 괜찮다.

 

신기하게도 저 PBR X 저 DPS 가 왜 수익이 좋게 나온지는 나도 잘 모르겠다. DIV(배당수익률)을 한다는 것이 실수로 DPS(주당 배당금)으로 했는데, 수익이 좋게 나왔다. 내 논리로는 설명이 되지 않지만, 사실이 이러니깐 이렇게 실제 투자를 시작했다.

 

코드를 보면 알겠지만, 거래량이 없는 종목은 제외하였고, 주식수가 변동된 것은 보수적으로 보정해 주었다. 

 

그럼에도 불구하고 실제 투자에서는 변수가 발생한다. 하지만, 큰 흐름에 영향을 줄 수준은 아닌 것 같다.

 

 

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from pykrx import stock
import pandas as pd
import numpy as np
import os
import time
 
# 백테스트 할 날짜를 생성하기
def make_date_list(m, d):
    date_list = []
    for y in range(20032021):
        day = str(y) + str(m) + str(d)
        b_day = stock.get_nearest_business_day_in_a_week(date=day) #휴일이면 근처의 영업일로 변경
        date_list.append(b_day)
    return date_list
 
 
# 연도별 수익률 구하기
def row_pbr_dps(date, date2):
    codes = stock.get_market_ticker_list(date, market='ALL')
    corp = []
    for code in codes:
        name = stock.get_market_ticker_name(code)
        corp.append([code, name])
    df1 = pd.DataFrame(data=corp, columns=['code''종목명'])
    df1 = df1.set_index('code')
 
    df_f = stock.get_market_fundamental_by_ticker(date=date, market='ALL')  # PER, PBR, DIV,... : KRX 우선가져오기
    df_c = stock.get_market_cap_by_ticker(date=date, market='ALL')  # 종가
 
    df_c2 = stock.get_market_cap_by_ticker(date2, market='ALL')  # 1년 후 종가
 
    time.sleep(1)
 
    df_c2 = df_c2[['종가''상장주식수']]
 
    df = pd.merge(df1, df_c, left_index=True, right_index=True)
    df = pd.merge(df, df_f, left_index=True, right_index=True)
    df = pd.merge(df, df_c2, left_index=True, right_index=True)
 
    df = df[['종목명''종가_x''상장주식수_x''PBR''DPS''종가_y''상장주식수_y''거래량']]
    df.columns = ['종목명''종가''상장주식수''PBR''DPS''1년후종가''1년후상장주식수''거래량']
    df['상장주식수변동'= df['1년후상장주식수'- df['상장주식수']
 
    df = df[df['PBR'> 0]  # PBR 0이상만 구하기
    df['pbr_rank'= df['PBR'].rank()
 
    df = df[df['DPS'> 0]
    df['dps_rank'= df['DPS'].rank()
 
    df['pbr_dps'= df['pbr_rank'+ df['dps_rank']
    df['pbr_dps_rank'= df['pbr_dps'].rank()
    df = df.sort_values(by='pbr_dps_rank')
 
    df = df[df['거래량'> 0]  # 거래량이 0 이상인 종목만 구하기
 
    df = df.iloc[:30]  # 종목개수
    df['수익'= df['1년후종가'- df['종가']
 
    df['수익'].loc[df['상장주식수변동'< 0= df['1년후종가'* (1 + df['상장주식수변동'/ df['상장주식수']) - df['종가']
 
    df['수익률'= (df['수익'/ df['종가'])
    df['투자년도'= np.array([date] * len(df))
 
    p = df['수익률'].mean()
 
    result = []
    result.append([date, date2, p])
 
    df_t = pd.DataFrame(data=result, columns=['투자일''1년후''수익률'])
    return df, df_t
 
# 투자 시작년도부터 마직막 년도까지 반복
def inverst_years(date_list):
    for n in range(len(date_list)):
        if n < len(date_list)-1:
            date = date_list[n]
            date2 = date_list[n+1]
 
            if n == 0:
                df_t = row_pbr_dps(date, date2)[1]
                df = row_pbr_dps(date, date2)[0]
 
            else:
                df_t = pd.concat([df_t, row_pbr_dps(date, date2)[1]])
                df = pd.concat([df, row_pbr_dps(date, date2)[0]])
 
    path2 = origin_path + folder_name + '\\저PBR_DPS(' + m + '월' + d + '일)_거래량 0이상_30개_All Market.xlsx'
    df.to_excel(path2)
    return df_t
    print(df_t)
 
test_days = ['4''27'# 매월 매수/매도일
 
for d in test_days:
    origin_path = 'C:\\Users\\passi\\Desktop'
    folder_name = '\\PBR_DPS백테스트(매월' + d + '일)거래량 0이상(30개)_All Market'
    os.mkdir(origin_path + folder_name)
 
    # 월별로 테스트를 반복하여 결과 얻기
    for m in range(12):
        if m == 0:
            m = '01'
            # 연도별 날짜 List 만들기
            date_list = make_date_list(m, d)
 
            # 백테스트 구동하기
            df_t = inverst_years(date_list)
 
        else:
            m += 1
            m = '0' + str(m)
            m = m[-2:]
            print(m)
 
            #연도별 날짜 List 만들기
            date_list = make_date_list(m, d)
 
            #백테스트 구동하기
            df_t = pd.concat([df_t, inverst_years(date_list)])
 
 
    path = origin_path + folder_name + '\\저PBR_DPS 백테스트(종합 매월'+ d + '일 투자) 거래량 0이상 30개.xlsx'
    df_t.to_excel(path)
 
 
cs
728x90
반응형

댓글