Added code to recursively search for a price in a given commodity.
This commit is contained in:
parent
6007e3cbfe
commit
b5386b2534
2 changed files with 111 additions and 27 deletions
106
src/commodity.cc
106
src/commodity.cc
|
|
@ -46,6 +46,9 @@ namespace ledger {
|
||||||
void commodity_t::base_t::history_t::add_price(const datetime_t& date,
|
void commodity_t::base_t::history_t::add_price(const datetime_t& date,
|
||||||
const amount_t& price)
|
const amount_t& price)
|
||||||
{
|
{
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
"add_price: " << date << ", " << price);
|
||||||
|
|
||||||
history_map::iterator i = prices.find(date);
|
history_map::iterator i = prices.find(date);
|
||||||
if (i != prices.end()) {
|
if (i != prices.end()) {
|
||||||
(*i).second = price;
|
(*i).second = price;
|
||||||
|
|
@ -58,6 +61,8 @@ void commodity_t::base_t::history_t::add_price(const datetime_t& date,
|
||||||
|
|
||||||
bool commodity_t::base_t::history_t::remove_price(const datetime_t& date)
|
bool commodity_t::base_t::history_t::remove_price(const datetime_t& date)
|
||||||
{
|
{
|
||||||
|
DEBUG("commodity.prices", "remove_price: " << date);
|
||||||
|
|
||||||
history_map::size_type n = prices.erase(date);
|
history_map::size_type n = prices.erase(date);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -67,6 +72,9 @@ bool commodity_t::base_t::history_t::remove_price(const datetime_t& date)
|
||||||
void commodity_t::base_t::varied_history_t::add_price(const datetime_t& date,
|
void commodity_t::base_t::varied_history_t::add_price(const datetime_t& date,
|
||||||
const amount_t& price)
|
const amount_t& price)
|
||||||
{
|
{
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
"varied_add_price: " << date << ", " << price);
|
||||||
|
|
||||||
optional<history_t&> hist = history(price.commodity());
|
optional<history_t&> hist = history(price.commodity());
|
||||||
if (! hist) {
|
if (! hist) {
|
||||||
std::pair<history_by_commodity_map::iterator, bool> result
|
std::pair<history_by_commodity_map::iterator, bool> result
|
||||||
|
|
@ -82,8 +90,11 @@ void commodity_t::base_t::varied_history_t::add_price(const datetime_t& date,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool commodity_t::base_t::varied_history_t::remove_price(const datetime_t& date,
|
bool commodity_t::base_t::varied_history_t::remove_price(const datetime_t& date,
|
||||||
const commodity_t& comm)
|
commodity_t& comm)
|
||||||
{
|
{
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
"varied_remove_price: " << date << ", " << comm);
|
||||||
|
|
||||||
if (optional<history_t&> hist = history(comm))
|
if (optional<history_t&> hist = history(comm))
|
||||||
return hist->remove_price(date);
|
return hist->remove_price(date);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -95,19 +106,35 @@ commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment)
|
||||||
optional<datetime_t> age;
|
optional<datetime_t> age;
|
||||||
optional<amount_t> price;
|
optional<amount_t> price;
|
||||||
|
|
||||||
if (prices.size() == 0)
|
#if defined(DEBUG_ON)
|
||||||
|
if (moment) {
|
||||||
|
DEBUG("commodity.prices", "find_price: " << *moment);
|
||||||
|
} else {
|
||||||
|
DEBUG("commodity.prices", "find_price");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (prices.size() == 0) {
|
||||||
|
DEBUG("commodity.prices", " there are no prices in the history");
|
||||||
return none;
|
return none;
|
||||||
|
}
|
||||||
|
|
||||||
if (! moment) {
|
if (! moment) {
|
||||||
history_map::const_reverse_iterator r = prices.rbegin();
|
history_map::const_reverse_iterator r = prices.rbegin();
|
||||||
age = (*r).first;
|
age = (*r).first;
|
||||||
price = (*r).second;
|
price = (*r).second;
|
||||||
|
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
" returning most recent price: " << age << ", " << price);
|
||||||
} else {
|
} else {
|
||||||
history_map::const_iterator i = prices.lower_bound(*moment);
|
history_map::const_iterator i = prices.lower_bound(*moment);
|
||||||
if (i == prices.end()) {
|
if (i == prices.end()) {
|
||||||
history_map::const_reverse_iterator r = prices.rbegin();
|
history_map::const_reverse_iterator r = prices.rbegin();
|
||||||
age = (*r).first;
|
age = (*r).first;
|
||||||
price = (*r).second;
|
price = (*r).second;
|
||||||
|
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
" returning last price: " << age << ", " << price);
|
||||||
} else {
|
} else {
|
||||||
age = (*i).first;
|
age = (*i).first;
|
||||||
if (*moment != *age) {
|
if (*moment != *age) {
|
||||||
|
|
@ -121,6 +148,9 @@ commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment)
|
||||||
} else {
|
} else {
|
||||||
price = (*i).second;
|
price = (*i).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
" returning found price: " << age << ", " << price);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,25 +169,79 @@ commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment)
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
commodity_t::base_t::varied_history_t::find_price
|
commodity_t::base_t::varied_history_t::find_price
|
||||||
(const optional<const commodity_t&>& commodity,
|
(const optional<commodity_t&>& commodity,
|
||||||
const optional<datetime_t>& moment)
|
const optional<datetime_t>& moment)
|
||||||
{
|
{
|
||||||
return none;
|
optional<amount_t> amt;
|
||||||
|
|
||||||
|
#if defined(DEBUG_ON)
|
||||||
|
DEBUG("commodity.prices", "varied_find_price");
|
||||||
|
|
||||||
|
if (commodity)
|
||||||
|
DEBUG("commodity.prices", " looking for commodity '" << *commodity << "'");
|
||||||
|
else
|
||||||
|
DEBUG("commodity.prices", " looking for any commodity");
|
||||||
|
|
||||||
|
if (moment)
|
||||||
|
DEBUG("commodity.prices", " time index: " << *moment);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (optional<history_t&> hist = history(commodity)) {
|
||||||
|
DEBUG("commodity.prices", " found a history for the commodity");
|
||||||
|
|
||||||
|
amt = hist->find_price(moment);
|
||||||
|
|
||||||
|
#if defined(DEBUG_ON)
|
||||||
|
if (amt)
|
||||||
|
DEBUG("commodity.prices", " found price in that history: " << *amt);
|
||||||
|
else
|
||||||
|
DEBUG("commodity.prices", " found no price in that history");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either we couldn't find a history for the target commodity, or we
|
||||||
|
// couldn't find a price. In either case, search all histories known
|
||||||
|
// to this commodity for a price which we can calculate in terms of
|
||||||
|
// the goal commodity.
|
||||||
|
if (! amt && commodity) {
|
||||||
|
foreach (history_by_commodity_map::value_type hist, histories) {
|
||||||
|
commodity_t& comm(*hist.first);
|
||||||
|
|
||||||
|
DEBUG("commodity.prices",
|
||||||
|
" searching for price via commodity '" << comm << "'");
|
||||||
|
|
||||||
|
amt = comm.find_price(commodity, moment);
|
||||||
|
// jww (2008-09-24): look for the most recent match
|
||||||
|
|
||||||
|
#if defined(DEBUG_ON)
|
||||||
|
if (amt)
|
||||||
|
DEBUG("commodity.prices", " found price there: " << *amt);
|
||||||
|
else
|
||||||
|
DEBUG("commodity.prices", " found no price there");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return amt;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
commodity_t::base_t::varied_history_t::find_price
|
commodity_t::base_t::varied_history_t::find_price
|
||||||
(const std::vector<const commodity_t *>& commodities,
|
(const std::vector<commodity_t *>& commodities,
|
||||||
const optional<datetime_t>& moment)
|
const optional<datetime_t>& moment)
|
||||||
{
|
{
|
||||||
|
foreach (commodity_t * commodity, commodities) {
|
||||||
|
if (optional<amount_t> amt = find_price(*commodity, moment))
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<commodity_t::base_t::history_t&>
|
optional<commodity_t::base_t::history_t&>
|
||||||
commodity_t::base_t::varied_history_t::history
|
commodity_t::base_t::varied_history_t::history
|
||||||
(const optional<const commodity_t&>& commodity)
|
(const optional<commodity_t&>& commodity)
|
||||||
{
|
{
|
||||||
const commodity_t * comm = NULL;
|
commodity_t * comm = NULL;
|
||||||
if (! commodity) {
|
if (! commodity) {
|
||||||
if (histories.size() > 1)
|
if (histories.size() > 1)
|
||||||
// jww (2008-09-20): Document which option switch to use here
|
// jww (2008-09-20): Document which option switch to use here
|
||||||
|
|
@ -177,14 +261,14 @@ commodity_t::base_t::varied_history_t::history
|
||||||
|
|
||||||
optional<commodity_t::history_t&>
|
optional<commodity_t::history_t&>
|
||||||
commodity_t::base_t::varied_history_t::history
|
commodity_t::base_t::varied_history_t::history
|
||||||
(const std::vector<const commodity_t *>& commodities)
|
(const std::vector<commodity_t *>& commodities)
|
||||||
{
|
{
|
||||||
// This function differs from the single commodity case avoid in that
|
// This function differs from the single commodity case avoid in that
|
||||||
// 'commodities' represents a list of preferred valuation commodities.
|
// 'commodities' represents a list of preferred valuation commodities.
|
||||||
// If no price can be located in terms of the first commodity, then
|
// If no price can be located in terms of the first commodity, then
|
||||||
// the second is chosen, etc.
|
// the second is chosen, etc.
|
||||||
|
|
||||||
foreach (const commodity_t * commodity, commodities) {
|
foreach (commodity_t * commodity, commodities) {
|
||||||
if (optional<history_t&> hist = history(*commodity))
|
if (optional<history_t&> hist = history(*commodity))
|
||||||
return hist;
|
return hist;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,26 +77,26 @@ public:
|
||||||
optional<amount_t> find_price(const optional<datetime_t>& moment = none);
|
optional<amount_t> find_price(const optional<datetime_t>& moment = none);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const commodity_t *, history_t> history_by_commodity_map;
|
typedef std::map<commodity_t *, history_t> history_by_commodity_map;
|
||||||
|
|
||||||
struct varied_history_t
|
struct varied_history_t
|
||||||
{
|
{
|
||||||
history_by_commodity_map histories;
|
history_by_commodity_map histories;
|
||||||
|
|
||||||
void add_price(const datetime_t& date, const amount_t& price);
|
void add_price(const datetime_t& date, const amount_t& price);
|
||||||
bool remove_price(const datetime_t& date, const commodity_t& commodity);
|
bool remove_price(const datetime_t& date, commodity_t& commodity);
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
find_price(const optional<const commodity_t&>& commodity = none,
|
find_price(const optional<commodity_t&>& commodity = none,
|
||||||
const optional<datetime_t>& moment = none);
|
const optional<datetime_t>& moment = none);
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
find_price(const std::vector<const commodity_t *>& commodities,
|
find_price(const std::vector<commodity_t *>& commodities,
|
||||||
const optional<datetime_t>& moment = none);
|
const optional<datetime_t>& moment = none);
|
||||||
|
|
||||||
optional<history_t&>
|
optional<history_t&>
|
||||||
history(const optional<const commodity_t&>& commodity = none);
|
history(const optional<commodity_t&>& commodity = none);
|
||||||
optional<history_t&>
|
optional<history_t&>
|
||||||
history(const std::vector<const commodity_t *>& commodities);
|
history(const std::vector<commodity_t *>& commodities);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define COMMODITY_STYLE_DEFAULTS 0x00
|
#define COMMODITY_STYLE_DEFAULTS 0x00
|
||||||
|
|
@ -230,12 +230,12 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<history_t&>
|
optional<history_t&>
|
||||||
history(const optional<const commodity_t&>& commodity);
|
history(const optional<commodity_t&>& commodity);
|
||||||
optional<history_t&>
|
optional<history_t&>
|
||||||
history(const std::vector<const commodity_t *>& commodities);
|
history(const std::vector<commodity_t *>& commodities);
|
||||||
|
|
||||||
optional<history_t>
|
optional<history_t>
|
||||||
find_price(const commodity_t& commodity,
|
find_price(commodity_t& commodity,
|
||||||
const optional<datetime_t>& moment,
|
const optional<datetime_t>& moment,
|
||||||
std::vector<bool *>& bools);
|
std::vector<bool *>& bools);
|
||||||
|
|
||||||
|
|
@ -249,23 +249,23 @@ public:
|
||||||
|
|
||||||
base->varied_history->add_price(date, price);
|
base->varied_history->add_price(date, price);
|
||||||
}
|
}
|
||||||
bool remove_price(const datetime_t& date, const commodity_t& commodity) {
|
bool remove_price(const datetime_t& date, commodity_t& commodity) {
|
||||||
if (base->varied_history)
|
if (base->varied_history)
|
||||||
base->varied_history->remove_price(date, commodity);
|
base->varied_history->remove_price(date, commodity);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
find_price(const optional<const commodity_t&>& commodity = none,
|
find_price(const optional<commodity_t&>& commodity = none,
|
||||||
const optional<datetime_t>& moment = none) {
|
const optional<datetime_t>& moment = none) {
|
||||||
if (base->varied_history)
|
if (base->varied_history)
|
||||||
return base->varied_history->find_price(commodity, moment);
|
return base->varied_history->find_price(commodity, moment);
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
find_price(const std::vector<const commodity_t *>& commodities,
|
find_price(const std::vector<commodity_t *>& commodities,
|
||||||
const optional<datetime_t>& moment = none) {
|
const optional<datetime_t>& moment = none) {
|
||||||
if (base->varied_history)
|
if (base->varied_history)
|
||||||
return base->varied_history->find_price(commodities, moment);
|
return base->varied_history->find_price(commodities, moment);
|
||||||
return none;
|
return none;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue