Well I’ve gotten a bunch done this week, but unfortunately I don’t have much in the way of results to show for it.
This week I’ve focused a few different things:
- A correction to the tax calculation of long term cap gains – which fortunately did not significantly affect any results I’ve published previously
- Extending the traditional withdrawal method to allow it to go down to $0, as part of the upcoming stress testing analysis
- A major refactor of the Tax and Penalty Minimization (TPM) method code
- Starting the process of extending the TPM method to go down to zero, as part of the upcoming stress testing analysis
Tax Calculation Correction
For the tax calculation correction, I discovered that I wasn’t properly filling the LT cap gain brackets with standard income first, before then calculating the taxes on the LT cap gains.
Fortunately there was no impact on the TPM method because it always shoots for the standard income to match the standard deduction, and so it was not filling the LT cap gain brackets at all.
And the impact on the traditional method was pretty minor. Here’s a plot of the traditional method with the previous “Bill and Barbara” example scenario before the tax calculation correction, using 2022 tax rates:
And here’s the same scenario with the tax calculation correction:
So you can see that the final total is about $61K (0.3%) lower, due to paying $30K (2.4%) more in taxes over the 52 years. Not a terribly huge impact fortunately. Though interestingly, it makes the TPM method even better than the traditional method, since the traditional method results are slightly worse and the TPM method is unaffected.
I also checked the LT cap gain tax calculation against a reputable online LT cap gain tax calculator, for a variety of scenarios, and my results are consistent. Something I should have done previously – I only tested against federal standard income tax calculators previously.
In general you have to accept that some non-zero number of bugs will exist in software you put out into the world, as any software engineer knows. Otherwise you’d never ship anything. But it still hurts to find bugs like this, even if they don’t have much impact.
Extending the Traditional Method To $0
As part of my big next effort to stress test the TPM method, I also needed to extend the Traditional method to be able to go down to $0 so that I can properly compare the methods for the most strenuous scenarios (e.g., when expenses are so high that you run out of money).
Fortunately it was pretty easy for the traditional method – again, the main benefit of the traditional method is that it’s simpler, which is definitely a substantial benefit for many folks.
I haven’t done the extensive analysis and plots that I want to do yet, but I did run a few relevant scenarios to test out the new capability. Starting from the same scenario shown in the previous section, if you increase annual expenses from $40K to $70K (again, always staying in 2022 dollars, so nominal expense total will increase with inflation), the assets vs time plot is:
You can see how the PostTax balance goes to zero first, then the 457b balance, then the Roth balance, all by the time the sim hits 55. At that point, the PreTax account is all that’s left (matching the total balance) and stays pretty flat (indicating returns are roughly matching expenses, which makes sense with $70K in expenses and a 7% ROI on approximately $1M in assets) until social security starts at age 67 and expenses drop at age 66 (house paid off) and thus total assets starts to climb quickly. You can also see the impact of Required Minimum Distributions (RMDs) when the sim hits age 72 and the pretax balance starts to drop away from the total, as it’s forced to move assets from the pretax account to the PostTax account. In the end though, assets still exceed $4M in 2022 dollars by the end of the sim – not bad at all!
Since increasing expenses by 75% wasn’t enough to run out of money, let’s increase by 100% to $80K/year:
Alrighty, we’ve officially run out of money! So it took doubling annual expenses from $40K to $80K to run out of money in the 52 years simulated, assuming average historical after-inflation returns of 7%). The same pattern holds as well: first PostTax runs out, then 457b, then Roth, then PreTax tracks the total amount until it also runs out at age 75. Which is only one year shy of the average age of death in the United States in 2021.
I plan to provide a lot more analysis results in a future post, hopefully next week.
Refactoring the Tax and Penalty Minimization (TPM) method code
After I finished updating the Traditional method, I started to look at the TPM method code. And I pretty quickly realized that I needed to do a major refactor of that code, as it had grown unwieldy and a number of methods were WAY too long, with WAY too many input and output arguments. Whenever that happens in any project I’m working on, I try to break down long methods into multiple shorter methods, and I try to put more of the variables and data into cleanly defined Python dictionaries.
So I did just that for the TPM method, and now it’s a great deal easier to read, understand, and work with the code. I’ll be updating the code in the github repo when I finish the stress testing analysis (again, hopefully next week, depending on how it goes).
Extending the TPM method to go down to $0
Now that the TPM code is in much better shape, I’ve started to work on extending the TPM method to handle a scenario where you completely run out of money in your (very nice and long) lifetime. I strongly suspect the TPM method will outperform the traditional method in terms of how long your money will last in the same scenario, but I’m very curious to see how much better.
As I mentioned in my previous post, extending the TPM method to go down to $0 is WAY harder than extending the Traditional method.
The TPM method targets a particular income instead of amount of cash, as it assumes it will generate enough cash to cover expenses or taxes due on that income with sources that don’t generate any taxes or penalties (e.g. Roth, bank account, etc.). But in a stress test, those sources will be fully depleted.
So I have to expand its capabilities to withdraw from sources that do generate taxes and penalties. But guess what? If I’m out of tax- and penalty-free sources to pay those taxes and penalties, then I need to withdraw even more money to pay those taxes and penalties, which will generate more taxes and penalties…. You can see where this is going. So I need to build an iteration capability like I’ve done with the Traditional method, to converge on the amount of money that must be pulled from sources that do generate taxes and penalties, such that there’s enough money to pay for expenses AND any taxes or penalties incurred.
That iteration capability I don’t think will be too tricky, especially since I’ve already done it for the Traditional method. What DOES seem particularly tricky is how I’m going to specify the order of accounts to pull from, and the amount to pull from each, such that it starts with the lowest tax+penalty rate and finishes with the highest tax+penalty rate. Especially if the user has specified maximum standard income above the standard deduction and/or the total income above the 0% LT cap gains bracket, which means there will already be non-zero taxes happening in the sim. And it’ll be even trickier if one person in a couple is over 60 (and thus no longer has to worry about penalties) and one person is under 60 (and still has to worry about penalties).
The final major tricky challenge is how to deal with social security income, which the Social Security Administration refers to as retirement insurance benefits (RIB), on the path to $0. Unfortunately the taxable amount of your RIB is a function of your RIB AND your other income – which means if you pull more from your pretax accounts or generated more capital gains from selling PostTax lots for greater expense levels, then your taxable RIB also may go up, which increases your taxes further, etc. I do not yet know how I’m going to tackle this, but I’m pretty sure it’s going to involve some kind of iteration and numerical convergence scheme – going to be tough I suspect.
Alrighty, that’s all for the update. Still lots of work to do before I can even start the stress testing analysis, but hopefully I’ll have some kind of results next week.