{% import "_query_table.html" as querytable with context %} {% import "_charts.html" as charts with context %} {% set new_querytable = extension.use_new_querytable() %} Investor: Reports, analyses, and tools for investments. {% set module = request.args.get('module') %}
{% for key, label in [('aa_class', _('Asset Allocation Classes')), ('aa_account', _('Asset Allocation Accounts')), ('cashdrag', _('Cash Drag')), ('tlh', _('Tax Loss Harvestor')) ] %}

{% if not (module == key) %}{{ label }}{% else %} {{ label }}{% endif %}

{% endfor %}
{% if (module == 'aa_account') %}

Portfolio: Asset Allocation by Accounts

{% set results = extension.build_aa_by_account() %} {% if results|length == 0 %} No regexes found in configuration. See example.beancount for how to configure this module. {% else %} {% for portfolio in results %}

{{portfolio[0]}}

{% if new_querytable %} {{ querytable.querytable(ledger, None, *portfolio[1]) }} {% else %} {{ querytable.querytable(None, *portfolio[1]) }} {% endif %}
{% endfor %} {% endif %} {% endif %} {% if (module == 'cashdrag') %}

Cash Drag Analysis

{% set results = extension.build_cashdrag() %} {% if new_querytable %} {{ querytable.querytable(ledger, None, *results) }} {% else %} {{ querytable.querytable(None, *results) }} {% endif %} {% endif %} {% if (module == 'tlh') %}

Tax Loss Harvester

{% set harvests = extension.build_tlh_tables() %}

Summary

{% for key, value in harvests[1].items() %} {% endfor %}
{{ _('Summary') }} {{ _('Val') }}
{{ key }} {{ value }}

Losses by Commodity

{% if new_querytable %} {{ querytable.querytable(ledger, None, *harvests[3]) }} {% else %} {{ querytable.querytable(None, *harvests[3]) }} {% endif %}

Candidates for tax loss harvesting

{% if new_querytable %} {{ querytable.querytable(ledger, None, *harvests[0]) }} {% else %} {{ querytable.querytable(None, *harvests[0]) }} {% endif %}

Potential wash sales: purchases within the past 30 days

Below, earliest_sale is the date on which a loss can be harvested without resulting in a wash sale. {% set table_empty_msg = None %} {% if harvests[2][0]|length == 0 %} {% set table_empty_msg = 'No purchases of the candidates above found within the last 30 days!' %} {% endif %} {% if new_querytable %} {{ querytable.querytable(ledger, table_empty_msg, *harvests[2]) }} {% else %} {{ querytable.querytable(table_empty_msg, *harvests[2]) }} {% endif %}

What not to buy

Below is a list of recent sales with losses. Assuming these losses were harvested, purchasing these within 30 days of the sale could result in the loss becoming a wash sale. {% set lossy_sales = extension.recently_sold_at_loss() %} {% set table_empty_msg = None %} {% if lossy_sales[1]|length == 0 %} {% set table_empty_msg = 'No sales with losses found in the last 30 days!' %} {% endif %} {% if new_querytable %} {{ querytable.querytable(ledger, table_empty_msg, *lossy_sales) }} {% else %} {{ querytable.querytable(table_empty_msg, *lossy_sales) }} {% endif %}
None of the above is meant to be financial, legal, tax, or other advice. {% endif %} {% set table_hover_text = _('Hold Shift while clicking to expand all children. Hold Ctrl or Cmd while clicking to expand one level.') %} {# TODO: - add a format_percentage() to fava's template_filters, and use that here - display 0 decimal places for assets (needed for all of fava_investor) - fix: asset bucket spacing is too wide - get currency from libassetalloc instead of looping: {% for currency in ledger.options.operating_currency %} - remove links from asset class name #} {% macro asset_tree(account_node) %}
  1. {% for currency in ledger.options.operating_currency %} {{ currency }} {% endfor %} {{ _('Percentage') }}

  2. {% for account in ([account_node] if account_node.name else account_node.children) recursive %} {% for currency in ledger.options.operating_currency %} {{ account.balance|format_currency(currency) }} {{ account.balance_children|format_currency(currency) }} {% endfor %} {% set percentage_parent = '{:3.0f}% of {}'.format(account.percentage_parent, account.parent.name) if account.parent else '' %} {{ '{:6.2f} %'.format(account.percentage) if account.percentage else '' }} {{ '{:6.2f} %'.format(account.percentage_children) if account.percentage_children else '' }}

    {% if account.children %}
      {{ loop(account.children|sort(attribute='name')) }}
    {% endif %} {% endfor %}
{% endmacro %} {% macro asset_allocation_hierarchy(serialised_tree, label=None) %} {% do charts.chart_data.append({ 'type': 'hierarchy', 'label': 'Asset Allocation' if not label else label, 'data': { 'modifier': 1, 'root': serialised_tree, }, }) %} {% endmacro %} {% if (module == 'aa_class') %}

Portfolio: Asset Allocation by Class

{% set results = extension.build_assetalloc_by_class() %} {{ asset_tree(results[0]) }} {{ asset_allocation_hierarchy(results[0].serialise(results[0]['currency']), label='Asset Allocation') }} {% endif %}