A few years ago, I was spending 2-3 hours every quarter manually rebalancing my portfolio across multiple accounts (401k, Roth IRA, taxable brokerage, rental property REIT allocation). I’d open each provider’s website, export balances to a spreadsheet, calculate asset class percentages, and try to figure out which trades would get me back to my 60/40 target without triggering unnecessary capital gains.
It was tedious, error-prone, and honestly not something I looked forward to. Every quarter I’d tell myself “there has to be a better way.”
Then I discovered Beancount. And then I discovered Python. And then I thought: “Wait… I can automate this, can’t I?”
The Journey to Automated Rebalancing
I want to share what I’ve learned building a portfolio rebalancing automation system with Beancount, because I see a lot of folks—especially those pursuing FIRE—struggling with the same quarterly ritual I used to dread.
Why Commercial Tools Weren’t Enough
Tools like Empower (formerly Personal Capital) and Copilot offer automatic rebalancing analysis with beautiful dashboards. But they have fundamental problems for Beancount users:
- No integration with Beancount - They want you to link accounts through Plaid, but can’t read your meticulously tracked Beancount transaction history
- Black-box calculations - You see outputs but can’t audit the raw data or understand exactly how they calculated drift
- Limited tax optimization - They don’t know which accounts are tax-advantaged vs taxable, so recommendations aren’t tax-aware
- No historical decisions - You can’t version control your rebalancing strategy or see how your target allocation evolved over time
For someone who values Beancount’s precision and auditability, trusting a proprietary tool felt like a step backward.
The Beancount Foundation
I found two excellent starting points on GitHub:
beancount_portfolio_allocation- Reports current portfolio allocations, useful for risk analysis and rebalancingbeancount_asset_allocation- Analyzes asset allocation by account using metadata
These tools calculate current allocations from Beancount files, which is great! But they don’t generate rebalancing recommendations, don’t consider tax implications, and don’t optimize across multiple account types.
So I built my own script that extends these ideas.
What I Built: A Tax-Aware Rebalancing Script
My script does four things:
1. Calculates Current Allocations by Asset Class
Using Beancount’s query language, it aggregates positions across all accounts and groups by asset class metadata:
Assets:Investments:Vanguard:VTSAX
asset_class: "US_Stocks"
Assets:Investments:Fidelity:VBTLX
asset_class: "US_Bonds"
The query sums up all US_Stocks, US_Bonds, International_Stocks, etc., and calculates percentages.
2. Compares Against Target Allocations
I keep my target portfolio in a YAML config file:
target_allocation:
US_Stocks: 48%
International_Stocks: 12%
US_Bonds: 35%
International_Bonds: 5%
This lives in version control, so I can track how my risk tolerance changes over time (I was 80/20 stocks/bonds in my 30s, now 60/40 at 42).
3. Generates Tax-Aware Rebalancing Recommendations
This is where it gets interesting. The script:
- Prioritizes tax-advantaged accounts (401k, IRA) for rebalancing—no capital gains to worry about
- Identifies tax-loss harvesting opportunities in taxable accounts—flag losses that could offset gains
- Considers transaction costs - Only recommends rebalancing if drift exceeds 5% (configurable threshold)
- Outputs specific trades like “Sell $2,500 of VTSAX in Fidelity 401k, buy $2,500 of VBTLX”
4. Tracks Decisions Over Time
Every rebalancing run is logged with a timestamp. I can see: “On 2024-03-15, portfolio was 67% stocks / 33% bonds, rebalanced back to 60/40 target.”
This historical record helps me understand if I’m rebalancing too often (wasting transaction costs) or not often enough (letting drift get out of hand).
Lessons Learned (So You Don’t Make My Mistakes)
Start simple. My first version just calculated drift—didn’t generate recommendations. I ran it for 3 months alongside my manual spreadsheet to verify accuracy. Don’t try to automate everything on day one.
Metadata is your friend. Tagging each investment with asset_class, tax_treatment (taxable vs tax-deferred), and expense_ratio makes queries incredibly powerful.
Tax-loss harvesting is complex. The wash-sale rule (can’t buy “substantially identical” security within 30 days before or after selling) is hard to automate safely. My script flags opportunities for manual review, but I approve before executing.
Drift tolerance matters. I use 5% drift as my rebalancing threshold. Lower thresholds mean more frequent rebalancing (higher transaction costs). Higher thresholds mean more risk drift. Find what works for your situation.
Version control your strategy. Storing target allocations in a config file (not hardcoded in scripts) means you can track how your investment philosophy evolves. It’s fascinating to look back and see how risk tolerance changes.
Questions for the Community
I’m curious how others are handling portfolio rebalancing with Beancount:
-
Are you automating rebalancing calculations, or still doing it manually? If manual, what’s your process?
-
What drift tolerance do you use? 3%? 5%? 10%? How did you choose that number?
-
For FIRE folks: do you rebalance more with contributions or by selling? Using new money to rebalance avoids transaction costs.
-
Has anyone automated tax-loss harvesting detection? I’d love to compare approaches to handling the wash-sale rule.
My script is open source on GitHub (I’ll share the link once I clean up the README). It’s not perfect, but it’s reduced my quarterly rebalancing from 2+ hours to about 15 minutes of reviewing recommendations.
For those tracking detailed portfolios in Beancount: what’s your biggest rebalancing pain point?