‹ Curious Bicycle

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 GBP
  • Assets:Cash shows the real amount of USD in the simple report that doesn’t convert the balances to GBP
  • Income: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.