Importando as séries de retorno para realização da atividade (fonte economática) :
retornos <- read_excel("Retornos_prova_1.xlsx")
str(retornos)
## tibble [1,237 x 15] (S3: tbl_df/tbl/data.frame)
## $ Data : POSIXct[1:1237], format: "2016-06-01" "2016-06-02" ...
## $ RADL3 : num [1:1237] 0.03585 0.00134 0.01269 0.00478 -0.0082 ...
## $ RENT3 : num [1:1237] -0.0018 -0.00422 0.02481 -0.01092 -0.03463 ...
## $ SANB11: num [1:1237] 0.01669 0.01811 0.01167 -0.01099 -0.00167 ...
## $ SBSP3 : num [1:1237] 0.02345 -0.00802 0.03195 -0.01604 0.01137 ...
## $ SULA11: num [1:1237] 0.01535 -0.01118 0.02793 0.00582 -0.00965 ...
## $ TAEE11: num [1:1237] -0.0345 -0.0236 0.0242 -0.0352 0.0268 ...
## $ TIMS3 : num [1:1237] -0.0154 -0.0114 0.0202 -0.0269 0.0407 ...
## $ TOTS3 : num [1:1237] 0.0027 0.032 0.0721 -0.0368 -0.0111 ...
## $ UGPA3 : num [1:1237] 0.003223 0.011392 0.000866 -0.005915 -0.013062 ...
## $ USIM5 : num [1:1237] -0.00599 0.03614 0.05814 0.05495 -0.02083 ...
## $ VALE3 : num [1:1237] 0.0148 0.036 0.0863 0.04 -0.0189 ...
## $ VIVT3 : num [1:1237] -0.02406 -0.00688 0.00837 -0.02147 0.00263 ...
## $ WEGE3 : num [1:1237] 0.03475 -0.00806 0.00406 0.00809 -0.00736 ...
## $ YDUQ3 : num [1:1237] 0.0203 0.2374 0.0131 0.0468 0.0172 ...
Para a otimização de Markowitz, com dados passados, deveríamos ignorar os dados referentes à crise do Covid-19. Isso é justificado pelo fato de que se trata de um evento bastante raro, assim, os parâmetros que utilizaríamos para a otimização estariam viesados, como as correlações, o desvio-padrão e os retornos médios.
Para demonstrar essas mudanças, selecionaremos os seguintes ativos: RADL3, RENT3, SANB11, SBSP3, SULA11, TAEE11 e TIMS3. Iremos dividir os retornos em dois intervalos, com e sem Covid.
retornos_sem_covid <- retornos %>% select(Data, RADL3, RENT3, SANB11, SBSP3, SULA11, TAEE11, TIMS3) %>% dplyr::filter(Data >= "2019-01-01" & Data <= "2020-01-31")
retornos_com_covid <- retornos %>% select(Data, RADL3, RENT3, SANB11, SBSP3, SULA11, TAEE11, TIMS3) %>% dplyr::filter(Data >= "2019-01-01" & Data <= "2020-05-31")
colMeans(retornos_sem_covid[,-1]) * 100
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.30953583 0.25811070 0.04145127 0.28242460 0.32198929 0.13289698 0.15816956
colMeans(retornos_com_covid[,-1]) * 100
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11
## 0.21679170 0.16774685 -0.07889634 0.23256745 0.18693916 0.09435227
## TIMS3
## 0.08491427
sqrt(diag(cov(retornos_sem_covid[,-1])))*sqrt(252)
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.3089279 0.3001999 0.2740210 0.3787365 0.3013689 0.1860544 0.2573285
sqrt(diag(cov(retornos_com_covid[,-1])))*sqrt(252)
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.3765196 0.6216069 0.4525103 0.5503430 0.4866146 0.2375464 0.4004034
cor(retornos_sem_covid[,-1])
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## RADL3 1.0000000 0.1682085 0.2416169 0.16660991 0.23850400 0.2190259 0.2155743
## RENT3 0.1682085 1.0000000 0.3499435 0.36440156 0.18750686 0.3971476 0.2298975
## SANB11 0.2416169 0.3499435 1.0000000 0.40918476 0.23514456 0.3926192 0.3735518
## SBSP3 0.1666099 0.3644016 0.4091848 1.00000000 0.09603015 0.4571384 0.2372740
## SULA11 0.2385040 0.1875069 0.2351446 0.09603015 1.00000000 0.1648096 0.1847474
## TAEE11 0.2190259 0.3971476 0.3926192 0.45713842 0.16480957 1.0000000 0.2467685
## TIMS3 0.2155743 0.2298975 0.3735518 0.23727404 0.18474744 0.2467685 1.0000000
cor(retornos_com_covid[,-1])
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## RADL3 1.0000000 0.3961141 0.3899429 0.2904670 0.3972990 0.3374538 0.4022739
## RENT3 0.3961141 1.0000000 0.6607275 0.5502601 0.6557908 0.5272821 0.5026579
## SANB11 0.3899429 0.6607275 1.0000000 0.6148691 0.5764619 0.5244641 0.5524389
## SBSP3 0.2904670 0.5502601 0.6148691 1.0000000 0.4525981 0.5554491 0.5244718
## SULA11 0.3972990 0.6557908 0.5764619 0.4525981 1.0000000 0.4482950 0.4611940
## TAEE11 0.3374538 0.5272821 0.5244641 0.5554491 0.4482950 1.0000000 0.4703177
## TIMS3 0.4022739 0.5026579 0.5524389 0.5244718 0.4611940 0.4703177 1.0000000
Pela análise dos parâmetros apresentados, percebe-se que há uma redução significativa do retorno esperado dos ativos, juntamente com um aumento do desvio-padrão e uma maior correlação entre eles, característico de períodos de crise. Assim, os parâmetros não seriam adequados para projeções futuras. Agora, ilustraremos os diferentes pesos que seriam resultado do portfólio em ambos os casos.
Primeiro, sem os dados referentes à pandemia.
PMV_sem_covid <- inv(cov(retornos_sem_covid[,-1])) %*% rep(1, 7)
PMV_sem_covid <- PMV_sem_covid / sum(PMV_sem_covid)
PMV_sem_covid
## [,1]
## RADL3 0.10121181
## RENT3 0.05596395
## SANB11 0.04652498
## SBSP3 -0.03533315
## SULA11 0.13570958
## TAEE11 0.51005655
## TIMS3 0.18586628
Agora, com dados referentes à pandemia.
PMV_com_covid <- inv(cov(retornos_com_covid[,-1])) %*% rep(1, 7)
PMV_com_covid <- PMV_com_covid / sum(PMV_com_covid)
PMV_com_covid
## [,1]
## RADL3 0.18341223
## RENT3 -0.12661906
## SANB11 0.03246517
## SBSP3 -0.07900900
## SULA11 0.04762976
## TAEE11 0.85117874
## TIMS3 0.09094217
Como Risk_free utilizaremos a meta da taxa selic ao final de 2019 (4.50% a.a.).
Risk_free <- (1.045)^(1/252) - 1
PT_sem_covid <- inv(cov(retornos_sem_covid[,-1])) %*% (colMeans(retornos_sem_covid[,-1]) - Risk_free)
PT_sem_covid <- PT_sem_covid/sum(PT_sem_covid)
PT_sem_covid
## [,1]
## RADL3 0.3216432
## RENT3 0.2453674
## SANB11 -0.4377839
## SBSP3 0.2017117
## SULA11 0.3953650
## TAEE11 0.1166349
## TIMS3 0.1570616
PT_com_covid <- inv(cov(retornos_com_covid[,-1])) %*% (colMeans(retornos_com_covid[,-1]) - Risk_free)
PT_com_covid <- PT_com_covid/sum(PT_com_covid)
PT_com_covid
## [,1]
## RADL3 0.9076615
## RENT3 0.1401579
## SANB11 -1.6061648
## SBSP3 0.7079756
## SULA11 0.4650566
## TAEE11 0.4900199
## TIMS3 -0.1047069
Assim, percebe-se que houveram mudanças significativas nos pesos dos ativos, logo, caso a utilização da otimização tivesse como objetivo obter um portfólio eficiente fora de eventos chamados outliers, devemos desconsiderar os dados da amostra, ou, alternativamente, reduzir o peso deles no todo.
Utilizando o pacote fPortfolio
Data = timeSeries(ts(retornos_sem_covid[,-1], frequency=12, start=c(2019,1)))
(ndm=dim(Data))
## [1] 270 7
Spec = portfolioSpec()
setTargetReturn(Spec) = mean(colMeans(Data,na.rm=T))
setRiskFreeRate(Spec) = Risk_free
setNFrontierPoints(Spec) = 50
Constraints = c( "maxW = c(0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4)", "maxsumW[1:7] = 1.1")
PMV=minvariancePortfolio(Data, Spec, Constraints)
PT=tangencyPortfolio(Data, Spec, Constraints)
PMV_sem_covid_constraints <- getWeights(PMV)
PT_sem_covid_constraints <- getWeights(PT)
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.11474419 0.07370383 0.05873187 0.00000000 0.14971314 0.40000000 0.20310697
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.27899255 0.18670828 0.00000000 0.12714389 0.33805481 0.01619577 0.05290470
## Risco Retorno
## RADL3 30.89279 0.30953583
## RENT3 30.01999 0.25811070
## SANB11 27.40210 0.04145127
## SBSP3 37.87365 0.28242460
## SULA11 30.13689 0.32198929
## TAEE11 18.60544 0.13289698
## TIMS3 25.73285 0.15816956
Data = timeSeries(ts(retornos_com_covid[,-1], frequency=12, start=c(2019,1)))
(ndm=dim(Data))
## [1] 350 7
Spec = portfolioSpec()
setTargetReturn(Spec) = mean(colMeans(Data,na.rm=T))
setRiskFreeRate(Spec) = Risk_free
setNFrontierPoints(Spec) = 50
Constraints = c( "maxW = c(0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4)", "maxsumW[1:7] = 1.1")
PMV=minvariancePortfolio(Data, Spec, Constraints)
PT=tangencyPortfolio(Data, Spec, Constraints)
PMV_com_covid_constraints <- getWeights(PMV)
PT_com_covid_constraints <- getWeights(PT)
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.33224149 0.00000000 0.03441395 0.00000000 0.03978203 0.40000000 0.19356253
## RADL3 RENT3 SANB11 SBSP3 SULA11 TAEE11 TIMS3
## 0.4000000 0.0000000 0.0000000 0.1948401 0.1158987 0.2892611 0.0000000
## Risco Retorno
## RADL3 37.65196 0.21679170
## RENT3 62.16069 0.16774685
## SANB11 45.25103 -0.07889634
## SBSP3 55.03430 0.23256745
## SULA11 48.66146 0.18693916
## TAEE11 23.75464 0.09435227
## TIMS3 40.04034 0.08491427
sum(colMeans(retornos_sem_covid[,-1]) * PMV_sem_covid_constraints)
## [1] 0.001904659
sum(colMeans(retornos_sem_covid[,-1]) * PT_sem_covid_constraints)
## [1] 0.002898285
sum(colMeans(retornos_com_covid[,-1]) * PMV_com_covid_constraints)
## [1] 0.00130926
sum(colMeans(retornos_com_covid[,-1]) * PT_com_covid_constraints)
## [1] 0.001809886
sqrt(t(PMV_sem_covid_constraints) %*% (cov(retornos_sem_covid[,-1]) %*% PMV_sem_covid_constraints)) * sqrt(252)
## [,1]
## [1,] 0.1544001
sqrt(t(PT_sem_covid_constraints) %*% (cov(retornos_sem_covid[,-1]) %*% PT_sem_covid_constraints)) * sqrt(252)
## [,1]
## [1,] 0.1946597
sqrt(t(PMV_com_covid_constraints) %*% (cov(retornos_com_covid[,-1]) %*% PMV_com_covid_constraints)) * sqrt(252)
## [,1]
## [1,] 0.2525089
sqrt(t(PT_com_covid_constraints) %*% (cov(retornos_com_covid[,-1]) %*% PT_com_covid_constraints)) * sqrt(252)
## [,1]
## [1,] 0.2869361
Nota-se uma mudança significativa, porém mais branda do que a otimização sem restrições, em ambos os portfólios. No caso de mínima variância, ambos os cenários atingiram o máximo de investimento no ativo TAEE11, a principal mudança ocorreu nos ativos RADL3, SANB11 e SULA11. Nos portfólios tangentes, houve concentração em RADL3 e TAEE11, ativos como RENT3 e TIMS3 tiveram suas posições zeradas.
Novamente, percebe-se o menor retorno esperado e o maior risco nas situações em que consideramos os dados do Covid-19.
Para a realização do Backtest, utilizaremos os dados que compreendem o período de 2019 e 2020. Embora os dados do Covid-19 vão obter um peso significativo na amostra, como já haverá ocorrido a retomada a otimização para o portfólio tangente não será afetada.
retornos_estim <- retornos %>% dplyr::filter(Data >= "2019-01-01" & Data <= "2020-12-31")
retornos_backtest <- retornos %>% dplyr::filter(Data >= "2021-01-01" & Data <= "2021-12-31")
R_Backtest<- xts(retornos_backtest[,-1], retornos_backtest$Data)
Pesos_Ingênuo <- matrix(rep(1/7,7), nrow = 5, ncol = 14)
Retorno_Ingênuo <- Return.portfolio(R_Backtest, as.ts(Pesos_Ingênuo), rebalance_on = c("months"))
## Warning in Return.portfolio.geometric(R = R, weights = weights, wealth.index =
## wealth.index, : The weights for one or more periods do not sum up to 1: assuming
## a return of 0 for the residual weights
names(Retorno_Ingênuo) <- "Portfólio Ingênuo"
var <- diag(cov(retornos_estim[,-1]))
wVT <- (1/var)^4/sum((1/var)^4)
Pesos_wVT <- matrix(wVT, nrow = 5, ncol = 14)
Retorno_wVT <- Return.portfolio(R_Backtest, as.ts(Pesos_wVT), rebalance_on = c("months"))
names(Retorno_wVT) <- "Portfólio Volatility Timing"
Pesos_Tangente <- inv(cov(retornos_estim[,-1])) %*% (colMeans(retornos_estim[,-1]) - Risk_free)
Pesos_Tangente <- Pesos_Tangente/sum(Pesos_Tangente)
Pesos_Tangente <- matrix(Pesos_Tangente, nrow = 5, ncol = 14)
Retorno_Tangente <- Return.portfolio(R_Backtest, as.ts(Pesos_Tangente), rebalance_on = c("months"))
names(Retorno_Tangente) <- "Portfólio Tangente"
retornos_consolidados <- cbind(Retorno_Ingênuo, Retorno_wVT, Retorno_Tangente)
table.AnnualizedReturns(retornos_consolidados)
## Portfólio.Ingênuo Portfólio.Volatility.Timing
## Annualized Return 0.1710 -0.2293
## Annualized Std Dev 0.4286 0.3455
## Annualized Sharpe (Rf=0%) 0.3990 -0.6636
## Portfólio.Tangente
## Annualized Return 0.6121
## Annualized Std Dev 0.3381
## Annualized Sharpe (Rf=0%) 1.8104
charts.PerformanceSummary(retornos_consolidados, main = "Retornos")
Percebe-se que o portfólio tangente cumpre sua função, não só obtendo o maior retorno como também apresentando o maior sharpe no período. Em seguida, temos o portfólio de portfólio ingênuo e por fim o portfólio de Timing de Volatilidade. Consideramos um rebalanceamento mensal durante o ano de 2021.
retornos_GARCH <- retornos %>% select(Data, RADL3, SULA11, TAEE11) %>% dplyr::filter(Data >= "2016-01-01" & Data <= "2021-05-31")
retornos_RADL3 <- xts(retornos_GARCH$RADL3, retornos_GARCH$Data)
retornos_SULA11 <- xts(retornos_GARCH$SULA11, retornos_GARCH$Data)
retornos_TAEE11 <- xts(retornos_GARCH$TAEE11, retornos_GARCH$Data)
gspec <- ugarchspec(mean.model=list(
armaOrder=c(2,1)), variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
distribution="std")
gfit <- ugarchfit(gspec, retornos_RADL3)
gfit@fit$robust.matcoef
## Estimate Std. Error t value Pr(>|t|)
## mu 8.196363e-04 4.098745e-04 1.99972506 4.552996e-02
## ar1 7.753448e-01 8.524901e-02 9.09505883 0.000000e+00
## ar2 4.120658e-04 3.316732e-02 0.01242385 9.900875e-01
## ma1 -8.202923e-01 8.532198e-02 -9.61407990 0.000000e+00
## omega 2.463522e-05 1.139963e-05 2.16105452 3.069113e-02
## alpha1 6.702274e-02 2.658561e-02 2.52101597 1.170165e-02
## beta1 8.688688e-01 4.827514e-02 17.99826424 0.000000e+00
## shape 7.187889e+00 1.482782e+00 4.84756829 1.249840e-06
forc = ugarchforecast(gfit, n.ahead=21)
forc@forecast$sigmaFor*sqrt(252)
## 2021-05-31
## T+1 0.3249756
## T+2 0.3241092
## T+3 0.3232962
## T+4 0.3225335
## T+5 0.3218181
## T+6 0.3211471
## T+7 0.3205178
## T+8 0.3199278
## T+9 0.3193746
## T+10 0.3188560
## T+11 0.3183698
## T+12 0.3179142
## T+13 0.3174872
## T+14 0.3170870
## T+15 0.3167121
## T+16 0.3163607
## T+17 0.3160316
## T+18 0.3157232
## T+19 0.3154343
## T+20 0.3151637
## T+21 0.3149103
forc@forecast$seriesFor
## 2021-05-31
## T+1 -0.0007814567
## T+2 -0.0004092847
## T+3 -0.0001338610
## T+4 0.0000798408
## T+5 0.0002456468
## T+6 0.0003742917
## T+7 0.0004741042
## T+8 0.0005515463
## T+9 0.0006116317
## T+10 0.0006582506
## T+11 0.0006944210
## T+12 0.0007224848
## T+13 0.0007442588
## T+14 0.0007611527
## T+15 0.0007742603
## T+16 0.0007844302
## T+17 0.0007923207
## T+18 0.0007984428
## T+19 0.0008031928
## T+20 0.0008068782
## T+21 0.0008097376
gspec <- ugarchspec(mean.model=list(
armaOrder=c(2,1)), variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
distribution="std")
gfit <- ugarchfit(gspec, retornos_SULA11)
gfit@fit$robust.matcoef
## Estimate Std. Error t value Pr(>|t|)
## mu 1.153105e-03 5.108818e-04 2.2570884 2.400255e-02
## ar1 5.319176e-01 1.734112e-01 3.0673774 2.159460e-03
## ar2 -1.988795e-02 3.199146e-02 -0.6216643 5.341627e-01
## ma1 -5.614361e-01 1.763842e-01 -3.1830291 1.457430e-03
## omega 2.616844e-05 9.083238e-06 2.8809591 3.964670e-03
## alpha1 7.606815e-02 3.058134e-02 2.4874040 1.286792e-02
## beta1 8.679234e-01 3.941126e-02 22.0222166 0.000000e+00
## shape 6.889962e+00 1.458790e+00 4.7230666 2.323147e-06
forc = ugarchforecast(gfit, n.ahead=21)
forc@forecast$sigmaFor*sqrt(252)
## 2021-05-31
## T+1 0.3276280
## T+2 0.3285157
## T+3 0.3293516
## T+4 0.3301387
## T+5 0.3308799
## T+6 0.3315782
## T+7 0.3322360
## T+8 0.3328557
## T+9 0.3334397
## T+10 0.3339900
## T+11 0.3345087
## T+12 0.3349976
## T+13 0.3354585
## T+14 0.3358930
## T+15 0.3363026
## T+16 0.3366888
## T+17 0.3370530
## T+18 0.3373964
## T+19 0.3377203
## T+20 0.3380257
## T+21 0.3383138
forc@forecast$seriesFor
## 2021-05-31
## T+1 -0.0005037531
## T+2 0.0003633052
## T+3 0.0007659482
## T+4 0.0009628772
## T+5 0.0010596194
## T+6 0.0011071618
## T+7 0.0011305264
## T+8 0.0011420090
## T+9 0.0011476521
## T+10 0.0011504254
## T+11 0.0011517883
## T+12 0.0011524581
## T+13 0.0011527873
## T+14 0.0011529491
## T+15 0.0011530286
## T+16 0.0011530676
## T+17 0.0011530868
## T+18 0.0011530963
## T+19 0.0011531009
## T+20 0.0011531032
## T+21 0.0011531043
gspec <- ugarchspec(mean.model=list(
armaOrder=c(2,1)), variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
distribution="std")
gfit <- ugarchfit(gspec, retornos_TAEE11)
gfit@fit$robust.matcoef
## Estimate Std. Error t value Pr(>|t|)
## mu 9.612878e-04 3.372985e-04 2.849961 4.372453e-03
## ar1 -9.833944e-01 3.298326e-02 -29.814949 0.000000e+00
## ar2 -5.182912e-02 3.040139e-02 -1.704827 8.822662e-02
## ma1 9.556148e-01 3.799372e-03 251.519146 0.000000e+00
## omega 1.490003e-05 3.605971e-06 4.132043 3.595530e-05
## alpha1 1.150612e-01 1.606614e-02 7.161717 7.966960e-13
## beta1 8.196811e-01 2.420287e-02 33.867102 0.000000e+00
## shape 8.691598e+00 1.994739e+00 4.357261 1.317002e-05
forc = ugarchforecast(gfit, n.ahead=21)
forc@forecast$sigmaFor*sqrt(252)
## 2021-05-31
## T+1 0.2098861
## T+2 0.2119723
## T+3 0.2139039
## T+4 0.2156938
## T+5 0.2173536
## T+6 0.2188937
## T+7 0.2203236
## T+8 0.2216518
## T+9 0.2228862
## T+10 0.2240338
## T+11 0.2251013
## T+12 0.2260946
## T+13 0.2270191
## T+14 0.2278799
## T+15 0.2286816
## T+16 0.2294284
## T+17 0.2301243
## T+18 0.2307730
## T+19 0.2313776
## T+20 0.2319413
## T+21 0.2324671
forc@forecast$seriesFor
## 2021-05-31
## T+1 4.073938e-04
## T+2 1.967782e-03
## T+3 2.151137e-07
## T+4 1.854236e-03
## T+5 1.329796e-04
## T+6 1.729561e-03
## T+7 2.487030e-04
## T+8 1.622221e-03
## T+9 3.482627e-04
## T+10 1.529878e-03
## T+11 4.339123e-04
## T+12 1.450436e-03
## T+13 5.075952e-04
## T+14 1.382094e-03
## T+15 5.709835e-04
## T+16 1.323301e-03
## T+17 6.255153e-04
## T+18 1.272722e-03
## T+19 6.724282e-04
## T+20 1.229209e-03
## T+21 7.127866e-04