Track foreign stock capital gains using hledger
Oct 15, 2023
This is how I track my foreign exchange capital gains using hledger. This is a continuation of a previous post on capital gains.
The post assumes GBP as the home currency.
According to the HMRC Capital Gains manual, capital gains on foreign assets is calculated based on the assets’ acquisition and disposal prices in pound sterling. The HMRC manual explains it better and also has some examples. Particularly important is that, both the acquisition and the disposal prices of the shares have to be converted back to sterling at the HMRC reference exchange rate for that date/month. This is regardless of how the shares were acquired (e.g. for USD; or even for a third currency, say if you were to exchange GBP to USD, then the USD to MXN and then buy some shares with the MXN). The capital gains has to be calculated between those two GBP amounts, the manual explicitly prohibits calculating the capital gains by converting back the gain from the intermediary currency (e.g. USD). This would seem to introduce some problems for hledger reports, but the method I’ve found actually makes the whole thing clearer while keeping track of all the prices and data as well.
Disclaimer: I’m not a tax professional and while I do use similar calculations for my personal tax reporting, I do not claim that any of this is correct or in agreement with HMRC rules.
Consider an example stock with ticker FOO
, bought for $100 (see the previous post for an explanation of the Income:Trading
account):
2023/10/15 buy FOO
Assets:Cash USD -100
Income:Trading:FOO USD 100
Income:Trading:FOO -1 FOO
Assets:FOO 1 FOO
Also, say that the HMRC reference exchange rate for October is $1 = £0.8:
P 2023/10/01 USD GBP 0.8
This would allow us to see the value of the shares when they were bought:
$ hledger ... bal -t --value=then,GBP
1 FOO
GBP -80.0 Assets
GBP -80.0 Cash
1 FOO FOO
-1 FOO
GBP 80.0 Income:Trading:FOO
--------------------
0
Selling
Say that, at a later time, the share is sold for $120. And the USD/GBP exchange rate has also changed:
P 2023/11/01 USD GBP 0.7
2023/11/03 sell FOO
Assets:Cash USD 120
Income:Trading:FOO 1 FOO
Income:Trading:FOO USD -100
Income:Gains USD -20
Assets:FOO -1 FOO
According to HMRC rules, the value of the capital gains, should be the difference between what we paid for the shares in GBP: £80 and what we sold them for: $120 * 0.7 = £ 84. That’s £84 - £80 = £4.
$ hledger ... bal -t --value=then,GBP
GBP 4.0 Assets:Cash
GBP -4.0 Income
GBP -14.0 Gains
GBP 10.0 Trading:FOO
--------------------
0
This looks right as far as the overall Income
account, but the split into £ -14 for gains and £ 10 for Trading is strange and hard to reconcile, especially since there’s nothing in the Income:Trading:FOO
account:
$ hledger -f ... bal --empty
USD 20 Assets:Cash
0 Assets:FOO
USD -20 Income:Gains
0 Income:Trading:FOO
--------------------
0
This type of situation can usually be reconciled by adding another account to the books.
Forex account
Instead of hiding the sterling value behind the pricing directive (P), we can make it explicit with a new account, Income:Forex:USD
will track an imaginary exchange to sterling at the set rate. So the previous postings are replaced by:
2023/10/15 buy FOO
Assets:Cash USD -100
Income:Forex:USD USD 100
Income:Forex:USD GBP -80
Income:Trading:FOO GBP 80
Income:Trading:FOO -1 FOO
Assets:FOO 1 FOO
2023/11/03 sell FOO
Assets:Cash USD 120
Income:Forex:USD USD -120
Income:Forex:USD GBP 84
Income:Trading:FOO GBP -80
Income:Gains GBP -4
Income:Trading:FOO 1 FOO
Assets:FOO -1 FOO
In the sell FOO
posting, the $120 for the sale (Assets:Cash
) is exchanged to GBP at the reference exchange rate for that date (£84). The Income:Trading:FOO
account is debited by the amount that one share cost when it was bought (£80) and the difference between the two is balanced in the Income:Gains
account (£4). Now the balance reports make more sense:
$ hledger ... bal -t --value=then,GBP
GBP 4.0 Assets:Cash
GBP -4.0 Income:Gains
--------------------
0
$ hledger ... bal -t
USD 20 Assets:Cash
USD -20 Income
GBP 4.0
USD -20 Forex:USD
GBP -4.0 Gains
--------------------
0
This version is better because:
Income:Gains
always shows the correct amount and in GBPAssets:Cash
shows the real amount of USD in the simple report that doesn’t convert the balances to GBPIncome:Forex:USD
balances to 0 when considering the value of the transactions at the time that they were done, which is how HMRC wants it. And it shows two balances (£4 and $-20) when the amounts aren’t converted. I usually ignore this account, except for making sure it balances to 0 on--value=then,GBP
.
Fees
This method also allows for tracking fees in the same way. They are not deducted from the capital gains, but could be useful for investment return calculations:
P 2023/10/01 USD GBP 0.8
2023/10/15 buy FOO
Assets:Cash USD -105
Income:Forex:USD USD 105
Income:Forex:USD GBP -84
Income:Trading:FOO GBP 80
Income:Trading:FOO 1 FOO
Assets:FOO -1 FOO
Income:Forex:USD GBP 4
Income:Forex:USD USD -5
Expenses:Fees USD 5
P 2023/11/01 USD GBP 0.7
2023/11/03 sell FOO
Assets:Cash USD 115
Income:Forex:USD USD -115
Income:Forex:USD GBP 80.5
Income:Trading:FOO -1 FOO
Income:Trading:FOO GBP -80
Income:Gains GBP -4
Assets:FOO 1 FOO
Income:Forex:USD GBP 3.5
Income:Forex:USD USD -5
Expenses:Fees USD 5
$ hledger ... bal -t
USD 10 Assets:Cash
USD 10 Expenses:Fees
USD -20 Income
GBP 4.0
USD -20 Forex:USD
GBP -4.0 Gains
--------------------
0
$ hledger ... bal -t --value=then,GBP
GBP -3.5 Assets:Cash
GBP 7.5 Expenses:Fees
GBP -4.0 Income:Gains
--------------------
I choose not to track the fees because it greatly complicates the journal.