The important part here is this part: this.sim[i][j].portfolio.start - this.sim[i][j].spending.
We can see that the spending is deducted from the portfolio start. This happens in the method calcEndPortfolio. If we look at the loop that computes the "cycle," we see that calcEndPortfolio is called aftercalcMarketGains. This is important because calcMarketGainshas already subtracted the spending!
This means that we subtract the spending two times when calculating the fee. This does not affect rebalanced portfolios. Commit f9150072bd629f4 removed subtracting spending for rebalanced portfolios to fix a bug, but it's not clear to me if leaving this in for non-rebalanced portfolios was on oversight or a separate issue (it's been a long time since that commit was added).
An easy way to verify this is the following:
Set constant growth of the portfolio: 0%
Set fees/drag to 0%
Set your portfolio to some amount (I used 625k)
Set withdrawal to some amount (I used 25k)
Put a breakpoint on the line that computes the fee, or console.log the value of this.sim[i][j].portfolio.start
In this situation, I would expect the first cycle to compute fees off of 600k, but it computes it off of 575k.
Because this is computing fees that are too low, non-rebalancing portfolios are producing results that are too optimistic.
This change allows for the calcEndPortfolio function to be written in a simpler way,
something like this (code not tested; just whipped that up quickly), but I did not add that refactoring to this PR to keep it clean.
I believe that the fees calculation for non-balanced portfolios is incorrect.
tl;dr, the fee is too low because the spending is deducted twice from the initial value before the fee is calculated.
This is the code fees calculation for non-rebalanced portfolios (link):
The important part here is this part:
this.sim[i][j].portfolio.start - this.sim[i][j].spending
.We can see that the spending is deducted from the portfolio start. This happens in the method
calcEndPortfolio
. If we look at the loop that computes the "cycle," we see thatcalcEndPortfolio
is called aftercalcMarketGains
. This is important becausecalcMarketGains
has already subtracted the spending!This means that we subtract the spending two times when calculating the fee. This does not affect rebalanced portfolios. Commit f9150072bd629f4 removed subtracting spending for rebalanced portfolios to fix a bug, but it's not clear to me if leaving this in for non-rebalanced portfolios was on oversight or a separate issue (it's been a long time since that commit was added).
An easy way to verify this is the following:
this.sim[i][j].portfolio.start
In this situation, I would expect the first cycle to compute fees off of 600k, but it computes it off of 575k.
Because this is computing fees that are too low, non-rebalancing portfolios are producing results that are too optimistic.
This change allows for the
calcEndPortfolio
function to be written in a simpler way, something like this (code not tested; just whipped that up quickly), but I did not add that refactoring to this PR to keep it clean.Thanks for reading!