Primeiro, importamos nossa base de dados e apresentamos sua estrutura.
dados <- read_excel("Retornos_L2.xlsx")
## tibble[,6] [3,766 x 6] (S3: tbl_df/tbl/data.frame)
## $ data : POSIXct[1:3766], format: "2006-01-02" "2006-01-03" ...
## $ ABEV3: num [1:3766] -0.00266 0.02 0.00854 0.00515 0.02515 ...
## $ BBAS3: num [1:3766] -0.0261 0.0219 0.1357 0.0298 0.0393 ...
## $ NTCO3: num [1:3766] 0.000194 -0.013592 0.057972 0.074519 0.021645 ...
## $ KLBN4: num [1:3766] -0.01446 0.04645 0.02336 -0.00457 0.00459 ...
## $ LREN3: num [1:3766] 0.000133 0.056133 0.05921 0.063766 0.008403 ...
Primeiro, estimamos a volatilidade para cada um dos ativos
dados_estim <- dados %>% dplyr::filter(data <= "2015-12-31")
gspec <- ugarchspec(mean.model=list(
armaOrder=c(2,1)), variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
distribution="std")
gfit_abev <- ugarchfit(gspec, dados_estim$ABEV3)
gfit_bbas <- ugarchfit(gspec, dados_estim$BBAS3)
gfit_ntco <- ugarchfit(gspec, dados_estim$NTCO3)
gfit_klbn <- ugarchfit(gspec, dados_estim$KLBN4)
gfit_lren <- ugarchfit(gspec, dados_estim$LREN3)
forc_abev <- ugarchforecast(gfit_abev, n.ahead=21)
forc_bbas <- ugarchforecast(gfit_bbas, n.ahead=21)
forc_ntco <- ugarchforecast(gfit_ntco, n.ahead=21)
forc_klbn <- ugarchforecast(gfit_klbn, n.ahead=21)
forc_lren <- ugarchforecast(gfit_lren, n.ahead=21)
expected_vol <- c(
as.numeric(forc_abev@forecast$sigmaFor[21]*sqrt(252)),
as.numeric(forc_bbas@forecast$sigmaFor[21]*sqrt(252)),
as.numeric(forc_ntco@forecast$sigmaFor[21]*sqrt(252)),
as.numeric(forc_klbn@forecast$sigmaFor[21]*sqrt(252)),
as.numeric(forc_lren@forecast$sigmaFor[21]*sqrt(252)))
names(expected_vol) <- c("abev", "bbas", "ntco", "klbn", "lren")
expected_vol
## abev bbas ntco klbn lren
## 0.2473283 0.4776932 0.4739789 0.3702503 0.3828149
Em seguida, apresentamos o portfólio ingênuo
dados_aval <- dados %>% dplyr::filter(data > "2015-12-31")
dados_aval <- xts(dados_aval[,-1], dados_aval$data)
pesos <- rep(0.2,5)
port_ingenuo <- Return.portfolio(dados_aval, pesos, rebalance_on = "months")
Primeiro, transformamos nosso vetor contendo a volatilidade em um vetor contendo as variâncias.
expected_var <- expected_vol ^ 2
## abev bbas ntco klbn lren
## 0.0611713 0.2281908 0.2246560 0.1370853 0.1465472
pesos_vt <- (1/expected_var)^4/sum((1/expected_var)^4)
port_vt <- Return.portfolio(dados_aval, pesos_vt, rebalance_on = "months")
Para a construção do portfólio de variância mínima precisamos não apenas da covariância do ativo com ele mesmo (variância) como também da covariância de um ativo com os outros ativos. Assim, consideraremos que as covariâncias são as mesmas do período de estimação e que apenas as variâncias são estimadas pelo GARCH.
estim_ret <- dados_estim %>% select(!data)
cov_estim <- cov(estim_ret)
diag(cov_estim) <- expected_var
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## ABEV3 0.0611712977 0.0001787557 0.0001127745 0.0001367976 0.0001626977
## BBAS3 0.0001787557 0.2281907579 0.0002175308 0.0002730899 0.0003340463
## NTCO3 0.0001127745 0.0002175308 0.2246560392 0.0001474610 0.0002364605
## KLBN4 0.0001367976 0.0002730899 0.0001474610 0.1370852657 0.0002442249
## LREN3 0.0001626977 0.0003340463 0.0002364605 0.0002442249 0.1465472379
pesos_vm <- inv(cov_estim) %*% rep(1,5)
pesos_vm <- as.vector(pesos_vm)
pesos_vm <- pesos_vm/sum(pesos_vm)
port_vm <- Return.portfolio(dados_aval, pesos_vm, rebalance_on = "months")
risco_ing <- (t(pesos)%*%cov(dados_aval)%*%pesos)^0.5
## [,1]
## [1,] 0.01772492
marginal_ing <- pesos%*%cov(dados_aval)/ as.numeric(risco_ing)
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.01219673 0.02346567 0.02236768 0.01069016 0.01990436
indiv_ing <- marginal_ing*pesos
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.002439346 0.004693135 0.004473536 0.002138032 0.003980872
risco_vt <- (t(pesos_vt)%*%cov(dados_aval)%*%pesos_vt)^0.5
## [,1]
## [1,] 0.01749295
marginal_vt <- pesos_vt%*%cov(dados_aval)/ as.numeric(risco_vt)
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.01811298 0.01332876 0.01211139 0.006558503 0.01303256
indiv_vt <- marginal_vt*pesos_vt
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.01676091 6.369364e-05 6.160559e-05 0.0002406246 0.0003661152
risco_vm <- (t(pesos_vm)%*%cov(dados_aval)%*%pesos_vm)^0.5
## [,1]
## [1,] 0.01616975
marginal_vm <- pesos_vm%*%cov(dados_aval)/ as.numeric(risco_vm)
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.01499041 0.02090103 0.01976915 0.01091536 0.01924277
indiv_vm <- marginal_vm*pesos_vm
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## [1,] 0.006246999 0.002323812 0.002238549 0.002025007 0.003335384
Mport <- portfolio.spec( assets = colnames(estim_ret))
Mport <- add.constraint( portfolio=Mport, type='box', min = 0, max=1 )
ObjSpec = add.objective( portfolio = Mport , type="risk",name="CVaR",
arguments=list(p=0.95,clean="boudt"), enabled=TRUE)
ObjSpec <- add.constraint(portfolio=ObjSpec, type="weight_sum",
min_sum=0.99, max_sum=1.01)
set.seed(15)
out <- optimize.portfolio(R=estim_ret_xts, portfolio=ObjSpec,
optimize_method="DEoptim", search_size=2000,
traceDE=5, itermax=50, trace=TRUE)
## Iteration: 5 bestvalit: 0.030800 bestmemit: 0.570000 0.028000 0.264000 0.100000 0.048000
## Iteration: 10 bestvalit: 0.030141 bestmemit: 0.538000 0.012000 0.260000 0.138000 0.044000
## Iteration: 15 bestvalit: 0.030141 bestmemit: 0.538000 0.012000 0.260000 0.138000 0.044000
## [1] 0.538 0.012 0.260 0.138 0.044
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
##
## Call:
## optimize.portfolio(R = estim_ret_xts, portfolio = ObjSpec, optimize_method = "DEoptim",
## search_size = 2000, trace = TRUE, traceDE = 5, itermax = 50)
##
## Optimal Weights:
## ABEV3 BBAS3 NTCO3 KLBN4 LREN3
## 0.538 0.012 0.260 0.138 0.044
##
## Objective Measures:
## CVaR
## 0.03014
Assim, com os pesos em mãos, podemos calcular o retorno do portfólio otimizado.
port_cvar <- Return.portfolio(dados_aval, out$weights, rebalance_on = "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
Realizando uma comparação com todas as outras estratégias,
Como podemos observar, a otimização por CVar não entregou um resultado supeior. Isso é consistente com múltiplas pesquisas que mostram que o \(1/n\) é simples, mas não é simplório.
Primeiro, importamos os dados com os dados sobre os ativos ESG e não ESG.
dados_esg <- read_excel("Retornos_L2.xlsx", sheet = 2)
## tibble[,11] [1,565 x 11] (S3: tbl_df/tbl/data.frame)
## $ Data : POSIXct[1:1565], format: "2015-07-07" "2015-07-08" ...
## $ ELET3 : num [1:1565] -0.01833 -0.01358 0 0 0.00169 ...
## $ BBDC3 : num [1:1565] 0.00146 -0.01424 0 0 0.01121 ...
## $ ITUB4 : num [1:1565] 0.00383 -0.01145 0 0 0.00923 ...
## $ LREN3 : num [1:1565] -0.019784 -0.014417 0 0 0.000259 ...
## $ KLBN11: num [1:1565] -0.00634 0.00266 0 0 0.01853 ...
## $ BBSE3 : num [1:1565] -0.00148 -0.01834 0 0 0.01164 ...
## $ CVCB3 : num [1:1565] -0.0107 -0.0119 0 0 0.022 ...
## $ PRIO3 : num [1:1565] -0.0049 -0.01478 0 0 0.00478 ...
## $ EQTL3 : num [1:1565] 0.003018 0.000274 0 0 -0.005427 ...
## $ GOAU4 : num [1:1565] -0.0196 -0.031 0 0 0.0398 ...
Selecionamos os ativos com base no rating ESG divulgado pela Standart & Poors. As 5 primeiras colunas contém aquelas empresas classificadas como “green companies” e as 5 últimas colunas contém aquelas empresas classificadas como “brown companies”.
green <- dados_esg[,1:6]
green_estim <- green %>% dplyr::filter(Data <= "2018-12-31")
green_aval <- green %>% dplyr::filter(Data > "2018-12-31")
green_aval <- xts(green_aval[,-1], green_aval$Data)
var_green <- apply(green_estim[,-1], 2, var)
pesos_vt_green <- (1/var_green)^4/sum((1/var_green)^4)
port_vt_green <- Return.portfolio(green_aval, pesos_vt_green, rebalance_on = "quarters")
brown <- dados_esg[,c(1, 7:11)]
brown_estim <- brown %>% dplyr::filter(Data <= "2018-12-31")
brown_aval <- brown %>% dplyr::filter(Data > "2018-12-31")
brown_aval <- xts(brown_aval[,-1], brown_aval$Data)
var_brown <- apply(brown_estim[,-1], 2, var)
pesos_vt_brown <- (1/var_brown)^4/sum((1/var_brown)^4)
port_vt_brown <- Return.portfolio(brown_aval, pesos_vt_brown, rebalance_on = "quarters")
Mport <- portfolio.spec( assets = colnames(green_estim[,-1]))
Mport <- add.constraint( portfolio=Mport, type='box', min = 0, max=1 )
ObjSpec <- add.objective(portfolio=Mport, type="risk_budget_objective",
name="CVaR", max_prisk=0.35,
arguments=list(p=0.95, clean="boudt"))
ObjSpec <- add.constraint(portfolio=ObjSpec, type="weight_sum",
min_sum=0.99, max_sum=1.01)
set.seed(15)
.storage <- new.env()
out <- optimize.portfolio(R=green_estim_xts, portfolio=ObjSpec,
optimize_method="DEoptim", search_size=2000,
traceDE=5, itermax=50, trace=TRUE)
## Iteration: 5 bestvalit: 0.000000 bestmemit: 0.168000 0.034000 0.270000 0.326000 0.210000
## [1] 0.200 0.188 0.236 0.252 0.122
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
##
## Call:
## optimize.portfolio(R = green_estim_xts, portfolio = ObjSpec,
## optimize_method = "DEoptim", search_size = 2000, trace = TRUE,
## traceDE = 5, itermax = 50)
##
## Optimal Weights:
## ELET3 BBDC3 ITUB4 LREN3 KLBN11
## 0.200 0.188 0.236 0.252 0.122
##
## Objective Measures:
## CVaR
## 0.03115
##
## contribution :
## ELET3 BBDC3 ITUB4 LREN3 KLBN11
## 0.009706 0.006428 0.006936 0.006983 0.001101
##
## pct_contrib_MES :
## ELET3 BBDC3 ITUB4 LREN3 KLBN11
## 0.31155 0.20632 0.22264 0.22416 0.03533
Assim, com os pesos em mãos, podemos calcular o retorno do portfólio otimizado.
port_cvar_green <- Return.portfolio(green_estim_xts, out$weights, rebalance_on = "months")
Mport <- portfolio.spec( assets = colnames(brown_estim[,-1]))
Mport <- add.constraint( portfolio=Mport, type='box', min = 0, max=1 )
ObjSpec <- add.objective(portfolio=Mport, type="risk_budget_objective",
name="CVaR", max_prisk=0.35,
arguments=list(p=0.95, clean="boudt"))
ObjSpec <- add.constraint(portfolio=ObjSpec, type="weight_sum",
min_sum=0.99, max_sum=1.01)
set.seed(15)
.storage <- new.env()
out <- optimize.portfolio(R=brown_estim_xts, portfolio=ObjSpec,
optimize_method="DEoptim", search_size=2000,
traceDE=5, itermax=50, trace=TRUE)
## Iteration: 5 bestvalit: 0.000000 bestmemit: 0.299390 0.118601 0.195758 0.296000 0.095740
## Iteration: 10 bestvalit: 0.000000 bestmemit: 0.308220 0.048040 0.224397 0.315269 0.098450
## [1] 0.30821985 0.04803965 0.22439701 0.31526896 0.09845022
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
##
## Call:
## optimize.portfolio(R = brown_estim_xts, portfolio = ObjSpec,
## optimize_method = "DEoptim", search_size = 2000, trace = TRUE,
## traceDE = 5, itermax = 50)
##
## Optimal Weights:
## BBSE3 CVCB3 PRIO3 EQTL3 GOAU4
## 0.3082 0.0480 0.2244 0.3153 0.0985
##
## Objective Measures:
## CVaR
## 0.03168
##
## contribution :
## BBSE3 CVCB3 PRIO3 EQTL3 GOAU4
## 0.008906 0.001073 0.010006 0.006217 0.005479
##
## pct_contrib_MES :
## BBSE3 CVCB3 PRIO3 EQTL3 GOAU4
## 0.28112 0.03387 0.31582 0.19625 0.17295
Assim, com os pesos em mãos, podemos calcular o retorno do portfólio otimizado.
port_cvar_brown <- Return.portfolio(brown_estim_xts, out$weights, rebalance_on = "months")
Esperamos, pela teoria financeira, que os ativos “green” tenham um desempenho superior em relaçao aos ativos “brown”. Assim, criamos um portfólio cash neutral 100% comprado nos ativos ESG e 100% vendido nos ativos não ESG.
ls_esg_vt <- port_vt_green - port_vt_brown
ls_esg_cvar <- port_cvar_green - port_cvar_brown
A implementação de uma regra de investimento long-short considerando 2 cenários (Markov) em função da volatilidade do índice Ibovespa pode ser algo bastante interessante. O primeiro passo seria entender em qual dos dois cenários estamos e qual é o comportamento costumaz do mercado nessa situação. O seguinte passo seria monitorar esse indicador visando captar a transição de estado.
Então, suponhamos um investidor que utiliza Markov no seu processo de tomada de decisão. Suponhamos também que seu modelo indique que o mercado se encontra no estado 1 - típico de um mercado bullish com menor volatilidade. Nosso investidor hipotético, sabendo disso, constrói um portfólio que tende a performar melhor nesse canário. Assim, o seu portfólio é composto de empresas com um beta mais alto e opções de compra. Durante um determinado período seu portfólio tem um bom desempenho, entretanto, ao longo do tempo nosso investidor começa a perceber que a matriz de transição passa a indicar uma probabilidade cada vez maior de um transição para o estado 2 - típico de um mercado bearish com maior volatilidade. Assim, de forma gradual, nosso gestor começa a alterar suas posições em direção a um portfólio mais conservador: as posições em empresas com um beta mais alto são reduzidas e as opções de compra também. O gestor leva algum tempo para alterar sua carteira, mas depois de um tempo já está comprado em empresas com um beta mais baixo e possui em seu portfólio algumas opções de venda e algumas opções de compra vendida.
O leitor mais atento pode perceber uma vantagem da abordagem acima: nosso investidor hipotético adotou um processo matemático que lhe fornece uma noção aproximada da probabilidade de transição entre estados do mercado, entretanto, ele o fez sem incorrer hora nenhuma em um risco de ter um desempenho muito pior que seus pares. Como o senso comum já sabe, é melhor errar e acertar com a multidão do que correr o risco de errar sozinho. Assim, na estratégia descrita acima, a probabilidade do investidor está totalmente errado enquanto a visão do mercado está correta é bem baixa, dada que as mudanças no portfólio são táticas. Entretanto, se o modelo estiver correto na média, os ganhos decorrentes dessa inclinação do portfólio de acordo com o estado atual do mercado irão gerar um efeito multiplicador nos retornos desse portfólio de modo que, no longo prazo, a carteira tenderá a ter um desempenho superior em relação aos pares.
Após a realização do trabalho podemos perceber que as formas de otimização de portfólio são úteis em algumas circunstâncias, entretanto, devem ser olhadas com um certo grau de ceticismo saudável. Podemos perceber, também, que não existe uma “fórmula mágica” que irá retornar um vetor de pesos “ideal” para um portfólio ou uma regra de investimento que sempre irá superar o benchmark. Assim, uma abordagem que pode ser recomendada é realizar backtests desses processos de otimização ficando atento a quais são os períodos de outperformance e underperformance, como é a distribuição dos retornos em um período de stress, etc. Por fim, a mensagem final é de que os modelos de otimização de portfólio e as regras de seleção de ativos foram/são um grande avanço na teoria financeira, entretanto, sua implementação deve sempre respeitar as limitações de cada modelo e tentar entender o comportamento do portfólio em diferentes cenários.