Performance de um portfolio

4 minute read

Introdução

E ai? quanto rendeu seu portfólio? Fácil, $$R_p = V_{final}/V_{inicial} - 1$$ certo? sim, se você investiu em um único aporte. Normalmente, as pessoas fazem vários aportes ao longo do tempo. Então, se você fez um aporte de 1.000,00, e depois fez outro aporte de 1.000,00; o valor final do seu portfólio é 2.000,00. Se usarmos a fórmula acima iremos obter 100% de retorno, isso indica "performance"?

Se em seu aporte, escolhesse outros tipos de ativos, teria o mesmo resultado? Com o retorno acima, não sabemos avaliar a escolha dos ativos. Esse retorno apenas mostra a evolução percentual da carteira em dois períodos. Não tem muita utilidade além de saber a taxa que seu patrimônio aumentou ou diminuiu. Não nos permite avaliar e tomar decisões financeiras, por exemplo, os ativos que escolheu foram adequados ou você precisa alterá-los?

Por sorte, existem outros métodos de avaliar retorno da carteira. Vou discutir um pouco sobre eles.

Métodos para avaliar retorno de um portfolio

Existem dois métodos utilizados para medir retorno de uma carteira. O primeiro é o time weighted rate of return (TWR) e o outro money weighted rate of return MWR.

O TWR mede o retorno entre cada período delimitado pelos aportes. Esse retorno corrige para distorções causada pelo aporte e mede apenas a performance real dos ativos alocados.

O MWR é a taxa interna de retorno TIR ou IRR 1 dos fluxos de caixa. A IRR é a taxa de desconto que leva todos os fluxos de caixa ao valor presente de forma que resultem no valor investido. Então ela mede um retorno igual para todos os aportes de forma a levar o investido ao valor final.

Métodos_para_avaliar_retorno_de_um_portfolio/2020-12-27_21-59-37_screenshot.png

Exemplo

Exemplo/2020-12-27_21-39-32_screenshot.png

Implementação

Preliminares

1import numpy as np
2import pandas as pd
3pd.options.display.float_format = '{:,.2f}'.format
4import matplotlib
5import matplotlib.pyplot as plt
6matplotlib.style.use('ggplot')
7import yahooquery as yf

Input

1trade_data = pd.read_csv('trade_data.csv')
2print(trade_data)
   17/09/2018    Buy  EGIE3  40  36,50
0  12/12/2018  Split  EGIE3  10   0,00
1  15/03/2019   Sell  EGIE3  25  39,00
2  25/03/2020    Buy  EGIE3  15  38,00
3  25/03/2020    Buy  EGIE3  10  37,50
4  27/07/2020    Buy  EGIE3  32  44,70
5  03/10/2018    Buy  ABEV3  28  18,26
6  16/10/2018    Buy  ABEV3  30  17,29
7  07/11/2018    Buy  ABEV3  25  16,80

Processar trades

 1def process_trades(trade_data_file):
 2    trades = pd.read_csv(trade_data_file, sep=',',
 3                         names=['date', 'type',
 4                                'ticker', 'volume',
 5                                'price'],
 6                         decimal=',',
 7                         parse_dates=['date'], infer_datetime_format=True)
 8    trades['total'] = trades.apply(lambda x: x.price * x.volume
 9					    if x.type in ['Buy', 'Split']
10					    else - x.price * x.volume, axis=1)
11    trades['vol_adj'] = trades.apply(lambda x: x.volume
12					    if x.type in ['Buy', 'Split']
13					    else
14					    (-x.volume if x.type in ['Sell'] else 0), axis=1)
15    return trades
16trades = process_trades('trade_data.csv')
17print(trades)
        date   type ticker  volume  price    total  vol_adj
0 2018-09-17    Buy  EGIE3      40  36.50 1,460.00       40
1 2018-12-12  Split  EGIE3      10   0.00     0.00       10
2 2019-03-15   Sell  EGIE3      25  39.00  -975.00      -25
3 2020-03-25    Buy  EGIE3      15  38.00   570.00       15
4 2020-03-25    Buy  EGIE3      10  37.50   375.00       10
5 2020-07-27    Buy  EGIE3      32  44.70 1,430.40       32
6 2018-10-03    Buy  ABEV3      28  18.26   511.28       28
7 2018-10-16    Buy  ABEV3      30  17.29   518.70       30
8 2018-11-07    Buy  ABEV3      25  16.80   420.00       25

Consolidar portfolio

 1def consolidate_portfolio(trades):
 2    portfolio = pd.DataFrame()
 3    portfolio['vol_liq'] = (trades
 4                            .groupby('ticker')['vol_adj']
 5                            .sum()) 
 6    portfolio['avg_price (R$)'] = (trades
 7                              .groupby('ticker')['total']
 8                              .sum() / portfolio.vol_liq)
 9    portfolio = portfolio[portfolio.vol_liq != 0]
10    portfolio['quote (R$)'] = portfolio.apply(lambda x: yf.Ticker(x.name+'.SA').quotes[x.name+'.SA']['bid'], axis=1)
11    portfolio['p/l (%)'] = (portfolio['quote (R$)'] - portfolio['avg_price (R$)']) / portfolio['avg_price (R$)'] * 100
12    portfolio['current_value'] = portfolio['quote (R$)'] * portfolio['vol_liq']
13    portfolio['sector'] = portfolio.apply(lambda x: yf.Ticker(x.name+'.SA').asset_profile[x.name+'.SA']['sector'], axis=1)
14    return portfolio
15portfolio = consolidate_portfolio(trades)
16print(portfolio)
        vol_liq  avg_price (R$)  quote (R$)  p/l (%)  current_value  \
ticker                                                                
ABEV3        83           17.47       15.79    -9.61       1,310.57   
EGIE3        82           34.88       44.71    28.17       3,666.22   

                    sector  
ticker                      
ABEV3   Consumer Defensive  
EGIE3            Utilities  

Retorno do portfolio

Para saber o valor total do portfolio na data anterior ao fluxo de caixa, precisamos saber:

  1. posição líquida antes do fluxo de caixa
  2. cotação de fechamento do dia anterior
 1def consolidate_partial_portfolio(trades, date):
 2    portfolio = pd.DataFrame()
 3    portfolio['vol_liq'] = (trades[trades.date < date]
 4                            .groupby('ticker')['vol_adj']
 5                            .sum()) 
 6    portfolio = portfolio[portfolio.vol_liq != 0]
 7
 8    def get_quote(row):
 9        quote = yf.Ticker(row.name+'.SA').history(
10            start=date + pd.DateOffset(-25), end=date)['close'].values
11        return quote[-1]
12
13    portfolio['quote'] = portfolio.apply(get_quote, axis=1)
14    portfolio['total'] = portfolio.vol_liq * portfolio.quote
15    return portfolio
16
17def process_returns(trades):
18    r = []
19    for (row, cf) in trades.iterrows():
20        partial_portfolio = consolidate_partial_portfolio(trades, cf.date)
21        # initial investment
22        if partial_portfolio.total.sum() == 0:
23            r.append({'date': cf.date,
24                    'ending_value': cf.total,
25                    'cf_value': 0})
26        else:
27            r.append({'date': cf.date,
28                    'ending_value': partial_portfolio.total.sum(),
29                    'cf_value': cf.total})
30        print(cf.date, partial_portfolio.total.sum())
31
32    returns = pd.DataFrame(r)
33    returns = returns.sort_values('date')
34    returns = returns.groupby(['date', 'ending_value'], as_index=False)['cf_value'].sum()
35    def hold_period_return(row):
36        index = returns.index.get_loc(row.name)
37        if index == 0:
38            return 0
39        prev_row = returns.iloc[index - 1]
40        return row.ending_value / (prev_row.ending_value + prev_row.cf_value)
41    returns['hpr'] = returns.apply(hold_period_return, axis=1)
42    return returns
1rr = pd.read_csv('returns.csv', parse_dates=['date'])
2print(rr)
3print(rr['hpr'].apply(lambda x: x + 1).prod())
        date  ending_value  cf_value   hpr
0 2018-09-17      1,460.00      0.00  0.00
1 2018-10-03      1,152.64    511.28 -0.21
2 2018-10-16      1,623.80    518.70 -0.02
3 2018-11-07      2,277.12    420.00  0.06
4 2018-12-12      2,722.89      0.00  0.01
5 2019-03-15      3,528.78   -975.00  0.30
6 2020-03-25      1,881.32    570.00 -0.26
7 2020-03-25      1,881.32    375.00 -0.23
8 2020-07-27      3,448.69  1,430.40  0.53
0.9258180510082121
2018-09-17 00:00:00
   Unnamed: 0       date  ending_value  cf_value   hpr
0           0 2018-09-17      1,460.00      0.00  0.00
1           6 2018-10-03      1,152.64    511.28 -0.21
2           7 2018-10-16      1,623.80    518.70 -0.02
3           8 2018-11-07      2,277.12    420.00  0.06
4           1 2018-12-12      2,722.89      0.00  0.01
5           2 2019-03-15      3,528.78   -975.00  0.30
6           3 2020-03-25      1,881.32    570.00 -0.26
7           4 2020-03-25      1,881.32    375.00 -0.23
8           5 2020-07-27      3,448.69  1,430.40  0.53
0.9258180510082121

Resultados

Footnotes


1

Internal rate of return


See Also

comments powered by Disqus