1 CONHECENDO OS DADOS

1.1 Dataset do projeto


Motivação da Escolha das ações

Com o objetivo de observar a rentabilidade de ativos que foram severamente impactados durante um período pandêmico, optamos por ações de empresas em setores que sofreram diferentes impáctos durante a pandemia de Covid 19. As ações escolhidas pelo grupo foram a Gol e a Hapvida, além da utilização da Selic como o ativo livre de risco.


Ativos

Ações

Aqui está uma lista das ações das empresas escolhidas junto com o ativo livre de risco:

Código Nome da Empresa Setor
GOLL4.SA Gol Linhas Aereas SA Empresas Aereas
HAPV3.SA Hapvida Participações e Investimentos S.A. Saúde Suplementar

Hapvida Participações e Investimentos S.A. :

Perfil Corporativo: A Hapvida é uma holding domiciliada no Brasil, com sede em Fortaleza, estado do Ceará. Ela atua no setor de saúde, oferecendo planos de assistência médica e odontológica. A empresa tem se destacado como a maior empresa de planos de saúde do Brasil, conquistando todos os estados do país. Seu compromisso é assegurar o acesso à saúde de qualidade para a população.

Cotação na B3: As ações da Hapvida (código HAPV3) estão listadas no Novo Mercado da B3. A companhia realizou seu IPO em 2018 e é controlada pela Ppar Pinheiro Participações S.A., que detém mais de 77% das ações ordinárias.

Gol Linhas Aéreas S.A. :

Perfil Corporativo: A Gol é uma companhia aérea brasileira que opera voos domésticos e internacionais. Com presença relevante nas principais regiões do Brasil, a Gol é conhecida por sua conectividade e serviços de transporte aéreo. Ela desempenha um papel fundamental no setor de aviação, proporcionando mobilidade e conectando pessoas e destinos.

Atuação na Pandemia: Durante a pandemia da COVID-19, a Gol enfrentou desafios significativos, mas também adaptou suas operações para garantir a segurança dos passageiros e tripulantes. A empresa continua sendo uma das principais escolhas para viagens aéreas no Brasil.

Livre de Risco

Estabelecemos a escolha mais segura como o ativo ‘Risk Free’, sendo ele a Selic, a qual é estabelecida pelo próprio governo brasileiro.

Taxa Selic (Banco Central) A sigla Selic provém do Sistema Especial de Liquidação e de Custódia, que é uma infraestrutura do mercado financeiro administrada pelo Banco Central. Essa taxa é calculada com base nas operações de empréstimos de um dia entre os bancos, nos quais títulos públicos federais são utilizados como garantia.

1.2 Obtenção dos Dados

Pacotes a serem utilizados:

Pacote Explicação
dplyr Manipulação eficiente de dados
quantmod Análise quantitativa de dados financeiros
forecast Previsão de séries temporais
fImport Importação de dados financeiros
tidytext Manipulação de texto estruturado em análise de dados
stringr Manipulação de strings e expressões regulares
ggplot2 Criação de gráficos e plots
GetBCBData API do Bacen para disponibilizar dados
gridExtra Organização de plot de multiplos graficos

Código utilizado para importar as bases de dados

packages <- c('dplyr','GetBCBData','ggplot2','stringr','tidytext','forecast','quantmod','fImport','gridExtra')

# Encontrar os pacotes que não estão instalados
to_install <- setdiff(packages, installed.packages()[, "Package"])

# Instalar os pacotes que não estão instalados
if (length(to_install) > 0) {
  install.packages(to_install)
}

# Carregar todos os pacotes
for (package in packages) {
  library(package, character.only = TRUE)
}
rm(package,packages)

Fonte dos Dados

A fonte dos dados é o Yahoo Finance, que é acessado por meio do pacote “quantmod” no R.

Ao chamar: getSymbols(symbol, src = "yahoo", from = start_date, to = end_date), o código está solicitando ao pacote “quantmod” para baixar os dados históricos da ação especificada usando o símbolo correspondente como um parâmetro de entrada.

Site de acesso a plataforma: https://finance.yahoo.com

Código gerado para obter os dados

Obetendo os dados das Ações

O Código abaixo, em resumo, define os símbolos das ações, utiliza o pacote "quantmod" para baixar os dados históricos dessas ações do https://finance.yahoo.com e armazena-los em objetos separados para análise posterior.

# Definir os símbolos das ações da área da saúde
chaves_acesso <- c("GOLL4.SA", "HAPV3.SA")

# Definir as datas de início e fim do período desejado
data_inicio <- as.Date("2023-05-01")
data_fim    <- as.Date("2024-02-01")

# Criar um loop para baixar os dados de todas as ações
for (chave in chaves_acesso) {
  # Baixar os dados da ação usando a função 'getSymbols' do 'quantmod'
  getSymbols(chave, src = "yahoo", from = data_inicio, to = data_fim)
  
  # Acessar os dados usando o nome do objeto criado pelo 'getSymbols'
  assign(chave, get(chave))
  
  # Aguardar um segundo antes de baixar o próximo símbolo
  # (para evitar sobrecarga no servidor)
  Sys.sleep(1)
}

# renomeando as bases
gol <- data.frame(GOLL4.SA) %>%  mutate(data = index(GOLL4.SA))
hapv <- data.frame(HAPV3.SA) %>% mutate(data = index(HAPV3.SA))

# Limpando os nomes das variaveis
names(gol) <- gsub('^GOLL4\\.SA\\.','',names(gol))
names(hapv) <- gsub('^HAPV3\\.SA\\.','',names(hapv))

# pegando apenas as primeias 121 observacoes das bases
gol  <- gol[1:121,] 
hapv <- hapv[1:121,] 

rm(GOLL4.SA,HAPV3.SA)

# Verificando os dados de uma ação específica
knitr::kable(data.frame(head(gol)),align = "c")
Open High Low Close Volume Adjusted data
2023-05-02 6.66 6.86 6.43 6.53 13491600 6.53 2023-05-02
2023-05-03 6.56 7.00 6.46 6.92 15218100 6.92 2023-05-03
2023-05-04 6.94 7.07 6.69 6.82 10483300 6.82 2023-05-04
2023-05-05 6.85 7.12 6.76 6.96 11993200 6.96 2023-05-05
2023-05-08 7.01 7.32 6.99 7.02 12572500 7.02 2023-05-08
2023-05-09 6.98 7.27 6.93 7.11 9011700 7.11 2023-05-09

Obtendo dados da Selic

O código a seguir, diferente do anterior, realiza a utilização de pacote que utiliza a API do Banco Central brasileiro para poder ter acesso ás suas informações

# utilizando a API do Bacen para pegar os dados
selic_data <- gbcbd_get_series(
  id         = 12,
  first.date = data_inicio,   
  last.date  = data_fim   
)

knitr::kable(head(selic_data),align = "c")
ref.date value id.num series.name
2023-04-28 0.050788 12 id = 12
2023-05-02 0.050788 12 id = 12
2023-05-03 0.050788 12 id = 12
2023-05-04 0.050788 12 id = 12
2023-05-05 0.050788 12 id = 12
2023-05-08 0.050788 12 id = 12

Ele trás as informações já com as porcentagens trazidas à valor diário.

Variáveis utilizadas

As bases de dados geradas pelo código fornecido contém informações de preços históricos das ações escolhidas durante o período de 2020-01-01 a 2021-01-01. Essas bases de dados contém as seguintes variáveis:

Date:

A data correspondente ao preço de fechamento da ação.

Open:

O preço de abertura da ação no dia específico.

High:

O preço mais alto alcançado pela ação durante o dia.

Low:

O preço mais baixo alcançado pela ação durante o dia.

Close:

O preço de fechamento da ação no dia específico.

Volume:

O volume de negociações da ação no dia específico.

Adjusted:

Preço ajustado que considera eventos como divisões de ações e dividendos

Observação

Os dados já vieram da fonte em formato de painel de séries temporaes (uma tabela em formato xts para cada ação da bolsa que foi importada), portanto, para melhor utilização das bases, foram feitas manipulações a fim de realizar o empilhamento dessas linhas para que se tenha um painel temporal das ações.

ESTATÍSTICAS DESCRITIVAS

Calculando os Retornos anualizados

Com base nos preços diários das ações, construimos os retornos anualizados, utilizando a formula de captalização contínua a partir da seguinte formula:

\[r_{i,t}= 252 \cdot \ln \left( \frac{P_{i,\ t}}{P_{i,\ t-1}} \right)\] onde:

  • \(P_{i,t}\) é o preço da ação;

  • \(i\) no período \(t\);

  • \(r_{i,t}\) é o retorno da ação \(i\) no período \(t\).

Para a Selic, como seus dados já estão em porcentagem trazida a valor diário, a formula para transforma-la em uma capitalização contínua será:
\[r_{(t)} = 252 \ \cdot \ \ln \left( 1+ \frac {Selic_{(t)}}{100} \right)\]

A fórmula transforma a variação percentual dos preços diários em um retorno contínuo e depois o anualiza, multiplicando pelo número de dias úteis no ano. Isso é útil para comparar retornos de diferentes ativos ao longo do tempo em uma base anualizada, mesmo que os preços sejam registrados diariamente.

Diferentemente da taxa de retorno simples, que poderia ser expressa em porcentagem, a taxa de retorno contínua é baseada no conceito de capitalização contínua, que assume que os rendimentos são reinvestidos e compostos a todo momento, não apenas no final de cada período.

Na prática, isso significa que a taxa de retorno contínua é mais precisa para cálculos financeiros que envolvem múltiplas composições ao longo do tempo. Ela é expressa em termos de logaritmos naturais (usando o símbolo: \(\ln\) ), o que facilita a manipulação matemática, especialmente quando se lida com múltiplos períodos de tempo ou composição contínua.

Um retorno contínuo não é deve ser diretamente interpretado como uma porcentagem. Para converter um retorno contínuo em uma taxa de retorno percentual aproximada, você pode usar a fórmula ( \(e^{r} - 1\) ), onde ( \(e\) ) é a base dos logaritmos naturais e ( r ) é o retorno contínuo.

Por exemplo, se o retorno contínuo anualizado for ( \(0.10\) ) (ou \(10\%\)), a taxa de retorno percentual aproximada seria ( \(e^{0.10} - 1 \approx 0.105\) ) ou 10.5%.

Aplicando o Código, Teremos:
retornos_gol     <- c()
retornos_hapvida <- c()
retornos_selic   <- c()

for (i in 2:nrow(gol)) {
  # calculando os retornos da GOL
  retornos_gol[i] <- 252 * log( 
    gol$Adjusted[i] / gol$Adjusted[i-1]
  )
  
  # calculando os retornos da HAPVIDA
  retornos_hapvida[i] <- 252 * log( 
    hapv$Adjusted[i] / hapv$Adjusted[i-1]
    )
    
  # calculando os valores da selic
  retornos_selic[i] <- 252 * log( 1 + (selic_data$value[i]/100) )
}

# retirando a primeira linha da base de dados
# pois ela foi perdida no calculo dos retornos
gol  <- gol[2:121,]
hapv <- hapv[2:121,]


# adicionando esses retornos nas bases de dados
gol$retornos_anualizados  <- retornos_gol[2:121]
hapv$retornos_anualizados <- retornos_hapvida[2:121]
retornos_selic            <- retornos_selic[-1]

# apresentando uma parte dos retornos para visualizacao
knitr::kable(
  data.frame(
    HAPVIDA_retornos = retornos_hapvida[2:6],
    GOL_retornos     = retornos_gol[2:6],
    SELIC_retornos   = retornos_selic[2:6]
  )
)
HAPVIDA_retornos GOL_retornos SELIC_retornos
-1.8129557 14.618219 0.1279533
6.2890906 -3.668184 0.1279533
7.8620028 5.120636 0.1279533
-0.8615385 2.163101 0.1279533
-3.4759137 3.210240 0.1279533

Apresentando estatísticas descritivas

Nesta sessão iremos apresentar algumas estatísticas descritivas básicas para cada um dos conjuntos de retornos calculados anteriormente, incluindo o livre de risco. *Para isso, iremos considerar apenas as primeiras 80 observações.

Calculando uma tabela com as descritivas:

# Estatísticas descritivas dos retornos
estatisticas_gol <- summary( gol$retornos_anualizados)
estatisticas_hpv <- summary(hapv$retornos_anualizados)


# Criando a tabela das estatísticas descritivas
tabela_estatisticas <- data.frame(
  Empresa       = c("Gol Linhas Aéreas S.A. (GOLL4.SA)", "Hapvida Investimentos S.A. (HAPV3.SA)"),
  `Média`          = c(estatisticas_hpv[[4]], estatisticas_gol[[4]]),
  `Mediana`        = c(estatisticas_hpv[[3]], estatisticas_gol[[3]]),
  `Mínimo`         = c(estatisticas_hpv[[1]], estatisticas_gol[[1]]),
  `Máximo`         = c(estatisticas_hpv[[5]], estatisticas_gol[[5]]),
  `Desvio Padrão`= c(sd(retornos_gol[-1]), sd(retornos_hapvida[-1])),
  `Variância`      = c( ( sd(retornos_gol[-1]) )^2 , ( sd(retornos_hapvida[-1]) )^2 )
)

# Imprimindo a tabela formatada
knitr::kable( tabela_estatisticas )
Empresa Média Mediana Mínimo Máximo Desvio.Padrão Variância
Gol Linhas Aéreas S.A. (GOLL4.SA) 0.6871471 0.2644217 -14.99519 4.796536 9.651137 93.14444
Hapvida Investimentos S.A. (HAPV3.SA) 0.1157403 0.4254359 -33.64991 4.982864 7.507137 56.35711

Calculando a curtose dos dados utilizando a formula:

\[\text{Curtose} = \frac{\sum_{i=1}^{n} (x_i - \bar{x})^4}{n \cdot s^4} - 3\] onde: - \(n\) é o número de observações;

  • \(x_i\) é cada observação individual;

  • \(xˉ\) é a média das observações;

  • \(s\) é o desvio padrão das observações.

aplicando em R, teremos:
# FUNCAO QUE CALCULA A CURTOSE
calculo_curtose <- function(retornos){
  
  # Calcular a média
  media <- mean(retornos)
  
  # Calcular os desvios da média
  desvios <- retornos - media
  
  # Calcular a quarta potência dos desvios
  quarta_potencia_desvios <- desvios^4
  
  # Calcular a variância
  variancia <- var(retornos)
  
  # Calcular a curtose
  curtose <- sum(quarta_potencia_desvios) / (length(retornos) * variancia^2) - 3
}

# APLICANDO A FUNCAO NOS RETORNOS
curtose_gol     <- calculo_curtose(gol$retornos_anualizados)
curtose_hapvida <- calculo_curtose(hapv$retornos_anualizados)

A partir dos dados, conseguimos obeter uma Curtose para os retornos da Gol de: 0.9863222 e um valor de curtose da Hapvida de 0.4204504.

Como pode-se ver, o cálculo feito foi o da curtose amostral a qual subtrai 3 da curtose populacional para dar uma medida que é 0 para uma distribuição normal.

Aplicando o calculo da Assimetria (Skewness)

A assimetria mede o grau de simetria da distribuição. Uma distribuição simétrica tem assimetria zero, logo, quanto mais distante de zero, mais assimétrica é esta distribuição em questão.

Além disso, o sinal deste indicador também entrega informações. Uma distribuição com uma cauda longa à direita (valores maiores) terá assimetria positiva, enquanto uma distribuição com uma cauda longa à esquerda (valores menores) terá assimetria negativa.

A partir da utilização da formula: \[ g_1=\frac{n}{(n-1)(n-2)}\sum_{i=1}^{n} \left( \frac{x_i-\bar{x}}{s} \right)^3 \] onde: - \(n\) é o número de observações;

  • \(x_i\) é cada valor individual;

  • \(\bar{x}\) é a média dos valores;

  • \(s\) é o desvio padrão.

aplicando em R, teremos:
# FUNCAO QUE CALCULA A ASSIMETRIA 
assimetria <- function(dados){
  
  # Calcule a média dos dados
  media <- mean(dados)
  
  # Calcule o desvio padrão dos dados
  desvio_padrao <- sd(dados)
  
  # Calcule a assimetria manualmente
  assimetria <- sum((dados - media)^3) / length(dados) / desvio_padrao^3
  
  return(assimetria)
}

# Aplicando a funcao para os retornos
assim_gol <- assimetria(gol$retornos_anualizados)
assim_hpv <- assimetria(hapv$retornos_anualizados)

Desta forma, obetemos um valor de Assimetria para os retornos da Gol de: -0.0611028 e um da hapvida de 0.4531635.

Realizando o plot de alguns gráficos

Para melhor visualização dos dados, fizemos alguns gráficos para mostrar o comportamento das ações:

# Gráfico no tempo dos preços de fechamento
historico_precos <- ggplot() +
  geom_line(data = gol, aes(x = data, y =Close), color = "blue", linetype = "solid") +
  geom_line(data = hapv, aes(x = data, y =Close), color = "red", linetype = "solid") +
  labs(title = "Gráfico no Tempo dos Preços de Fechamento", x = "Data", y = "Pre") +
  scale_x_date(date_labels = "%Y-%m", date_breaks = "1 month") +
  scale_y_continuous() +
  theme_classic()

historico_rentabilidade <- ggplot() +
  geom_line(data = gol, aes(x = data, y =retornos_anualizados), color = "blue", linetype = "solid") +
  geom_line(data = hapv, aes(x = data, y =retornos_anualizados), color = "red", linetype = "solid") +
  labs(title = "Gráfico no Tempo dos retornos", x = "Data", y = "Retornos Anualizados") +
  scale_x_date(date_labels = "%Y-%m", date_breaks = "1 month") +
  scale_y_continuous() +
  theme_classic()

# Gráfico estimando a distribuição dos retornos
dist_retornos <- ggplot() +
  geom_density(data = gol, aes(x = retornos_anualizados, fill = "GOL Linhas Aéreas"), alpha = 0.5) +
  geom_density(data = hapv, aes(x = retornos_anualizados, fill = "Hapvida"), alpha = 0.5) +
  labs(title = "Estimativa da Distribuição dos Retornos", x = "Retornos Diários", y = "Densidade") +
  # xlim(-120, 120) +
  geom_vline(aes(xintercept = 0), color = "black", linetype = "dashed",size = 1) +
  scale_fill_manual(name = "Empresa", values = c("GOL Linhas Aéreas" = "blue", "Hapvida" = "red")) +
  theme_classic()

# Combinação dos gráficos lado a lado
gridExtra::grid.arrange(historico_precos, historico_rentabilidade ,dist_retornos, ncol = 1)

Observação: Click no Gráfico para visualiza-lo

Os Gráficos apresentados neste Documento Web são todos clicaveis

QUESTÃO 2

2.1 Assumindo uma aversão ao risco igual a 2.5, faremos:

Consideirando apenas as 80 primeiras observações iniciais das duas ações escolhidas, faremos inicialmente uma figura com as combinações viáveis do retorno esperado e do desvio padrão.

Apresentando a fórmula dos retornos para uma carteira com duas ações, teremos: \[ r_p = w_g r_g + w_h r_h \]

onde:

  • \(w_g\) eh a proporcao das acoes da gol na carteira \(p\);

  • \(w_h\) sendo a proporcao das acoes da hapivida e \(w_e = 1 − w_d\);

  • \(r_p\) é o retorno da carteira de ações.

2.1.1 Encontrando os Retornos Esperados

Existem inúmeras formas de encontrar os Retornos Esperados. Como há uma incerteza em relação ao cenário futuro, a melhor forma seria encontrarmos uma estimativa boa o suficiente e não viesada dessa esperança em questão. Mas para isso precisariamos de modelos que tornariam este trabalho muito extenso.

Por conta disso, iremos avaliar o \(E[r]\) como sendo a média simples dos retornos anualizados calculados no capítulo anterior.

# estabelecendo variaveis para serem utilizadas nos calculos
retorno_g = mean(gol$retornos_anualizados )
retorno_h = mean(hapv$retornos_anualizados)

2.1.2 Encontrando os desvios

•Uma medida de risco usual é o desvio-padrão, que mede a dispersão dos possíveis retornos em relação ao retorno esperado.

desvio_padrao_g = tabela_estatisticas$Desvio.Padrão[1]
desvio_padrao_h = tabela_estatisticas$Desvio.Padrão[2]

2.1.3 Encontrando a Covariância e a Correlação

  1. Covariância: A covariância entre dois vetores pode ser calculada usando a seguinte fórmula: \[Cov(r_g , r_h ) = \frac{1}{n} \sum_{i=1}^n (r_g - \bar{r_g}) (r_h - \bar{r_h}) \]

  2. Correlação: Já a correlação, esta é calculada a partir da equação: \[ Corr(r_g,r_h) = \frac{cov(r_g,r_h)}{\sigma_{r_g} \cdot \sigma_{r_h}} \]

Aplicando a função no R:

# Covariância
covariancia <- cov(gol$retornos_anualizados, hapv$retornos_anualizados)

# Correlação
correlacao <- cor(gol$retornos_anualizados, hapv$retornos_anualizados)

2.1.4 Função da Variância e do Desvio Padrão de \(r_p\)

temos a função da variância como: \[\sigma^2_p = Var[r_p] = Varr[w_hr_h+w_gr_g] = w_h^2\sigma_h^2+w_g^2\sigma_g^2 + 2w_hw_gCov(r_h,r_g) \] onde: - \(\sigma_g^2 = Var[r_g]\); - \(\sigma_h^2 = Var[r_h]\).

Percebemos neste caso que a variância da carteira diminui se o termo da covariância for negativo.

Agora, achando o Desvio Padrão utilizando a formula acima \[\sigma_p = (Var[r_p])^{1/2} = \sqrt{ \ w_h^2r_h^2+w_g^2r_g^2 + 2w_hw_gCov(r_h,r_g)} \]

2.1.5 Aplicando as combinações de pesos

Para isso, iremos criar uma tabela com os possíveis valores de de pesos das duas ações e testar suas combinações a fim de gerar um vetor com os possíveis valores de retorno esperado e desvio padrão. Com eles, iremos estabelecer o gráfico com os retornos e desvios.

Tabela com os Pesos

# produzindo tabela para calcular a fronteira de retornos
tabela_pesos <- data.frame(
  w_g = seq(0,1, 0.0001),
  w_h = seq(1,0,-0.0001)
)

Para cada um dos valores de \(w_g\) e \(w_h\), faremos o calculo do retorno da carteira a fim de produzir um grafico da fronteira de retornos.

2.1.6 Calculando os valores de Retorno esperado e Desvio Padrão para as ações

Agora, iremos fazer um loop para poder calcular os valores de desvio-padrão e Retorno esperado da carteira para todos os possíveis pares de pesos \([w_g,\ w_h]\) sabendo que, \(w_g + w_h = 1\). E, a partir desses resultados, podemos encontrar o gráfico de retornos possíveis para cada desvio-padrão e construir a fronteira eficiente.:

Realizando o loop para todos os pessos possíveis:

# variaveis de armazenamento dos valores
retorno_carteira <- c()
desvio_carteira <- c()

# renomeando para melhor visualizacao
sd_g <- desvio_padrao_g
sd_h <- desvio_padrao_h

# aplicacao do loop
for ( i in 1:nrow(tabela_pesos) ) {
  Wg <- tabela_pesos$w_g[i] # iterando os pesos
  Wh <- tabela_pesos$w_h[i] # iterando os pesos
  
  # utilizando a formula de retorno de p
  retorno_carteira[i] <-(Wg * retorno_g) + (Wh * retorno_h)
  
  # utilizando a formula do desvio da carteira
  desvio_carteira[i] <- (
    ( (Wg^2 * sd_g^2) + (Wh^2 * sd_h^2) + (2*Wg*Wh*covariancia) )^(0.5)
  )
}

# Criando um data.frame com os dados
tabela_retornos <- data.frame(
  retorno  = retorno_carteira,
  desvio   = desvio_carteira,
  peso_gol = tabela_pesos$w_g,
  peso_hpv = tabela_pesos$w_h
  )

# plotando a tabela no HTML
knitr::kable( head(tabela_retornos) )
retorno desvio peso_gol peso_hpv
0.6871471 7.507137 0e+00 1.0000
0.6870899 7.506731 1e-04 0.9999
0.6870328 7.506324 2e-04 0.9998
0.6869757 7.505918 3e-04 0.9997
0.6869185 7.505511 4e-04 0.9996
0.6868614 7.505105 5e-04 0.9995

Agora, plotando o gráfico da fronteira eficiente, temos:

ggplot(tabela_retornos, aes(x = desvio, y = retorno)) +
  geom_point(color = "darkblue", size = 1.5) +
  labs(
    x = "Desvio Padrão (σ)",
    y = "Retorno Esperado (E[r])",
    title = "Relação entre Desvio Padrão e Retorno Esperado",
    subtitle = "Análise de Portfólio",
    caption = "Fonte: Yahoo.finance"
  ) +
  theme_classic() +
  annotate(
    "segment",
    x = min(tabela_retornos$desvio)+0.1,
    xend = min(tabela_retornos$desvio) + 1.2 ,
    y = tabela_retornos[tabela_retornos$desvio == min(tabela_retornos$desvio),"retorno"],
    yend= tabela_retornos[tabela_retornos$desvio == min(tabela_retornos$desvio),"retorno"],
    arrow = arrow(length = unit(0.3, "cm"),ends = 'first', type = 'open'),
    color = "black"
    ) +
    annotate(
      "text",
      x = min(tabela_retornos$desvio) +1.3,
      y = tabela_retornos[tabela_retornos$desvio == min(tabela_retornos$desvio),"retorno"]-0.01,
      label = paste("Ponto de risco mínimo e com retorno = ",round(tabela_retornos[tabela_retornos$desvio == min(tabela_retornos$desvio),"retorno"],3)),
      hjust = 0,
      vjust = 0,
      color = "black"
      ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(face = "italic", size = 12),
    plot.caption = element_text(size = 8),
    axis.title.x = element_text(face = "bold", size = 12),
    axis.title.y = element_text(face = "bold", size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "none"
  ) +
  scale_x_continuous(labels = scales::comma)

### Observação: Click no Gráfico para visualiza-lo

Como podemos ver no gráfico, temos a o valor com o menor desvio padrão como aquele ponto da curva que é tangenciado por uma linha vertical. Portanto, temos que a carteira de mínima variância é aquela de mínimo desvio-padrão, que seria:

\[w_g = 0.312\] \[w_h = 0.688\]

2.2 Minimizando o Desvio-Padrão

Temos algumas formas diferentes para poder encontrar a carteira de mínima variância.

Como foi visto no exercício anterior, calculamos todas os desvios possíveis para as carteiras. Dessa forma, encontramos o valor de menor risco é só achar qual par de pesos gerou o menor desvio.

Contudo, podemos também resolver esse execício através de uma ótica matemática, interpretanto as formulas como um problema de minimização da equação do desvio dado a restrição de \(m_g + m_h = 1\).

fariamos isso dessa forma:

  1. Caso Geral: \[\sigma^2_p = w_h^2\sigma_h^2+w_g^2\sigma_g^2 + 2w_hw_gCov(r_h,r_g) \] Dado a restrição de que $w_g = 1 -w_h $, podemos substituir para encontrar:

    \[\sigma^2_p = w_h^2\sigma_h^2+(1 -w_h)^2\sigma_g^2 + 2w_h(1 -w_h)Cov(r_h,r_g) \]

Portando, minimizaremos a Função escolhendo o valor de \(w_h\), aplicando a CPO: \[\frac{\partial(\sigma^2_p)}{\partial w_h} = 2w_h\sigma_h^2 - 2(1 - w_h)\sigma_g^2 + 2(1 - 2w_h)Cov(r_h,r_g)\]

Aplicando a segunda derivada desta função para saber se ela é convexa, ou seja, se sua segunda derivada é maior que zero:

\[\frac{\partial}{\partial w_h} \left[\frac{\partial(\sigma^2_p)}{\partial w_h} \right] = 2\sigma_h^2 + 2\sigma_g^2 + 2Cov(r_h,r_g) = Var[r_g-r_h]\]

\[Var[r_g-r_h] > 0\]

Como a segunda derivada da função da variância é negativa, temos que se trata de uma curva convexa e, portanto, ao acharmos o valor que torne a CPO = zero, teremos seu valor mínimo.

Igualando a derivada a zero e encontrando o valor de \(w_h\) que minimiza a variância

\[2w_h\sigma_h^2 - 2\sigma_g^2 + 2w_h\sigma_g^2 + 2Cov(r_h,r_g) - 4w_hCov(r_h,r_g) = 0\]

\[w_h^* = \frac{\sigma_g^2 - Cov(r_h,r_g)}{\sigma_h^2 + \sigma_g^2 - 2Cov(r_h,r_g)}\]

Agora, podemos aplicar a função utilizando os valores calculados anteriormente para encontrar a carteira que minimiza a variância sem ter que testar todos os pesos possíveis.

Aplicando a Fórmula em R:

# aplicacao da formula para o peso que min. o risco
w_h_menor_var <- 
  (desvio_padrao_g^2 - covariancia) / 
  (desvio_padrao_g^2 + desvio_padrao_h^2 - (2*covariancia) )

# encontrando o outro peso da acao
w_g_menor_var <- 1 - w_h_menor_var

Portanto, o resultado utilizando a fórmula foi de: \[w_h^* = 0.6879856\] \[w_g^* = 0.3120144\]

2.2.1 Valores de estatísticas para o valor de mínima variância

\[ \begin{align} \begin{cases} E[r_p] & = 0.5088682 \\ \sigma_p^2 & = 46.8314918 \\ \sigma_p & = 6.8433538 \end{cases} \end{align} \]

2.3 Pesos que maximizam a Utilidade do investidor

Fórmula da Utilidade é: \[U = E[r_p] - \frac{1}{2}A\sigma^2_p\]

Da mesma forma que achamos a carteira de mínima variância calculando os resultados para todos os pesos possíveis, podemos forçar a maximização da utilidade dessa mesma forma:

# definindo a aversao ao risco
A <- 2.5
# vetor vazio de armazenamento das utilidades
utilidades <- c()
# Calculando a utilidade para todos os possiveis pesos
for (i in 1:nrow(tabela_pesos)) {

  # definindo as variaveis pelo iterador em questao
  w_g <- tabela_pesos$w_g[i]
  w_h <- tabela_pesos$w_h[i]
  desvio <- tabela_retornos$desvio[i]
  retorno_esperado <- tabela_retornos$retorno[i]


  # aplicando o calculo da utilidade para cada par de pesos
  utilidades[i] <- (retorno_esperado - (0.5 * A * desvio^2) )
}

# acrescentando os valores da utilidade para cada peso
tabela_retornos$utilidades <- utilidades

Como as utilidades são calculadas por meio da subtração do retorno esperado menos um produto do desvio padrão, temos boa parte das utilidades negativas. Ainda assim, como a parte importante das funções utilidades é o seu carácter ordinal e não seu valor em si, só a utilizaremos para ver qual par de pesos que a tornou máxima.

\[Max(Utilidade) \rightarrow w_g = 0.3097; w_h = 0.6903 \]

2.3.1 Calculando a Utilidade por meio das Fórmulas:

Temos:

\[U = \color{green}{E[r_p]} - 0.5 A \color{red}{ \sigma_p^2} \] \[\color{green}{E[r_p]} = w_gE[r_g] + w_hE[r_h]\]

\[\color{red}{\sigma^2_p} = w_h^2\sigma_h^2+w_g^2\sigma_g^2 + 2w_hw_gCov(r_h,r_g) \]

Portanto, a utilidade pode ser escrita como: \[U = \color{green}{w_gE[r_g]+w_hE[r_h]} - 0.5A \color{red}{[w_g^2\sigma_g^2+w_h^2\sigma_h^2+2w_gw_hCov(r_g,r_h)]}\]

Dessa forma, quando maximizamos ela, teremos:

\[w_g^* = \frac{E[r_g] - E[r_h] + A[\sigma^2_h - 2Cov(r_D, r_E)]}{A[\sigma^2_g + \sigma^2_h - 2Cov(r_g, r_h)]}\] \[w_h^* = 1 - w_g^* = \frac{E[r_g] - E[r_h] + A[\sigma^2_g 2Cov(r_g, r_h)] }{A[\sigma^2_g + \sigma^2_h - 2Cov(r_g, r_h)]}\]

2.3.2 Aplicando a formula utilizando o R:

# aplicacao da formula para o peso que max a Utilidade
w_g_max_uti <- 
  ( retorno_g - retorno_h + (A * (desvio_padrao_h^2 - covariancia)) ) / 
  ( A * (desvio_padrao_g^2 + desvio_padrao_h^2 - (2*covariancia) ) )

# encontrando o outro peso da acao
w_h_max_uti <- 1 - w_g_max_uti

Dessa forma, a partir da formula, temos que os valores que maximizam a utilidade são, respectivamente:

\[Max(Utilidade) \rightarrow w_g = 0.3096785; w_h = 0.6903215 \]

2.3.3 Alguns valores importantes para o exercicio 2

\[ \begin{align} \begin{cases} E[r_p] & = 0.5101824 \\ \sigma_p^2 & = 46.8320159 \\ \sigma_p & = 6.8433921 \end{cases} \end{align} \]

QUESTÃO 3

3.1 Risk Free na maximização da Carteira de Ações

Quando adicionamos o Risk Free ao modelo, de fato teremos três ativos para poder realizar o exercício de maximização da Utilidade, porém matematicamente isso ficaria muito trabalhoso. Por conta desta dificuldade, foram desenvolvidas técnicas diferentes de aplicação desses modelos os quais veremos nos exercícios abaixo.

3.1.1 Figura de retorno esperado e Desvio-Padrão das ações junto a LAC.

Para podermos encontrar a carteira que maximiza a Utilidade do Consumidor, podemos utilizar a formula do índice de Sharpe a fim de encontrar o par de pesos que maximize o índice de Sharpe. Como o Sharpe é a relação entre o retorno e o risco assumido. encontrar a carteira que deixe o Sharpe mais alto é encontrar a razão que deixe o retorno mais compensatório com relação ao seu risco.

Isso por si só já nos entrega a carteira ideal para ser utilizada em combinação com o Risk Free.

dado que a \(r_f\) é a taxa do risk free, A fórmula do Índice de Sharpe pode ser dada por: \[S = \frac{E[r_c] - r_f}{\sigma_c}\]

3.1.2 Aplicando o calculo do Sharpe em R para todos os pesos:

# Risk free
risk_free <- mean(retornos_selic)

# vetor vazio de armazenamento dos Sharpes calculados
sharpe <- c()

# Calculando a utilidade para todos os possiveis pesos
for (i in 1:nrow(tabela_pesos)) {

  # definindo as variaveis pelo iterador em questao
  w_g <- tabela_pesos$w_g[i]
  w_h <- tabela_pesos$w_h[i]
  desvio <- tabela_retornos$desvio[i]
  retorno_esperado <- tabela_retornos$retorno[i]


  # aplicando o calculo do sharpe para cada par de pesos
  sharpe[i] <- (retorno_esperado - risk_free) / (desvio)
}

# acrescentando os valores da utilidade para cada peso
tabela_retornos$sharpe <- sharpe

# pontos que maximizam o sharpe tirando aqueles abaixo da linha de min(Variancia)
tabela_acima_min_risco <- tabela_retornos[
  tabela_retornos$retorno > tabela_retornos[
    tabela_retornos$desvio == min(tabela_retornos$desvio),"retorno"
    ],
  ]

  # encontrando pontos de maximo sharpe
  w_g_max_sharpe <- tabela_acima_min_risco[
    tabela_acima_min_risco$sharpe == max(tabela_acima_min_risco$sharpe),"peso_gol"
  ]

w_h_max_sharpe <- 1 - w_g_max_sharpe

Os pesos que maximizam o sharpe forçando a maximização por loop são, respectivamente: \[Max(Sharpe) \rightarrow w_g = 0; w_h = 1 \]

Agora, iremos plotar na figura a reta que passa pelo eixo zero e corta a curva do conjunto de oportunidades no ponto de tangência:

# adicionando os pontos de sharpe maximo
x_ponto_desvio  <- tabela_retornos[tabela_retornos$peso_gol == w_g_max_sharpe,"desvio"]
y_ponto_retorno <- tabela_retornos[tabela_retornos$peso_gol == w_g_max_sharpe,"retorno"]

ggplot(tabela_retornos, aes(x = desvio, y = retorno)) +
  geom_point(color = "black", size = 1) +
  geom_point(data = data.frame(x = x_ponto_desvio, y = y_ponto_retorno), aes(x = x, y = y), color = "darkred", size = 3) + # Adicionando o ponto
  geom_segment(x = 0, y = 0, xend = 2*x_ponto_desvio, yend = 2*y_ponto_retorno, color = "red", linetype = "solid") + # Desenhando a linha da origem ao ponto vermelho
  labs(
    x = "Desvio Padrão (σ)",
    y = "Retorno Esperado (E[r])",
    title = "Relação entre Desvio Padrão e Retorno Esperado",
    subtitle = "Análise de Portfólio",
    caption = "Fonte: Yahoo.finance"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(face = "italic", size = 12),
    plot.caption = element_text(size = 8),
    axis.title.x = element_text(face = "bold", size = 12),
    axis.title.y = element_text(face = "bold", size = 12),
    axis.text.x = element_text(angle = 25, hjust = 1),
    legend.position = "none"
    ) +
    scale_x_continuous(
      expand = c(0, 0),
      limits = c(0, 2+ max(tabela_retornos$desvio)),
      breaks = seq(0, 2+ max(tabela_retornos$desvio), by = 1)
      ) +
  scale_y_continuous(
    expand = c(0, 0),
    limits = c(0, 0.2 + max(tabela_retornos$retorno)),
    breaks = seq(0, 0.2 + max(tabela_retornos$retorno),by = 0.1)
    )

3.1.3 Apresentando os valores importantes do ponto de máximo

\[ \begin{align} \begin{cases} E[r_p] & = 0.6871471 \\ \sigma_p^2 & = 56.3571085 \\ \sigma_p & = 7.5071372 \\ S_p & = 0.074851 \end{cases} \end{align} \]

3.2 Pesos ótimos da carteira completa C

Quando queremos maximizar o Sharpe por meio das equações escolhendo um dos pesos, teremos:

\[\max_{w_e,w_D} S_p\] \[ \begin{align} \text{s.a.} \quad & \begin{cases} w_g + w_h = 1 \\ E[r_p] = w_gE[r_g] + w_hE[r_h] \\ \sigma_p = (\sigma^2_p)^{1/2} \\ \sigma_P^2 = w_g^2\sigma_g^2 + w_h^2\sigma_h^2+ 2w_gw_h \cdot Cov(r_g,r_h) \end{cases} \end{align} \]

Se substituirmos tudo, teremos um problema de maximização dado por: \[ \max_{w_g} \frac{(1-w_g)E[r_h]+w_gE[r_g] - r_f} {\sqrt{ [w_g^2\sigma_g^2 + (1-w_g)^2\sigma_h^2+ 2w_g(1-w_g) \cdot Cov(r_g,r_h)]}} \]

Aplicando a maximização, teremos os pesos ótimos dados pela equação: \[ w_G^* =\frac{E[R_G]\sigma_H^2 - E[R_H] Cov(R_G,R_H)} {E[R_G]\sigma_H^2 - E[R_H]\sigma_G^2 - (E[R_G] - E[R_H]) \cdot Cov(R_G,R_H)} \]

onde consideramos os retornos excedentes: \[E[R_G] = E[r_g-r_f]\] \[E[R_H] = E[r_h-r_f]\] ### 3.2.1 Aplicando a formula em R para os pontos:

# definindo variaveis
R_G <- retorno_g - risk_free
R_H <- retorno_h - risk_free

w_g_maximo_sharpe <- 
    ( (R_G * desvio_padrao_h^2) - (R_G * covariancia) ) / # dividido por...
  (
    (R_G*desvio_padrao_h^2) - (R_H*desvio_padrao_g^2) - 
    ( (R_G - R_H) * (covariancia) )
  )

w_h_maximo_sharpe <- 1 - w_g_maximo_sharpe

Os pesos que maximizam o sharpe por meio das equações são, respectivamente: \[Max(Utilidade) \rightarrow w_g = 0.0076013; w_h = 0.9923987 \]

3.2.2 Pesos otimo carteira C que maximixam a utilidade do investidor.

Agora, tendo a carteira ótima de títulos de risco P, usaremos o grau de aversão ao risco A, para calcular a proporção ótima da carteira completa a ser investida no componente de risco

Calculando o peso em acoes

\[ y =\frac{E[r_p] - r_f}{A\sigma_p^2} \]

Aplicando em R, teremos

pesoacoes <- (retorno_sharpe - risk_free)/(A*desvio_sharpe^2)
pesoselic <- 1 - pesoacoes

peso_g <- w_g_maximo_sharpe*pesoacoes
peso_h <- w_h_maximo_sharpe*pesoacoes

Apresentando os resultados:

\[Max(Utilidade Risk Free)\] \[w_g = 3.0315985\times 10^{-5};\] \[w_h = 0.0039579\] \[y = 0.9960117 \] ### 3.2.3 calculando as variaveis de saída:

retorno_c   <- (pesoselic * risk_free) + (pesoacoes*retorno_sharpe)

desvio_c    <- ((pesoacoes^2 * desvio_sharpe^2) )^(0.5)
variancia_c <- ((pesoacoes^2 * desvio_sharpe^2) )

sharpe_c    <- ( (retorno_sharpe - risk_free) / (desvio_sharpe) )   

\[ \begin{align} \begin{cases} E[r_c] & = 0.1274717 \\ \sigma_c^2 & = 8.964267\times 10^{-4} \\ \sigma_c & = 0.0299404 \\ S_c & = 0.074851 \end{cases} \end{align} \]

ANÁLISE DAS CARTEIRAS

Retorno em excesso médio para as 40 observações finais

Aplicando o retorno em excesso dos ativos comparado ao risk free

# Realizando as contas, teremos:
R_excesso_gol <- mean(gol$retornos_anualizados[80:120] - retornos_selic[80:120])
R_excesso_hpv <- mean(hapv$retornos_anualizados[80:120] - retornos_selic[80:120])

\[ \begin{align} \begin{cases} E[r_g-r_f] & = -0.7796444 \\ E[r_h-r_f] & = -1.1298017 \\ \end{cases} \end{align} \] ### desvio-padrão para as 40 observações finais

# Realizando as contas, teremos:
desvio_gol <- sd(gol$retornos_anualizados[80:120] - retornos_selic[80:120])
desvio_hpv <- sd(hapv$retornos_anualizados[80:120] - retornos_selic[80:120])

\[ \begin{align} \begin{cases} \sqrt{Var[r_g-r_f]} & = 9.1709857 \\ \sqrt{Var[r_h-r_f]} & = 6.8831021 \\ \end{cases} \end{align} \]

O desvio-padrão parcial inferior para as 40 observações finais, considerando como referência ora o retorno médio ora a taxa de juros livre de risco

# Calculando o desvio padrão
desvio_padrao_g <- sd(gol$retornos_anualizados[80:120])
desvio_padrao_h <- sd(hapv$retornos_anualizados[80:120])

# Calculando o limite inferior do intervalo de confianca para o desvio padrao
# Usando um nível de confiança de 95%
alpha <- 0.05
n <- length(gol$retornos_anualizados[80:120])
limite_inferior_g <- desvio_padrao_g * sqrt((n - 1) / qchisq(1 - alpha/2, n - 1))
limite_inferior_h <- desvio_padrao_h * sqrt((n - 1) / qchisq(1 - alpha/2, n - 1))

\[ \begin{align} \begin{cases} \text{Limite inferior Gol} & = 9.1709857 \\ \text{Limite inferior Hapivida} & = 6.8831021 \\ \end{cases} \end{align} \]

O índice de Sharpe para as 40 observações finais;

Calculando o Sharpe para as ações

sharpe_gol <- (R_excesso_gol - risk_free) / (desvio_padrao_g)
sharpe_hpv <- (R_excesso_hpv - risk_free) / (desvio_padrao_h)

\[ \begin{align} \begin{cases} \text{Índice de Sharpe Gol} & = -0.0986699 \\ \text{Índice de Sharpe Hapivida} & = -0.1823336 \\ \end{cases} \end{align} \]

O VaR a 10% para as 80 observações iniciais. Para tanto, ora assuma a distribuição normal, ora use simplesmente o percentil apropriado dos retornos. Posteriormente, avalie o desempenho desse VaR com base nas 40 observações finais.

# Separe os dados em observações iniciais e finais
gol_iniciais <- gol$retornos_anualizados[1:80]
hpv_iniciais <- hapv$retornos_anualizados[1:80]

# Calcule o VaR a 10% assumindo uma distribuição normal
media_gol <- mean(gol_iniciais)
media_hpv <- mean(hpv_iniciais)

desvio_padrao_gol <- sd(gol_iniciais)
desvio_padrao_hpv <- sd(hpv_iniciais)

VaR_normal_gol <- qnorm(0.1, mean = media_gol, sd = desvio_padrao_gol)
VaR_normal_hpv <- qnorm(0.1, mean = media_hpv, sd = desvio_padrao_hpv)

# Calcule o VaR a 10% usando o percentil apropriado dos retornos
VaR_percentil_gol <- quantile(gol_iniciais, 0.1)
VaR_percentil_hpv <- quantile(hpv_iniciais, 0.1)

As iniciais são: \[ \begin{align} \begin{cases} \text{Iniciais Var Normal Gol} & = -12.0749811 \\ \text{Iniciais Var Normal Hapivida} & = -8.2091618 \\ \text{Iniciais Var Percentil Gol} & = -9.236938 \\ \text{Iniciais Var Percentil Hapivida} & = -7.0239081 \\ \end{cases} \end{align} \] As finais são:

# Separe os dados em observações iniciais e finais
gol_finais <- gol$retornos_anualizados[80:120]
hpv_finais <- hapv$retornos_anualizados[80:120]

# Calcule o VaR a 10% assumindo uma distribuição normal
media_gol <- mean(gol_finais)
media_hpv <- mean(hpv_finais)

desvio_padrao_gol <- sd(gol_finais)
desvio_padrao_hpv <- sd(hpv_finais)

VaR_normal_gol <- qnorm(0.1, mean = media_gol, sd = desvio_padrao_gol)
VaR_normal_hpv <- qnorm(0.1, mean = media_hpv, sd = desvio_padrao_hpv)

# Calcule o VaR a 10% usando o percentil apropriado dos retornos
VaR_percentil_gol <- quantile(gol_finais, 0.1)
VaR_percentil_hpv <- quantile(hpv_finais, 0.1)

\[ \begin{align} \begin{cases} \text{Finais Var Normal Gol} & = -12.411028 \\ \text{Finais Var Normal Hapivida} & = -9.8295516 \\ \text{Finais Var Percentil Gol} & = -12.1383292 \\ \text{Finais Var Percentil Hapivida} & = -9.8608435 \\ \end{cases} \end{align} \]

A expectativa condicionada das caudas de distribuição (ECCD), considerando o VaR a 10% obtido com as 80 observações iniciais. Posteriormente, avalie o desempenho dessa ECCD com base nas 40 observações finais.

# Calculando o VaR a 10% para os dados iniciais
VaR_10_gol <- quantile(gol_iniciais, 0.1)
VaR_10_hpv <- quantile(hpv_iniciais, 0.1)

# Calculando a ECCD
ECCD_gol <- mean(gol$retornos_anualizados[gol$retornos_anualizados > VaR_10_gol])
ECCD_hpv <- mean(hapv$retornos_anualizados[hapv$retornos_anualizados > VaR_10_hpv])
# Calculando a ECCD para as últimas 40 observações
ECCD_final_gol <-  quantile(gol_finais, 0.1)
ECCD_final_hpv <-  quantile(hpv_finais, 0.1)


# Avaliando o desempenho
desempenho_gol <- ECCD_final_gol - ECCD_gol
desempenho_hpv <- ECCD_final_hpv - ECCD_hpv

Os resultados são: \[ \begin{align} \begin{cases} \text{Iniciais ECCD Gol} & = 2.5742965 \\ \text{Iniciais ECCD Hapivida} & = 2.4818222 \\ \text{Finais ECCD Gol} & = -14.7126257 \\ \text{Finais ECCD Hapivida} & = -14.7126257 \\ \end{cases} \end{align} \]