퀀트투자 분할매수 백테스트(파이썬)
본문 바로가기
파이썬으로 만든 것들/퀀트투자

퀀트투자 분할매수 백테스트(파이썬)

by Squat Lee 2022. 8. 31.

저의 취미 중 하나가 프로그래밍입니다.

 

또 다른 취미는 주식투자 입니다.  투자관련 서적들을 보면 여러가지 투자 방법들을 알 수 있는데, 실제로 수익이 나는지 증명해 보고 싶을때가 있습니다.

 

작년에 저PBR x 저DPS로 백테스를 해 본적이 있습니다.

 

아래 링크는 제가 백테스트 한 내용을 적은 포스트입니다.

 

2021.12.14 - [인생발자국/처음부터 다시 쓰는 투자일기] - 퀀트투자 백테스트 코드 (저PBR X 저DPS)

 

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

강환국 님의 '할수있다 퀀트투자'를 읽고나서 파이썬으로 만들어 보았다. 여러 조건을 백테스트 해 보았고, 이 조건이 가장 괜찮았다. 2003년부터 매월 11월 4일 즈음에 매수를 하고, 1년 후 매도

dotsnlines.tistory.com

 

그리고 주제넘게 파이썬으로 퀀트투자를 하는 강의 포스트도 올린적이 있습니다.

 

지금 생각해도 제가 겸손하지 못했다는 생각이 듭니다.

 

2021.12.28 - [집구석 강의/파이썬 퀀트투자 쉽게하기] - 파이썬 퀀트투자 쉽게하기 - 10. 전체 코드(마지막)

 

파이썬 퀀트투자 쉽게하기 - 10. 전체 코드(마지막)

저 PBR 주식을 선별해서 퀀트투자 백테스트를 할 수 있는 전체 코드입니다. 개인 사정상 강의를 계속 올리기 위한 시간이 충분치 않아서 급하게 마무리하게 됨을 이해하여 주시기 바랍니다. 아래

dotsnlines.tistory.com

 

어쨌든 저PBR X 저DPS 기준으로 투자를 해 보았고, 약간의 이익을 본 후 전량 매도 했습니다.

 

아래 링크는 제가 찾은 퀀트투자 방식으로 투자를 한 기록을 남겨놓은 포스트입니다.

 

2022.03.27 - [인생발자국/처음부터 다시 쓰는 투자일기] - 퀀트투자 결과(22.03.25 전량매도)

 

퀀트투자 결과(22.03.25 전량매도)

작년 11월 초에 퀀트투자 20개 종목을 선정해서 투자를 시작했다. 그리고 지난 3월 25일 전량 매도했다. 최근 수익률이 4~5%대를 왔다갔다 했는데, 나는 가격이 떨어 졌을때 팔았다. 원래 1년을 넘게

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
98
99
100
101
102
103
104
105
106
from pykrx import stock
import pandas as pd
import time
 
# 1월부터 11월까지 영업일을 List로 가져오기
def make_date_list(y, d):
    date_list = []
    for m in range(112):
        if len(str(m)) == 1:
            m = str(0+ str(m)
        if len(str(d)) == 1:
            d = str(0+ str(d)
        b_day = str(y) + str(m) + str(d)
        b_day = stock.get_nearest_business_day_in_a_week(date=b_day)
        date_list.append(b_day)
    return date_list
 
# 투자 종목 고르기
def row_pbr_dps(date):
    codes = stock.get_market_ticker_list(date, market='ALL'# code list 만들기
    corp = [] #Code와 Name을 저장할 List
    for code in codes:
        name = stock.get_market_ticker_name(code) #종목 이름 가져오기
        corp.append([code, name]) #Code와 이름으로 리스트를 만들기
    df1 = pd.DataFrame(data=corp, columns=['code''종목명'])#code와 종목명을 데이터프레임으로 만들기
    df1 = df1.set_index('code')#code를 Index로 설정하기
 
    df_f = stock.get_market_fundamental_by_ticker(date=date, market='ALL')#BPS, PER, PBR, EPS, DIV, DPS 가져와서 데이터 프레임 만들기
    df_c = stock.get_market_cap_by_ticker(date=date, market='ALL')#종가, 시가총액, 거래량, 거래대금, 상장주식수 가져오기
 
    time.sleep(0.1)
 
    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 + PER, PBR...
    #column은 '종목명', '종가', '시가총액', '거래량', '거래대금', '상장주식수', 'BPS', 'PER', 'PBR', 'EPS', 'DIV', 'DPS'
    df = df[df['PBR'> 0#PBR이 0이상만 구하기
    df['pbr_rank'= df['PBR'].rank()
 
    df = df[df['DPS'> 0#DPS 0이상만 구하기
    df['dps_rank'= df['DPS'].rank()
 
    df['pbr_dps'= df['pbr_rank'+ df['dps_rank']#pbr 순위와 dps 순위를 더하기
    df['pbr_dps_rank'= df['pbr_dps'].rank()#더한 PBR, DPS 순위의 순위 매기기
    df = df.sort_values(by='pbr_dps_rank'#pbr_dps_rank의 숫자가 낮은 순으로 정렬하기
 
    df = df[df['거래량'> 0#거래량이 0 이상인 종목만 구하기
    df = df.iloc[:20#20개 종목만 구하기
 
    return df
 
 
# 백테스트 하기
 
def pbr_dps_test(y, d):
    date_list = make_date_list(y, d)
 
    for n, date in enumerate(date_list[0:10]):
        if n == 0:
            df = row_pbr_dps(date)
            df['매수금액'= (1000000 // df['종가']) * df['종가']
            df['매수수량'= 1000000 // df['종가']
            df['매수금액' + date] = (1000000 // df['종가']) * df['종가']
            df['매수수량' + date] = 1000000 // df['종가']
 
        else:
            print(date)
            df_p = stock.get_market_cap_by_ticker(date=date, market='ALL')
            df_p = df_p[['종가''상장주식수']]
            df_p.columns = ['종가'+date, '상장주식수'+date]
            df = pd.merge(df, df_p, left_index=True, right_index=True)
            df['매수금액'= df['매수금액'+ (1000000 // df['종가'+date]) * df['종가'+date]
            df['매수수량'= df['매수수량'+ (1000000 // df['종가'+date])
            df['매수금액'+ date] = (1000000 // df['종가'+date]) * df['종가'+date]
            df['매수수량'+ date] = 1000000 // df['종가'+date]
 
 
    df_p = stock.get_market_cap_by_ticker(date=date_list[-1], market='ALL')#매도가격(11월) 가져오기
    df_p = df_p[['종가','상장주식수']]
    df_p.columns = ['매도가격''매도상장주식수']
    df = pd.merge(df, df_p, left_index=True, right_index=True)
 
    df['수익'= (df['매도가격'* df['매수수량']) - df['매수금액']
    df['수익률'= (df['수익']/df['매수금액'])
 
    print(df)
 
    total_profit = df['수익'].sum()
    total_profit_ratio = total_profit/df['매수금액'].sum()
 
    print(total_profit)
    print(total_profit_ratio)
 
    df.to_excel('분할매수 Test' + str(y) + '.xlsx')
 
    return df, total_profit, total_profit_ratio
 
li_profit_per_year = []
for y in range(20032022):
    result = pbr_dps_test(y, '04')
    result[0]
    li_profit_per_year.append([y, result[1], result[2]])
df_total_profit = pd.DataFrame(data=li_profit_per_year, columns=['년도''수익''수익률'])
df_total_profit.to_excel('분할매수 백테스트(연도별 수익률).xlsx')
 
 
 
cs

 

위와 같이 간단하게 코드를 작성해 보았습니다.

 

조건은 저PBR X 저DPS 로 20개 종목을 선정한 후 매년 1월부터 10월까지 동일금액으로 매수 후 11월에 일괄 매도하는 방식으로 백테스트 하는 것입니다.

 

기존에 했던 방식인 1년에 1번 사서 다음해 같은 날에 파는 것 보다는 변동성이 줄었으나, 최대 손실이 -30%까지 발생하는 등 제가 생각했던 것 만큼 변동성이 줄어들지 않았습니다.

 

좀 더 고민을 해 봐야겠습니다.

 

그리고 파이썬으로 코딩을 하며, 공부를 하다보니 더욱더 효율적으로 코딩하는 방식들을 알게 되더라구요.

 

세상은 알아갈 수록 제가 모르고 있다는 사실을 더욱더 절실히 느끼게 되는 것 같습니다. 

 

이번 포스트에서 기록한 코드에는 '수정주가'가 반영이 되어 있지 않습니다. 이러한 여러 개선할 사항들을 찾아내며 고민을 해 보는 시간이 필요할 것 같습니다. 

 

세상에는 쉬운게 하나도 없네요.

 

경제적자유를 이루는 그날까지 열심히 공부하며, 기록을 남겨 보겠습니다.

728x90
반응형

댓글