Um passo a passo inicial para a otimização de carteiras

Carregamento dos pacotes necessários

pacman::p_load(tidyverse, tidyquant, PortfolioAnalytics, quantmod, 
               PerformanceAnalytics, zoo, plotly, ggthemes, timetk)

Este pacote dá capacidade multiprocessamento para o pacote PortfolioAnalytics.

library(doParallel)
registerDoParallel()

Obtenção dos dados

Relacione os ativos e estabeleça a data de início da série histórica.

simbolos <- c("PETR4.SA", "ITUB4.SA", "MGLU3.SA", "EMBR3.SA", "VALE3.SA")

inicio <- '2016-01-01'
precos_acoes  <- tq_get(simbolos, 
                        get = "stock.prices", 
                        from = inicio)

precos_acoes <- precos_acoes %>%
    select(symbol, date, adjusted) %>%
    rename(Acao = symbol, Preco = adjusted) 

knitr::kable(precos_acoes[1:6,])
Acao date Preco
PETR4.SA 2016-01-04 6.373318
PETR4.SA 2016-01-05 6.197053
PETR4.SA 2016-01-06 5.937296
PETR4.SA 2016-01-07 5.807419
PETR4.SA 2016-01-08 5.816695
PETR4.SA 2016-01-11 5.649709

Remova itens duplicados (acontece) e tidy os dados

precos_acoes <- precos_acoes[!duplicated(precos_acoes), ]

# Uma alternativa:

#precos_acoes <- precos_acoes[unique(precos_acoes), ]
precos_acoes2 <- precos_acoes %>% spread(Acao, Preco)
knitr::kable(precos_acoes2[1:6,])
date EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA
2016-01-04 28.46402 12.10981 0.188820 6.373318 11.309562
2016-01-05 28.46402 12.21104 0.190714 6.197053 11.158054
2016-01-06 28.05628 12.16285 0.174199 5.937296 10.338134
2016-01-07 27.44467 11.93155 0.151056 5.807419 9.723193
2016-01-08 27.54175 11.93632 0.151687 5.816695 9.393443
2016-01-11 27.43496 11.79662 0.151687 5.649709 9.126077

Note: a função periodReturn() do pacote quantmod pode ser utilizada para converter prços diários em retornos.

Obtenha e apresente os retornos mensais (aritméticos) das ações por data

precos_acoes2 <- simbolos %>%
    tq_get(get  = "stock.prices",
           from = inicio,
           to   = today() -1) %>%  #ontem
    group_by(symbol) 

knitr::kable(precos_acoes2[1:6,])
symbol date open high low close volume adjusted
PETR4.SA 2016-01-04 6.57 7.03 6.55 6.87 45962100 6.373318
PETR4.SA 2016-01-05 6.92 7.00 6.62 6.68 29446700 6.197053
PETR4.SA 2016-01-06 6.53 6.54 6.40 6.40 67507200 5.937296
PETR4.SA 2016-01-07 6.19 6.43 6.08 6.26 57387900 5.807419
PETR4.SA 2016-01-08 6.38 6.45 6.13 6.27 52100300 5.816695
PETR4.SA 2016-01-11 6.27 6.30 6.05 6.09 51334000 5.649709
retornos_carteira <- precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "daily",
                 type       = "arithmetic",
                 col_rename = "returns") %>%
    spread(key = symbol, value = returns)

knitr::kable(retornos_carteira[1:6,])
date EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA
2016-01-04 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
2016-01-05 0.0000000 0.0083588 0.0100307 -0.0276567 -0.0133965
2016-01-06 -0.0143249 -0.0039464 -0.0865956 -0.0419162 -0.0734823
2016-01-07 -0.0217992 -0.0190170 -0.1328538 -0.0218748 -0.0594828
2016-01-08 0.0035374 0.0003997 0.0041773 0.0015973 -0.0339138
2016-01-11 -0.0038776 -0.0117035 0.0000000 -0.0287081 -0.0284630
precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns") %>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_bar(stat = "identity", width = 30) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = "Retornos Mensais",
         subtitle = "",
         y = "Retornos", x = "") + 
    facet_wrap(~ symbol, ncol = 2, scales = "free") +
    theme_tq() + 
    scale_fill_tq()

precos_acoes_daily <- precos_acoes2 %>%
    group_by(symbol)
precos_acoes_daily %>%
    ggplot(aes(x = date, y = adjusted, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "Preços Diáros",
         x = "", y = "Preços Ajustados", color = "") +
    facet_wrap(~ symbol, ncol = 2, scales = "free") +
    scale_y_continuous(labels = scales::dollar) +
    theme_tq() + 
    scale_color_tq()

precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_line(aes(color = symbol)) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = "Retornos Mensais",
         subtitle = "",
         y = "Retornos", x = "") + 
    facet_wrap(~ symbol, ncol = 2, scales = "free") +
    theme_tq() + 
    scale_fill_tq()

precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_smooth(aes(color=symbol), method = 'loess' , formula = y ~ x) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = "Retornos Mensais",
         subtitle = "",
         y = "Retornos", x = "") + 
    facet_wrap(~ symbol, ncol = 2, scales = "free") +
    theme_tq() + 
    scale_fill_tq()

precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_density(stat = "identity") +
    theme_bw()

precos_acoes2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "quarterly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_density(stat = "identity", alpha=0.6) +
    labs(title = "Retornos Mensais",
         subtitle = "",
         y = "Retornos", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free") +
    theme_tq() + 
    scale_fill_tq()

library(ggthemes)

stockd <- tq_get(simbolos, get = "stock.prices", from = inicio)
stockd %>% 
    ggplot(aes(x = date, y = adjusted)) +
    geom_line() + # Plot stock price
    geom_bbands(aes(high = high, low = low, close = close), 
                ma_fun = SMA, 
                n = 100,
                show.legend = TRUE) +
    ggthemes::theme_hc() +
    scale_colour_hc() +
    facet_wrap(~  symbol, ncol = 2, scales = "free")

Converta os retornos das ações em objetos xts (séries temporais)

retornos_carteira <- retornos_carteira %>%
    tk_xts()

retornos_carteira %>% head()
##                EMBR3.SA      ITUB4.SA     MGLU3.SA     PETR4.SA    VALE3.SA
## 2016-01-04  0.000000000  0.0000000000  0.000000000  0.000000000  0.00000000
## 2016-01-05  0.000000000  0.0083587569  0.010030717 -0.027656709 -0.01339645
## 2016-01-06 -0.014324892 -0.0039464295 -0.086595635 -0.041916214 -0.07348235
## 2016-01-07 -0.021799187 -0.0190170098 -0.132853805 -0.021874773 -0.05948278
## 2016-01-08  0.003537371  0.0003996967  0.004177259  0.001597267 -0.03391376
## 2016-01-11 -0.003877567 -0.0117035273  0.000000000 -0.028708055 -0.02846305

Salva o vetor de retornos médios e a matriz de covariância

retornos_carteira <- na.omit(retornos_carteira)
retornos_medios <- colMeans(retornos_carteira)
mat_covariancia <- cov(retornos_carteira)

knitr::kable(mat_covariancia)
EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA
EMBR3.SA 0.0008312 0.0002435 0.0002707 0.0003298 0.0002748
ITUB4.SA 0.0002435 0.0004487 0.0003231 0.0004380 0.0002517
MGLU3.SA 0.0002707 0.0003231 0.0017757 0.0005038 0.0003767
PETR4.SA 0.0003298 0.0004380 0.0005038 0.0011054 0.0005292
VALE3.SA 0.0002748 0.0002517 0.0003767 0.0005292 0.0009707

A carteira ótima com os atuais parâmetros é independente dos pesos inciais.

p <- portfolio.spec(assets = colnames(retornos_carteira))
p
## **************************************************
## PortfolioAnalytics Portfolio Specification 
## **************************************************
## 
## Call:
## portfolio.spec(assets = colnames(retornos_carteira))
## 
## Number of assets: 5 
## Asset Names
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"

A carteira ótima de Markowitz considera a minimização do risco(variância) e maximização do retorno médio.

p <- add.objective(portfolio = p, 
                   type = "risk", 
                   name = "var")

p <- add.constraint(portfolio = p, 
                    type = "full_investment")

o parâmetro type = 'full_investment" é equivalente à restrição de que os pesos das ações na carteira devem somar 1. Esta opção é compatível com um investidor com baixa tolerância ao risco. A otimização, portanto, obtém os pesos que formam a carteira com a menor variância. Esta é a carteira com mínima variância global.

Se uma carteira eficiente está sendo procurada, então uma restrição adicional, especificamente o mínimo retorno esperado, deve ser adicionada.

retorno_alvo <- mean(retornos_medios)

p <- add.constraint(portfolio = p, 
                    type = "return", 
                    return_target = retorno_alvo)
p
## **************************************************
## PortfolioAnalytics Portfolio Specification 
## **************************************************
## 
## Call:
## portfolio.spec(assets = colnames(retornos_carteira))
## 
## Number of assets: 5 
## Asset Names
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"
## 
## Constraints
## Enabled constraint types
##      - full_investment 
##      - return 
## 
## Objectives:
## Enabled objective names
##      - var

O retorno_alvo deve ser substituído pelo valor de interesse. Foi selecionada a média global dos retornos no período.

Por exemplo, se estivermos trabalhando com retornos diários, e nossa expectativa mínima de retorno seja de 15% a.a., escolheríamos retorno_alvo = 0.15/250, refletindo o fato de termos 250 dias úteis no ano.

Para otimizar esta carteira devemos ter como entrada **R** a série temporal de retornos e especificar a função de otimização desejada para a função objetivo. Vejamos o uso do retorno sobre o Investimento (ROI):

# Otimizar com ROI

optimize.portfolio(R = retornos_carteira, 
                   portfolio = p, 
                   optimize_method = "ROI", 
                   trace = TRUE)
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
## 
## Call:
## optimize.portfolio(R = retornos_carteira, portfolio = p, optimize_method = "ROI", 
##     trace = TRUE)
## 
## Optimal Weights:
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##   0.0739   0.5882   0.2023  -0.0924   0.2279 
## 
## Objective Measure:
##  StdDev 
## 0.02042

Criando a especificação de uma carteira

Utilizaremos as funções do pacote PortfolioAnalytics.

Usando PortfolioAnalytics::porfolio.spec()

Inicie com os nomes dos ativos

port <- portfolio.spec(assets = colnames(retornos_carteira))

Incluindo agumas restrições (constraints)

Box constraints leverage (soma dos pesos)

# Box
port <- add.constraint(port, 
                       type = "box", 
                       min = 0.05, 
                       max = 0.8)

# Leverage
port <- add.constraint(portfolio = port, 
                       type = "full_investment")

port
## **************************************************
## PortfolioAnalytics Portfolio Specification 
## **************************************************
## 
## Call:
## portfolio.spec(assets = colnames(retornos_carteira))
## 
## Number of assets: 5 
## Asset Names
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"
## 
## Constraints
## Enabled constraint types
##      - box 
##      - full_investment

Um teste inicial

A função random_porfolios cria um conjunto de carteiras viáveis que satisfaçam às restrições especificadas.

# Gera carteiras aleatórias

rportfolios <- random_portfolios(port, 
                                 permutations = 5000, 
                                 rp_method = "sample")

Vamos adicionar alguns objetivos e otimizar, inicialmente utilizando apenas a média-variância (à la Markowitz).

# Obtém a carteira de mínima variância
minvar.port <- add.objective(port, 
                             type = "risk", 
                             name = "var")

# Optimiza a carteira
minvar.opt <- optimize.portfolio(retornos_carteira, 
                                 minvar.port, 
                                 optimize_method = "random", 
                                 rp = rportfolios)

# Adiciona o objetivo de máximo retorno
maxret.port <- add.objective(port, 
                             type = "return", 
                             name = "mean")

# Optimiza acarteira
maxret.opt <- optimize.portfolio(retornos_carteira, 
                                 maxret.port, 
                                 optimize_method = "random", 
                                 rp = rportfolios)

# Gera o vetor de retornos
minret <- 0.06/100  # arbitrário

maxret <- maxret.opt$weights %*% retornos_medios

vec <- seq(minret, maxret, length.out = 50)

Já é possível construir a fronteira eficiente neste estágio, após especificarmos as carteiras de mínima variância e máximo retorno. Adicionaremos um objetivo de máxima concentração de pesos para prevenir carteiras muito concentradas em um único ativo. Note que a função random_portfolios()ignora qualquer especificação de restrições.

Primeiro, vamos criar um vetor com os nomes dos ativos do fundo de ações.

nome_fundos <- colnames(retornos_carteira)

Criando o objeto carteira (portfolio)

O objeto carteira é criado com a função portfolio.spec(). O argumento principal, que é necessário, é assets. Ele pode ser um valor escalar com o número de ativos, um vetor de caracteres com os nomes do fundo, ou um vetor (com nomes) de pesos iniciais. Se os pesos não forem fornecidos, assume-se uma carteira com pesos iguais para todos os ativos. O objeto S3 criado é da classe portfolio. Inicialmente, ele possui um elemento chamado assets com os pesos iniciais, um elemento chamado category_labels, um elemento chamdo named weight_seq com a sequência de pesos, se especificados, uma lista (vazia) de restrições e uma lista (vazia) de objetivos.

Vamos especificar um objeto portfolio passando o vetor de caracteres nome_fundos para o argumento assets.

pspec <- portfolio.spec(assets = nome_fundos)

print.default(pspec)
## $assets
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##      0.2      0.2      0.2      0.2      0.2 
## 
## $category_labels
## NULL
## 
## $weight_seq
## NULL
## 
## $constraints
## list()
## 
## $objectives
## list()
## 
## $call
## portfolio.spec(assets = nome_fundos)
## 
## attr(,"class")
## [1] "portfolio.spec" "portfolio"

Adicionando restrições

A adição de restrições à carteira é feita por meio da função add.constraint(), que é a interface principal para adicionar e/ou atualizar (utilizando o argumento indexnum) restrições ao objeto do tipo portfolio.

Pode-se especificar o tipo de restrição, os argumentos para ela, e se a restrição está ativa ou não (enabled = TRUE é o padrão).

Restrição da soma dos pesos

A restrição de soma dos pesos, “weight_sum”, estabelece o valor necessário para a soma dos pesos da carteira. “leverage” e “weight” podem ser utilizados como sinônimos.

Vamos impor que a soma dos pesos seja exatamente igual a 1, ou seja, uma restrição de investimento completo (todas as ações).

pspec <- add.constraint(portfolio = pspec,
                        type = "weight_sum",
                        min_sum = 1,
                        max_sum = 1)

A mesma restrição poderia ser especificada com type = "full_investment".

Há dois casos especiais para a restrição “leverage”:

  1. A soma dos pesos igual a 1, isto é, a restrição de investimento completo, que pode ser escificado com type = 'full_investment. Isso é equivalente a especificar min_sum = 1 e max_sum = 1.
  2. A soma dos pesos igual a 0. É especificado com type = “dollar_neutral” ou type = “active”.

Restrição de “Caixa” - Box

As restrições de Box" permitem que o usuário especifique limites superiores e inferiores aos pesos dos ativos.

Vamos dar um exemplo (mas não executar) de restrições de “Box” para os pesos de ativos de modo que o peso mínimo de qualquer ativo seja maior ou igual a 0,05 e o peso máximo de qualquer ativo seja menor ou igual a 0,4. Os valores para min e max podem ser passados como escalares ou vetores. Se min e max forem escalares, os valores serão replicados como vetores para todos os ativos. Se min e max não forem especificados, um peso mínimo de 0 e peso máximo de 1 são assumidos.

Adicionando restrições de “Box”

# pspec <- add.constraint(portfolio = pspec,
#                         type = "box",
#                         min = 0.05,
#                         max = 0.4)

# min e max especificados para cada ativo
# pspec <- add.constraint(portfolio = pspec,
#                         type = "box",
#                         min = c(0.05, 0, 0.08, 0.1, 0.15),
#                         max = c(0.4, 0.3, 0.7, 0.55, 0.4))

type = "long_only" é padrão se min e max não forem especificados e implica em min = 0 e max = 1.

Restrições de grupo

As restrições de grupo permitem que o usuário especifique a soma dos pesos por grupo de ativos. As restrições do grupo podem atualmente ser utilizadas com os otimizadores de portfólio ROI, DEoptim e “random portfolio”.

O seguinte código agrupa os ativos de tal forma que os três primeiros estarão no mesmo grupo, chamado “GrupoA” e os dois últimoso ativos estão em seu próprio grupo denominado “GrupoB”. O argumento group_min especifica que a soma dos pesos em no GrupoA deve ser maior ou igual a 0,1 e a soma dos pesos no GrupoB deve ser maior ou igual a 0,15. O argumento group_max especifica que a soma dos pesos no GrupoA deve ser menor ou igual a 0,85 e a soma dos pesos no GrupoB deve ser menor ou igual a 0,55. O argumento group_labels é opcional e é útil se o argumento groups não for uma lista nomeada para rotular os grupos em termos de capitalização de mercado, setor, etc.

Adicionando restrições de grupo

pspec <- add.constraint(portfolio = pspec, 
                        type = "group",
                        groups = list(groupA = c(1, 2, 3),
                                      grouB = c(4, 5)),
                        group_min = c(0.1, 0.15),
                        group_max = c(0.85, 0.55))

Restrições de limite de posições

A restrição do limite de posições permite que o usuário especifique limites no número de ativos com posições não-zero, longas ou curtas.

Nota técnica: O otimizador ROI possui interface para o pacote Rglpk (ou seja, usando o plugin glpk) para resolver a maximização de retorno e os objetivos ETL/ES/cVaR. O pacote Rglpk suporta programação inteira e, portanto, restrições de limite de posição para o argumento max_pos. O pacote quadprog não suporta programação inteira, e, portanto, max_pos não é suportado para o otimizador de ROI usando o plugin quadprog. Observe que max_pos_long e max_pos_short não são suportados para nenhum dos solucionador de ROI. Todas as restrições de limite de posições são totalmente suportadas para DEoptim e otimizadores aleatórios.

Vamos Adicionar uma restrição de limite de posições de tal forma que teremos um número máximo de três ativos com peso maior do que zero.

pspec <- add.constraint(portfolio = pspec, 
                        type = "position_limit", 
                        max_pos = 3)

Pode-se, também, especifiar o máximo número de posições “longas” e “curtas” com o seguinte:

pspec <- add.constraint(portfolio = pspec, type = "position_limit", max_pos_long = 3, max_pos_short = 3)
### Restrição de diversificação

A restrição de diversificação permite que o usuário busque a diversificação da carteira. A diversificação é calculada como \(1 - \sum_{i=1}^nweights^2\). A restrição de diversificação é implementada nos otimizadores globais aplicando uma penalidade se o valor de diversificação estiver a mais de 5% do parâmetro div_target. A restrição de diversificação não é suportada para os otimizadores de ROI, apenas para os otimizadores numéricos globais. Veja neste link um tutorial sobre otimizadores em R.

pspec <- add.constraint(portfolio = pspec, 
                        type = "diversification", 
                        div_target = 0.7)

Restrições de turnover

O volume de negócios daturnover* de uma carteira é uma medida de quão frequentemente os ativos são comprados e vendidos pelos gestores. O turnover é calculado tomando o valor total dos novos títulos comprados ou o número de títulos vendidos (o que for menor) durante um determinado período, dividido pelo valor total do ativo líquido da carteira. A medida é geralmente feita para um período de 12 meses.

Um determinado turnover-alvo pode ser especificado como uma restrição. o turnover inicial é calculado a partir de um conjunto de pesos iniciais; por padrão, são os pesos iniciais no objeto da carteira. A restrição de turnover é implementada para os otimizadores globais aplicando uma penalidade se o seu valor estiver a mais de 5% do alvo. Essa restrição não é suportada atualmente para a otimização quadrática e para problemas de mínima variância usando o otimizador de ROI.

pspec <- add.constraint(portfolio = pspec, 
                        type = "turnover", 
                        turnover_target = 0.2)

Restrição de retorno_alvo

Como vimos, esta restrição habilita a especificação de um retorno médio como alvo do investimento.

retorno_alvo <- 0.007
pspec <- add.constraint(portfolio = pspec, 
                        type = "return", 
                        return_target = retorno_alvo)

Restrição de fator de exposição

A restrição de fator de exposição permite que o usuário estabeleça limites superiores e inferiores para a exposição a fatores de risco. As exposições podem ser passads como um vetor ou uma matriz. Aqui especificamos um vetor para B com valores arbitrários, isto é, betas dos ativos, com uma faixa de exposição ao risco de mercado de 0,6 a 0,9.

pspec <- add.constraint(portfolio = pspec, 
                        type = "factor_exposure",
                        B = c(0.08, 0.37, 0.79, 1.43, 0.5),
                        lower = 0.6, 
                        upper = 0.9)

Restrição de custo da transação

A restrição de custo da transação permite que o usuário especifique os custos proporcionais das transações (negócios). As restrições podem ser implementadas para o otimizador quadrático e para problemas de mínima variância mínima usando o otimizador de ROI. Os custos de transação são considerados como uma penalidade para os otimizadores numéricos globais. Aqui adicionamos a restrição de custo proporcional da transação com o valor 1%.

pspec <- add.constraint(portfolio = pspec, 
                        type = "transaction_cost", 
                        ptc = 0.01)

O método print() do objeto portfolio mostra de modo conciso a carteira e as restrições que foram adicionadas. O método summary() apresenta mais detallhes.

print(pspec)
## **************************************************
## PortfolioAnalytics Portfolio Specification 
## **************************************************
## 
## Call:
## portfolio.spec(assets = nome_fundos)
## 
## Number of assets: 5 
## Asset Names
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"
## 
## Constraints
## Enabled constraint types
##      - weight_sum 
##      - group 
##      - position_limit 
##      - diversification 
##      - turnover 
##      - return 
##      - factor_exposure 
##      - transaction_cost
summary(pspec)
## $assets
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##      0.2      0.2      0.2      0.2      0.2 
## 
## $enabled_constraints
## $enabled_constraints[[1]]
## An object containing 6 nonlinear constraints.
## 
## $enabled_constraints[[2]]
## An object containing 7 nonlinear constraints.
## 
## $enabled_constraints[[3]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[4]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[5]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[6]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[7]]
## An object containing 6 nonlinear constraints.
## 
## $enabled_constraints[[8]]
## An object containing 4 nonlinear constraints.
## 
## 
## $disabled_constraints
## list()
## 
## $enabled_objectives
## list()
## 
## $disabled_objectives
## list()
## 
## attr(,"class")
## [1] "summary.portfolio"

Adicionando objetivos

Os objetivos podem ser adicionados ao objeto da carteira com a função add.objective(). Esta é a principal função para adicionar e/ou atualizar objetivos de negócios à carteira, permitindo ao usuário especificar o portfólio para adicionar os objetivos, o tipo (atualmente ‘return’, ‘risk’, ‘risk budget’, ou ‘weight concentration’), nome da função-objetivo, argumentos para a função-objetivo, e se o objetivo está ou não habilitado. Se desejarmos atualizar uma restrição existente, o argumento indexnum deve ser especificado.

Objetivo risco da carteira

O objetivo de risco da carteira permite que o usuário especifique uma função de risco a ser minimizada.

Aqui adicionamos um objetivo de risco para minimizar a perda de cauda esperada da carteira com um nível de confiança de 0,95. Outros argumentos padrão para a função podem ser passados em como uma lista nomeada (p = ...). Observe que o nome da função deve corresponder a uma função em R. Muitas funções estão disponíveis no pacote PerformanceAnalytics. É possível utilizar uma função definida pelo usuário.

pspec <- add.objective(portfolio = pspec,
                       type = 'risk',
                       name = 'ETL',
                       arguments = list(p = 0.95))

Objetivo retorno da carteira

O objetivo de retorno permite que o usuário especifique uma função-objetivo de retorno a ser maximizada.

Aqui desejamos maximizar o retorno médio do portfólio.

pspec <- add.objective(portfolio = pspec,
                       type = 'return',
                       name = 'mean')

Objetivo orçamento de risco da carteira

O objetivo de orçamento de risco da carteira (Portfolio Risk Budget) permite ao usuário especificar restrições para minimizar a contribuição dos componentes (ou seja, contribuição iguais de risco) ou especificar limites superiores e inferiores para a contribuição de risco percentual.

Aqui especificamos que nenhum ativo pode contribuir com mais de 30% para o risco total da carteira. Consulte a vinheta de otimização do orçamento de risco para obter exemplos mais detalhados de otimizações de portfólio com orçamentos de risco.

pspec <- add.objective(portfolio = pspec, 
                       type = "risk_budget", 
                       name = "ETL",
                       arguments = list(p = 0.95), 
                       max_prisk = 0.3)

Para uma carteira com contribuições iguais ao risco, inclua o argumento min_concentration = TRUE:

pspec <- add.objective(portfolio=pspec, type="risk_budget", name="ETL", arguments=list(p=0.95), min_concentration=TRUE).

Objetivo concentração de pesos

O objetivo de concentração de pesos permite ao usuário especificar um objetivo para minimizar a concentração medida pelo Índice Herndahl-Hirschman, ou HHI. Para problemas de otpimização resolvidos com os otimizadores numéricos globais, o valor de HHI da carteira é penalizado usando o parâmetro conc_aversion como multiplicador.

Para problemas de otimização quadrática utilizando a concentração de pesos como objetivo utilizando o solucionador de ROI, isso é implementado como uma penalidade para a função-objetivo. A função-objetivo é implementada da seguinte forma:

\[\underset {\omega} {maximize} \;\;\; \omega^´ \mu - \frac \lambda 2 \;(\omega^´ \Sigma \omega + \lambda_{hhi} \times HHI)\]

Onde \(\mu\) é o retorno médio estimado do ativo, \(\lambda\) é o parâmetro de aversão ao risco, \(|lambda_{hhi}\) é o parâmetro de aversão à concentração, HHI é o índice HHI da carteira, \(\Sigma\) é a matriz de covariância estimada dos retornos dos ativos e \(\omega\) é o conjunto dos pesos. Aqui adicionamos um objetivo de concentração de pesos.

pspec <- add.objective(portfolio = pspec, 
                       type = "weight_concentration",
                       name = "HHI", 
                       conc_aversion = 0.1)

O parâmetro de aversão à concentração de peso por grupos também pode ser especificado.

spec <- add.objective(portfolio = pspec, 
                       type = "weight_concentration",
                       name = "HHI",
                       conc_aversion = c(0.03, 0.06),
                       conc_groups = list(c(1, 2, 3), c(4, 5)))

O método print() do objeto do portfólio mostrará agora todas as restrições e objetivos que foram adicionados. O método summary()apresenta mais detalhes.

print(pspec)
## **************************************************
## PortfolioAnalytics Portfolio Specification 
## **************************************************
## 
## Call:
## portfolio.spec(assets = nome_fundos)
## 
## Number of assets: 5 
## Asset Names
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"
## 
## Constraints
## Enabled constraint types
##      - weight_sum 
##      - group 
##      - position_limit 
##      - diversification 
##      - turnover 
##      - return 
##      - factor_exposure 
##      - transaction_cost 
## 
## Objectives:
## Enabled objective names
##      - ETL 
##      - mean 
##      - ETL 
##      - HHI
summary(pspec)
## $assets
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##      0.2      0.2      0.2      0.2      0.2 
## 
## $enabled_constraints
## $enabled_constraints[[1]]
## An object containing 6 nonlinear constraints.
## 
## $enabled_constraints[[2]]
## An object containing 7 nonlinear constraints.
## 
## $enabled_constraints[[3]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[4]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[5]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[6]]
## An object containing 4 nonlinear constraints.
## 
## $enabled_constraints[[7]]
## An object containing 6 nonlinear constraints.
## 
## $enabled_constraints[[8]]
## An object containing 4 nonlinear constraints.
## 
## 
## $disabled_constraints
## list()
## 
## $enabled_objectives
## $enabled_objectives[[1]]
## $name
## [1] "ETL"
## 
## $target
## NULL
## 
## $arguments
## $arguments$p
## [1] 0.95
## 
## $arguments$portfolio_method
## [1] "single"
## 
## 
## $enabled
## [1] TRUE
## 
## $multiplier
## [1] 1
## 
## $call
## add.objective(portfolio = pspec, type = "risk", name = "ETL", 
##     arguments = list(p = 0.95))
## 
## attr(,"class")
## [1] "portfolio_risk_objective" "objective"               
## 
## $enabled_objectives[[2]]
## $name
## [1] "mean"
## 
## $target
## NULL
## 
## $arguments
## list()
## 
## $enabled
## [1] TRUE
## 
## $multiplier
## [1] -1
## 
## $call
## add.objective(portfolio = pspec, type = "return", name = "mean")
## 
## attr(,"class")
## [1] "return_objective" "objective"       
## 
## $enabled_objectives[[3]]
## $name
## [1] "ETL"
## 
## $target
## NULL
## 
## $arguments
## $arguments$p
## [1] 0.95
## 
## $arguments$portfolio_method
## [1] "component"
## 
## 
## $enabled
## [1] TRUE
## 
## $multiplier
## [1] 1
## 
## $max_prisk
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##      0.3      0.3      0.3      0.3      0.3 
## 
## $min_concentration
## [1] FALSE
## 
## $min_difference
## [1] FALSE
## 
## $call
## add.objective(portfolio = pspec, type = "risk_budget", name = "ETL", 
##     arguments = list(p = 0.95), max_prisk = 0.3)
## 
## attr(,"class")
## [1] "risk_budget_objective" "objective"            
## 
## $enabled_objectives[[4]]
## $name
## [1] "HHI"
## 
## $target
## NULL
## 
## $arguments
## list()
## 
## $enabled
## [1] TRUE
## 
## $multiplier
## [1] 1
## 
## $conc_aversion
## [1] 0.1
## 
## $call
## add.objective(portfolio = pspec, type = "weight_concentration", 
##     name = "HHI", conc_aversion = 0.1)
## 
## attr(,"class")
## [1] "weight_concentration_objective" "objective"                     
## 
## 
## $disabled_objectives
## list()
## 
## attr(,"class")
## [1] "summary.portfolio"

Carteiras aleatórias

O pacote PortfolioAnalytics possui três métodos para a geração de carteiras aleatórias: ‘sample’, ‘simplex’ e ‘grid’. Detalhes de imlementação podem ser obtidos na documentação do pacote ou aqui.

O gráfico a seguir mostra a diferença entre os três tipos:

R <- edhec[, 1:4]

# Cria uma carteira simples

pspec <- portfolio.spec(assets = colnames(R))

pspec <- add.constraint(portfolio = pspec, 
                        type ="leverage",
                        min_sum = 0.99, 
                        max_sum = 1.01) 

pspec <- add.constraint(portfolio = pspec, 
                        type = "box", min = 0, max = 1)

# gera 1000 carteiras aleatórias com os três métodos do pacote: 'sample', simplex' e 'grid'

rp1 <- random_portfolios(portfolio = pspec, 
                         permutations = 1000,
                         rp_method = 'sample')

rp2 <- random_portfolios(portfolio = pspec, 
                         permutations = 1000,
                         rp_method = 'simplex')

rp3 <- random_portfolios(portfolio = pspec, 
                         permutations = 1000,
                         rp_method = 'grid')

# mostra as carteiras viáveis no espaço média-dp
tmp1.mean <- apply(rp1, 1, function(x) mean(R %*% x))

tmp1.StdDev <- apply(rp1, 1, function(x) StdDev(R = R, weights = x))

tmp2.mean <- apply(rp2, 1, function(x) mean(R %*% x))

tmp2.StdDev <- apply(rp2, 1, function(x) StdDev(R = R, weights = x))

tmp3.mean <- apply(rp3, 1, function(x) mean(R %*% x))

tmp3.StdDev <- apply(rp3, 1, function(x) StdDev(R = R, weights = x))

# gráfico das carteiras viáveis

plot(x = tmp1.StdDev, 
     y = tmp1.mean, 
     col = "blue", 
     main = "Métodos para a geração de carteiras aleatórias",
     ylab = "retorno médio", 
     xlab = "Desvio-padrão")

points(x = tmp2.StdDev, 
       y = tmp2.mean, 
       col = "red", 
       pch = 2)

points(x = tmp3.StdDev, 
       y = tmp3.mean, 
       col = "black", 
       pch = 5)

legend("bottomright", 
       legend = c("sample", "simplex", "grid"),
       col = c("blue", "red", "black"), 
       pch = c(1, 2, 5), 
       bty = "n")

O gráfico mostra o espaço viável utilizando os três métodos. O método ‘sample’ tem cobertura relativamente uniforme do espaço viável. O método ‘simplex’ também tem cobertura relativamente uniforme do espaço, mas é mais concentrado em torno dos ativos. O método ‘grid’ é mais voltado para o interior do espaço devido à normalização. O argumento fev pode ser utilizado para controlar esses efeitos. Valores mais elevados para fev resultarão em pesos mais concentrados em um único ativo.

Isso pode ser notado nos gráficos a seguir.

fev <- 0:5
par(mfrow = c(2, 3))
for(i in 1:length(fev)){
  rp <- rp_simplex(portfolio = pspec, permutations=2000, fev=fev[i])
  tmp.mean <- apply(rp, 1, function(x) mean(R %*% x))
  tmp.StdDev <- apply(rp, 1, function(x) StdDev(R=R, weights=x))
  plot(x=tmp.StdDev, y=tmp.mean, main=paste("FEV =", fev[i]),
  ylab="mean", xlab="StdDev", col=rgb(0, 0, 100, 50, maxColorValue=255))
}

par(mfrow=c(1,1))

O argumento fev pode ser passado como um vetor para um maior controle da cobertura (geração de carteiras) do espaço viável. O valor padrão é fev = 0:5.

par(mfrow=c(1, 2))
# simplex
rp_simplex <- random_portfolios(portfolio=pspec, permutations=2000,
rp_method='simplex')
tmp.mean <- apply(rp_simplex, 1, function(x) mean(R %*% x))
tmp.StdDev <- apply(rp_simplex, 1, function(x) StdDev(R=R, weights=x))
plot(x=tmp.StdDev, y=tmp.mean, main="rp_method=simplex fev=0:5",
ylab="mean", xlab="StdDev", col=rgb(0, 0, 100, 50, maxColorValue=255))
#sample
rp_sample <- random_portfolios(portfolio=pspec, permutations=2000,
rp_method='sample')
tmp.mean <- apply(rp_sample, 1, function(x) mean(R %*% x))
tmp.StdDev <- apply(rp_sample, 1, function(x) StdDev(R=R, weights=x))
plot(x=tmp.StdDev, y=tmp.mean, main="rp_method=sample",
ylab="mean", xlab="StdDev", col=rgb(0, 0, 100, 50, maxColorValue=255))

par(mfrow=c(1,1))

Otimizadores

O pacote PortfolioAnalytics atualmente suporta, como otimizadores, carteiras aleatórias, DEoptim (differential evolution), pso (particle swarm optimization), GenSA (generalized simmulated annealing) e ROI (return on investment). Alguns problemas de otimização quadrática e programação linear são resolvidos diretamente com Rglpk e quadprog. O otimizador pode ser especificado com o argumento optimize_method em optimize.portfolio e optimize.portfolio.rebalancing.

Detalhes sobre os otimizadores utilizados no pacote PortfolioAnalyticspodem ser obtidos no item 5 da referência.

Uma boa descrição dos otimizadores mais comuns encontrados no R pode ser encontrada aqui.

Exemplos

As seções anteriores monstraram como especificar um objeto de carteira, adicionar restrições, adicionar objetivos e relacionou os solucionadores disponíveis. Vamos demonstrar como executar as otimizações por meio da função optimize.portfolio() com dois exemplos simples.

Inicialmente utilizaremos a carteira de ações que já montamos com os ativos especificadoes em nome_fundos e os retornos em retornos_carteira.

Exemplo 1

library(DEoptim)
library(ROI)
require(ROI.plugin.glpk)
require(ROI.plugin.quadprog)

nome_fundos
## [1] "EMBR3.SA" "ITUB4.SA" "MGLU3.SA" "PETR4.SA" "VALE3.SA"
head(retornos_carteira)
##                EMBR3.SA      ITUB4.SA     MGLU3.SA     PETR4.SA    VALE3.SA
## 2016-01-04  0.000000000  0.0000000000  0.000000000  0.000000000  0.00000000
## 2016-01-05  0.000000000  0.0083587569  0.010030717 -0.027656709 -0.01339645
## 2016-01-06 -0.014324892 -0.0039464295 -0.086595635 -0.041916214 -0.07348235
## 2016-01-07 -0.021799187 -0.0190170098 -0.132853805 -0.021874773 -0.05948278
## 2016-01-08  0.003537371  0.0003996967  0.004177259  0.001597267 -0.03391376
## 2016-01-11 -0.003877567 -0.0117035273  0.000000000 -0.028708055 -0.02846305
# Cria o objeto portfolio com restrições de 'leverage' e 'box'
carteira1 <- portfolio.spec(assets = nome_fundos)
carteira1 <- add.constraint(portfolio = carteira1, 
                            type = "leverage",
                            min_sum = 0.99, 
                            max_sum = 1.01)

carteira1 <- add.constraint(portfolio = carteira1, 
                            type = "box", 
                            min = 0.05, 
                            max = 0.65)

# Addiciona um objetivo para maximizar o retorno médio e maximiza o retorno médio com ROI

maxret <- add.objective(portfolio = carteira1, 
                        type = "return", 
                        name = "mean")

# Executa a otimização

opt_maxret <- optimize.portfolio(R = retornos_carteira, 
                                 portfolio = maxret,
                                 optimize_method = "ROI",
                                 trace = TRUE)
print(opt_maxret)
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
## 
## Call:
## optimize.portfolio(R = retornos_carteira, portfolio = maxret, 
##     optimize_method = "ROI", trace = TRUE)
## 
## Optimal Weights:
## EMBR3.SA ITUB4.SA MGLU3.SA PETR4.SA VALE3.SA 
##     0.05     0.05     0.65     0.05     0.21 
## 
## Objective Measure:
##     mean 
## 0.004454

Exemplo 2

O pacote PortfolioAnalytics possui um conjunto de dados com retornos de um fundo composto de ativos diferenciados, chamado edhec. Há vários exemplos de otimização utilizando este fundo na vinheta do pacote. Vamos ver como maximizar o retorno esperado utilizando ROI.

Inicializa o objeto carteira (portfolio)

data(edhec)
R <- edhec[, 1:6]

head(R)
##            Convertible Arbitrage CTA Global Distressed Securities
## 1997-01-31                0.0119     0.0393                0.0178
## 1997-02-28                0.0123     0.0298                0.0122
## 1997-03-31                0.0078    -0.0021               -0.0012
## 1997-04-30                0.0086    -0.0170                0.0030
## 1997-05-31                0.0156    -0.0015                0.0233
## 1997-06-30                0.0212     0.0085                0.0217
##            Emerging Markets Equity Market Neutral Event Driven
## 1997-01-31           0.0791                0.0189       0.0213
## 1997-02-28           0.0525                0.0101       0.0084
## 1997-03-31          -0.0120                0.0016      -0.0023
## 1997-04-30           0.0119                0.0119      -0.0005
## 1997-05-31           0.0315                0.0189       0.0346
## 1997-06-30           0.0581                0.0165       0.0258
colnames(R) <- c("CA", "CTAG", "DS", "EM", "EQMN", "ED")

fundo <- colnames(R)

# Cria uma carteira inicial 
init <- portfolio.spec(assets = fundo)

# Adiciona as restrições
init <- add.constraint(portfolio = init, 
                       type = "leverage",
                       min_sum = 0.99, 
                       max_sum = 1.01)

init <- add.constraint(portfolio = init, 
                       type = "box", 
                       min = 0.05, 
                       max = 0.65)

Maximiza o retorno médio

maxret <- add.objective(portfolio = init, 
                        type = "return", 
                        name = "mean")

opt_maxret <- optimize.portfolio(R = R, 
                                 portfolio = maxret,
                                 optimize_method = "ROI",
                                 trace=TRUE)

Minimiza a variância

minvar <- add.objective(portfolio = init, 
                        type = "risk", 
                        name = "var")

# Note que, apesar de ’var’ ser a métrica de risco, o dp é calculado
otim_minvar <- optimize.portfolio(R = R, 
                                 portfolio = minvar,
                                 optimize_method = "ROI", 
                                 trace = TRUE)
print(otim_minvar)
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
## 
## Call:
## optimize.portfolio(R = R, portfolio = minvar, optimize_method = "ROI", 
##     trace = TRUE)
## 
## Optimal Weights:
##     CA   CTAG     DS     EM   EQMN     ED 
## 0.0623 0.1277 0.0500 0.0500 0.6500 0.0500 
## 
## Objective Measure:
##   StdDev 
## 0.009046

Gráfico dos pesos e da carteira ótima com chart.EfficientFrontier

Isso é feito por padrão com o otimizador quadprog´ na infraestrutura do pacoteROI`.

plot(otim_minvar, 
     risk.col = "StdDev", 
     return.col = "mean",
     main = "Mínima Variância", 
     chart.assets = TRUE,
     xlim = c(0, 0.05),   
     ylim = c(0,0.0085))

front_eficiente  <-  create.EfficientFrontier(R = R, 
                                             portfolio = init,  
                                             type = "mean-StdDev", 
                                             n.portfolios = 15)
# Apresenta os pesos das 15 carteiras na fronteira eficiente
 
summary(front_eficiente, digits = 2)
## **************************************************
## PortfolioAnalytics Efficient Frontier 
## **************************************************
## 
## Call:
## create.EfficientFrontier(R = R, portfolio = init, type = "mean-StdDev", 
##     n.portfolios = 15)
## 
## Efficient Frontier Points: 14 
## 
## Weights along the efficient frontier:
##      CA CTAG   DS   EM EQMN   ED
## 1  0.06 0.13 0.05 0.05 0.65 0.05
## 2  0.07 0.10 0.08 0.05 0.65 0.05
## 3  0.05 0.09 0.12 0.05 0.65 0.05
## 4  0.05 0.08 0.17 0.05 0.61 0.05
## 5  0.05 0.08 0.22 0.05 0.56 0.05
## 6  0.05 0.09 0.28 0.05 0.50 0.05
## 7  0.05 0.09 0.33 0.05 0.44 0.05
## 8  0.05 0.09 0.38 0.05 0.39 0.05
## 9  0.05 0.10 0.43 0.05 0.33 0.05
## 10 0.05 0.10 0.49 0.05 0.27 0.05
## 11 0.05 0.11 0.54 0.05 0.21 0.05
## 12 0.05 0.11 0.59 0.05 0.16 0.05
## 13 0.05 0.12 0.64 0.05 0.10 0.05
## 14 0.05 0.11 0.65 0.05 0.05 0.10
## 
## Risk and return metrics along the efficient frontier:
##    mean StdDev out
## 1  0.00   0.01   0
## 2  0.00   0.01   0
## 3  0.00   0.01   0
## 4  0.01   0.01   0
## 5  0.01   0.01   0
## 6  0.01   0.01   0
## 7  0.01   0.01   0
## 8  0.01   0.01   0
## 9  0.01   0.01   0
## 10 0.01   0.01   0
## 11 0.01   0.01   0
## 12 0.01   0.01   0
## 13 0.01   0.01   0
## 14 0.01   0.01   0
# Apresenta as primeiras 5 carteiras na fronteira eficiente
 
front_eficiente$frontier[1:5,]
##                 mean      StdDev          out       w.CA     w.CTAG       w.DS
## result.1 0.004659314 0.009046441 8.183809e-05 0.06233094 0.12766906 0.05000000
## result.2 0.004777581 0.009237852 8.533792e-05 0.07084585 0.09771355 0.07959804
## result.3 0.004895849 0.009484747 8.996043e-05 0.05000000 0.09102813 0.11897187
## result.4 0.005014116 0.009833770 9.670303e-05 0.05000000 0.07692386 0.16993685
## result.5 0.005132384 0.010229145 1.046354e-04 0.05000000 0.08135556 0.22252011
##          w.EM    w.EQMN w.ED
## result.1 0.05 0.6500000 0.05
## result.2 0.05 0.6500000 0.05
## result.3 0.05 0.6500000 0.05
## result.4 0.05 0.6131393 0.05
## result.5 0.05 0.5561243 0.05
# Apresenta o gráfico da fronteira eficiente
renda_fixa <- 0.002
 
chart.EfficientFrontier(front_eficiente, 
                        match.col = "StdDev", 
                        type = "l", 
                        rf = renda_fixa, 
                        chart.assets = TRUE,
                        RAR.text = "Índice Sharp", 
                        pch = 4,
                        main = 'Fronteira Eficiente')

summary(front_eficiente, digits = 2)
## **************************************************
## PortfolioAnalytics Efficient Frontier 
## **************************************************
## 
## Call:
## create.EfficientFrontier(R = R, portfolio = init, type = "mean-StdDev", 
##     n.portfolios = 15)
## 
## Efficient Frontier Points: 14 
## 
## Weights along the efficient frontier:
##      CA CTAG   DS   EM EQMN   ED
## 1  0.06 0.13 0.05 0.05 0.65 0.05
## 2  0.07 0.10 0.08 0.05 0.65 0.05
## 3  0.05 0.09 0.12 0.05 0.65 0.05
## 4  0.05 0.08 0.17 0.05 0.61 0.05
## 5  0.05 0.08 0.22 0.05 0.56 0.05
## 6  0.05 0.09 0.28 0.05 0.50 0.05
## 7  0.05 0.09 0.33 0.05 0.44 0.05
## 8  0.05 0.09 0.38 0.05 0.39 0.05
## 9  0.05 0.10 0.43 0.05 0.33 0.05
## 10 0.05 0.10 0.49 0.05 0.27 0.05
## 11 0.05 0.11 0.54 0.05 0.21 0.05
## 12 0.05 0.11 0.59 0.05 0.16 0.05
## 13 0.05 0.12 0.64 0.05 0.10 0.05
## 14 0.05 0.11 0.65 0.05 0.05 0.10
## 
## Risk and return metrics along the efficient frontier:
##    mean StdDev out
## 1  0.00   0.01   0
## 2  0.00   0.01   0
## 3  0.00   0.01   0
## 4  0.01   0.01   0
## 5  0.01   0.01   0
## 6  0.01   0.01   0
## 7  0.01   0.01   0
## 8  0.01   0.01   0
## 9  0.01   0.01   0
## 10 0.01   0.01   0
## 11 0.01   0.01   0
## 12 0.01   0.01   0
## 13 0.01   0.01   0
## 14 0.01   0.01   0

A fronteira eficiente com CVar

O CVaR (conditional value at risk) também é às vezes chamado de expected shortfall (ES) ou expected tail loss (ETL). O CVar, ou o expected shortfall, isto é, o déficit esperado ao nível q% é o retorno esperado da carteira nos piores casos. o CVar é uma alternativa ao valor em risco que é mais sensível à forma da cauda da distribuição de perdas e é calculada tomando uma média ponderada das perdas “extremas” na cauda da distribuição de possíveis retornos, além do ponto de corte de valor em risco (VaR).

O CVaR tenta resolver as deficiências do modelo VaR, que é uma técnica estatística usada para medir o nível de risco financeiro dentro de uma empresa ou uma carteira de investimentos em um período específico. Enquanto o VaR representa uma perda pior associada a uma probabilidade e um horizonte de tempo, o CVaR é a perda esperada se este limiar (q%) de pior caso for cruzado. o CVaR, em outras palavras, quantifica as perdas esperadas que ocorrem além do ponto de ruptura do VaR.

A nova fronteira eficiente

front_eficiente2  <-  create.EfficientFrontier(R = R, 
                                               portfolio = init,  
                                               type = "mean-ES", 
                                               n.portfolios = 15)
summary(front_eficiente2, digits = 2)
## **************************************************
## PortfolioAnalytics Efficient Frontier 
## **************************************************
## 
## Call:
## create.EfficientFrontier(R = R, portfolio = init, type = "mean-ES", 
##     n.portfolios = 15)
## 
## Efficient Frontier Points: 15 
## 
## Weights along the efficient frontier:
##      CA CTAG   DS   EM EQMN   ED
## 1  0.05 0.21 0.05 0.05 0.58 0.05
## 2  0.05 0.22 0.07 0.05 0.58 0.05
## 3  0.05 0.27 0.12 0.05 0.47 0.05
## 4  0.05 0.30 0.18 0.05 0.38 0.05
## 5  0.05 0.33 0.23 0.05 0.30 0.05
## 6  0.05 0.36 0.29 0.05 0.21 0.05
## 7  0.05 0.39 0.35 0.05 0.13 0.05
## 8  0.05 0.38 0.40 0.05 0.08 0.05
## 9  0.05 0.36 0.45 0.05 0.05 0.05
## 10 0.05 0.31 0.50 0.05 0.05 0.05
## 11 0.05 0.26 0.55 0.05 0.05 0.05
## 12 0.05 0.21 0.60 0.05 0.05 0.05
## 13 0.05 0.16 0.65 0.05 0.05 0.05
## 14 0.05 0.11 0.65 0.05 0.05 0.10
## 15 0.05 0.05 0.65 0.16 0.05 0.05
## 
## Risk and return metrics along the efficient frontier:
##    mean   ES  out
## 1  0.00 0.02 0.02
## 2  0.00 0.02 0.02
## 3  0.00 0.02 0.02
## 4  0.00 0.02 0.02
## 5  0.01 0.02 0.02
## 6  0.01 0.02 0.02
## 7  0.01 0.02 0.02
## 8  0.01 0.02 0.02
## 9  0.01 0.03 0.03
## 10 0.01 0.03 0.03
## 11 0.01 0.03 0.03
## 12 0.01 0.03 0.03
## 13 0.01 0.03 0.03
## 14 0.01 0.03 0.03
## 15 0.01 0.04 0.04
chart.EfficientFrontier(front_eficiente2, 
                        match.col = "ES", 
                        main = "Fronteira Eficiente - CVar", 
                        type = "l", 
                        rf = renda_fixa,
                        col = "blue", 
                        RAR.text = "Índice Sharpe")

A função chart.EF.Weights() produz um gráfico de barras empilhado dos pesos ao longo da fronteira eficiente.

chart.EF.Weights(front_eficiente2, 
                 by.groups = FALSE, 
                 colorset = rainbow(n = length(fundo)), 
                 match.col = "ES")