IBOV vs CDI: which one is Brazil's best passive investment strategy?
TL;DR: for almost all investment window sizes, with or without taxation, investing in a IBOV tracking security or fund performs, on average and in most of the times, better than investing on Brazil’s CDI tracking government bonds (Tesouro Direto  LFT)
Edit: after your feedback, this post was massively edited to improve the visualizations and to further explain the techniques used
One of these days I overheard one of my coworkers mentioning a Twitter debate in which, from what I understood, one person was defending that the best passive investment strategy was investing in Brazil’s fixed income bonds (which yield’s the Brazil’s CDI fixed income rate), while the other person defended that investing in Brazil’s main stock market index (IBOV) (or in some IBOV index fund) would yield a better result.
That got me curious so I started writing some scripts to be able to give a quantitative perspective to this debate.
The question that I tried to answer with my research was: Which investment was more profitable on average for a given investment window?
To accomplish this task I wrote some code that calculated the return for each index^{1} for all possible window sizes. I used the data starting from 19950101 to eliminate pre plano real hyperinflation effects.
Windowing
So what is windowing anyway? Let’s say that a given security has the following daily returns:
>>> returns = [0.987, 1.01, 1.003, 1.013, 1.12, 0.98, 0.81]
This means that the value of the security in the day 1 is 1.01 times the value of this security on the day 0.
where is the security’s value in the th day and is the security’s return (as the ratio) on the th day.
In our example we have 7 days of returns. If we want to know the total (cumulative) return of this security during the whole period we only need to multiply all daily returns
>>> import numpy as np
>>> np.prod(returns) # equivalent to returns[0] * returns[1] * ...
0.9004881914524542
Now let’s imagine that on the 3th day we decided to sell the security. In that case the total return of our investment will be
>>> np.prod(returns[:3])
0.9998606099999999
That’s better. But what if instead of investing on day 0 and selling on the 3th day we invest on the first day and sell on the 4th?
>>> np.prod(returns[1:4])
1.0261993899999997
That’s much better. In this case we still invested for 3 days but instead of starting in the day 0 we’ve started on day 1. We say that in both cases our investment window was 3 days long.
Let’s continue our experiment by analyzing this security’s return for each 3day window size. As we have 7 days worth of returns we can calculate the return for the following 3day windows:
 Start at 0, finish at 2
 Start at 1, finish at 3
 Start at 2, finish at 4
 Start at 3, finish at 5
 Start at 4, finish at 6
 Start at 5, finish at 7
This can be accomplished with the following code:
>>> for start_index in range(len(returns)  2):
... end_index = start_index + 3
... text = f'Starting at {start_index}, stopping at {end_index  1}'
... r = np.prod(returns[start_index:start_index + 3])
... print(f'{text}: {r}')
...
Starting at 0, stopping at 2: 0.9998606099999999
Starting at 1, stopping at 3: 1.0261993899999997
Starting at 2, stopping at 4: 1.1379636799999997
Starting at 3, stopping at 5: 1.1118688
Starting at 4, stopping at 6: 0.8890560000000002
We can also estimate what the returns would be for each window size:
>>> for window_size in range(1, len(returns) + 1):
... for start_index in range(len(returns)  (window_size  1)):
... end_index = start_index + window_size
... text = f'Window size: {window_size}, starting at {start_index},' \
... f' stopping at {end_index  1}.'
... r = np.prod(returns[start_index:start_index + 3])
... print(f'{text}: {r}')
...
Window size: 1, starting at 0, stopping at 0.: 0.9998606099999999
Window size: 1, starting at 1, stopping at 1.: 1.0261993899999997
Window size: 1, starting at 2, stopping at 2.: 1.1379636799999997
Window size: 1, starting at 3, stopping at 3.: 1.1118688
Window size: 1, starting at 4, stopping at 4.: 0.8890560000000002
Window size: 1, starting at 5, stopping at 5.: 0.7938000000000001
Window size: 1, starting at 6, stopping at 6.: 0.81
Window size: 2, starting at 0, stopping at 1.: 0.9998606099999999
Window size: 2, starting at 1, stopping at 2.: 1.0261993899999997
Window size: 2, starting at 2, stopping at 3.: 1.1379636799999997
# ...
Window size: 4, starting at 2, stopping at 5.: 1.1379636799999997
Window size: 4, starting at 3, stopping at 6.: 1.1118688
Window size: 5, starting at 0, stopping at 4.: 0.9998606099999999
Window size: 5, starting at 1, stopping at 5.: 1.0261993899999997
Window size: 5, starting at 2, stopping at 6.: 1.1379636799999997
Window size: 6, starting at 0, stopping at 5.: 0.9998606099999999
Window size: 6, starting at 1, stopping at 6.: 1.0261993899999997
Window size: 7, starting at 0, stopping at 6.: 0.9998606099999999
You’ve just witnessed exactly what I’m doing with the CDI’s and IBOV’s returns: I’ve calculated the return for each window size for every possible staring day (notice that the number of possible windows in the period decrease with the increase of the window size).
In all of this post’s graphs the horizontal axis represents a window size (usually in years) and the vertical axis the total (cumulative) return.
The data
Some data was scrapped and download, and some data was generated from the original data. All used data is available here.
Data source
 CDI data: Calculadora do Cidadão  Banco Central do Brasil
 IBOV data: Comdinheiro
The results
Let’s start by taking a look at the quartile distribution of the CDI and IBOV indices:
As we can see in the figures above, as expected the IBOV returns’ are much more positively skewed than the CDI’s returns for almost all investment windows, which is a direct consequence of the higher IBOV volatility.
Now, even though it gives us no further knowledge about the data, let’s plot ALL IBOV’s and CDI’s percentiles for all windows (get ready for some cool graphs):
The graphs above are showing all return percentiles (from 0 to 100), transitioning from 0 = red
to 100 = green
.
If we do a semilog plot of both graphs (in order to reduce the effect the scale of bigger windows), we get the following:
Quick refresher:
Taking a look at the after taxes^{2} percentiles:
Now that we have a good idea of the distribution of returns for each window size for each index let’s compare them. Let’s first start by comparing their averages:
This graph shows us that, for almost all window sizes, both on average^{3} (the difference between the average window returns is positive) and in most of the times^{4} (the difference between the median window returns is positive) it was better to invest in an IBOV indexed security than in a CDI indexed one.
Let’s now take a look on the difference between all window quantiles, both pre and post taxes:
Looking at this graph we get the strong impression that, almost always, IBOV is a better passive investment than CDI, and you would be . . . right!
Take a look at the graphs bellow:
The line in the graphs above represent, for each window size, the proportion of windows in which the IBOV’s return was greater thant that of the CDI’s.
A simple interpretation of the graphs above is the following: imagine that we go back in the past and pick, at random, a day to start investing both on CDI and IBOV indexed securities. The line represents, for each window size, the probability that the IBOV indexed security would perform better than the CDI indexed security.
I drew a line in the middle of the graphs so we can see the window sizes for which a IBOV indexed security would probably outperform a CDI indexed security.
Conclusion
So, that’s it! If you believe that past returns are a good indicative of future returns and you want to pick a passive strategy, go out and buy some BOVA11.
It’s also quite interesting to see that for investment windows between 11 and 14 years it was better to have invested in CDI than in IBOV.
My impression
I have to admit that I’m pretty impressed. Brazil’s notorious for its historically high government bond interest rates so I always believed that CDI’s indexed securities would beat Brazil’s main stock market, specially in big investment windows. It’s always good to know when you’re wrong.

For the IBOV’s index I used it’s corrected value. This is important because this way we take into account corporate actions such as dividends. ↩

For taxation purposes, I used the Tesouro Direto’s taxation table for the CDI rate and the FIA’s tax for the IBOV index. ↩

I am aware that to reach this conclusion in the right way I should had run a Difference in Means Hipothesis Test, but this post was intended to be just a superficial analysis. If enough people ask for it and I find the time, I can do a more in depth analysis of the data. ↩

When I say most of the times I’m trying to say that if you were to pick a window of any size starting at any possible date. ↩