Skip to content

Instantly share code, notes, and snippets.

@pycrawling
Last active October 31, 2020 16:08
Show Gist options
  • Save pycrawling/6ce405c6848c10bbed7a90d4e5f0d2ac to your computer and use it in GitHub Desktop.
Save pycrawling/6ce405c6848c10bbed7a90d4e5f0d2ac to your computer and use it in GitHub Desktop.
portfolio theory, rebalancing, backtest
from datetime import datetime, timedelta # 사용법: https://dojang.io/mod/page/view.php?id=2463
import FinanceDataReader as fdr
import matplotlib.pyplot as plt
import pandas as pd
from dateutil.relativedelta import relativedelta # month는 timedelta 사용불가 relativedelta
def load_data(code, start_date):
data = fdr.DataReader(code, start_date)
return data['Close'] # 종가만 남김.
def buy_etf(cash, etf_price, last_etf_num, fee_rate, etf_rate):
etf_num = cash * etf_rate // etf_price
etf_money = etf_num * etf_price
etf_fee = (last_etf_num - etf_num) * etf_price * fee_rate if last_etf_num > etf_num else 0
while cash < (etf_money + etf_fee):
etf_num -= 1
etf_money = etf_num * etf_price
etf_fee = (last_etf_num - etf_num) * etf_price * fee_rate if last_etf_num > etf_num else 0
cash -= etf_money + etf_fee
return cash, etf_num, etf_money
def back_test(money: int, fee_rate: float, interval: int, code1: str, code2: str, code3: str, start_date: str):
start_date = datetime.strptime(start_date, '%Y-%m-%d') # 조회시작일
# 데이터를 받습니다.
etf1 = load_data(code1, start_date)
etf2 = load_data(code2, start_date)
etf3 = load_data(code3, start_date)
# 3종류의 종가 데이터를 하나의 데이터프레임으로 합칩니다.
df = pd.concat([etf1, etf2, etf3], axis=1, keys=['etf1', 'etf2', 'etf3'])
# 리밸런싱 날짜의 데이터만 new_df에 남깁니다.
new_df = pd.DataFrame()
while start_date <= df.index[-1]:
temp_date = start_date
while temp_date not in df.index and temp_date < df.index[-1]:
temp_date += timedelta(days=1) # 영업일이 아닐 경우 1일씩 증가.
new_df = new_df.append(df.loc[temp_date])
start_date += relativedelta(months=interval) # interval 개월씩 증가.
etf1_num = etf2_num = etf3_num = 0 # 구매한 ETF 개수
backtest_df = pd.DataFrame() # 백테스트를 위한 데이터프레임
for each in new_df.index:
etf1_price = new_df.loc[each]['etf1']
etf2_price = new_df.loc[each]['etf2']
etf3_price = new_df.loc[each]['etf3']
# 보유 ETF 매도
money += etf1_num * etf1_price
money += etf2_num * etf2_price
money += etf3_num * etf3_price
# ETF 매입
money, etf1_num, etf1_money = buy_etf(money, etf1_price, etf1_num, fee_rate, 1 / 3)
money, etf2_num, etf2_money = buy_etf(money, etf2_price, etf2_num, fee_rate, 1 / 2)
money, etf3_num, etf3_money = buy_etf(money, etf3_price, etf3_num, fee_rate, 1)
total = money + etf1_money + etf2_money + etf3_money
backtest_df[each] = [int(total)]
# 행열을 바꿈
backtest_df = backtest_df.transpose()
backtest_df.columns = ['backtest', ]
# 백테스트 결과 출력
print(backtest_df)
# 최종 데이터 프레임, 3개의 지표와 백테스트 결과
final_df = pd.concat([new_df, backtest_df], axis=1)
# 시작점을 1로 통일함.
final_df['etf1'] = final_df['etf1'] / final_df['etf1'][0]
final_df['etf2'] = final_df['etf2'] / final_df['etf2'][0]
final_df['etf3'] = final_df['etf3'] / final_df['etf3'][0]
final_df['backtest'] = final_df['backtest'] / final_df['backtest'][0]
# 그래프 출력
plt.plot(final_df['etf1'].index, final_df['etf1'], label='etf1', color='r')
plt.plot(final_df['etf2'].index, final_df['etf2'], label='etf2', color='g')
plt.plot(final_df['etf3'].index, final_df['etf3'], label='etf3', color='b')
plt.plot(final_df['backtest'].index, final_df['backtest'], label='back_test', color='violet')
plt.legend(loc='upper left')
plt.show()
back_test(10_000_000, 0.002, 4, '102110', '148070', '157450', '2012-06-01')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment