Skip to content

Commit

Permalink
Preserve costs during tax adjustment (#83)
Browse files Browse the repository at this point in the history
* Preserve costs during tax adjustment

Previously, tax adjustment discarded the cost of positions, causing
beancount.core.convert.convert_position to miss some conversion paths
via the cost currency. This necessitated a fallback to operating
currencies for finding viable transitive conversions.

With this patch, tax adjustment preserves the cost of positions.
Therefore, the cost currency is still available for automatic detection
of transitive conversions when computing the asset allocation.

One important assumption is that tax adjustment only ever encounters
costs after realization, as having a cost spec for the total cost would
change the cost per unit. This assumption is checked via assert and has
been manually tested without error on the multicurrency example.

The patch leaves the fallback logic for conversion via operating
currencies in place as an alternative when conversion via cost currency
fails.

* Fix lint warnings
  • Loading branch information
korrat authored Jun 26, 2023
1 parent 661fedd commit 9441bc7
Showing 1 changed file with 8 additions and 5 deletions.
13 changes: 8 additions & 5 deletions fava_investor/modules/assetalloc_class/libassetalloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import re

from beancount.core import convert
from beancount.core import amount
from beancount.core import inventory
from beancount.core import position
from beancount.core import realization
from beancount.core.number import Decimal

Expand Down Expand Up @@ -176,8 +176,12 @@ def scale_inventory(balance, tax_adj):
"""Scale inventory by tax adjustment"""
scaled_balance = inventory.Inventory()
for pos in balance.get_positions():
scaled_pos = amount.Amount(pos.units.number * (Decimal(tax_adj / 100)), pos.units.currency)
scaled_balance.add_amount(scaled_pos)
# One important assumption is that tax adjustment only ever encounters costs after realization, as
# having a cost spec for the total cost would change the cost per unit.
assert pos.cost is None or isinstance(pos.cost, position.Cost)

scaled_pos = pos * Decimal(tax_adj / 100)
scaled_balance.add_position(scaled_pos)
return scaled_balance

account_open_close = accapi.get_account_open_close()
Expand All @@ -197,7 +201,6 @@ def assetalloc(accapi, config={}):
# print(realization.compute_balance(realacc).reduce(convert.get_units))

balance = realization.compute_balance(realacc)
vbalance = balance.reduce(convert.get_units)
asset_buckets = bucketize(vbalance, accapi)
asset_buckets = bucketize(balance, accapi)

return treeify(asset_buckets, accapi), realacc

0 comments on commit 9441bc7

Please sign in to comment.