Tracking Betterment/Wealthfront portfolios in Beancount - automation strategies?

I use Betterment for my taxable brokerage and Wealthfront for my Roth IRA. Trying to track both in Beancount and running into challenges. Looking for advice on automation strategies.

Why Robo-Advisors + Beancount?

The robo-advisor market is exploding - expected to hit $14.29B in 2025 and $54.73B by 2030. I use them because:

  • Automatic rebalancing (I’m lazy)
  • Tax-loss harvesting in taxable account
  • Low fees (0.25% at Betterment)

But I want Beancount for:

  • Consolidated view across all accounts
  • Custom queries and analysis
  • Long-term archival
  • Net worth tracking with real estate, crypto, etc.

Current Challenges

1. Transaction Volume

Robo-advisors rebalance frequently. My Betterment account had 47 transactions last month - mostly small rebalancing trades. Manually importing these would be insane.

2. Tax-Loss Harvesting Complexity

Betterment swaps between similar ETFs (e.g., VTI ↔ SCHB) to harvest losses. This creates:

  • Wash sale tracking nightmares
  • Cost basis that differs from what Beancount calculates
  • Lots that I need to track but didn’t explicitly create

3. No Good API

Neither Betterment nor Wealthfront has a public API. I’m stuck with:

  • Manual CSV downloads
  • Screen scraping (fragile)
  • Plaid (expensive for personal use)

What I’ve Tried

OFX Downloads: Betterment supports OFX but the data is incomplete - missing cost basis info.

CSV + Custom Importer: Works but requires manual download and doesn’t handle the tax lot complexity well.

Questions

  1. Has anyone automated Betterment/Wealthfront imports? What’s your stack?

  2. How do you handle the cost basis discrepancy between robo-advisor’s records and Beancount’s FIFO/LIFO calculations?

  3. Is there a plugin for tracking tax-loss harvesting swaps properly?

  4. Should I just trust the robo-advisor’s tax docs and only track at the account level (not individual lots)?

Appreciate any guidance from folks who’ve solved this.

Hot take: the complexity you’re describing is a sign you should ditch the robo-advisors entirely.

The Case for Manual Three-Fund Portfolio

I track a simple three-fund portfolio in Beancount:

  • VTI (US Total Market)
  • VXUS (International)
  • BND (Bonds)

Rebalancing: Once per year, maybe 6 transactions total. Takes 30 minutes.

Tax-loss harvesting: I do it manually when markets drop significantly. Maybe 2-3 times per year. I control which lots to sell (specific identification), so Beancount’s tracking is always accurate.

Fees: Vanguard charges nothing. Betterment’s 0.25% on $100K = $250/year. Over 30 years with 7% returns, that’s ~$20K in lost gains.

Why This Works Better

  1. Simplicity - 6 transactions/year vs 47/month
  2. Control - I know exactly what I own and why
  3. Tax efficiency - I choose when to harvest, not an algorithm
  4. Beancount compatibility - Trivial to track

The whole point of robo-advisors is “set and forget.” But if you’re already tracking in Beancount, you’re not forgetting - you’re adding complexity for marginal benefit.

Just my 2 cents. The robo-advisor market growth you cited is mostly from people who don’t track their finances at all. We’re a different audience.

I’ve dealt with this exact problem. Here’s what worked for me:

The Cost Basis Problem

You’re right that Beancount’s calculated cost basis will diverge from Betterment’s. This happens because:

  • Betterment uses specific lot identification for tax optimization
  • Beancount defaults to FIFO
  • Wash sale adjustments aren’t automatic in Beancount

My Solution: beancount-asset-transfer Plugin

The beancount-asset-transfer plugin is designed for exactly this. It generates in-kind transfer entries between accounts while preserving the original cost basis.

Use case: When Betterment swaps VTI → SCHB for tax-loss harvesting:

2024-03-15 * "Tax-loss harvest swap"
  Assets:Betterment:VTI  -100 VTI {45.00 USD} @ 42.00 USD
  Assets:Betterment:SCHB  100 SCHB {45.00 USD}
  Income:Capital:Losses  300.00 USD

The SCHB inherits VTI’s cost basis, which is what happens for tax purposes.

For Wash Sales

You need to manually adjust cost basis when wash sales occur. I add metadata:

2024-03-20 * "Buy SCHB" ^wash-sale-adj
  Assets:Betterment:SCHB  50 SCHB {48.50 USD}
    wash_sale_adjustment: 3.00 USD

Then I have a custom query that adds these adjustments to cost basis.

My Recommendation

For your question #4: Don’t track at account level only. The whole point of Beancount for investments is accurate cost basis for tax planning. If you give that up, you might as well use a spreadsheet.

Yes, it’s work. But you only need to reconcile with Betterment’s 1099 once per year. The monthly tracking is just data entry.

I use Schwab Intelligent Portfolios (it’s free - no management fee) and track everything in Beancount. Here’s my workflow:

Why Schwab

  • No advisory fee (Betterment’s 0.25% adds up)
  • Still get automatic rebalancing and TLH
  • Good OFX support
  • Can call a human if needed

Trade-off: They keep ~6% in cash (that’s how they make money). I’m fine with that for the convenience.

My Import Workflow

Monthly Process (~20 min)

  1. Download OFX from Schwab
  2. Run importer using beancount-reds-importers - I customized the Schwab module
  3. Review and adjust - The importer handles 90% correctly, I fix edge cases
  4. Reconcile with Schwab’s month-end statement

Code Snippet

# schwab_importer.py
from beancount_reds_importers import schwab

class SchwabIntelligent(schwab.Importer):
    def categorize_transaction(self, row):
        if 'REBALANCE' in row['description']:
            return 'rebalance'
        if 'TAX LOSS' in row['description']:
            return 'tlh_swap'
        return super().categorize_transaction(row)

On the Cost Basis Question

I gave up on matching Schwab’s cost basis exactly. Instead:

  1. I use Beancount’s cost basis for planning (estimated tax impact)
  2. I use Schwab’s 1099-B for filing (actual tax basis)

The discrepancy is usually small (<5%) and I’d rather have slightly imprecise estimates than spend hours reconciling lot-by-lot.

For Betterment/Wealthfront

Your best bet might be Plaid even though it’s not free. The plaid-to-beancount project on GitHub pulls transactions automatically. Costs ~$500/year for personal use, but saves hours of manual work.

Thanks everyone - this is exactly the kind of practical advice I needed.

@diy_investor - Point Taken

You’re not wrong about the irony. I chose robo-advisors for simplicity but now I’m spending more time wrestling with imports than I would just doing manual rebalancing.

The fee math is sobering too. $250/year × 30 years compounded… yeah, that’s a new car.

I think the real value prop was behavioral: I started with robo-advisors when I didn’t trust myself not to panic-sell. Now that I’ve been through a few market cycles, maybe I’m ready for the three-fund approach. Something to think about.

@tax_optimizer - Exactly What I Needed

The beancount-asset-transfer plugin is the missing piece! I didn’t know it preserved cost basis on swaps. That solves my tax-loss harvesting tracking problem.

Your wash sale metadata approach is clever. I’ll implement something similar:

2024-03-20 * "SCHB purchase" #wash-sale
  Assets:Betterment:SCHB  50 SCHB {48.50 USD}
    wash_adjustment: 3.00 USD
    original_lot: "VTI-2024-01-15"

And you’ve convinced me not to go account-level only. The whole point is accurate tax planning.

@hybrid_inv - Schwab Is Interesting

I hadn’t considered Schwab Intelligent Portfolios. No fee + good OFX is appealing. The 6% cash drag is annoying, but probably less than Betterment’s 0.25% over time.

Your two-tier approach makes sense:

  • Beancount for planning (good enough estimates)
  • 1099-B for filing (actual basis)

I was trying to match exactly, which is probably overkill.

My Plan

  1. Short term: Implement beancount-asset-transfer for TLH swaps, stop trying to match cost basis exactly
  2. Medium term: Evaluate moving Wealthfront IRA to Schwab for better OFX
  3. Long term: Consider moving taxable to three-fund manual management

Thanks again - this community is invaluable.