Added new command: "pricemap [DATE]"
This outputs the pricing relationship of commodities in your data file, as of DATE (optional), using the DOT language. If you have graphviz installed, it can be viewed quite simply using: ledger pricemap | dotty - Each relationship in the graph shows the conversion factor to exchange one commodity for another, and the date at which this factor was determined.
This commit is contained in:
parent
946534b102
commit
dbac09405f
4 changed files with 94 additions and 0 deletions
72
src/pool.cc
72
src/pool.cc
|
|
@ -364,4 +364,76 @@ commodity_pool_t::parse_price_expression(const std::string& str,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void commodity_pool_t::print_pricemap(std::ostream& out,
|
||||||
|
const keep_details_t& keep,
|
||||||
|
const optional<datetime_t>& moment)
|
||||||
|
{
|
||||||
|
typedef std::map<commodity_t *, commodity_t *> comm_map_t;
|
||||||
|
|
||||||
|
comm_map_t comm_map;
|
||||||
|
|
||||||
|
foreach (const commodities_map::value_type& comm_pair, commodities) {
|
||||||
|
commodity_t * comm(&comm_pair.second->strip_annotations(keep));
|
||||||
|
comm_map.insert(comm_map_t::value_type(comm, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "digraph commodities {\n";
|
||||||
|
|
||||||
|
foreach (const comm_map_t::value_type& comm_pair, comm_map) {
|
||||||
|
commodity_t * comm(comm_pair.first);
|
||||||
|
if (comm->has_flags(COMMODITY_BUILTIN))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out << " ";
|
||||||
|
if (commodity_t::symbol_needs_quotes(comm->symbol()))
|
||||||
|
out << comm->symbol() << ";\n";
|
||||||
|
else
|
||||||
|
out << "\"" << comm->symbol() << "\";\n";
|
||||||
|
|
||||||
|
if (! comm->has_flags(COMMODITY_NOMARKET) &&
|
||||||
|
(! commodity_pool_t::current_pool->default_commodity ||
|
||||||
|
comm != commodity_pool_t::current_pool->default_commodity)) {
|
||||||
|
if (optional<commodity_t::varied_history_t&> vhist =
|
||||||
|
comm->varied_history()) {
|
||||||
|
foreach (const commodity_t::history_by_commodity_map::value_type& pair,
|
||||||
|
vhist->histories) {
|
||||||
|
datetime_t most_recent;
|
||||||
|
amount_t most_recent_amt;
|
||||||
|
foreach (const commodity_t::history_map::value_type& inner_pair,
|
||||||
|
pair.second.prices) {
|
||||||
|
if ((most_recent.is_not_a_date_time() ||
|
||||||
|
inner_pair.first > most_recent) &&
|
||||||
|
(! moment || inner_pair.first <= moment)) {
|
||||||
|
most_recent = inner_pair.first;
|
||||||
|
most_recent_amt = inner_pair.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! most_recent.is_not_a_date_time()) {
|
||||||
|
out << " ";
|
||||||
|
if (commodity_t::symbol_needs_quotes(comm->symbol()))
|
||||||
|
out << comm->symbol();
|
||||||
|
else
|
||||||
|
out << "\"" << comm->symbol() << "\"";
|
||||||
|
|
||||||
|
out << " -> ";
|
||||||
|
|
||||||
|
if (commodity_t::symbol_needs_quotes(pair.first->symbol()))
|
||||||
|
out << pair.first->symbol();
|
||||||
|
else
|
||||||
|
out << "\"" << pair.first->symbol() << "\"";
|
||||||
|
|
||||||
|
out << " [label=\""
|
||||||
|
<< most_recent_amt.number() << "\\n"
|
||||||
|
<< format_date(most_recent.date(), FMT_WRITTEN)
|
||||||
|
<< "\" fontcolor=\"#008e28\"];\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,12 @@ public:
|
||||||
const bool add_prices = true,
|
const bool add_prices = true,
|
||||||
const optional<datetime_t>& moment = none);
|
const optional<datetime_t>& moment = none);
|
||||||
|
|
||||||
|
// Output the commodity price map for a given date as a DOT file
|
||||||
|
|
||||||
|
void print_pricemap(std::ostream& out,
|
||||||
|
const keep_details_t& keep,
|
||||||
|
const optional<datetime_t>& moment = none);
|
||||||
|
|
||||||
#if defined(HAVE_BOOST_SERIALIZATION)
|
#if defined(HAVE_BOOST_SERIALIZATION)
|
||||||
private:
|
private:
|
||||||
/** Serialization. */
|
/** Serialization. */
|
||||||
|
|
|
||||||
|
|
@ -842,6 +842,18 @@ value_t report_t::echo_command(call_scope_t& scope)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_t report_t::pricemap_command(call_scope_t& scope)
|
||||||
|
{
|
||||||
|
interactive_t args(scope, "&s");
|
||||||
|
std::ostream& out(output_stream);
|
||||||
|
|
||||||
|
commodity_pool_t::current_pool->print_pricemap
|
||||||
|
(out, what_to_keep(), args.has(0) ?
|
||||||
|
optional<datetime_t>(datetime_t(parse_date(args.get<string>(0)))) : none);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
option_t<report_t> * report_t::lookup_option(const char * p)
|
option_t<report_t> * report_t::lookup_option(const char * p)
|
||||||
{
|
{
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
|
|
@ -1415,6 +1427,9 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
|
||||||
HANDLER(prepend_width_).value.to_long()),
|
HANDLER(prepend_width_).value.to_long()),
|
||||||
*this, "#pricedb"));
|
*this, "#pricedb"));
|
||||||
}
|
}
|
||||||
|
else if (is_eq(p, "pricemap")) {
|
||||||
|
return MAKE_FUNCTOR(report_t::pricemap_command);
|
||||||
|
}
|
||||||
else if (is_eq(p, "payees")) {
|
else if (is_eq(p, "payees")) {
|
||||||
return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this,
|
return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this,
|
||||||
"#payees"));
|
"#payees"));
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ public:
|
||||||
|
|
||||||
value_t reload_command(call_scope_t&);
|
value_t reload_command(call_scope_t&);
|
||||||
value_t echo_command(call_scope_t& scope);
|
value_t echo_command(call_scope_t& scope);
|
||||||
|
value_t pricemap_command(call_scope_t& scope);
|
||||||
|
|
||||||
keep_details_t what_to_keep() {
|
keep_details_t what_to_keep() {
|
||||||
bool lots = HANDLED(lots) || HANDLED(lots_actual);
|
bool lots = HANDLED(lots) || HANDLED(lots_actual);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue