#### 1) ( Simulation을 이용한 Portfolio 최적화 ) * \(P_t\) : t 시점의 주식가격, \(t=0,1,2,...\)
t 시점의 주가 수익률(return) : \(r_t = (P_t - P_t-1)/P_t-1\)
t 시점 로그수익률 (log-return) : \(ln(1+r_t) = lnP_t - lnP_t-1\)
단, \(\mu\) : 연평균 로그 수익률 = 0.05
\(\sigma\) : 로그 수익률의 표준편차 (주가 변동성: volatility) = 0.3 이다.
이때,
\(V_0\) : 초기 투자금액 (initial fortune 단위 억원) = 1억원
\(n\) : 투자기간 (만기: maturity) (단위 년) = 5년
\(i\) : 정기예금금리 (risk-free interest rate) = 0.02
5 년간 연평균 목표수익률을 4%로 설정하였다.
\(r^*\) : 목표수익률 ( target return) = 0.04
매년 총자산중 일정비율 a ,\(0≦ a ≦\) 1 만큼은 위험자산(risky asset) 주식(stock)에 투자하고 나머지는 연 \(100*r_0\)%인 정기예금에 투자할 경우 미래 \(t\) 시점의 펀드의 자산가치 \(V_t\)는 아래와 같이 주어진다.
\(V_1=V_0(1+r_{p1})\)
\(V_2=V_1(1+r_{p2})=V_0(1+r_{p1})(1+r_{p2})\)
\(....\)
\(V_4 = V_0 \prod_{j=1}^{t} (1+r_{pj}) , t=1,2,...\)
단,\(t\)시점의 Portfolio a의 수익률 \(r_{pt} (a)\)은
\(r_{pt}(a) = (1-a)*i + a*r_t, t=1,2,...\) 로 주어진다.
Portfolio의 투자성과를 판단하는 객관적 기준으로 만기(n)시점의 Portfolio의 자산가치 \(V_n(a)\)가 연평균 목표 수익률(\(r^*\))을 초과할 확률(Roy 의 Safety First Criterion):
\(RSFC(a)=P(V_n(a)>V_0(1+r^*)^n )\) 을 설정하고 이 확률값을 Simulation 방법으로 구한다.
Setup
library(tidyverse)
library(knitr)
library(kableExtra)
total <- 20; sim <- 1000
#given data
mu <- 0.05
sigma <- 0.3
v0 <- 1
maturity <- 5
risk.free.interst <- 0.02
target.return <- 0.04
a <- 0.5
# 비율, 목표수익률, 만기에 따른 함수 생성
portfolio <- function(mu, sigma, a, target.return, total) {
set.seed(1234)
#random.matrix
random.matrix <- matrix(rnorm(sim*total, 0, 1), sim, total)
#v0~v20 value matrix
value.matrix <- matrix(1, sim, total+1) #v0~v20
colnames(value.matrix) <- c(0:total) #assign Colnames
value.matrix[,1] <- c(1) #set V0 to 1
#Calculate rates
rt <- exp(mu + sigma * random.matrix) - 1 #Stock return at t
rpt_a <- (1 - a)*risk.free.interst + a * rt #t시점의 Portfolio a의 수익률
for (i in 1:total) {
value.matrix[,i+1] <- value.matrix[,i]*(1+rpt_a[,i])
}
return(value.matrix)
}
#만기시점의 portfolio의 자산가치가 연평균 목표 수익율을 초과할 확률 (Roy의 Safety First Criterion)
rsfc <- function(mu, sigma, a, target.return, total) {
# maturity matrix (1~20년)
maturity.matrix <- matrix(1:total, 1, total)
# n=1~20/ 목표 수익율
target.matrix <- matrix(1*(1+target.return)^maturity.matrix, sim, total, byrow = TRUE)
value.matrix <- portfolio(mu, sigma, a, target.return, total)
rsfc <- colMeans(matrix(as.numeric(value.matrix[,-1]>target.matrix), sim, total))
return(rsfc)
}
목표 달성 확률
rsfc(mu, sigma, a, target.return, total)
## [1] 0.470 0.497 0.514 0.518 0.534 0.542 0.544 0.567 0.568 0.568 0.571
## [12] 0.561 0.571 0.570 0.584 0.572 0.569 0.566 0.565 0.568
v.1_5 <- portfolio(mu, sigma, a, target.return, total)[1:5, 1:11] #choose v1 to v10
df <- data.frame(Simulation=c('S1','S2','S3','S4','S5'),v.1_5)
newdf <- gather(df, type, value, -Simulation)
ggplot(newdf,aes(x = type, y = value, group = Simulation, color = Simulation) ) +
geom_line() +
labs(x='t years',y='Vt(a)', title = 'Vt(a)') +
scale_x_discrete(limit=c("X0","X1","X2","X3","X4","X5","X6","X7","X8","X9","X10")) +
theme_bw()
a.table <- matrix(c(seq(0, 1, 0.1), rep(0,11)), 11, 2)
for (i in 0:10){
a.table[i+1, 2] <- rsfc(mu, sigma, i/10, target.return, maturity)[maturity]
}
colnames(a.table) <- c("a", "prob.")
a.table
## a prob.
## [1,] 0.0 0.000
## [2,] 0.1 0.188
## [3,] 0.2 0.393
## [4,] 0.3 0.479
## [5,] 0.4 0.516
## [6,] 0.5 0.534
## [7,] 0.6 0.540
## [8,] 0.7 0.543
## [9,] 0.8 0.545
## [10,] 0.9 0.540
## [11,] 1.0 0.539
ggplot(data.frame(a.table), aes(a, prob.)) +
geom_point() + geom_line() +
labs(title = 'Roy Criterion', x="Portfolio a", y='Pr(Vn(a)>Vn*)') +
theme_bw()
sensitivity <- function(mu, sigma, target.return, maturity) {
prob <- NA
for (i in 0:10){
prob[i+1] <- rsfc(mu, sigma, i/10, target.return, maturity)[maturity]
}
a.star_prob <- max(prob)
a.star <- sprintf('%.1f',0.1*(which.max(prob)-1))
opt.a <- data.frame("a.star"=a.star, "prob"=a.star_prob)
return(opt.a)
}
kable(sensitivity(mu, sigma, target.return, maturity)) %>%
kable_styling(full_width = F,
position = "left")
a.star | prob |
---|---|
0.8 | 0.545 |
e.sensitivity <- rbind(sensitivity(mu, sigma, target.return=0.03, maturity=5),
sensitivity(mu, sigma, target.return=0.03, maturity=10),
sensitivity(mu, sigma, target.return=0.04, maturity=5),
sensitivity(mu, sigma, target.return=0.04, maturity=10),
sensitivity(mu, sigma, target.return=0.06, maturity=5),
sensitivity(mu, sigma, target.return=0.06, maturity=10))
kable(cbind("r*"=c(0.03, 0.03, 0.04, 0.04, 0.06, 0.06), "만기 n"=rep(c(5,10),3),e.sensitivity))%>% kable_styling(full_width = FALSE, position="left")
r* | 만기 n | a.star | prob |
---|---|---|---|
0.03 | 5 | 0.5 | 0.592 |
0.03 | 10 | 0.4 | 0.638 |
0.04 | 5 | 0.8 | 0.545 |
0.04 | 10 | 0.7 | 0.584 |
0.06 | 5 | 1.0 | 0.482 |
0.06 | 10 | 0.9 | 0.489 |
Problem : (KOSPI 수익률분포 찾기)
#1 에서 최적 Portfolio를 구하기 위해 필요한 주식의 로그수익률 \(ln(1+r_t)\) 분포를 2004.1-2018.1. 기간의 매 월말 KOSPI 시계열자료를 이용하여 구한다.
setup
#setting
library(lubridate)
setwd("D:\\0_grad\\data")
kospi <- read.csv("kospi.csv", skip=3)
#data setting
colnames(kospi) <- c("Date", "P")
kospi$P <- as.numeric(gsub( ",", "", kospi$P))
kospi$Date <- as.POSIXlt(paste(kospi$Date, 1, sep="/"), format="%Y/%m/%d")
kospi$Date <-as.Date(kospi$Date)
kospi <- kospi %>% mutate(lnPt=log(as.numeric(P)))
#Time Series Plot
#Pt
ggplot(kospi, aes(Date, P)) +
geom_point() + geom_line() +
theme_bw() + labs(title="P(t) time series", x="Date", y="P(t)")
#lnPt
ggplot(kospi, aes(Date, lnPt)) +
geom_point() + geom_line() +
theme_bw() + labs(title="lnP(t) time series", x="Date", y="lnP(t)")
kospi$dlnPt[1] <- NA
for (i in 2:nrow(kospi)){
kospi$dlnPt[i] <- kospi$lnPt[i] -kospi$lnPt[i-1]
}
#time series
ggplot(kospi, aes(Date, dlnPt)) + geom_point() + geom_line() +
theme_bw() +labs(title="dlnP(t) time series", x="Date", y="dlnP(t)")
#Histogram
ggplot(kospi) + geom_histogram(aes(dlnPt), stat="bin") + geom_rug(aes(dlnPt)) +
theme_bw() +labs(title="ln(1+r(t)) histogram", x="dlnP(t)")
c) (정규성 검정) 로그수익률 \(ln(1+r_t)\) 분호가 정규분포를 따르는지 정규 Q-Q plot을 그려보고 정규성 가정이 성립 하는지 검토하시오.
kospi <- kospi %>% mutate(rank=rank(dlnPt), pr=rank/(nrow(kospi)+1)) %>% mutate(norm=qnorm(pr))
ggplot(kospi, aes(norm, dlnPt)) + geom_point(size=2) +
geom_smooth(method="lm", se=F) +
labs(title = "Normal Q-Q Plot",
subtitle = paste("R.sq = ", round(summary(lm(dlnPt ~ norm, kospi))$r.squared,4)*100, "%", sep = ""),
x="", y="dlnPt") + theme_bw()
직선에 가까우므로 정규성 가정이 성립한다.
mu.kospi <- 12*mean(kospi$dlnPt, na.rm=TRUE)
sd.kospi <- sqrt(12)*sd(kospi$dlnPt, na.rm=TRUE)
c(mu.kospi, sd.kospi)
## [1] 0.07905805 0.17885606
kable(sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.04, maturity=10)) %>%
kable_styling(full_width = F,
position = "left")
a.star | prob |
---|---|
1.0 | 0.752 |
f.sensitivity <- rbind(sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.04, maturity=5),
sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.04, maturity=10),
sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.04, maturity=20),
sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.05, maturity=5),
sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.05, maturity=10),
sensitivity(mu=mu.kospi, sigma=sd.kospi, target.return=0.05, maturity=20))
kable(cbind("r*"=c(0.04, 0.04, 0.04, 0.05, 0.05, 0.05), "만기 n"=rep(c(5,10,20),2),f.sensitivity))%>% kable_styling(full_width = FALSE, position="left")
r* | 만기 n | a.star | prob |
---|---|---|---|
0.04 | 5 | 1.0 | 0.680 |
0.04 | 10 | 1.0 | 0.752 |
0.04 | 20 | 1.0 | 0.855 |
0.05 | 5 | 1.0 | 0.638 |
0.05 | 10 | 1.0 | 0.701 |
0.05 | 20 | 1.0 | 0.792 |