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

-- 
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beancount/20210423000540.4krdukadsie2e5ei%40moth.falsifian.org.

Reply via email to