On Sun, Mar 07, 2021 at 04:48:05AM +0000, James Cook wrote:
> Thanks, Martin and Ben. It sounds I should go ahead with the first step
> of my plan, i.e. entering all the data from the US point of view. After
> that I'll consult the resources you linked and see what I can put together.
I wrote some code. I haven't yet tried using it to do my taxes, so I
don't know how useful it will be in practice. Canadian taxes are due
soon so I should know soon...
My code ended up taking the form of a plugin which computes average
cost base and outputs the result in the form of a new metadata field,
without touching anything else.
The code is here:
https://hub.darcs.net/falsifian/misc-pub/browse/beancount_plugins/falsifian/parallel_average_cost.py
One issue I haven't yet thought about: I'll be entering all my costs in
USD, which will cause this plugin to compute average cost bases in USD.
But I need to report to Canada in CAD. This might be the kind of thing
where it's acceptible to just do some reasonable approximation. Or
maybe I'll update my code to use the price database to convert
everything to a target currency.
Here's a copy of the documentation, which includes examples:
********
This plugin is intended to help when you need to calculate your capital gains
in two different ways, and one of them is average-cost booking.
WARNING: I'm not an accountant. Don't trust this for your taxes. Use your own
judgement.
I plan to use this to file taxes in the US and Canada. It works like this: I
enter my data in Beancount using from the US point of view. Then this plugin
does its own accounting of lots using average cost booking, *without changing
the ordinary Beancount-tracked lots*. This plugin reports its results by adding
metadata fields to transactions. This plugin does not make any changes to the
stream other than adding metadata.
For example, on this input:
plugin "falsifian.parallel_average_cost"
2000-01-01 open Assets:Brokerage0
2000-01-01 open Assets:Brokerage1
2000-01-01 open Assets:Chequing
; Capital gains according to the manually-entered booking.
2000-01-01 open Income:Capital-gains
2000-01-01 * "Buy"
Assets:Chequing -400.00 USD
Assets:Brokerage0 4 ACME {100.00 USD}
2000-02-01 * "Buy again"
Assets:Chequing -50.00 USD
Assets:Brokerage1 1 ACME {50.00 USD}
2000-03-01 * "Sell"
Assets:Chequing 220.00 USD
Assets:Brokerage0 -2 ACME {} @ 220.00 USD
Income:Capital-gains -20.00 USD
Thi last transaction becomes this:
2000-03-01 * "Sell"
Assets:Chequing 220.00 USD
Assets:Brokerage0 -2 ACME {100.00 USD, 2000-01-01} @ 220.00 USD
parallel_average_cost_base: 180.00 USD
Income:Capital-gains -20.00 USD
A couple of things to notice:
* A new parallel_average_cost_base field was added. It indicates that the average
cost base for those 2 ACME is 180.00 USD (9.00 USD per unit of ACME).
* The average cost booking was done across all accounts. It doesn't matter that
one buy happened with Assets:Brokerage0 and the other with Assets:Brokerage1.
In this example, I'd use the Income:Capital-gains field for my US taxes, and
use the computed parallel_average_cost_base field to help my compute my
Canadian taxes. (One issue here: the amount is in USD, not CAD.)
Once the cost base has been computed for a posting, it probably shouldn't
change. To make sure, you can add the value as an assertion. For example:
2000-02-01 * "Sell"
Assets:Chequing 200.00 USD
Assets:Brokerage -5 ACME {20.00 USD} @ 40.00 USD
parallel_average_cost_base_assert: 100.00 USD
Income:Capital-gains -100.00 USD
An error will be raised if the computed average cost base is not 100.00 USD.
You may wish to manually set the cost base. For example, when I moved to
Canada, I was "deemed" by Canada to have aquired all my equity at that moment
in time. You can use a "parallel_average_cost_base_set" custom directive to do
that, like so:
2000-02-01 custom "parallel_average_cost_set" 4 ACME 400.00 USD "extra"
This directive does two things:
* It asserts that your total balance of ACME across all accounts is 4.
* It sets the total cost of those 4 ACME to 400.00 USD (so, 100.00 USD per
ACME).
If you transfer equity between two brokerage accounts without buying or
selling, you'll want to turn off the plugin for those postings so it doesn't
adjust your cost base, by adding the "parallel_average_cost_ignore" metadata
field with any value. For example:
2000-03-01 * "Transfer to a different account"
Assets:Brokerage0 -5 ACME {}
parallel_average_cost_ignore: 1
Assets:Brokerage1 4 ACME {10.00 USD, 2000-01-01}
; The metadata value doesn't matter.
parallel_average_cost_ignore: ""
Assets:Brokerage1 1 ACME {20.00 USD, 2000-02-01}
; The metadata value doesn't matter.
parallel_average_cost_ignore: ""
See parallel_average_cost_test.py for more examples.
--
James