Все ведь знают, что инвестировать в портфель выгоднее и безопаснее, чем в отдельную акцию? Сегодня мы узнаем, почему так происходит и научимся моделировать риски для целых портфелей ценных бумаг.
Начнем как обычно: quantmod, getSymbols только теперь получим две котировки:
library(quantmod)
getSymbols("YNDX", from="2012-01-01", to="2015-01-01")
## [1] "YNDX"
getSymbols("GOGL", from="2012-01-01", to="2015-01-01")
## [1] "GOGL"
plot(Ad(YNDX))
plot(Ad(GOGL))
prices1 <- as.numeric(Ad(YNDX))
prices2 <- as.numeric(Ad(GOGL))
ret1 <- diff(prices1)/head(prices1, -1)
ret2 <- diff(prices2)/head(prices2, -1)
И посмотрим на базовые характеристики наших векторов цен и доходностей:
length(ret1) == length(ret2) # Они хотя бы одинаковой длины? Вопрос: почему могут отличаться?
## [1] TRUE
mean(ret1)
## [1] 0.0002489355
mean(ret2)
## [1] -0.0005305659
sd(ret1)
## [1] 0.02730779
sd(ret2)
## [1] 0.03363116
cor(ret1, ret2)
## [1] 0.2325816
cor.test(ret1, ret2)
##
## Pearson's product-moment correlation
##
## data: ret1 and ret2
## t = 6.5535, df = 751, p-value = 1.044e-10
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.1638586 0.2990580
## sample estimates:
## cor
## 0.2325816
Сначала немного забежим вперед (у вас курс по финансовым рынкам будет весной). Если есть два актива \(x\) и \(y\) (доходности), каждый со своим средним доходом \(E(x) = \mu_x, E(y) = \mu_y\) и со своим средним стандартным отклонением дохода: \(V(x) = \sigma_x^2, V(y) = \sigma_y^2\), то ставится задача оптимального распределения капитала между этими двумя активами. Что значит оптимального?
Пусть мы вкладываем \(\gamma\) в актив \(x\) и \(1-\gamma\) в \(y\). Тогда ожидаемая доходность равна: \(\mu = \gamma\mu_x + (1-\gamma)\mu_y\). И тут даже обсуждать не интересно. А ожидаемая дисперсия равна: \(\sigma^2 = \gamma^2*\sigma_x^2 + (1-\gamma)^2\sigma_y^2 + 2\gamma(1-\gamma) cov(x, y)\).
Построим график?
gammas <- seq(0,1,0.001)
var <- var(ret1)*gammas^2 + var(ret2)*(1-gammas)^2 + 2*cov(ret1, ret2)*gammas*(1-gammas)
optimal <- (var(ret2) - cov(ret1, ret2))/(var(ret1) + var(ret2) - 2*cov(ret1, ret2))
optimal
## [1] 0.6329153
plot(gammas, var, type="l")
abline(v = optimal, col = 2)
Теперь соберем портфель для дальнейшего исследования:
prt <- optimal*ret1 + (1-optimal)*ret2
mean(prt)
## [1] -3.720754e-05
sd(prt)
## [1] 0.02346027
Для интереса: график коэффициента Шарпа:
variance <- var(ret1)*gammas^2 + var(ret2)*(1-gammas)^2 + 2*cov(ret1, ret2)*gammas*(1-gammas)
plot(gammas, (gammas*mean(ret1) + (1-gammas)*mean(ret2))/variance, type="l")
Почему нельза просто отдельно моделировать риски каждой бумаги?
Как вариант – использовать многомерные распределения:
library(ghyp)
## Loading required package: numDeriv
## Loading required package: gplots
##
## Attaching package: 'gplots'
##
## The following object is masked from 'package:stats':
##
## lowess
rets <- cbind(ret1, ret2)
head(rets)
## ret1 ret2
## [1,] -0.029888551 0.027941113
## [2,] 0.007310757 0.037196031
## [3,] -0.035251424 -0.029655263
## [4,] 0.006448092 0.041222459
## [5,] 0.006940790 0.013651933
## [6,] 0.018027571 -0.005387156
model <- fit.tmv(rets, silent=TRUE)
А дальше Монте-Карло:
N <- 1e5 # 100 тысяч
MCpoints <- rghyp(N, model)
prt_ret <- optimal*MCpoints[,1] + (1-optimal)*MCpoints[,2]
quantile(prt_ret, 0.05) # Что это?
## 5%
## -0.037782
mean(sort(prt_ret)[1:(N*0.05)]) # А это?
## [1] -0.0563028
Но можно придумать лучше!
Этот человек никак не связан с копулами.
Копула (лат. Copula) — это многомерная функция распределения, определённая на n-мерном единичном кубе, такая, что каждое её маргинальное распределение равномерно на интервале [0,1]. Теми кто сразу все понял, я восхищаюсь.
Копула для многомерной функции распределения \(H(x,y)\) – это такая функция \(C\), что \(H(x,y) = C(F(x), G(y))\), где \(F(x) = H(x, \infty)\) и \(G(y) = H(\infty, y)\).
Идею копул намного проще объяснить на пальцах, чем описать, поэтому тут особо рассказов не будет, все расскажу вживую. Но идейно – это способ отобразить совместное распределение двух случайных величин, на ограниченном пространстве (единичном кубе).
Копул бывает много, вот самые популярные:
library(copula)
persp(normalCopula(dim=2, param = 0.9), dCopula)
contour(normalCopula(dim=2, param = 0.9), dCopula, nlevels=40)
persp(tCopula(dim=2, param = 0.2, df = 2), dCopula)
contour(tCopula(dim=2, param = 0.2, df=2), dCopula, nlevels=40)
persp(gumbelCopula(dim=2, param = 2), dCopula)
contour(gumbelCopula(dim=2, param = 2), dCopula, nlevels=40)
persp(claytonCopula(dim=2, param = 1), dCopula)
contour(claytonCopula(dim=2, param = 1), dCopula, nlevels=40)
Нам надо взять наше эмпирическое двумерное распределение доходностей, посчитать
cdf <- pobs(rets)
plot(cdf)
И теперь замоделируем эту штуку кем-то из наших копул. Фитирование имеет особенность: мы инициализируем копулы, а потом подгоним параметры каждой.
t.cop <- tCopula(dim = 2, param = 0.5, df = 2, df.fixed = TRUE)
fit <- fitCopula(data = cdf, copula = t.cop)
summary(fit)
## $method
## [1] "maximum pseudo-likelihood"
##
## $loglik
## [1] -7.812359
##
## $convergence
## [1] 0
##
## $coefficients
## Estimate Std. Error z value Pr(>|z|)
## rho.1 0.2255592 0.04760094 4.738545 2.152579e-06
##
## attr(,"class")
## [1] "summary.fitCopula"
persp(fit@copula, dCopula)
contour(fit@copula, dCopula, nlevels=10)
Использовать будем Монте-Карло:
N <- 1e5
points_cop <- rCopula(copula = fit@copula, N)
plot(points_cop, cex=0.2)
ret1_cop <- quantile(ret1, points_cop)
ret2_cop <- quantile(ret2, points_cop)
prt_ret <- optimal*ret1_cop + (1-optimal)*ret2_cop
quantile(prt_ret, 0.05) # Что это?
## 5%
## -0.0492457
mean(sort(prt_ret)[1:(N*0.05)]) # А это?
## [1] -0.08286575
А кривых VaR не будет, все в домашке :)
Easy:
Hard:
God-mode:
Тем кто не смотрел, посмтреть.