diff options
-rw-r--r-- | src/balance.cc | 59 | ||||
-rw-r--r-- | src/balance.h | 2 | ||||
-rw-r--r-- | src/report.cc | 11 | ||||
-rw-r--r-- | src/report.h | 9 |
4 files changed, 81 insertions, 0 deletions
diff --git a/src/balance.cc b/src/balance.cc index 5f5e6fc9..f0065dc5 100644 --- a/src/balance.cc +++ b/src/balance.cc @@ -345,4 +345,63 @@ void put_balance(property_tree::ptree& st, const balance_t& bal) put_amount(st.add("amount", ""), pair.second); } +balance_t average_lot_prices(const balance_t& bal) +{ + // First, we split the balance into multiple balances by underlying + // commodity. + typedef std::map<optional<std::string>, + std::pair<amount_t, annotation_t> > balance_map; + balance_map bycomm; + + foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) { + optional<std::string> sym(pair.first->symbol()); + amount_t quant(pair.second.strip_annotations(keep_details_t())); + + balance_map::iterator i = bycomm.find(sym); + if (i == bycomm.end()) { + bycomm.insert( + balance_map::value_type(sym, std::make_pair(quant, annotation_t()))); + i = bycomm.find(sym); // must succeed now + } else { + (*i).second.first += quant; + } + + if (pair.first->has_annotation()) { + annotated_commodity_t& acomm(static_cast<annotated_commodity_t&>(*pair.first)); + annotation_t& ann((*i).second.second); + + if (acomm.details.price) { + if (ann.price) + ann.price = *ann.price + (*acomm.details.price * quant); + else + ann.price = *acomm.details.price * quant; + } + + if (acomm.details.date) { + if (! ann.date || *acomm.details.date < *ann.date) + ann.date = *acomm.details.date; + } + } + } + + balance_t result; + + foreach (balance_map::value_type& pair, bycomm) { + amount_t amt(pair.second.first); + if (! amt.is_realzero()) { + if (pair.second.second.price) + pair.second.second.price = *pair.second.second.price / amt; + + commodity_t * acomm = + commodity_pool_t::current_pool->find_or_create( + amt.commodity(), pair.second.second); + amt.set_commodity(*acomm); + + result += amt; + } + } + + return result; +} + } // namespace ledger diff --git a/src/balance.h b/src/balance.h index bd373cb9..19b6bd84 100644 --- a/src/balance.h +++ b/src/balance.h @@ -603,6 +603,8 @@ inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) { void put_balance(property_tree::ptree& pt, const balance_t& bal); +balance_t average_lot_prices(const balance_t& bal); + } // namespace ledger #endif // _BALANCE_H diff --git a/src/report.cc b/src/report.cc index cc165184..c5d6d14e 100644 --- a/src/report.cc +++ b/src/report.cc @@ -563,6 +563,14 @@ value_t report_t::fn_should_bold(call_scope_t& scope) return false; } +value_t report_t::fn_averaged_lots(call_scope_t& args) +{ + if (args.has<balance_t>(0)) + return average_lot_prices(args.get<balance_t>(0)); + else + return args[0]; +} + value_t report_t::fn_market(call_scope_t& args) { value_t result; @@ -1130,6 +1138,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) else OPT(average); else OPT(account_width_); else OPT(amount_width_); + else OPT(average_lot_prices); break; case 'b': OPT(balance_format_); @@ -1370,6 +1379,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return MAKE_FUNCTOR(report_t::fn_ansify_if); else if (is_eq(p, "abs")) return MAKE_FUNCTOR(report_t::fn_abs); + else if (is_eq(p, "averaged_lots")) + return MAKE_FUNCTOR(report_t::fn_averaged_lots); break; case 'b': diff --git a/src/report.h b/src/report.h index 7775e21d..5325c3a2 100644 --- a/src/report.h +++ b/src/report.h @@ -202,6 +202,7 @@ public: value_t fn_to_string(call_scope_t& scope); value_t fn_to_mask(call_scope_t& scope); value_t fn_to_sequence(call_scope_t& scope); + value_t fn_averaged_lots(call_scope_t& scope); value_t fn_now(call_scope_t&) { return terminus; @@ -298,6 +299,7 @@ public: HANDLER(limit_).report(out); HANDLER(lot_dates).report(out); HANDLER(lot_prices).report(out); + HANDLER(average_lot_prices).report(out); HANDLER(lot_notes).report(out); HANDLER(lots).report(out); HANDLER(lots_actual).report(out); @@ -745,6 +747,13 @@ public: OPTION(report_t, lot_dates); OPTION(report_t, lot_prices); + OPTION_(report_t, average_lot_prices, DO() { + OTHER(lot_prices).on(whence); + OTHER(display_amount_) + .on(whence, "averaged_lots(display_amount)"); + OTHER(display_total_) + .on(whence, "averaged_lots(display_total)"); + }); OPTION(report_t, lot_notes); OPTION(report_t, lots); OPTION(report_t, lots_actual); |