SAVEPOINT ;
[Python] Monte Carlo VaR - 모수적(독립적) 본문
from selenium.webdriver.common.by import By
from selenium import webdriver
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from datetime import datetime, date, timedelta
import scipy.stats as stats
from scipy.stats import multivariate_normal
from scipy.stats import norm,beta,cauchy,expon,rayleigh,uniform,multivariate_t,t,kendalltau,rankdata
import statsmodels.api as sm
import FinanceDataReader as fdr
from matplotlib.patches import Ellipse
import matplotlib.transforms as transforms
import math
from mpl_toolkits.mplot3d import Axes3D
from pycopula.copula import ArchimedeanCopula
from pycopula.copula import GaussianCopula
import seaborn as sns
sns.set_theme(style='whitegrid')
모든 기능 로드, 모두 필요하지는 않지만 일일이 골라내기 힘들다.
#현재 USD/KRW 환율 로드
USDKRW=fdr.DataReader('USD/KRW')['Close']
USDKRW=USDKRW.iloc[len(USDKRW)-1]
#웹 페이지 열기
driver=webdriver.Chrome()
driver.get('게시한 구글 스프레드 시트 주소')
driver.find_element(By.XPATH,'//*[@id="sheet-button-1233126621"]/a').click() #탭 클릭
#내 포트폴리오 정보 크롤링
Data=pd.DataFrame() #빈 DataFrame 생성
for i in range(3,20):
Data.loc[i-3,'종목명']=driver.find_element(By.XPATH,f'//*[@id="1233126621"]/div/table/tbody/tr[{i}]/td[1]').text
Data.loc[i-3,'통화']=driver.find_element(By.XPATH,f'//*[@id="1233126621"]/div/table/tbody/tr[{i}]/td[3]').text
Data.loc[i-3,'티커']=driver.find_element(By.XPATH,f'//*[@id="1233126621"]/div/table/tbody/tr[{i}]/td[4]').text
Data.loc[i-3,'잔고주식수']=driver.find_element(By.XPATH,f'//*[@id="1233126621"]/div/table/tbody/tr[{i}]/td[7]').text
Data.loc[i-3,'잔고평가액']=driver.find_element(By.XPATH,f'//*[@id="1233126621"]/div/table/tbody/tr[{i}]/td[11]').text
Data['잔고평가액']=Data['잔고평가액'].str.replace(",","").astype('float') #잔고평가액 쉼표 없애고 실수로 변환
Data.loc[Data['통화']=='USD','잔고평가액']=Data['잔고평가액']*USDKRW # USD는 환율 곱해주어 KRW로 환산
Data=Data.loc[Data["잔고평가액"]>0,:] #'잔고평가액' > 0 인 행만 추출
웹 크롤링으로 보유하고 있는 종목의 '종목명 / 통화 / 티커 / 잔고주식수 / 잔고평가액'을 가져온다.
USD로 표시된 미국 ETF의 경우 현재 환율을 곱해주어 KRW로 환산
잔고평가액이 0을 초과하는 (현재 투자하고 있는) 종목만 선택
years=3
endDate=datetime.now()
startDate=endDate-timedelta(365*years)
tickers=Data['티커'].to_list()
returns=pd.DataFrame()
for i in tickers:
try:
returns[i]=fdr.DataReader(i,start=startDate,end=endDate)['Adj Close']
except:
returns[i]=fdr.DataReader(i,start=startDate,end=endDate)['Close']
returns=returns.dropna(axis=0).pct_change().dropna()
returns_mean=returns.mean()
returns_std=returns.std()
수익률을 가져올 기간을 설정해주고, FinanceDataReader를 통해 주가 크롤링 및 수익률로 변환.
한국 주식의 경우 'Adj Close'가 없는 경우가 있어 오류가 발생하면 'Close'를 가져오도록 함.
그리고 각 다섯 종목의 평균 수익률과 표준편차를 구한다.
mc_sims=1000 #시뮬레이션 횟수
T=90 #Days
VaR_Percentile=95
portfolio_sim_result=pd.DataFrame()
Only_means=np.full(shape=(T,len(Data)),fill_value=returns_mean)
Only_stds=np.full(shape=(T,len(Data)),fill_value=returns_std)
for x in range(0,mc_sims):
random_variates=np.random.standard_t(3,size=(T,len(Data)))
simulated_returns=Only_means+Only_stds*random_variates+1
simulated_returns=np.insert(simulated_returns,0,np.repeat(1.0,len(Data)),axis=0) #첫 행에 [1 1 ... 1 1] 추가
portfolio_sim=pd.DataFrame()
for i in range(0,len(Data)):
portfolio_sim[tickers[i]]=np.cumprod(simulated_returns[:,i])*Data.iloc[i,4] #'T' Days의 누적 수익률 * 기초 투자 금액
portfolio_sim_result[x]=np.sum(portfolio_sim,axis=1)/10000
시뮬레이션을 돌리기 위해 T=90일 동안의 수익률을 생성해야 한다.
분포는 자유도가 3인 Student's t-Distribution 사용
이런 방식으로 행이 90개 (90일 시뮬레이션), 열이 5개 (5 종목)인 각 종목의 90일 수익률 시뮬레이션을 생성.
이 값들에 1을 더해주고 맨 처음 행에 [1 1 1 1 1]을 삽입해 준다. (시뮬레이션의 처음 값은 현재 포트폴리오 가치가 되도록)
각 종목의 가치 변화를 시뮬레이션하고, 이를 가로 방향으로 합하면 전체 포트폴리오 가치의 변화가 된다.
이 계산을 시뮬레이션 횟수 (1000번) 만큼 반복하면
90개의 행 (90일 가치 변화), 1000개의 열 (시뮬레이션 횟수)를 지닌 Dataframe이 생성된다.
plt.figure(figsize=(8,4))
plt.plot(portfolio_sim_result,linewidth=1)
plt.ylabel('Portfolio (10 Thousands)')
plt.yscale
plt.xlabel('Days')
plt.title('MC Simulation for Portfolio')
portfolio_sim_result_lastvalues=portfolio_sim_result.iloc[len(portfolio_sim_result)-1,:]
VaR=np.percentile(portfolio_sim_result_lastvalues,100-VaR_Percentile)
plt.figure(figsize=(8,4))
sns.kdeplot(portfolio_sim_result_lastvalues,fill=True)
plt.xlim(750,3000)
plt.ylabel('Density')
plt.xlabel('Value (10 Thousands)')
plt.title('Distribution of Portfolio Value')
plt.axvline(x=Data['잔고평가액'].sum()/10000,color='k',linestyle='dashed',label=f'Initial Value {Data['잔고평가액'].sum()/10000:.0f}',linewidth=1.5)
plt.axvline(x=VaR,color='r',linestyle='dashed',label=f'{T} Days {VaR_Percentile}% VaR {VaR:.0f} ({VaR-Data['잔고평가액'].sum()/10000:.0f})',linewidth=1.5)
plt.legend()
'투자 > 생각' 카테고리의 다른 글
[Python] Bootstrapping VaR (0) | 2024.02.23 |
---|---|
[Python] Monte Carlo VaR - 모수적(Copula) (1) | 2024.02.15 |
[Python] 포트폴리오 최적화 (1) | 2024.02.12 |
[Python] 투자 포트폴리오 델타-노말/공헌/한계/증분 VaR 구하기 (0) | 2024.02.11 |
Max Drawdown distribution (S&P500) (1) | 2024.01.04 |