All tests are working again but one
This commit is contained in:
parent
5d8cb30774
commit
8d6bf11334
11 changed files with 325 additions and 175 deletions
|
|
@ -605,16 +605,13 @@ void amount_t::in_place_negate()
|
|||
}
|
||||
}
|
||||
|
||||
amount_t amount_t::inverted() const
|
||||
void amount_t::in_place_invert()
|
||||
{
|
||||
if (! quantity)
|
||||
throw_(amount_error, _("Cannot invert an uninitialized amount"));
|
||||
|
||||
amount_t t(*this);
|
||||
t._dup();
|
||||
mpq_inv(MP(t.quantity), MP(t.quantity));
|
||||
|
||||
return t;
|
||||
_dup();
|
||||
mpq_inv(MP(quantity), MP(quantity));
|
||||
}
|
||||
|
||||
void amount_t::in_place_round()
|
||||
|
|
|
|||
|
|
@ -327,7 +327,12 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
amount_t inverted() const;
|
||||
amount_t inverted() const {
|
||||
amount_t temp(*this);
|
||||
temp.in_place_invert();
|
||||
return temp;
|
||||
}
|
||||
void in_place_invert();
|
||||
|
||||
/** Yields an amount whose display precision when output is truncated
|
||||
to the display precision of its commodity. This is normally the
|
||||
|
|
|
|||
|
|
@ -43,11 +43,20 @@ bool commodity_t::decimal_comma_by_default = false;
|
|||
void commodity_t::add_price(const datetime_t& date, const amount_t& price,
|
||||
const bool reflexive)
|
||||
{
|
||||
if (! reflexive)
|
||||
if (reflexive) {
|
||||
DEBUG("history.find", "Marking "
|
||||
<< price.commodity().symbol() << " as a primary commodity");
|
||||
price.commodity().add_flags(COMMODITY_PRIMARY);
|
||||
} else {
|
||||
DEBUG("history.find", "Marking " << symbol() << " as a primary commodity");
|
||||
add_flags(COMMODITY_PRIMARY);
|
||||
}
|
||||
|
||||
DEBUG("history.find", "Adding price: " << symbol()
|
||||
<< " for " << price << " on " << date);
|
||||
|
||||
pool().commodity_price_history.add_price(*this, date, price);
|
||||
|
||||
DEBUG("commodity.prices.find", "Price added, clearing price_map");
|
||||
base->price_map.clear(); // a price was added, invalid the map
|
||||
}
|
||||
|
||||
|
|
@ -55,27 +64,52 @@ void commodity_t::remove_price(const datetime_t& date, commodity_t& commodity)
|
|||
{
|
||||
pool().commodity_price_history.remove_price(*this, commodity, date);
|
||||
|
||||
DEBUG("commodity.prices.find", "Price removed, clearing price_map");
|
||||
DEBUG("history.find", "Removing price: " << symbol() << " on " << date);
|
||||
|
||||
base->price_map.clear(); // a price was added, invalid the map
|
||||
}
|
||||
|
||||
void commodity_t::map_prices(function<void(datetime_t, const amount_t&)> fn,
|
||||
const optional<datetime_t>& moment,
|
||||
const optional<datetime_t>& _oldest)
|
||||
{
|
||||
datetime_t when;
|
||||
if (moment)
|
||||
when = *moment;
|
||||
else if (epoch)
|
||||
when = *epoch;
|
||||
else
|
||||
when = CURRENT_TIME();
|
||||
|
||||
pool().commodity_price_history.map_prices(fn, *this, when, _oldest);
|
||||
}
|
||||
|
||||
optional<price_point_t>
|
||||
commodity_t::find_price(const optional<commodity_t&>& commodity,
|
||||
const optional<datetime_t>& moment,
|
||||
const optional<datetime_t>& oldest) const
|
||||
{
|
||||
optional<commodity_t&> target;
|
||||
if (commodity)
|
||||
target = commodity;
|
||||
else if (pool().default_commodity)
|
||||
target = *pool().default_commodity;
|
||||
|
||||
if (target && *this == *target)
|
||||
return none;
|
||||
|
||||
optional<base_t::time_and_commodity_t> pair =
|
||||
base_t::time_and_commodity_t(base_t::optional_time_pair_t(moment, oldest),
|
||||
commodity ? &(*commodity) : NULL);
|
||||
|
||||
DEBUG("commodity.prices.find", "looking for memoized args: "
|
||||
DEBUG("history.find", "looking for memoized args: "
|
||||
<< (moment ? format_datetime(*moment) : "NONE") << ", "
|
||||
<< (oldest ? format_datetime(*oldest) : "NONE") << ", "
|
||||
<< (commodity ? commodity->symbol() : "NONE"));
|
||||
{
|
||||
base_t::memoized_price_map::iterator i = base->price_map.find(*pair);
|
||||
if (i != base->price_map.end()) {
|
||||
DEBUG("commodity.prices.find", "found! returning: "
|
||||
DEBUG("history.find", "found! returning: "
|
||||
<< ((*i).second ? (*i).second->price : amount_t(0L)));
|
||||
return (*i).second;
|
||||
}
|
||||
|
|
@ -89,12 +123,6 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
|
|||
else
|
||||
when = CURRENT_TIME();
|
||||
|
||||
optional<commodity_t&> target;
|
||||
if (commodity)
|
||||
target = commodity;
|
||||
else if (pool().default_commodity)
|
||||
target = *pool().default_commodity;
|
||||
|
||||
optional<price_point_t> point =
|
||||
target ?
|
||||
pool().commodity_price_history.find_price(*this, *target, when, oldest) :
|
||||
|
|
@ -102,13 +130,13 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
|
|||
|
||||
if (pair) {
|
||||
if (base->price_map.size() > base_t::max_price_map_size) {
|
||||
DEBUG("commodity.prices.find",
|
||||
DEBUG("history.find",
|
||||
"price map has grown too large, clearing it by half");
|
||||
for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
|
||||
base->price_map.erase(base->price_map.begin());
|
||||
}
|
||||
|
||||
DEBUG("commodity.prices.find",
|
||||
DEBUG("history.find",
|
||||
"remembered: " << (point ? point->price : amount_t(0L)));
|
||||
base->price_map.insert
|
||||
(base_t::memoized_price_map::value_type(*pair, point));
|
||||
|
|
|
|||
|
|
@ -271,6 +271,10 @@ public:
|
|||
const bool reflexive = true);
|
||||
void remove_price(const datetime_t& date, commodity_t& commodity);
|
||||
|
||||
void map_prices(function<void(datetime_t, const amount_t&)> fn,
|
||||
const optional<datetime_t>& moment = none,
|
||||
const optional<datetime_t>& _oldest = none);
|
||||
|
||||
optional<price_point_t>
|
||||
find_price(const optional<commodity_t&>& commodity = none,
|
||||
const optional<datetime_t>& moment = none,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "report.h"
|
||||
#include "compare.h"
|
||||
#include "pool.h"
|
||||
#include "history.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -688,6 +689,27 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct create_price_xact {
|
||||
post_t& post;
|
||||
const date_t& current;
|
||||
price_map_t& all_prices;
|
||||
|
||||
create_price_xact(post_t& _post, const date_t& _current,
|
||||
price_map_t& _all_prices)
|
||||
: post(_post), current(_current), all_prices(_all_prices) {}
|
||||
|
||||
void operator()(datetime_t& date, const amount_t& price) {
|
||||
if (date.date() > post.value_date() && date.date() < current) {
|
||||
DEBUG("filters.revalued",
|
||||
post.value_date() << " < " << date << " < " << current);
|
||||
DEBUG("filters.revalued", "inserting " << price << " at " << date);
|
||||
all_prices.insert(price_map_t::value_type(date, price));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void changed_value_posts::output_intermediate_prices(post_t& post,
|
||||
const date_t& current)
|
||||
{
|
||||
|
|
@ -754,38 +776,17 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
|
|||
// fall through...
|
||||
|
||||
case value_t::BALANCE: {
|
||||
#if 0
|
||||
// jww (2012-03-04): TODO
|
||||
commodity_t::history_map all_prices;
|
||||
price_map_t all_prices;
|
||||
|
||||
foreach (const balance_t::amounts_map::value_type& amt_comm,
|
||||
display_total.as_balance().amounts) {
|
||||
if (optional<commodity_t::varied_history_t&> hist =
|
||||
amt_comm.first->varied_history()) {
|
||||
foreach
|
||||
(const commodity_t::history_by_commodity_map::value_type& comm_hist,
|
||||
hist->histories) {
|
||||
foreach (const commodity_t::history_map::value_type& price,
|
||||
comm_hist.second.prices) {
|
||||
if (price.first.date() > post.value_date() &&
|
||||
price.first.date() < current) {
|
||||
DEBUG("filters.revalued", post.value_date() << " < "
|
||||
<< price.first.date() << " < " << current);
|
||||
DEBUG("filters.revalued", "inserting "
|
||||
<< price.second << " at " << price.first.date());
|
||||
all_prices.insert(price);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
display_total.as_balance().amounts)
|
||||
amt_comm.first->map_prices(create_price_xact(post, current, all_prices));
|
||||
|
||||
// Choose the last price from each day as the price to use
|
||||
typedef std::map<const date_t, bool> date_map;
|
||||
date_map pricing_dates;
|
||||
|
||||
BOOST_REVERSE_FOREACH
|
||||
(const commodity_t::history_map::value_type& price, all_prices) {
|
||||
BOOST_REVERSE_FOREACH(const price_map_t::value_type& price, all_prices) {
|
||||
// This insert will fail if a later price has already been inserted
|
||||
// for that date.
|
||||
DEBUG("filters.revalued",
|
||||
|
|
@ -799,7 +800,6 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
|
|||
output_revaluation(post, price.first);
|
||||
last_total = repriced_total;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
189
src/history.cc
189
src/history.cc
|
|
@ -67,6 +67,9 @@ void commodity_history_t::add_price(const commodity_t& source,
|
|||
if (! result.second) {
|
||||
// There is already an entry for this moment, so update it
|
||||
(*result.first).second = price;
|
||||
} else {
|
||||
last_reftime = none; // invalidate the FGraph cache
|
||||
last_oldest = none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,64 +85,128 @@ void commodity_history_t::remove_price(const commodity_t& source,
|
|||
|
||||
// jww (2012-03-04): If it fails, should we give a warning?
|
||||
prices.erase(date);
|
||||
|
||||
last_reftime = none; // invalidate the FGraph cache
|
||||
last_oldest = none;
|
||||
}
|
||||
|
||||
optional<price_point_t>
|
||||
commodity_history_t::find_price(const commodity_t& source,
|
||||
const datetime_t& moment,
|
||||
const optional<datetime_t>& oldest)
|
||||
void commodity_history_t::map_prices(function<void(datetime_t,
|
||||
const amount_t&)> fn,
|
||||
const commodity_t& source,
|
||||
const datetime_t& moment,
|
||||
const optional<datetime_t>& _oldest)
|
||||
{
|
||||
vertex_descriptor sv = vertex(*source.graph_index(), price_graph);
|
||||
|
||||
// Filter out edges which came into being after the reference time
|
||||
FGraph fg(price_graph,
|
||||
recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap>
|
||||
(get(edge_weight, price_graph), pricemap, ratiomap,
|
||||
moment, oldest));
|
||||
|
||||
datetime_t most_recent = moment;
|
||||
amount_t price;
|
||||
reftime = moment;
|
||||
oldest = _oldest;
|
||||
|
||||
graph_traits<FGraph>::adjacency_iterator f_vi, f_vend;
|
||||
for (tie(f_vi, f_vend) = adjacent_vertices(sv, fg); f_vi != f_vend; ++f_vi) {
|
||||
std::pair<Graph::edge_descriptor, bool> edgePair = edge(sv, *f_vi, fg);
|
||||
Graph::edge_descriptor edge = edgePair.first;
|
||||
|
||||
const price_map_t& prices(get(ratiomap, edge));
|
||||
|
||||
foreach (const price_map_t::value_type& pair, prices) {
|
||||
const datetime_t& when(pair.first);
|
||||
|
||||
if ((! _oldest || when >= *_oldest) && when <= moment) {
|
||||
if (pair.second.commodity() == source) {
|
||||
amount_t price(pair.second);
|
||||
price.in_place_invert();
|
||||
if (source == *get(namemap, sv))
|
||||
price.set_commodity(const_cast<commodity_t&>(*get(namemap, *f_vi)));
|
||||
else
|
||||
price.set_commodity(const_cast<commodity_t&>(*get(namemap, sv)));
|
||||
}
|
||||
fn(when, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optional<price_point_t>
|
||||
commodity_history_t::find_price(const commodity_t& source,
|
||||
const datetime_t& moment,
|
||||
const optional<datetime_t>& _oldest)
|
||||
{
|
||||
vertex_descriptor sv = vertex(*source.graph_index(), price_graph);
|
||||
|
||||
DEBUG("history.find", "sv commodity = " << get(namemap, sv)->symbol());
|
||||
#if defined(DEBUG_ON)
|
||||
if (source.has_flags(COMMODITY_PRIMARY))
|
||||
DEBUG("history.find", "sv commodity is primary");
|
||||
#endif
|
||||
DEBUG("history.find", "tv commodity = none ");
|
||||
|
||||
datetime_t most_recent = moment;
|
||||
amount_t price;
|
||||
|
||||
reftime = moment;
|
||||
oldest = _oldest;
|
||||
|
||||
graph_traits<FGraph>::adjacency_iterator f_vi, f_vend;
|
||||
for (tie(f_vi, f_vend) = adjacent_vertices(sv, fg); f_vi != f_vend; ++f_vi) {
|
||||
std::pair<Graph::edge_descriptor, bool> edgePair = edge(sv, *f_vi, fg);
|
||||
Graph::edge_descriptor edge = edgePair.first;
|
||||
|
||||
DEBUG("history.find", "u commodity = " << get(namemap, sv)->symbol());
|
||||
DEBUG("history.find", "v commodity = " << get(namemap, *f_vi)->symbol());
|
||||
|
||||
const price_point_t& point(get(pricemap, edge));
|
||||
|
||||
if (price.is_null() || point.when > most_recent) {
|
||||
most_recent = point.when;
|
||||
price = point.price;
|
||||
}
|
||||
|
||||
DEBUG("history.find", "price was = " << price.unrounded());
|
||||
|
||||
if (price.commodity() == source) {
|
||||
price.in_place_invert();
|
||||
if (source == *get(namemap, sv))
|
||||
price.set_commodity(const_cast<commodity_t&>(*get(namemap, *f_vi)));
|
||||
else
|
||||
price.set_commodity(const_cast<commodity_t&>(*get(namemap, sv)));
|
||||
}
|
||||
|
||||
DEBUG("history.find", "price is = " << price.unrounded());
|
||||
}
|
||||
|
||||
if (price.is_null())
|
||||
last_reftime = reftime; // invalidate the FGraph cache
|
||||
last_oldest = oldest;
|
||||
|
||||
if (price.is_null()) {
|
||||
DEBUG("history.find", "there is no final price");
|
||||
return none;
|
||||
else
|
||||
} else {
|
||||
DEBUG("history.find", "final price is = " << price.unrounded());
|
||||
return price_point_t(most_recent, price);
|
||||
}
|
||||
}
|
||||
|
||||
optional<price_point_t>
|
||||
commodity_history_t::find_price(const commodity_t& source,
|
||||
const commodity_t& target,
|
||||
const datetime_t& moment,
|
||||
const optional<datetime_t>& oldest)
|
||||
const optional<datetime_t>& _oldest)
|
||||
{
|
||||
vertex_descriptor sv = vertex(*source.graph_index(), price_graph);
|
||||
vertex_descriptor tv = vertex(*target.graph_index(), price_graph);
|
||||
|
||||
// Filter out edges which came into being after the reference time
|
||||
FGraph fg(price_graph,
|
||||
recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap>
|
||||
(get(edge_weight, price_graph), pricemap, ratiomap,
|
||||
moment, oldest));
|
||||
|
||||
DEBUG("history.find", "sv commodity = " << get(namemap, sv)->symbol());
|
||||
DEBUG("history.find", "tv commodity = " << get(namemap, tv)->symbol());
|
||||
|
||||
std::vector<vertex_descriptor> predecessors(num_vertices(fg));
|
||||
std::vector<long> distances(num_vertices(fg));
|
||||
|
||||
PredecessorMap predecessorMap(&predecessors[0]);
|
||||
DistanceMap distanceMap(&distances[0]);
|
||||
|
||||
reftime = moment;
|
||||
oldest = _oldest;
|
||||
|
||||
dijkstra_shortest_paths(fg, /* start= */ sv,
|
||||
predecessor_map(predecessorMap)
|
||||
.distance_map(distanceMap)
|
||||
|
|
@ -149,7 +216,7 @@ commodity_history_t::find_price(const commodity_t& source,
|
|||
datetime_t least_recent = moment;
|
||||
amount_t price;
|
||||
|
||||
FNameMap ptrs = get(vertex_name, fg);
|
||||
const commodity_t * last_target = ⌖
|
||||
|
||||
vertex_descriptor v = tv;
|
||||
for (vertex_descriptor u = predecessorMap[v];
|
||||
|
|
@ -161,73 +228,85 @@ commodity_history_t::find_price(const commodity_t& source,
|
|||
|
||||
const price_point_t& point(get(pricemap, edge));
|
||||
|
||||
const commodity_t * last_source = &source;
|
||||
|
||||
bool first_run = false;
|
||||
if (price.is_null()) {
|
||||
least_recent = point.when;
|
||||
price = point.price;
|
||||
first_run = true;
|
||||
}
|
||||
else if (point.when < least_recent) {
|
||||
least_recent = point.when;
|
||||
}
|
||||
|
||||
DEBUG("history.find", "u commodity = " << get(ptrs, u)->symbol());
|
||||
DEBUG("history.find", "v commodity = " << get(ptrs, v)->symbol());
|
||||
DEBUG("history.find", "last source = " << last_source->symbol());
|
||||
DEBUG("history.find", "u commodity = " << get(namemap, u)->symbol());
|
||||
DEBUG("history.find", "v commodity = " << get(namemap, v)->symbol());
|
||||
DEBUG("history.find", "last target = " << last_target->symbol());
|
||||
|
||||
// Determine which direction we are converting in
|
||||
amount_t pprice(point.price);
|
||||
DEBUG("history.find", "pprice = " << pprice);
|
||||
DEBUG("history.find", "pprice = " << pprice.unrounded());
|
||||
|
||||
DEBUG("history.find", "price was = " << price);
|
||||
if (! first_run) {
|
||||
if (pprice.commodity() == *last_source)
|
||||
DEBUG("history.find", "price was = " << price.unrounded());
|
||||
if (pprice.commodity() != *last_target)
|
||||
price *= pprice.inverted();
|
||||
else
|
||||
price *= pprice;
|
||||
}
|
||||
else if (price.commodity() == *last_source) {
|
||||
price = price.inverted();
|
||||
else if (pprice.commodity() != *last_target) {
|
||||
price = pprice.inverted();
|
||||
}
|
||||
DEBUG("history.find", "price is = " << price);
|
||||
else {
|
||||
price = pprice;
|
||||
}
|
||||
DEBUG("history.find", "price is = " << price.unrounded());
|
||||
|
||||
if (*last_source == *get(ptrs, v))
|
||||
last_source = get(ptrs, u);
|
||||
if (*last_target == *get(namemap, v))
|
||||
last_target = get(namemap, u);
|
||||
else
|
||||
last_source = get(ptrs, v);
|
||||
last_target = get(namemap, v);
|
||||
|
||||
DEBUG("history.find", "last target now = " << last_target->symbol());
|
||||
}
|
||||
|
||||
price.set_commodity(const_cast<commodity_t&>(target));
|
||||
DEBUG("history.find", "final price is = " << price);
|
||||
last_reftime = reftime; // invalidate the FGraph cache
|
||||
last_oldest = oldest;
|
||||
|
||||
if (price.is_null())
|
||||
if (price.is_null()) {
|
||||
DEBUG("history.find", "there is no final price");
|
||||
return none;
|
||||
else
|
||||
} else {
|
||||
price.set_commodity(const_cast<commodity_t&>(target));
|
||||
DEBUG("history.find", "final price is = " << price.unrounded());
|
||||
|
||||
return price_point_t(least_recent, price);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Name>
|
||||
class label_writer {
|
||||
public:
|
||||
label_writer(Name _name) : name(_name) {}
|
||||
|
||||
template <class VertexOrEdge>
|
||||
void operator()(std::ostream& out, const VertexOrEdge& v) const {
|
||||
out << "[label=\"" << name[v]->symbol() << "\"]";
|
||||
}
|
||||
|
||||
private:
|
||||
Name name;
|
||||
};
|
||||
|
||||
void commodity_history_t::print_map(std::ostream& out,
|
||||
const optional<datetime_t>& moment)
|
||||
{
|
||||
#if 0
|
||||
dynamic_properties p;
|
||||
p.property("label", get(edge_weight, price_graph));
|
||||
p.property("weight", get(edge_weight, price_graph));
|
||||
p.property("node_id", get(vertex_index, price_graph));
|
||||
|
||||
if (moment) {
|
||||
// Filter out edges which came into being after the reference time
|
||||
FGraph fg(price_graph,
|
||||
recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap>
|
||||
(get(edge_weight, price_graph), pricemap, ratiomap,
|
||||
*moment));
|
||||
write_graphviz(out, fg, p);
|
||||
reftime = *moment;
|
||||
write_graphviz(out, fg, label_writer<FNameMap>(namemap));
|
||||
last_reftime = reftime;
|
||||
} else {
|
||||
write_graphviz(out, price_graph, p);
|
||||
write_graphviz(out, price_graph,
|
||||
label_writer<NameMap>(get(vertex_name, price_graph)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -70,36 +70,50 @@ public:
|
|||
PricePointMap price_point;
|
||||
PriceRatioMap ratios;
|
||||
|
||||
datetime_t reftime;
|
||||
optional<datetime_t> oldest;
|
||||
datetime_t * reftime;
|
||||
optional<datetime_t> * last_reftime;
|
||||
optional<datetime_t> * oldest;
|
||||
optional<datetime_t> * last_oldest;
|
||||
|
||||
recent_edge_weight() { }
|
||||
recent_edge_weight(EdgeWeightMap _weight,
|
||||
PricePointMap _price_point,
|
||||
PriceRatioMap _ratios,
|
||||
datetime_t _reftime,
|
||||
const optional<datetime_t>& _oldest = none)
|
||||
recent_edge_weight(EdgeWeightMap _weight,
|
||||
PricePointMap _price_point,
|
||||
PriceRatioMap _ratios,
|
||||
datetime_t * _reftime,
|
||||
optional<datetime_t> * _last_reftime,
|
||||
optional<datetime_t> * _oldest,
|
||||
optional<datetime_t> * _last_oldest)
|
||||
: weight(_weight), price_point(_price_point), ratios(_ratios),
|
||||
reftime(_reftime), oldest(_oldest) { }
|
||||
reftime(_reftime), last_reftime(_last_reftime),
|
||||
oldest(_oldest), last_oldest(_last_oldest) { }
|
||||
|
||||
template <typename Edge>
|
||||
bool operator()(const Edge& e) const
|
||||
{
|
||||
const price_map_t& prices(get(ratios, e));
|
||||
if (prices.empty())
|
||||
return false;
|
||||
if (*last_reftime && *reftime == **last_reftime &&
|
||||
*oldest == *last_oldest)
|
||||
return get(weight, e) != std::numeric_limits<std::size_t>::max();
|
||||
|
||||
price_map_t::const_iterator low = prices.upper_bound(reftime);
|
||||
const price_map_t& prices(get(ratios, e));
|
||||
if (prices.empty()) {
|
||||
put(weight, e, std::numeric_limits<std::size_t>::max());
|
||||
return false;
|
||||
}
|
||||
|
||||
price_map_t::const_iterator low = prices.upper_bound(*reftime);
|
||||
if (low != prices.end() && low == prices.begin()) {
|
||||
put(weight, e, std::numeric_limits<std::size_t>::max());
|
||||
return false;
|
||||
} else {
|
||||
--low;
|
||||
assert(((*low).first <= reftime));
|
||||
assert(((*low).first <= *reftime));
|
||||
|
||||
if (oldest && (*low).first < *oldest)
|
||||
if (*oldest && (*low).first < **oldest) {
|
||||
put(weight, e, std::numeric_limits<std::size_t>::max());
|
||||
return false;
|
||||
}
|
||||
|
||||
long secs = (reftime - (*low).first).total_seconds();
|
||||
long secs = (*reftime - (*low).first).total_seconds();
|
||||
assert(secs >= 0);
|
||||
|
||||
put(weight, e, secs);
|
||||
|
|
@ -160,10 +174,24 @@ public:
|
|||
PriceRatioMap> > FGraph;
|
||||
typedef property_map<FGraph, vertex_name_t>::type FNameMap;
|
||||
|
||||
FGraph fg;
|
||||
FNameMap namemap;
|
||||
|
||||
// jww (2012-03-05): Prevents threading
|
||||
mutable datetime_t reftime;
|
||||
mutable optional<datetime_t> last_reftime;
|
||||
mutable optional<datetime_t> oldest;
|
||||
mutable optional<datetime_t> last_oldest;
|
||||
|
||||
commodity_history_t()
|
||||
: indexmap(get(vertex_index, price_graph)),
|
||||
pricemap(get(edge_price_point, price_graph)),
|
||||
ratiomap(get(edge_price_ratio, price_graph)) {}
|
||||
ratiomap(get(edge_price_ratio, price_graph)),
|
||||
fg(price_graph,
|
||||
recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap>
|
||||
(get(edge_weight, price_graph), pricemap, ratiomap,
|
||||
&reftime, &last_reftime, &oldest, &last_oldest)),
|
||||
namemap(get(vertex_name, fg)) {}
|
||||
|
||||
void add_commodity(commodity_t& comm);
|
||||
|
||||
|
|
@ -174,6 +202,11 @@ public:
|
|||
const commodity_t& target,
|
||||
const datetime_t& date);
|
||||
|
||||
void map_prices(function<void(datetime_t, const amount_t&)> fn,
|
||||
const commodity_t& source,
|
||||
const datetime_t& moment,
|
||||
const optional<datetime_t>& _oldest = none);
|
||||
|
||||
optional<price_point_t>
|
||||
find_price(const commodity_t& source,
|
||||
const datetime_t& moment,
|
||||
|
|
|
|||
104
src/iterators.cc
104
src/iterators.cc
|
|
@ -75,6 +75,55 @@ void journal_posts_iterator::increment()
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct create_price_xact {
|
||||
account_t * account;
|
||||
temporaries_t& temps;
|
||||
xacts_list& xact_temps;
|
||||
|
||||
std::map<string, xact_t *> xacts_by_commodity;
|
||||
|
||||
create_price_xact(account_t * _account, temporaries_t& _temps,
|
||||
xacts_list& _xact_temps)
|
||||
: account(_account), temps(_temps), xact_temps(_xact_temps) {}
|
||||
|
||||
void operator()(datetime_t& date, const amount_t& price) {
|
||||
xact_t * xact;
|
||||
string symbol = price.commodity().symbol();
|
||||
|
||||
std::map<string, xact_t *>::iterator i =
|
||||
xacts_by_commodity.find(symbol);
|
||||
if (i != xacts_by_commodity.end()) {
|
||||
xact = (*i).second;
|
||||
} else {
|
||||
xact = &temps.create_xact();
|
||||
xact_temps.push_back(xact);
|
||||
xact->payee = symbol;
|
||||
xact->_date = date.date();
|
||||
xacts_by_commodity.insert
|
||||
(std::pair<string, xact_t *>(symbol, xact));
|
||||
}
|
||||
|
||||
bool post_already_exists = false;
|
||||
|
||||
foreach (post_t * post, xact->posts) {
|
||||
if (post->date() == date.date() && post->amount == price) {
|
||||
post_already_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! post_already_exists) {
|
||||
post_t& temp = temps.create_post(*xact, account);
|
||||
temp._date = date.date();
|
||||
temp.amount = price;
|
||||
|
||||
temp.xdata().datetime = date;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void posts_commodities_iterator::reset(journal_t& journal)
|
||||
{
|
||||
journal_posts.reset(journal);
|
||||
|
|
@ -88,57 +137,10 @@ void posts_commodities_iterator::reset(journal_t& journal)
|
|||
commodities.insert(&comm);
|
||||
}
|
||||
|
||||
std::map<string, xact_t *> xacts_by_commodity;
|
||||
|
||||
#if 0
|
||||
// jww (2012-03-04): TODO
|
||||
foreach (commodity_t * comm, commodities) {
|
||||
if (optional<commodity_t::varied_history_t&> history =
|
||||
comm->varied_history()) {
|
||||
account_t * account = journal.master->find_account(comm->symbol());
|
||||
|
||||
foreach (commodity_t::history_by_commodity_map::value_type& pair,
|
||||
history->histories) {
|
||||
foreach (commodity_t::history_map::value_type& hpair,
|
||||
pair.second.prices) {
|
||||
xact_t * xact;
|
||||
string symbol = hpair.second.commodity().symbol();
|
||||
|
||||
std::map<string, xact_t *>::iterator i =
|
||||
xacts_by_commodity.find(symbol);
|
||||
if (i != xacts_by_commodity.end()) {
|
||||
xact = (*i).second;
|
||||
} else {
|
||||
xact = &temps.create_xact();
|
||||
xact_temps.push_back(xact);
|
||||
xact->payee = symbol;
|
||||
xact->_date = hpair.first.date();
|
||||
xacts_by_commodity.insert
|
||||
(std::pair<string, xact_t *>(symbol, xact));
|
||||
}
|
||||
|
||||
bool post_already_exists = false;
|
||||
|
||||
foreach (post_t * post, xact->posts) {
|
||||
if (post->_date == hpair.first.date() &&
|
||||
post->amount == hpair.second) {
|
||||
post_already_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! post_already_exists) {
|
||||
post_t& temp = temps.create_post(*xact, account);
|
||||
temp._date = hpair.first.date();
|
||||
temp.amount = hpair.second;
|
||||
|
||||
temp.xdata().datetime = hpair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
foreach (commodity_t * comm, commodities)
|
||||
comm->map_prices
|
||||
(create_price_xact(journal.master->find_account(comm->symbol()),
|
||||
temps, xact_temps));
|
||||
|
||||
xacts.reset(xact_temps.begin(), xact_temps.end());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
P 1989/01/15 12:00:00 GAL $3
|
||||
|
||||
1990/01/01 Payee
|
||||
Expenses:Gas 100 GAL {=$2}
|
||||
Liabilities:MasterCard $-200
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ test -f $sourcepath/src/amount.h reg -> 7
|
|||
__ERROR__
|
||||
While parsing file "$sourcepath/src/amount.h", line 66:
|
||||
Error: No quantity specified for amount
|
||||
While parsing file "$sourcepath/src/amount.h", line 726:
|
||||
While parsing file "$sourcepath/src/amount.h", line 731:
|
||||
Error: Invalid date/time: line amount_t amoun
|
||||
While parsing file "$sourcepath/src/amount.h", line 732:
|
||||
While parsing file "$sourcepath/src/amount.h", line 737:
|
||||
Error: Invalid date/time: line string amount_
|
||||
While parsing file "$sourcepath/src/amount.h", line 738:
|
||||
While parsing file "$sourcepath/src/amount.h", line 743:
|
||||
Error: Invalid date/time: line string amount_
|
||||
While parsing file "$sourcepath/src/amount.h", line 744:
|
||||
While parsing file "$sourcepath/src/amount.h", line 749:
|
||||
Error: Invalid date/time: line string amount_
|
||||
While parsing file "$sourcepath/src/amount.h", line 750:
|
||||
While parsing file "$sourcepath/src/amount.h", line 755:
|
||||
Error: Invalid date/time: line std::ostream&
|
||||
While parsing file "$sourcepath/src/amount.h", line 757:
|
||||
While parsing file "$sourcepath/src/amount.h", line 762:
|
||||
Error: Invalid date/time: line std::istream&
|
||||
end test
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(testPriceHistory)
|
|||
|
||||
amt = x1.value(CURRENT_TIME(), euro);
|
||||
BOOST_CHECK(amt);
|
||||
BOOST_CHECK_EQUAL(string("EUR 1366.87"), amt->rounded().to_string());
|
||||
BOOST_CHECK_EQUAL(string("EUR 1787.50"), amt->rounded().to_string());
|
||||
|
||||
// Add a newer Euro pricing
|
||||
aapl.add_price(jan17_07, amount_t("EUR 23.00"));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue