Tax season is around the corner, and I’ve been diving deep into tax-loss harvesting strategies. But here’s the thing that keeps me up at night: wash sale violations. They’re like hidden landmines in your investment portfolio, and if you’re not careful, they can blow up your tax-saving strategies.
The 61-Day Window of Doom
Most people think it’s just a “30-day rule,” but the reality is more complex. The IRS wash sale rule creates a 61-day window around every sale:
- 30 days BEFORE the sale
- The day of the sale itself
- 30 days AFTER the sale
If you sell a security at a loss and purchase a “substantially identical” security anywhere within that 61-day window, the IRS disallows your loss deduction. And here’s the kicker: it applies across ALL your accounts — your Fidelity brokerage, your Vanguard IRA, your spouse’s 401(k), everything.
The Brokerage Reporting Gap
Here’s what I learned the hard way: brokers only track wash sales within their own accounts.
Last year, I sold VTI (Vanguard Total Stock Market ETF) at a $3,200 loss in my Fidelity taxable account. Smart tax move, right? Wrong. Two weeks later, my automated investment plan at Vanguard bought VTSAX (Vanguard Total Stock Market Index Fund) — which the IRS considers “substantially identical” to VTI.
My Fidelity 1099-B looked clean. My Vanguard 1099-B looked clean. But when I prepared my taxes, I realized I had triggered a wash sale that neither broker flagged. I had to manually disallow the loss on Form 8949 and adjust my cost basis. Painful lesson.
Why This Matters for Beancount Users
This is where Beancount can be a game-changer — IF we use it correctly. We have the power to track every transaction across every account with precise metadata. We can run queries that span the entire 61-day window. We can catch wash sales BEFORE they happen, not after.
But I’m still figuring out the best approach. Here’s what I’m struggling with:
My Current Challenge
I have:
- 3 taxable brokerage accounts (Fidelity, Vanguard, Schwab)
- 2 IRAs (Fidelity Roth, Vanguard Traditional)
- My spouse has 2 accounts (401k and IRA)
When I want to harvest a loss, I need to check:
- Did I buy this security (or something “substantially identical”) in the past 30 days in ANY account?
- Do I have any scheduled purchases (auto-invest, DRIPs, 401k contributions) in the next 30 days?
- Did my spouse buy anything similar?
Right now, I’m doing this manually with spreadsheets and it’s error-prone.
What I Want to Build
I’m envisioning a Beancount-based system where I can:
- Run a pre-trade query that answers: “Is it safe to sell security X at a loss today?”
- Get warnings about potential wash sales before executing the trade
- Track cost basis by lot for every position across all accounts
- Maintain a mapping of “substantially identical” securities (VTI ↔ VTSAX, SPY ↔ VOO, etc.)
My Questions for the Community
I need your collective wisdom:
Account Structure: How should I structure my Beancount accounts to track multiple brokers and account types (taxable vs. IRA)?
Assets:Investments:Fidelity:Taxable:VTI
Assets:Investments:Fidelity:Roth:VTI
Is this granular enough?
Metadata Strategy: What metadata should I attach to each stock transaction?
ticker: "VTI"
cusip: "922908769"
lot_date: 2024-03-15
cost_basis_per_share: 185.50
account_type: "taxable"
What am I missing?
Query Approach: Has anyone written a BQL query to detect potential wash sales across a 61-day window? How do you handle the lookback AND look-forward?
Substantially Identical Definition: The IRS is vague about what counts as “substantially identical.” Obviously, same ticker = identical. But what about:
- VTI (ETF) vs VTSAX (mutual fund) — both Vanguard Total Market
- SPY vs VOO vs IVV — all S&P 500 index funds
- Different share classes of the same fund
How are you tracking these relationships in Beancount?
IRA Coordination: How do you make sure you don’t accidentally trigger a wash sale between taxable and IRA accounts? (Especially important since IRA wash sales are PERMANENTLY disallowed, not just deferred!)
Why I’m Obsessed With This
I’m on a FIRE (Financial Independence, Retire Early) path, and tax optimization is a significant lever. Tax-loss harvesting can save thousands per year, but only if done correctly. One wash sale violation can wipe out months of careful planning.
I believe Beancount’s plain-text, query-able, version-controlled approach is perfect for this problem. We just need to develop the right conventions and tooling.
Has anyone built something like this? What’s working for you? What pitfalls have you discovered?
Let’s build a community knowledge base around tax-loss harvesting best practices with Beancount. Share your experiences, your code, your mistakes — let’s learn together.
Disclaimer: I’m not a tax professional. This is my personal experience and learning journey. Consult a CPA or tax advisor for your specific situation.