# 필요한 라이브러리들을 임포트합니다.
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
IPython_default = plt.rcParams.copy() # 원래의 Matplotlib 스타일 설정을 저장합니다.
import yfinance as yf # Yahoo Finance에서 금융 데이터를 다운로드하기 위한 라이브러리
import pyfolio as pf # 포트폴리오 성능 분석을 위한 라이브러리
import quantstats as qs # 투자 포트폴리오의 통계 분석을 위한 라이브러리
# 분석할 자산의 티커들을 리스트로 정의합니다.
tickers = ['SPY', 'TLT', 'GLD', 'BIL', 'IEF']
# 지정된 티커들의 최대 기간 일간 종가 데이터를 Yahoo Finance에서 다운로드합니다.
df_close = yf.download(tickers=tickers,
period='max',
interval='1d',
auto_adjust=True # 자동으로 주가 조정(배당, 분할 등 반영)
)['Close'][tickers]
# 각 자산의 시작 날짜를 출력합니다.
print('Start date of each stock')
print('-'*25)
for ticker in tickers:
print(f"{ticker}: {df_close[[ticker]].dropna().iloc[0].name.strftime('%Y-%m-%d')}")
print('-'*25)
# 'CASH'라는 새로운 열을 추가하고 모든 값에 1을 할당합니다.
df_close['CASH'] = 1
# 자산 목록을 업데이트합니다.
tickers = ['SPY', 'TLT', 'GLD', 'CASH']
# 결측치를 제거한 후 필요한 자산만 포함하는 새로운 데이터 프레임을 생성합니다.
df = df_close[tickers].dropna()
# 트레이딩 기간을 정의합니다.
time_period = df.index.to_frame() # 인덱스를 데이터 프레임으로 변환
trading_period = time_period.resample('BM').last().iloc[::12, :].rename(columns={'Date':'start_date'})
trading_period = trading_period.assign(end_date=trading_period.start_date.shift(-1).fillna(time_period.iloc[-1].name))
print(trading_period)
def get_mdd(df_price, start, end, col):
"""자산 가격의 최대 낙폭을 계산합니다."""
df_price = df_price[start:end].copy()
return ((df_price[col] - df_price[col].cummax()) / df_price[col].cummax()).cummin()
def get_pf_returns(df_price, tickers, start, end, weights=None, use_signal=None):
"""포트폴리오 수익률을 생성합니다."""
if weights is None:
weights = [1/len(tickers) for _ in range(len(tickers))]
ret_dict = {ticker+'_RET': df_price[ticker].pct_change().fillna(0) for ticker in tickers}
df_price = df_price.assign(**ret_dict)
ret_cols = [ticker+'_RET' for ticker in tickers] # 일일 수익률 컬럼 이름을 리스트로 저장
df_trade = df_price.loc[start:end].copy()
df_trade.loc[start, ret_cols] = 0 # 첫 거래일의 수익률은 0으로 설정
df_trade = df_trade.assign(PF_RET=df_trade[ret_cols].dot(weights))
cumret_dict = {col+'_CUMRET': (1 + df_trade[col+'_RET']).cumprod() for col in tickers}
df_trade = df_trade.assign(**cumret_dict, PF_CUMRET=(1 + df_trade['PF_RET']).cumprod())
mdd_dict = {col.split('_')[0]+'_MDD': get_mdd(df_price=df_trade, start=df_trade.index[0], end=df_trade.index[-1], col=col+'_CUMRET') for col in tickers}
df_trade = df_trade.assign(**mdd_dict)
return df_trade
# 각 거래 기간에 대한 결과를 집계합니다.
df_res = pd.DataFrame()
for i in range(len(trading_period)):
df_trade = get_pf_returns(df_price=df,
tickers=tickers,
start=trading_period.iloc[i].start_date,
end=trading_period.iloc[i].end_date)
df_res = pd.concat([df_res, df_trade], axis=0)
# 중복된 행을 제거합니다.
df_res = df_res.reset_index().drop_duplicates(['Date'], keep='first').set_index('Date')
# 그래프 스타일을 복원하고 새로운 스타일을 설정합니다.
plt.rcParams.update(IPython_default)
plt.style.use('_mpl-gallery')
# 누적 수익률을 다양한 색상으로 그래프에 표시합니다.
color_map = ['blue', 'green', 'red', 'pink','yellow'] # 색상 지정
(1 + df_res[['SPY_RET', 'TLT_RET', 'GLD_RET', 'CASH_RET', 'PF_RET']]).cumprod().plot(figsize=(12, 8), linewidth=1, color=color_map)
plt.show()
'재테크•투자•경제•주식' 카테고리의 다른 글
2차 전지 개발 관련 재 추진 정책 (0) | 2024.05.05 |
---|---|
SPY 누적수익률, 최고점, 일별수익률 (0) | 2024.04.28 |
각 자산의 시장 시작 날짜 확인 (0) | 2024.04.28 |
QuantStats (0) | 2024.04.28 |
pyfolio (0) | 2024.04.28 |