Added an --unrealized option, for use with bal -V
When this option is on, then in balance report which show market values, any gains or losses in value will be balanced into a pair of accounts called Equity:Unrealized Gains and Equity:Unrealized Losses.
This commit is contained in:
parent
3f1861fb1e
commit
63fee4c837
6 changed files with 94 additions and 15 deletions
19
src/chain.cc
19
src/chain.cc
|
|
@ -77,18 +77,23 @@ post_handler_ptr chain_post_handlers(report_t& report,
|
||||||
report.what_to_keep());
|
report.what_to_keep());
|
||||||
handler.reset(new filter_posts(handler, display_predicate, report));
|
handler.reset(new filter_posts(handler, display_predicate, report));
|
||||||
}
|
}
|
||||||
|
|
||||||
// changed_value_posts adds virtual posts to the list to account for
|
|
||||||
// changes in market value of commodities, which otherwise would affect
|
|
||||||
// the running total unpredictably.
|
|
||||||
if (report.HANDLED(revalued))
|
|
||||||
handler.reset(new changed_value_posts(handler, report));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// changed_value_posts adds virtual posts to the list to account for changes
|
||||||
|
// in market value of commodities, which otherwise would affect the running
|
||||||
|
// total unpredictably.
|
||||||
|
if (report.HANDLED(revalued) && (! for_accounts_report ||
|
||||||
|
report.HANDLED(unrealized)))
|
||||||
|
handler.reset(new changed_value_posts(handler, report,
|
||||||
|
for_accounts_report,
|
||||||
|
report.HANDLED(unrealized)));
|
||||||
|
|
||||||
// calc_posts computes the running total. When this appears will determine,
|
// calc_posts computes the running total. When this appears will determine,
|
||||||
// for example, whether filtered posts are included or excluded from the
|
// for example, whether filtered posts are included or excluded from the
|
||||||
// running total.
|
// running total.
|
||||||
handler.reset(new calc_posts(handler, expr, ! for_accounts_report));
|
handler.reset(new calc_posts(handler, expr, (! for_accounts_report ||
|
||||||
|
(report.HANDLED(revalued) &&
|
||||||
|
report.HANDLED(unrealized)))));
|
||||||
|
|
||||||
// filter_posts will only pass through posts matching the
|
// filter_posts will only pass through posts matching the
|
||||||
// `secondary_predicate'.
|
// `secondary_predicate'.
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,7 @@ namespace {
|
||||||
const date_t& date = date_t(),
|
const date_t& date = date_t(),
|
||||||
const value_t& total = value_t(),
|
const value_t& total = value_t(),
|
||||||
const bool direct_amount = false,
|
const bool direct_amount = false,
|
||||||
|
const bool mark_visited = false,
|
||||||
const optional<post_functor_t>& functor = none)
|
const optional<post_functor_t>& functor = none)
|
||||||
{
|
{
|
||||||
post_t& post = temps.create_post(*xact, account);
|
post_t& post = temps.create_post(*xact, account);
|
||||||
|
|
@ -308,6 +309,11 @@ namespace {
|
||||||
DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
|
DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
|
||||||
|
|
||||||
(*handler)(post);
|
(*handler)(post);
|
||||||
|
|
||||||
|
if (mark_visited) {
|
||||||
|
post.xdata().add_flags(POST_EXT_VISITED);
|
||||||
|
post.account->xdata().add_flags(ACCOUNT_EXT_VISITED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,8 +412,12 @@ void related_posts::flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
changed_value_posts::changed_value_posts(post_handler_ptr handler,
|
changed_value_posts::changed_value_posts(post_handler_ptr handler,
|
||||||
report_t& _report)
|
report_t& _report,
|
||||||
: item_handler<post_t>(handler), report(_report), last_post(NULL),
|
bool _for_accounts_report,
|
||||||
|
bool _show_unrealized)
|
||||||
|
: item_handler<post_t>(handler), report(_report),
|
||||||
|
for_accounts_report(_for_accounts_report),
|
||||||
|
show_unrealized(_show_unrealized), last_post(NULL),
|
||||||
revalued_account(temps.create_account(_("<Revalued>"))),
|
revalued_account(temps.create_account(_("<Revalued>"))),
|
||||||
rounding_account(temps.create_account(_("<Rounding>")))
|
rounding_account(temps.create_account(_("<Rounding>")))
|
||||||
{
|
{
|
||||||
|
|
@ -419,6 +429,14 @@ changed_value_posts::changed_value_posts(post_handler_ptr handler,
|
||||||
report.HANDLER(display_total_).expr);
|
report.HANDLER(display_total_).expr);
|
||||||
display_total_expr = report.HANDLER(display_total_).expr;
|
display_total_expr = report.HANDLER(display_total_).expr;
|
||||||
changed_values_only = report.HANDLED(revalued_only);
|
changed_values_only = report.HANDLED(revalued_only);
|
||||||
|
|
||||||
|
gains_equity_account =
|
||||||
|
report.session.journal->master->find_account(_("Equity:Unrealized Gains"));
|
||||||
|
gains_equity_account->add_flags(ACCOUNT_GENERATED);
|
||||||
|
|
||||||
|
losses_equity_account =
|
||||||
|
report.session.journal->master->find_account(_("Equity:Unrealized Losses"));
|
||||||
|
losses_equity_account->add_flags(ACCOUNT_GENERATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void changed_value_posts::flush()
|
void changed_value_posts::flush()
|
||||||
|
|
@ -460,10 +478,35 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
|
||||||
xact.payee = _("Commodities revalued");
|
xact.payee = _("Commodities revalued");
|
||||||
xact._date = is_valid(date) ? date : post.date();
|
xact._date = is_valid(date) ? date : post.date();
|
||||||
|
|
||||||
handle_value(diff, &revalued_account, &xact, temps, handler,
|
if (! for_accounts_report) {
|
||||||
*xact._date, repriced_total, false,
|
handle_value
|
||||||
optional<post_functor_t>
|
(/* value= */ diff,
|
||||||
(bind(&changed_value_posts::output_rounding, this, _1)));
|
/* account= */ &revalued_account,
|
||||||
|
/* xact= */ &xact,
|
||||||
|
/* temps= */ temps,
|
||||||
|
/* handler= */ handler,
|
||||||
|
/* date= */ *xact._date,
|
||||||
|
/* total= */ repriced_total,
|
||||||
|
/* direct_amount= */ false,
|
||||||
|
/* mark_visited= */ false,
|
||||||
|
/* functor= */ (optional<post_functor_t>
|
||||||
|
(bind(&changed_value_posts::output_rounding,
|
||||||
|
this, _1))));
|
||||||
|
}
|
||||||
|
else if (show_unrealized) {
|
||||||
|
handle_value
|
||||||
|
(/* value= */ - diff,
|
||||||
|
/* account= */ (diff < 0L ?
|
||||||
|
losses_equity_account :
|
||||||
|
gains_equity_account),
|
||||||
|
/* xact= */ &xact,
|
||||||
|
/* temps= */ temps,
|
||||||
|
/* handler= */ handler,
|
||||||
|
/* date= */ *xact._date,
|
||||||
|
/* total= */ value_t(),
|
||||||
|
/* direct_amount= */ false,
|
||||||
|
/* mark_visited= */ true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -513,7 +556,8 @@ void changed_value_posts::operator()(post_t& post)
|
||||||
if (changed_values_only)
|
if (changed_values_only)
|
||||||
post.xdata().add_flags(POST_EXT_DISPLAYED);
|
post.xdata().add_flags(POST_EXT_DISPLAYED);
|
||||||
|
|
||||||
output_rounding(post);
|
if (! for_accounts_report)
|
||||||
|
output_rounding(post);
|
||||||
|
|
||||||
item_handler<post_t>::operator()(post);
|
item_handler<post_t>::operator()(post);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -378,18 +378,24 @@ class changed_value_posts : public item_handler<post_t>
|
||||||
expr_t display_total_expr;
|
expr_t display_total_expr;
|
||||||
report_t& report;
|
report_t& report;
|
||||||
bool changed_values_only;
|
bool changed_values_only;
|
||||||
|
bool for_accounts_report;
|
||||||
|
bool show_unrealized;
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
value_t last_total;
|
value_t last_total;
|
||||||
value_t last_display_total;
|
value_t last_display_total;
|
||||||
temporaries_t temps;
|
temporaries_t temps;
|
||||||
account_t& revalued_account;
|
account_t& revalued_account;
|
||||||
account_t& rounding_account;
|
account_t& rounding_account;
|
||||||
|
account_t * gains_equity_account;
|
||||||
|
account_t * losses_equity_account;
|
||||||
|
|
||||||
changed_value_posts();
|
changed_value_posts();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
changed_value_posts(post_handler_ptr handler,
|
changed_value_posts(post_handler_ptr handler,
|
||||||
report_t& _report);
|
report_t& _report,
|
||||||
|
bool _for_accounts_report,
|
||||||
|
bool _show_unrealized);
|
||||||
|
|
||||||
virtual ~changed_value_posts() {
|
virtual ~changed_value_posts() {
|
||||||
TRACE_DTOR(changed_value_posts);
|
TRACE_DTOR(changed_value_posts);
|
||||||
|
|
|
||||||
|
|
@ -887,6 +887,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
||||||
case 'u':
|
case 'u':
|
||||||
OPT(unbudgeted);
|
OPT(unbudgeted);
|
||||||
else OPT(uncleared);
|
else OPT(uncleared);
|
||||||
|
else OPT(unrealized);
|
||||||
else OPT(unround);
|
else OPT(unround);
|
||||||
else OPT(unsorted);
|
else OPT(unsorted);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,7 @@ public:
|
||||||
HANDLER(truncate_).report(out);
|
HANDLER(truncate_).report(out);
|
||||||
HANDLER(unbudgeted).report(out);
|
HANDLER(unbudgeted).report(out);
|
||||||
HANDLER(uncleared).report(out);
|
HANDLER(uncleared).report(out);
|
||||||
|
HANDLER(unrealized).report(out);
|
||||||
HANDLER(unround).report(out);
|
HANDLER(unround).report(out);
|
||||||
HANDLER(unsorted).report(out);
|
HANDLER(unsorted).report(out);
|
||||||
HANDLER(weekly).report(out);
|
HANDLER(weekly).report(out);
|
||||||
|
|
@ -873,6 +874,8 @@ public:
|
||||||
parent->HANDLER(limit_).on(string("--uncleared"), "uncleared|pending");
|
parent->HANDLER(limit_).on(string("--uncleared"), "uncleared|pending");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPTION(report_t, unrealized);
|
||||||
|
|
||||||
OPTION_(report_t, unround, DO() {
|
OPTION_(report_t, unround, DO() {
|
||||||
parent->HANDLER(display_amount_)
|
parent->HANDLER(display_amount_)
|
||||||
.set_expr(string("--unround"), "unrounded(amount_expr)");
|
.set_expr(string("--unround"), "unrounded(amount_expr)");
|
||||||
|
|
|
||||||
20
test/baseline/opt-unrealized.test
Normal file
20
test/baseline/opt-unrealized.test
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
bal -V --unrealized
|
||||||
|
<<<
|
||||||
|
2008/10/01 Sample
|
||||||
|
Assets:Brokerage 10 AAPL
|
||||||
|
Assets:Checking $-200.00
|
||||||
|
|
||||||
|
P 2008/10/20 12:00:00 AAPL $30.00
|
||||||
|
|
||||||
|
; 2008/10/20 <Generated Transaction>
|
||||||
|
; Assets:Brokerage $100
|
||||||
|
; Equity:Unrealized Gains
|
||||||
|
>>>1
|
||||||
|
$100.00 Assets
|
||||||
|
$300.00 Brokerage
|
||||||
|
$-200.00 Checking
|
||||||
|
$-100.00 Equity:Unrealized Gains
|
||||||
|
--------------------
|
||||||
|
0
|
||||||
|
>>>2
|
||||||
|
=== 0
|
||||||
Loading…
Add table
Reference in a new issue