Comparação de carteira com IBOV usando Python
Comparação de carteira com Ibov usando python published at the “Open Code Community”
Nesse post, vou mostrar como fazer como comparar uma carteira qualquer com o IBOV utilizando o python.
1. Instalando e importando bibliotecas
!pip install yfinance
import yfinance as yf
import yfinance as yf
import pandas as pd
import numpy as np
2. Importando dados
Repare que vou importar também os dados da cotação do dólar. Posteriormente vou converter a cotação do Ethereum para reais, por isso que estou trazendo a cotação do dólar. Ou seja, multiplicar a cotação de Dolar-Real pelo preço do ETH em dólar para obter o preço do ETH em real.
Criando o vetor dos tickers.
ativos = ['PETR4.SA','VALE3.SA', 'WEGE3.SA',
'RADL3.SA', 'OIBR3.SA','KNRI11.SA',
'SMAL11.SA','AAPL34.SA','IVVB11.SA','ETH-USD','USDBRL=X']
Criando uma data de inicio e de fim da captação de dados.
inicio = '2020-05-01'
fim = '2021-08-24'
Criando o data.frame dos preços.
precos = pd.DataFrame()
Baixando as cotações
for i in ativos:
precos[i] = yf.download(i, start = inicio, end = fim)['Adj Close']
Vamos converter a cotação do Ethereum para reais:
precos['ETH-BRL'] = precos['ETH-USD']*precos['USDBRL=X']
Agora podemos remover as colunas do Ethereum em dólares e da cotação do dólar
precos = precos.drop(columns=['ETH-USD', 'USDBRL=X'])
precos.to_csv('Dados.csv', sep = ';', decimal=',')
Vamos normalizar o preço dos ativos para visualizar seus desempenhos.
normalizado = precos/precos.iloc[0]
normalizado.plot(figsize = (8,8));
3. Simulação de uma carteira vs. IBOV
Criando um dicionário com as alocações que vamos fazer para cada ativo na nossa carteira
compras = {'PETR4.SA': 1000, 'VALE3.SA': 700, 'WEGE3.SA': 1500,
'RADL3.SA': 700, 'OIBR3.SA': 200, 'KNRI11.SA': 700,
'SMAL11.SA': 1500, 'AAPL34.SA': 2000, 'IVVB11.SA': 1500,
'ETH-BRL': 200}
compras_df = pd.Series(data=compras, index=list(compras.keys()))
Qual o valor total da nossa carteira?
sum(compras.values())
10000
Obtendo preços dos ativos no primeiro dia do investimento
primeiro = precos.iloc[0]
Quantidade de papéis comprados de cada ativo
qtd_acoes = compras_df/primeira
Criando um dataframe que contém a posição diária de cada ativo
PL = precos*qtd_acoes
PL.head(3)
PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | |
---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||
2020-05-04 | 1000.000000 | 700.000000 | 1500.000000 | 700.000000 | 200.000000 | 700.000000 | 1500.000000 | 2000.000000 | 1500.000000 | 200.000000 |
2020-05-05 | 1032.221098 | 696.335118 | 1468.750176 | 696.987266 | 205.882347 | 702.685449 | 1479.377360 | 2059.369090 | 1526.950431 | 200.962154 |
2020-05-06 | 994.246331 | 706.373761 | 1461.973107 | 693.037478 | 205.882347 | 717.231486 | 1462.333842 | 2137.167589 | 1548.315577 | 199.662245 |
PL.tail()
PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | |
---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||
2021-08-17 | 1703.360143 | 1892.935908 | 2648.266605 | 855.407388 | 299.999991 | 594.955233 | 2217.361714 | 3962.566078 | 2256.649004 | 2781.549609 |
2021-08-18 | 1688.235983 | 1829.425319 | 2563.528423 | 852.039629 | 297.058818 | 595.134300 | 2220.259080 | 3953.062200 | 2273.936211 | 2804.717612 |
2021-08-19 | 1678.783279 | 1725.048452 | 2686.437068 | 883.022892 | 299.999991 | 587.659883 | 2275.309569 | 3985.575125 | 2308.422157 | 3002.797046 |
2021-08-20 | 1676.262645 | 1725.756108 | 2746.746469 | 898.177773 | 305.882339 | 596.566489 | 2316.384508 | 3993.578089 | 2303.102954 | 3121.606584 |
2021-08-23 | 1702.729955 | 1701.873164 | 2729.188091 | 892.452603 | 338.235284 | 623.196980 | 2316.213906 | 4037.095425 | 2332.358166 | 3131.866252 |
Criando uma coluna que contém a posição consolidada da nossa carteira diariamente
PL['PL Total'] = PL.iloc[:].sum(axis = 1)
PL.head()
PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | PL Total | |
---|---|---|---|---|---|---|---|---|---|---|---|
Date | |||||||||||
2020-05-04 | 1000.000000 | 700.000000 | 1500.000000 | 700.000000 | 200.000000 | 700.000000 | 1500.000000 | 2000.000000 | 1500.000000 | 200.000000 | 10000.000000 |
2020-05-05 | 1032.221098 | 696.335118 | 1468.750176 | 696.987266 | 205.882347 | 702.685449 | 1479.377360 | 2059.369090 | 1526.950431 | 200.962154 | 10069.520489 |
2020-05-06 | 994.246331 | 706.373761 | 1461.973107 | 693.037478 | 205.882347 | 717.231486 | 1462.333842 | 2137.167589 | 1548.315577 | 199.662245 | 10126.223764 |
2020-05-07 | 1003.452454 | 733.780947 | 1471.762093 | 694.175587 | 197.058826 | 716.112560 | 1431.655459 | 2199.999886 | 1622.340455 | 212.823946 | 10283.162213 |
2020-05-08 | 1063.291199 | 778.397410 | 1439.759181 | 700.803383 | 202.941174 | 727.301819 | 1433.359785 | 2220.108426 | 1602.393646 | 217.769114 | 10386.125134 |
PL.tail()
PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | PL Total | |
---|---|---|---|---|---|---|---|---|---|---|---|
Date | |||||||||||
2021-08-17 | 1703.360143 | 1892.935908 | 2648.266605 | 855.407388 | 299.999991 | 594.955233 | 2217.361714 | 3962.566078 | 2256.649004 | 2781.549609 | 19213.051672 |
2021-08-18 | 1688.235983 | 1829.425319 | 2563.528423 | 852.039629 | 297.058818 | 595.134300 | 2220.259080 | 3953.062200 | 2273.936211 | 2804.717612 | 19077.397575 |
2021-08-19 | 1678.783279 | 1725.048452 | 2686.437068 | 883.022892 | 299.999991 | 587.659883 | 2275.309569 | 3985.575125 | 2308.422157 | 3002.797046 | 19433.055463 |
2021-08-20 | 1676.262645 | 1725.756108 | 2746.746469 | 898.177773 | 305.882339 | 596.566489 | 2316.384508 | 3993.578089 | 2303.102954 | 3121.606584 | 19684.063959 |
2021-08-23 | 1702.729955 | 1701.873164 | 2729.188091 | 892.452603 | 338.235284 | 623.196980 | 2316.213906 | 4037.095425 | 2332.358166 | 3131.866252 | 19805.209825 |
Obtendo dados do IBOV para comparar com a nossa carteira
ibov = yf.download('^BVSP', start = inicio, end = fim)
ibov.head()
Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|
Date | ||||||
2020-05-04 | 80501.0 | 80502.0 | 77640.0 | 78876.0 | 78876.0 | 8594200 |
2020-05-05 | 78887.0 | 81066.0 | 78886.0 | 79471.0 | 79471.0 | 9154700 |
2020-05-06 | 79473.0 | 79996.0 | 78056.0 | 79064.0 | 79064.0 | 9775900 |
2020-05-07 | 79072.0 | 80061.0 | 78061.0 | 78119.0 | 78119.0 | 13808900 |
2020-05-08 | 78152.0 | 80557.0 | 78152.0 | 80263.0 | 80263.0 | 10734400 |
ibov.rename(columns = {'Adj Close': 'IBOV'}, inplace = True)
ibov = ibov.drop(ibov.columns[[0,1,2,3,5]], axis = 1)
ibov
IBOV | |
---|---|
Date | |
2020-05-04 | 78876.0 |
2020-05-05 | 79471.0 |
2020-05-06 | 79064.0 |
2020-05-07 | 78119.0 |
2020-05-08 | 80263.0 |
... | ... |
2021-08-17 | 117904.0 |
2021-08-18 | 116643.0 |
2021-08-19 | 117165.0 |
2021-08-20 | 118053.0 |
2021-08-23 | 117472.0 |
324 rows × 1 columns
Verificando se o índice dos dataframes está no formato ‘data’
ibov.index = pd.to_datetime(ibov.index)
PL.index = pd.to_datetime(PL.index)
Juntando tudo num dataframe só
novo_df = pd.merge(ibov, PL, how = 'inner', on = 'Date')
novo_df.head()
IBOV | PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | PL Total | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||
2020-05-04 | 78876.0 | 1000.000000 | 700.000000 | 1500.000000 | 700.000000 | 200.000000 | 700.000000 | 1500.000000 | 2000.000000 | 1500.000000 | 200.000000 | 10000.000000 |
2020-05-05 | 79471.0 | 1032.221098 | 696.335118 | 1468.750176 | 696.987266 | 205.882347 | 702.685449 | 1479.377360 | 2059.369090 | 1526.950431 | 200.962154 | 10069.520489 |
2020-05-06 | 79064.0 | 994.246331 | 706.373761 | 1461.973107 | 693.037478 | 205.882347 | 717.231486 | 1462.333842 | 2137.167589 | 1548.315577 | 199.662245 | 10126.223764 |
2020-05-07 | 78119.0 | 1003.452454 | 733.780947 | 1471.762093 | 694.175587 | 197.058826 | 716.112560 | 1431.655459 | 2199.999886 | 1622.340455 | 212.823946 | 10283.162213 |
2020-05-08 | 80263.0 | 1063.291199 | 778.397410 | 1439.759181 | 700.803383 | 202.941174 | 727.301819 | 1433.359785 | 2220.108426 | 1602.393646 | 217.769114 | 10386.125134 |
Normalizando esse novo dataframe que contém o IBOV, todos os ativos e o PL da nossa carteira
PL_normalizado = novo_df/novo_df.iloc[0]
PL_normalizado.head()
IBOV | PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | PL Total | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||
2020-05-04 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
2020-05-05 | 1.007543 | 1.032221 | 0.994764 | 0.979167 | 0.995696 | 1.029412 | 1.003836 | 0.986252 | 1.029685 | 1.017967 | 1.004811 | 1.006952 |
2020-05-06 | 1.002383 | 0.994246 | 1.009105 | 0.974649 | 0.990054 | 1.029412 | 1.024616 | 0.974889 | 1.068584 | 1.032210 | 0.998311 | 1.012622 |
2020-05-07 | 0.990403 | 1.003452 | 1.048258 | 0.981175 | 0.991679 | 0.985294 | 1.023018 | 0.954437 | 1.100000 | 1.081560 | 1.064120 | 1.028316 |
2020-05-08 | 1.017585 | 1.063291 | 1.111996 | 0.959839 | 1.001148 | 1.014706 | 1.039003 | 0.955573 | 1.110054 | 1.068262 | 1.088846 | 1.038613 |
PL_normalizado.tail()
IBOV | PETR4.SA | VALE3.SA | WEGE3.SA | RADL3.SA | OIBR3.SA | KNRI11.SA | SMAL11.SA | AAPL34.SA | IVVB11.SA | ETH-BRL | PL Total | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||
2021-08-17 | 1.494802 | 1.703360 | 2.704194 | 1.765511 | 1.222011 | 1.500000 | 0.849936 | 1.478241 | 1.981283 | 1.504433 | 13.907748 | 1.921305 |
2021-08-18 | 1.478815 | 1.688236 | 2.613465 | 1.709019 | 1.217199 | 1.485294 | 0.850192 | 1.480173 | 1.976531 | 1.515957 | 14.023588 | 1.907740 |
2021-08-19 | 1.485433 | 1.678783 | 2.464355 | 1.790958 | 1.261461 | 1.500000 | 0.839514 | 1.516873 | 1.992788 | 1.538948 | 15.013985 | 1.943306 |
2021-08-20 | 1.496691 | 1.676263 | 2.465366 | 1.831164 | 1.283111 | 1.529412 | 0.852238 | 1.544256 | 1.996789 | 1.535402 | 15.608033 | 1.968406 |
2021-08-23 | 1.489325 | 1.702730 | 2.431247 | 1.819459 | 1.274932 | 1.691176 | 0.890281 | 1.544143 | 2.018548 | 1.554905 | 15.659331 | 1.980521 |
Plot da nossa carteira vs. o IBOV
PL_normalizado[['IBOV', 'PL Total']].plot(figsize = (10,10));
Podemos observar que nossa carteira teórica, montada pelos ativos descritos anteriomentes e seus respectivos pesos, bate o IBOV (tem um retorno maior). Esse exercício de montar carteiras a partir de um racional, e olhar como ela teria se comportado no passado, se chama backtest. Portanto, pelo nosso backtest, nossa carteira bate o IBOV.
Please, cite this work:
Gomes, Victor (2021), “Comparação de carteira com Ibov usando python published at the “Open Code Community” ”, Mendeley Data, V1, doi: 10.17632/49knfhr5t5.1