Construindo uma carteira de ações (portfólio) em Python

By | mercado financeiro

A combinação de diferentes ativos financeiros pode trazer benefícios, entre eles, conseguir uma boa diversificação de forma diluir os diversos riscos existentes. Porém, para construir portfólio, é necessário ter o entendimento correto sobre como construir formas de avaliação: de retorno e risco. No post de hoje, mostramos como podemos construir estas duas métricas utilizando o Python.

Um portfólio de ações consiste no conjunto de diferentes ativos escolhidos, através de uma metodologia, e mantidas durante um período de tempo. Ao realizar a escolha de ativos, é necessário que haja formas de avaliar o quão bem essas escolhas combinadas performaram, e qual o risco empregado por estes ativos.

Retornos do portfolio

Uma ação possui uma variação entre dois períodos históricos diferentes, podemos computar essa variação da seguinte forma:

     $$r_i = \frac{P_t - P_{t-1}}{P_{t-1}}$$

Portanto, podemos saber o quanto essa ação rendeu de um período para outro. Mas, e para o caso de haver mais de uma ação em nossa carteira? Como podemos calcular? Para isso, devemos levar em consideração o peso de cada ação no total investido na carteira, obtendo a seguinte equação:

     $$ r_p = w_1 * r_1 + w_2 * r_2 ... w_i * r_i $$

Em que  $w_i$ é o peso do ativo no portfólio, podendo ser calculado como:

    $$w = \frac{valor\;do\;ativo}{total\;investido\;no\;portfolio}$$

Ou seja, ponderamos o retorno do ativos com o seus pesos dentro da carteira.

Iremos realizar um exemplo utilizando ações da Ibovespa. Abaixo, capturamos o preço ajustado de quatro ações e computamos os retornos individuais.

Utilizamos o método pct_change para computar a variação diária dos preços ajustados das quatro ações.

Calculado os retornos, devemos obter os pesos de cada ativo. Selecionamos manualmente pesos iguais para todas as ações, construindo um portfolio conhecido como Equal Weighted Portfolio. Por fim, calculamos o retorno diário do portfólio multiplicando os pesos com os retornos e somando cada resultado.

Retornos acumulados

Essa forma de cálculo representará os retornos diários dos ativos e do portfolio, o que não muito útil para acompanhar o acumulado ao longo de um período de tempo. Desta forma, podemos calcular o retorno acumulado das ações e do portfolio somando 1 aos retorno e utilizando a função cumprod() para calcular o produto acumulado das variações.


Retornos Anualizados

O retorno anualizado é uma forma de transformar a escala dos retornos em termos "anualizados" (o que é diferente de retornos no ano). O objetivo de computar este tipo de retorno se encontra no fato de poder comparar ativos de períodos e janelas de tempo diferentes em uma mesma escala.

A taxa anualizada para períodos diários é calculada como:

     $$ra_i = (1 + r_i)^{252/N} - 1 $$

Em que 252 representa o número de dias úteis em um ano, e N o número de dias da série. Portanto,  r_i será a variação da última observação da série em relação a primeira observação, o mesmo que o retorno acumulado durante o período.

Abaixo, utilizaremos a última observação do retorno acumulado já computado.

Risco

Até agora já obtivemos as métricas necessárias para computar o retorno das ações, porém, devemos levar em conta o quão arriscado cada ativo é (para justificar o retorno e a alocação dos mesmos), bem como a composição do risco total do portfólio.

O risco (volatilidade) das ações individuais pode ser calculado como o desvio padrão de seus retornos. Calculamos abaixo com base em seu valor anualizado (que possui o mesmo significado que os retornos anualizados).

Entretanto, não podemos realizar o mesmo procedimento para o cálculo da volatilidade de um portfólio, afinal, as ações podem possuir uma relação, portanto, devemos levar em conta a correlação entre os ativos.

Calculamos a variância do portfólio em notação matricial

    $$\sigma^2_{pf} = \begin{bmatrix}{w_1 w_2}\end{bmatrix} \begin{bmatrix}{\sigma^2_1}&{\sigma_{1,2}} \\[0.3em] {\sigma_{2,1}}&{\sigma^2}\end{bmatrix} \begin{bmatrix}{w_1} \\{w_2}\end{bmatrix} $$

E podemos facilmente realizar este cálculo utilizando o Python.

Juntamos os resultados dos retornos anualizados e do desvio padrão (risco) anualizado em um data frame, e geramos um gráfico mostrando o retorno das ações e do portfolio dado o nível de risco.

Quer saber mais?

Veja nossos cursos da trilha de Finanças Quantitativas.

Análise de Dados da Inflação utilizando o Python

By | Indicadores

A inflação é conhecida como o termo que representa a taxa de crescimento do nível geral de preços entre dois períodos distintos. No Brasil, o indicador que consolidou-se como o principal índice de preços é o Índice de Preços ao Consumidor Amplo (IPCA), divulgado pelo IBGE e amplamente utilizado pela autoridade monetária como referência para realizar o controle da inflação. No post de hoje, mostraremos como podemos realizar a importação dos dados do IPCA e visualizar como forma de obter um análise.

O IPCA é divulgado mensalmente pelo IBGE, portanto, podemos importar diretamente do SIDRA os dados do indicador utilizando a biblioteca {sidrapy}. Primeiro, iremos buscar a série que diz respeito a variação mensal, acumulada em 3 meses, acumulada em 6 meses, acumulada em 12 meses e acumulado no ano, que diz respeito a tabela 1737.

Em um segundo momento, buscaremos a série de pesos e variação de cada grupo do IPCA, e veremos a contribuição de cada grupo sobre o IPCA, através da tabela 7060.

Para importar as séries com a função get_table do {sidrapy}, buscamos a API das tabelas, com os parâmetros configurados, de forma a obter os códigos. Ensinamos este processo em um post anterior: Coletando dados do SIDRA com o Python.

Variações do IPCA: tabela 1737



 

IPCA Contribuição por grupo: tabela 7060



Quer saber mais?

Veja nossos cursos de Macroeconomia através da nossa trilha de Macroeconomia Aplicada.

Modelagem e Previsão em 6 Passos: fluxo de trabalho com séries temporais

By | Data Science

Produzir modelos preditivos para séries temporais é uma tarefa difícil e bastante valorizada no mercado de trabalho. São diversos os procedimentos que um profissional dessa área precisa sempre ter no radar e, se generalizarmos isso em um fluxo, a distância entre a idealização do modelo e sua implementação pode ser mais curta e menos árdua. Neste texto descrevemos resumidamente o dia a dia de um profissional que trabalha com previsões e mostramos um exemplo de rotinas em R!

Fluxo de trabalho

O processo de desenvolver modelos preditivos para séries temporais pode ser generalizado e dividido em 6 etapas:

Fonte: Hyndman and Athanasopoulos (2021)

Este fluxo, em resumo, descreve como é o dia a dia de trabalho de modelagem e previsão em algumas etapas organizadas. São elas:

Preparar os dados

O primeiro passo é preparar os dados no formato correto para uso em modelos. Esse processo pode envolver a coleta e importação de dados, a identificação de valores ausentes, agregação/sumarização/ajustes/filtros nas séries e outras tarefas de pré-processamento (veja um post sobre coleta de dados aqui). O objetivo será, em geral, construir uma matriz de variáveis onde cada variável terá sua própria coluna, cada linha formará uma observação e os valores são armazenados nas células. Esse é o princípio de dados "tidy". A facilidade que o pacote {tsibble} e outros do {tidyverse} oferecem simplifica consideravelmente esta etapa usando o R.

Vale dizer que muitos modelos têm pressupostos e requisitos diferentes, sendo que você precisará levar isso em consideração ao preparar os dados. Alguns exigem que a série seja estacionária, outros exigem que não haja valores ausentes. Dessa forma, você precisará conhecer bem os seus dados enquanto os prepara e a análise exploratória é outra etapa que caminhará lado a lado.

Visualizar os dados

A visualização é uma etapa essencial para a compreensão dos dados. Suas séries temporais apresentam tendência? Possuem sazonalidade? Há quebras ou observações extremas nas séries (outliers)? Observar seus dados, através de uma análise exploratória (veja um post sobre aqui no blog) permite identificar estes padrões comuns e, posteriormente, especificar um modelo apropriado. Essa etapa pode andar em conjunto com a etapa de preparação dos dados, de modo que após entender os dados você talvez precise voltar a um passo anterior e aplicar uma transformação, por exemplo, nas séries. Os pacotes {ggplot2}, {feasts}, {fabletools} e outros oferecem formas elegantes e práticas de visualizar seus dados.

Definir o modelo

Existem muitos modelos de séries temporais diferentes que podem ser usados para previsão. Especificar um modelo apropriado para os dados é essencial para produzir previsões. Nesse sentido, além de conhecer os seus dados você precisará ter conhecimento sobre os modelos que pretende trabalhar. Papers publicados são, em geral, boas fontes para buscar esse conhecimento técnico.

Grande parte dos modelos econométricos é descrita em Hyndman and Athanasopoulos (2021) e podem ser implementados pelo pacote {fable} através de funções específicas como ARIMA(), TSLM(), VAR(), etc., cada uma usando uma interface de fórmula (y ~ x). As variáveis de resposta são especificadas à esquerda da fórmula e a estrutura do modelo, que pode variar, é escrita à direita. Para outros modelos fora do escopo do {fable} a lógica e sintaxe é semelhante, quase sempre utilizando uma interface de fórmula.

Estimar o modelo

Uma vez que um modelo apropriado é definido, passamos à estimação do modelo com os dados. Uma ou mais especificações de modelo podem ser estimadas usando a função model() do pacote {fabletools} — framework que contempla grande parte dos modelos econométricos; para outros modelos há pacotes e funções específicas, mas com sintaxe semelhante.

Avaliar a performance

Após termos um modelo estimado, é importante verificar o desempenho dele nos dados. Existem várias ferramentas de diagnóstico disponíveis para verificar o ajuste do modelo, assim como medidas de acurácia que permitem comparar um modelo com outro; o RMSE é a métrica mais comumente utilizada para a maioria dos problemas de previsão. Conforme o diagnóstico do modelo, em seguida possivelmente sejam necessárias readequações, seja na especificação ou até mesmo nos dados utilizados. Em outras palavras, o fluxo de trabalho não é simplesmente um amontoado de procedimentos a serem implementados sequencialmente, mas sim um processo de descobrimento que envolve, na vida real, sucessivas tentativas e erros.

Além disso, se o interesse é previsão, há técnicas como a validação cruzada que auxiliam na tomada de decisão entre mais de um modelo (veja um post sobre isso aqui no blog). É sempre preferível ter mais de um modelo "candidato" potencialmente usado para fazer previsões, além de modelos básicos para simples comparação.

Realizar previsões

Com um modelo especificado, estimado e diagnosticado, é hora de produzir as previsões fora da amostra. Para alguns modelos você poderá simplesmente chamar uma função, como a forecast() ou predict() no R, especificando o número de períodos (horizonte de previsão) que deseja obter previsões; para outros você precisará prover uma tabela com os valores futuros das variáveis regressoras utilizadas no modelo, que servirá para produzir as previsões da variável de interesse, ou seja, você precisará de cenários.

Exemplo no R

Com esse esquema em mente, vamos ilustrar o fluxo de trabalho com um exercício prático e didático: construir um modelo de previsão para a taxa de crescimento anual do PIB brasileiro.

Para reproduzir o exercício a seguir você precisará dos seguintes pacotes:

Preparar os dados

Por conveniência, utilizaremos o dataset global_economy armazenado como um objeto tsibble, trazendo variáveis econômicas em frequência anual para diversos países. Nosso interesse é a série da taxa de crescimento do PIB brasileiro:

Visualizar os dados

Visualização é uma etapa essencial para entender os dados, o que permite identificar padrões e modelos apropriados. No nosso exemplo, primeiro criamos um gráfico de linha para plotar a série do PIB brasileiro usando a função autoplot():

Podemos também plotar os correlogramas ACF e PACF para identificar o processo estocástico da série, obtendo alguns modelos candidatos:

Definir o modelo

Existem muitos modelos de séries temporais diferentes que podem ser usados para previsão, e especificar um modelo apropriado para os dados é essencial para produzir previsões. Nesse exercício didático focaremos em modelos univariados simples para explicar o PIB brasileiro.

Se formos analisar somente pelos correlogramas ACF e PACF, podemos identificar alguns modelos possivelmente candidatos: ARIMA(1,0,2), ARIMA(1,0,0) e ARIMA(0,0,2). Contudo, se nossa leitura estiver incorreta, podemos contar ainda com a tecnologia ao nosso favor utilizando a seleção automatizada da estrutura do modelo. Isso é possível graças ao algoritmo de seleção automatizada da especificação do ARIMA criado pelo prof. Rob Hyndman.

Por fim, além destes possíveis modelos candidatos, também estimaremos um modelo de benchmark na forma de um passeio aleatório, apenas para ter uma base de comparação de previsões dos modelos.

Estimar o modelo

Identificado um modelo (ou mais) apropriado, podemos em seguida fazer a estimação usando a função model()1. Existem diversas funções especiais para definir a estrutura do modelo e em ambos os lados da fórmula podem ser aplicadas transformações. Nesse caso definiremos apenas a estrutura básica do ARIMA; a função ARIMA() também define automaticamente a estrutura sazonal, mas você pode desabilitar isso (consulte detalhes da documentação do {fable}).

O objeto resultante é uma "tabela de modelo" ou mable, com a saída de cada modelo em cada coluna.

Diagnóstico do modelo

Para obter os critérios de informação use a função glance():

Os critérios de informação indicam que, dos modelos estimados, o modelo automatizado ARIMA(1,1,1) apresentou o menor valor de AICc — seguido pelos demais identificados pelos correlogramas ACF e PACF. Com a função gg_tsresiduals() podemos verificar o comportamento dos resíduos deste modelo, indicando que os resíduos se comportam como ruído branco:

Um teste de autocorrelação (Ljung Box) retorna um p-valor grande, também indicando que os resíduos são ruído branco:

Também pode ser interessante visualizar o ajuste do modelo. Utilize a função augment() para obter os valores estimados:

Outros diagnósticos e avaliações podem ser realizados. Se você estiver especialmente interessado em previsão, considere implementar o método de validação cruzada, como explicado neste post.

Realizar previsões

Com o modelo escolhido, previsões podem ser geradas com a função forecast() indicando um horizonte de escolha.

Perceba que os pontos de previsão médios gerados são bastante similares a um processo de passeio aleatório (equivalente a um ARIMA(0,1,0)). O trabalho adicional de especificar termos AR e MA trouxe pouca diferença para os pontos de previsão neste exemplo, apesar de ser perceptível que os intervalos de confiança do modelo auto ARIMA são mais estreitos do que de um passeio aleatório.

Além disso, a previsão fora da amostra gerada ficou bastante aquém dos dados reais para a taxa de crescimento do PIB brasileiro observados no horizonte em questão, configurando apenas um exercício didático.

Saiba mais

Este é apenas um exercício simples e didático demonstrando um fluxo de trabalho de modelagem e previsão. Existem diversos tópicos que podem ser aprofundados e se você quiser saber mais confira o curso de Modelos Preditivos da Análise Macro.

Confira também outros exercícios aplicados com pacotes do {tidyverts}:

Referências

Hyndman, R. J., & Athanasopoulos, G. (2021) Forecasting: principles and practice, 3rd edition, OTexts: Melbourne, Australia. OTexts.com/fpp3. Accessed on 2022-04-01.

 


1A função suporta estimação dos modelos com computação paralela usando o pacote {future}, veja detalhes na documentação e este post para saber mais sobre o tema.

Afinal, o que é Probabilidade?

By | Hackeando o R

Infelizmente não possuímos uma bola de cristal de forma que possamos prever o futuro, e por isso, sempre há uma incerteza em relação a um resultado. Entretanto, apesar de ser extremamente difícil ter 100% de certeza, podemos quantificar essa incerteza, e pelo menos, haver a possibilidade de acertar um certo nível de um resultado. No post de hoje explicamos o que é probabilidade e o seu papel na Análise de Dados.

Antes de introduzir o conceito da probabilidade, devemos entender o conceito de aleatoriedade. A grosso modo, algo é aleatório quando sabemos que haverá um resultado, porém, não sabemos qual será o valor deste resultado, ou seja, segue uma distribuição de probabilidade e não um valor determinístico.

Podemos utilizar o velho exemplo dos dados de seis lados. Se jogarmos o dado, saberemos que o resultado será entre um a seis, porém, não sabemos qual será o seu valor. Essas possibilidade de resultados do dado (um a seis) é chamado de Espaço Amostral. Cada lado desse dado representa uma fração da possibilidade do resultado, sendo sua soma igual a 1 (100%).

Se a probabilidade depende do número de casos favoráveis de cair um lado do dado e do número do casos possíveis, então podemos definir pela equação da probabilidade teórica.

     $$P(evento) = \frac{n°de casos que podem ocorrer}{total de resultados possíveis}$$

No caso do dado, qual a probabilidade de cair no número dois? Obviamente 1/6.

Construímos um tibble com os valores do dado, e "jogamos" ele com a função sample_n

A função set.seed permite que possamos obter o mesmo resultado sempre. Útil para reprodutibilidade e comunicação dos resultados.

E se estivermos jogando um jogo em que não possamos tirar o mesmo lado novamente? Devemos então levar em conta a amostra sem reposição.

Caso não houvesse esta regra, poderíamos rodar o dado novamente com reposição, utilizando o argumento replace = TRUE na função.

Isto nos ajuda a entender o conceito de Independência de eventos, que no caso, aplica-se a rodar o dado com reposição, isto porque, rodar o dado na primeira vez não afeta o resultado da probabilidade na segunda. O que não podemos dizer sobre o caso de rodar o dado sem reposição, o que leva a termo eventos dependentes.

Distribuição de probabilidades

Uma distribuição de probabilidades é uma lista dos possíveis resultados que um evento pode ter, e como cada resultado é comum entre si. Elencaremos duas formas de distribuição de probabilidade: Discreta e Contínua

Discreta

Uma distribuição é considerada discreta quando seus números são contagens em formato de inteiros. Em relação ao dado, sua distribuição segue como discreta devido ao fato de que, teoricamente, seus resultados possuem a mesma probabilidade (1/6).

Contínua

Uma distribuição é considerada contínua quando o resultado pode ser qualquer valor entre dois outros valores. Uma importante distribuição contínua pode ser representada pela distribuição normal, muito famosa pelo seu formato de sino. Esta distribuição, construída por um histograma, possui uma forma simétrica e o seu centro equivale a sua média.

Podemos gerar uma distribuição normal utilizando a função rnorm.

Veja que o histograma acima não representa fielmente a distribuição normal perfeitamente, porém, se adicionarmos cada vez mais valores, poderemos ver que a distribuição cada vez mais se aproxima de uma normal.

Isso ocorre devido ao que é conhecido como Teorema Central do Limite, que permite dizer que quanto maior a amostra, mais a distribuição dos dados se tornam normais e próximas da média.

____________________________________________

Quer saber mais?

Veja nossos cursos de R e Python aplicados para a Análise de Dados e Economia

Estrutura a Termo da Taxa de Juros em Python

By | mercado financeiro

A Estrutura a Termo da Taxa de Juros demonstra a relação das taxas de juros dos diferentes instrumentos de renda fixa com os prazos de vencimentos (maturidade). A ETTJ é importante para determinar o comportamento futuro do juros, dado o nível de risco dos agentes de mercado, e é útil para a realização de cálculos para a precificação de ativos de renda fixa. No post de hoje, mostraremos como podemos obter a ETTJ utilizando o Python.

Para obter a ETTJ, podemos importá-la através do site da B3, que oferece os dados de cada dia útil do vencimento da taxa de juros. O processo de extração pode ser feito de diferente formas, a mais simples é utilizando o pacote {pyettj}, que utilizaremos aqui.

Como exemplo, utilizaremos a curva da DI x pré 252 dias, que é determinada com base no DI futuro para obter a ETTJ pré.

O primeiro passo é escolher a data com base em um dia útil do cálculo da curva. Em seguida, utiliza-se a função get_ettj para buscar a série com base na data escolhida. Será retornado um data frame contendo diferentes tipos de taxas disponibilizadas pela B3. Como queremos utilizar a Curva pré, estaremos interessados apenas em sua respectiva coluna. O data frame também contém os dias corridos que se referem ao vencimento da taxa , bem com uma coluna especificando a data do período que buscamos a série. Por fim, podemos visualizar a ETTJ pré com a função plot_ettj fornecida pelo pacote.

Também é possível buscar mais de um período utilizando um for loop. Útil para comparar a evolução das taxas em diferentes períodos.

Quer saber mais?

Veja nossos cursos da trilha de Finanças Quantitativas.

Receba diretamente em seu e-mail gratuitamente nossas promoções especiais
e conteúdos exclusivos sobre Análise de Dados!

Assinar Gratuitamente