Multi-currency investments and Section 988 gains

108 views
Skip to first unread message

SomeCallMeTim

unread,
Mar 11, 2026, 6:29:34 AMMar 11
to Beancount

I’ve been working on a pattern to track:

* EUR cash lots with USD basis (for U.S. section 988-style FX gain/loss)
* A stock traded in EUR, with cost basis in EUR (not USD)
* Capital gains in both EUR and USD for tax reporting
* FX gain only when EUR is actually disposed (when a stock is bought with EUR, or when a EUR to USD conversion occurs)

I’d really appreciate feedback on whether this is idiomatic Beancount and if there are cleaner ways to express the same economics.

Below is a complete, runnable example with prices/rates chosen to keep the math simple.  I’d love any feedback on more elegant patterns, potential pitfalls, or ways to simplify this while still keeping explicit EUR lots, EUR-based stock cost, and U.S. tax reporting needs (section 988-style FX plus capital gains in both currencies).

option "operating_currency" "USD"

1970-01-01 open Assets:US:Checking
1970-01-01 open Assets:EU:Checking
1970-01-01 open Assets:IBKR:BVME:IMBL
  name: "Internazionale Imobiliare - Milan Exchange"
1970-01-01 open Income:US:FX:Sec988
1970-01-01 open Income:CapGains:USD
1970-01-01 open Income:CapGains:EUR
1970-01-01 open Equity:Tax:CapGains:Bridge
1970-01-01 open Equity:Opening-Balances

; ----------------------------------------------------------------------
; EUR/USD Price Table
; ----------------------------------------------------------------------

2026-02-01 price EUR 1.20 USD
2026-03-01 price EUR 1.15 USD
2026-04-01 price EUR 1.25 USD
2026-05-01 price EUR 1.30 USD
2026-06-01 price EUR 1.40 USD

; ----------------------------------------------------------------------
; Initial funding in USD
; ----------------------------------------------------------------------

2026-01-01 * "Initial funding of US Checking"
  Assets:US:Checking              5000.00 USD
  Equity:Opening-Balances        -5000.00 USD

; ----------------------------------------------------------------------
; Buy EUR in two lots (these EUR lots later fund the IMBL buy)
;   Lot 1: 500 EUR for 600 USD -> 1.20 USD/EUR
;   Lot 2: 500 EUR for 575 USD -> 1.15 USD/EUR
;   Combined EUR basis: 1175 USD
; ----------------------------------------------------------------------

2026-02-01 * "Buy EUR lot 1"
  Assets:EU:Checking              500 EUR {"20260201"} @@ 600.00 USD
  Assets:US:Checking             -600 USD

2026-03-01 * "Buy EUR lot 2"
  Assets:EU:Checking              500 EUR {"20260301"} @@ 575.00 USD
  Assets:US:Checking             -575 USD

; ----------------------------------------------------------------------
; Buy 100 IMBL with 1000 EUR (10 EUR/sh)
;   At trade time, 1 EUR = 1.25 USD, so 1000 EUR = 1250 USD.
;   Section 988 gain on EUR used: 1250 - 1175 = 75 USD.
;   IMBL is kept with EUR cost; FX gain goes to Income:US:FX:Sec988.
; ----------------------------------------------------------------------

2026-04-01 * "Buy 100 IMBL with EUR, realize FX gain on EUR lots"
  Assets:EU:Checking             -500 EUR {"20260201"} @ 1.25 USD
  Assets:EU:Checking             -500 EUR {"20260301"} @ 1.25 USD
  Assets:EU:Checking              1000 EUR @@ 1250 USD
  Income:US:FX:Sec988            -75 USD
  Assets:IBKR:BVME:IMBL           100 IMBL {"20260401"} @@ 1000 EUR
  Assets:EU:Checking             -1000 EUR

; ----------------------------------------------------------------------
; Sell the 100 IMBL for EUR, no immediate 988 gain
;   Price: 11 EUR/sh -> proceeds 1100 EUR.
;   EUR/USD = 1.30, so proceeds get a new USD basis 1430.
;   Capital gain: 100 EUR, also tracked in USD (130 USD) for tax.
; ----------------------------------------------------------------------

2026-05-01 * "Sell 100 IMBL for EUR, record EUR capital gain"
  Assets:IBKR:BVME:IMBL          -100 IMBL {"20260401"}
  Assets:EU:Checking              1100.00 EUR
  Income:CapGains:EUR            -100.00 EUR
  Assets:EU:Checking             -1100.00 EUR @@ 1430.00 USD
  Assets:EU:Checking              1100 EUR {"20260501"} @@ 1430.00 USD
  Income:CapGains:USD            -130 USD @@ 100.00 EUR
  Equity:Tax:CapGains:Bridge      100 EUR

; ----------------------------------------------------------------------
; Later EUR -> USD conversion (where section 988 is realized)
;   Assume one month later, 1 EUR = 1.40 USD.
;   EUR disposed: 1100 EUR
;   USD received: 1540 USD
;   FX gain: 1540 - 1430 = 110 USD (section 988-style).
; ----------------------------------------------------------------------

2026-06-01 * "Convert 1100 EUR back to USD, realize section 988 gain"
  Assets:EU:Checking             -1100 EUR {"20260501"}
  Income:US:FX:Sec988            -110.00 USD
  Assets:US:Checking              1540.00 USD


Thanks in advance...

Chary Ev2geny

unread,
Mar 12, 2026, 9:51:45 AMMar 12
to Beancount
Hi, there!

disclaimer: I am not an accountant and I just learned about the Section 988 gains after I have read your post. But I thought that this may be related to the sing_curr_conv which I created.

As far as I see, what you recorded makes sense. But I am just thinking that the issue here is that you try to combine a simple transaction record as well as post transaction tax analytics in one place.

In a real world (personal or corporate) this would not be in one place. In a corporate world some corporation would just go around doing business in a local currency and then some specially trained person would then do some clever analytics to calculate the exchange -rate fluctuation - related   gains in a functional currency. And this analytics would also depend on the on the source of exchange rate the person uses (so a bit subjective thing)

I think the best way to use beancount is to do the same: you just record transactions they way you did them, and then you do a later analytics to calculate all the difficult to calculate gains. May be you even outsource this to somebody else.

I am sorry I do not have straight answer to your question, but I will think how I would approach this.

SomeCallMeTim

unread,
Mar 12, 2026, 3:27:51 PMMar 12
to Beancount
Thanks for the feedback.  Yes, it would be preferred if I could just do something like:

2026-04-01 * "Buy 100 IMBL with EUR"

  Assets:EU:Checking             -1000 EUR
  Assets:IBKR:BVME:IMBL           100 IMBL {"20260401"} @@ 1000 EUR

However this then creates a balance sheet that looks like:

beanquery> SELECT account, sum(position) WHERE date <= 2026-04-01 AND account ~ 'Asset' GROUP BY account
Assets:EU:Checking       500 EUR { 1.20 USD}    500 EUR { 1.15 USD}  -1000 EUR

I'm not sure if that's a problem per-se.  I suppose a follow-on parsing script could handle this.  Since the disposal occurred in euro, there's no precise exchange rate, I can just use whatever tax authority exchange rate is needed.

On the actual currency conversions, I do need to specify the precise exchange rate because the price I get from the bank/brokerage at the instant of the conversion may be different from the daily published spot rate.  I suppose I could not use lots and instead do something like:

2026-02-01 * "Buy EUR"
  Assets:EU:Checking              500 EUR @@ 600.0 USD

  Assets:US:Checking              -600 USD

This would make the balance sheet query cleaner, but would require a parsing script to find all the EUR/USD currency conversions and calculate the section 988 gains automatically.

I'm curious if anyone is actually doing something like this in practice.

SomeCallMeTim

unread,
Sep 22, 2026, 11:42:06 PMSep 22
to Beancount
Following up on this.  Thanks for the suggestion from Chary Ev2geny, I decided to tackle the problem like this:

1. Beancount represents the actual bookkeeping transactions.

2. A separate python processing script performs foreign currency acquisition and disposal tracking (including foreign currency lot tracking, using beancount price directives) and calculates the section 988 gains automatically.

This requires some additional per-transaction or per-commodity info which I embed as metadata tags in the beancount ledger.  Examples include:
- Is the commodity on an exchange with T+1 settlement or T+2 settlement.  For marketable securities purchases, US treasury regulations require the use of a forex rate on the settlement date not the trade date
- Is the transaction for business/investment or personal.  Personal transactions are currently subject to a $200 gain exemption (but losses are excluded entirely) whereas business/investment transactions track forex gains and losses.

Some related scripts handle other US tax preparation concepts, such as identifying wash sales, long term vs short term capital gains, Section 1256 mark to market gains, etc.  I don't have a public repo for these, but happy to discuss further if anyone is interested. 

Reply all
Reply to author
Forward
0 new messages