A further simplification of -V and -X
With -X COMM, all values are computed in terms of COMM, regardless. With -V, only secondary commodities will ever be computed, never primaries. Further, if a secondary commodities has an associated price, the valuation is done in terms of that price's commodity.
This commit is contained in:
parent
ae8ab81062
commit
be6cef93c4
14 changed files with 64 additions and 68 deletions
|
|
@ -724,8 +724,7 @@ void amount_t::in_place_unreduce()
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
amount_t::value(const bool primary_only,
|
amount_t::value(const optional<datetime_t>& moment,
|
||||||
const optional<datetime_t>& moment,
|
|
||||||
const optional<commodity_t&>& in_terms_of) const
|
const optional<commodity_t&>& in_terms_of) const
|
||||||
{
|
{
|
||||||
if (quantity) {
|
if (quantity) {
|
||||||
|
|
@ -740,28 +739,33 @@ amount_t::value(const bool primary_only,
|
||||||
"amount_t::value: in_terms_of = " << in_terms_of->symbol());
|
"amount_t::value: in_terms_of = " << in_terms_of->symbol());
|
||||||
#endif
|
#endif
|
||||||
if (has_commodity() &&
|
if (has_commodity() &&
|
||||||
(! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) {
|
(in_terms_of || ! commodity().has_flags(COMMODITY_PRIMARY))) {
|
||||||
if (in_terms_of &&
|
optional<price_point_t> point;
|
||||||
commodity().referent() == in_terms_of->referent()) {
|
optional<commodity_t&> comm(in_terms_of);
|
||||||
|
|
||||||
|
if (comm && commodity().referent() == comm->referent()) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
else if (has_annotation() && annotation().price &&
|
else if (has_annotation() && annotation().price) {
|
||||||
annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
|
if (annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
|
||||||
amount_t price(*annotation().price);
|
point = price_point_t();
|
||||||
price.multiply(*this, true);
|
point->price = *annotation().price;
|
||||||
price.in_place_round();
|
}
|
||||||
return price;
|
else if (! in_terms_of) {
|
||||||
|
comm = annotation().price->commodity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! point) {
|
||||||
|
point = commodity().find_price(comm, moment);
|
||||||
|
// Whether a price was found or not, check whether we should attempt
|
||||||
|
// to download a price from the Internet. This is done if (a) no
|
||||||
|
// price was found, or (b) the price is "stale" according to the
|
||||||
|
// setting of --price-exp.
|
||||||
|
if (point)
|
||||||
|
point = commodity().check_for_updated_price(point, moment, comm);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
optional<price_point_t> point =
|
|
||||||
commodity().find_price(in_terms_of, moment);
|
|
||||||
|
|
||||||
// Whether a price was found or not, check whether we should
|
|
||||||
// attempt to download a price from the Internet. This is done
|
|
||||||
// if (a) no price was found, or (b) the price is "stale"
|
|
||||||
// according to the setting of --price-exp.
|
|
||||||
point = commodity().check_for_updated_price(point, moment,
|
|
||||||
in_terms_of);
|
|
||||||
if (point) {
|
if (point) {
|
||||||
amount_t price(point->price);
|
amount_t price(point->price);
|
||||||
price.multiply(*this, true);
|
price.multiply(*this, true);
|
||||||
|
|
@ -769,7 +773,6 @@ amount_t::value(const bool primary_only,
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw_(amount_error,
|
throw_(amount_error,
|
||||||
_("Cannot determine value of an uninitialized amount"));
|
_("Cannot determine value of an uninitialized amount"));
|
||||||
|
|
|
||||||
|
|
@ -399,8 +399,7 @@ public:
|
||||||
$100.00.
|
$100.00.
|
||||||
*/
|
*/
|
||||||
optional<amount_t>
|
optional<amount_t>
|
||||||
value(const bool primary_only = true,
|
value(const optional<datetime_t>& moment = none,
|
||||||
const optional<datetime_t>& moment = none,
|
|
||||||
const optional<commodity_t&>& in_terms_of = none) const;
|
const optional<commodity_t&>& in_terms_of = none) const;
|
||||||
|
|
||||||
amount_t price() const;
|
amount_t price() const;
|
||||||
|
|
|
||||||
|
|
@ -185,16 +185,14 @@ balance_t& balance_t::operator/=(const amount_t& amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<balance_t>
|
optional<balance_t>
|
||||||
balance_t::value(const bool primary_only,
|
balance_t::value(const optional<datetime_t>& moment,
|
||||||
const optional<datetime_t>& moment,
|
|
||||||
const optional<commodity_t&>& in_terms_of) const
|
const optional<commodity_t&>& in_terms_of) const
|
||||||
{
|
{
|
||||||
balance_t temp;
|
balance_t temp;
|
||||||
bool resolved = false;
|
bool resolved = false;
|
||||||
|
|
||||||
foreach (const amounts_map::value_type& pair, amounts) {
|
foreach (const amounts_map::value_type& pair, amounts) {
|
||||||
if (optional<amount_t> val = pair.second.value(primary_only, moment,
|
if (optional<amount_t> val = pair.second.value(moment, in_terms_of)) {
|
||||||
in_terms_of)) {
|
|
||||||
temp += *val;
|
temp += *val;
|
||||||
resolved = true;
|
resolved = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -384,8 +384,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<balance_t>
|
optional<balance_t>
|
||||||
value(const bool primary_only = false,
|
value(const optional<datetime_t>& moment = none,
|
||||||
const optional<datetime_t>& moment = none,
|
|
||||||
const optional<commodity_t&>& in_terms_of = none) const;
|
const optional<commodity_t&>& in_terms_of = none) const;
|
||||||
|
|
||||||
balance_t price() const;
|
balance_t price() const;
|
||||||
|
|
|
||||||
|
|
@ -264,10 +264,6 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
|
||||||
if (comm == source)
|
if (comm == source)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Only value secondary commodities in terms of primary ones
|
|
||||||
if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
DEBUG_INDENT("commodity.prices.find", indent + 1);
|
DEBUG_INDENT("commodity.prices.find", indent + 1);
|
||||||
DEBUG("commodity.prices.find",
|
DEBUG("commodity.prices.find",
|
||||||
"searching for price via commodity '" << comm << "'");
|
"searching for price via commodity '" << comm << "'");
|
||||||
|
|
@ -370,8 +366,7 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
|
||||||
#endif
|
#endif
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
if (! has_flags(COMMODITY_WALKED) && base->varied_history &&
|
if (! has_flags(COMMODITY_WALKED) && base->varied_history) {
|
||||||
(commodity || ! has_flags(COMMODITY_PRIMARY))) {
|
|
||||||
optional<base_t::time_and_commodity_t> pair;
|
optional<base_t::time_and_commodity_t> pair;
|
||||||
#if defined(VERIFY_ON)
|
#if defined(VERIFY_ON)
|
||||||
optional<price_point_t> checkpoint;
|
optional<price_point_t> checkpoint;
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ struct price_point_t
|
||||||
datetime_t when;
|
datetime_t when;
|
||||||
amount_t price;
|
amount_t price;
|
||||||
|
|
||||||
|
price_point_t() {}
|
||||||
|
price_point_t(datetime_t _when, amount_t _price)
|
||||||
|
: when(_when), price(_price) {}
|
||||||
|
|
||||||
bool operator==(const price_point_t& other) const {
|
bool operator==(const price_point_t& other) const {
|
||||||
return when == other.when && price == other.price;
|
return when == other.when && price == other.price;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,16 @@ using namespace boost::python;
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
boost::optional<amount_t> py_value_0(const amount_t& amount) {
|
boost::optional<amount_t> py_value_0(const amount_t& amount) {
|
||||||
return amount.value(false, CURRENT_TIME());
|
return amount.value(CURRENT_TIME());
|
||||||
}
|
}
|
||||||
boost::optional<amount_t> py_value_1(const amount_t& amount,
|
boost::optional<amount_t> py_value_1(const amount_t& amount,
|
||||||
commodity_t& in_terms_of) {
|
commodity_t& in_terms_of) {
|
||||||
return amount.value(false, CURRENT_TIME(), in_terms_of);
|
return amount.value(CURRENT_TIME(), in_terms_of);
|
||||||
}
|
}
|
||||||
boost::optional<amount_t> py_value_2(const amount_t& amount,
|
boost::optional<amount_t> py_value_2(const amount_t& amount,
|
||||||
commodity_t& in_terms_of,
|
commodity_t& in_terms_of,
|
||||||
datetime_t& moment) {
|
datetime_t& moment) {
|
||||||
return amount.value(false, moment, in_terms_of);
|
return amount.value(moment, in_terms_of);
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_parse_2(amount_t& amount, object in, unsigned char flags) {
|
void py_parse_2(amount_t& amount, object in, unsigned char flags) {
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,16 @@ using namespace boost::python;
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
boost::optional<balance_t> py_value_0(const balance_t& balance) {
|
boost::optional<balance_t> py_value_0(const balance_t& balance) {
|
||||||
return balance.value(false, CURRENT_TIME());
|
return balance.value(CURRENT_TIME());
|
||||||
}
|
}
|
||||||
boost::optional<balance_t> py_value_1(const balance_t& balance,
|
boost::optional<balance_t> py_value_1(const balance_t& balance,
|
||||||
commodity_t& in_terms_of) {
|
commodity_t& in_terms_of) {
|
||||||
return balance.value(false, CURRENT_TIME(), in_terms_of);
|
return balance.value(CURRENT_TIME(), in_terms_of);
|
||||||
}
|
}
|
||||||
boost::optional<balance_t> py_value_2(const balance_t& balance,
|
boost::optional<balance_t> py_value_2(const balance_t& balance,
|
||||||
commodity_t& in_terms_of,
|
commodity_t& in_terms_of,
|
||||||
datetime_t& moment) {
|
datetime_t& moment) {
|
||||||
return balance.value(false, moment, in_terms_of);
|
return balance.value(moment, in_terms_of);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<amount_t>
|
boost::optional<amount_t>
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,16 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2)
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
boost::optional<value_t> py_value_0(const value_t& value) {
|
boost::optional<value_t> py_value_0(const value_t& value) {
|
||||||
return value.value(false, CURRENT_TIME());
|
return value.value(CURRENT_TIME());
|
||||||
}
|
}
|
||||||
boost::optional<value_t> py_value_1(const value_t& value,
|
boost::optional<value_t> py_value_1(const value_t& value,
|
||||||
commodity_t& in_terms_of) {
|
commodity_t& in_terms_of) {
|
||||||
return value.value(false, CURRENT_TIME(), in_terms_of);
|
return value.value(CURRENT_TIME(), in_terms_of);
|
||||||
}
|
}
|
||||||
boost::optional<value_t> py_value_2(const value_t& value,
|
boost::optional<value_t> py_value_2(const value_t& value,
|
||||||
commodity_t& in_terms_of,
|
commodity_t& in_terms_of,
|
||||||
datetime_t& moment) {
|
datetime_t& moment) {
|
||||||
return value.value(false, moment, in_terms_of);
|
return value.value(moment, in_terms_of);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject * py_base_type(value_t& value)
|
PyObject * py_base_type(value_t& value)
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ value_t report_t::fn_market(call_scope_t& scope)
|
||||||
/* add_prices= */ false,
|
/* add_prices= */ false,
|
||||||
moment);
|
moment);
|
||||||
else
|
else
|
||||||
result = args.value_at(0).value(true, moment);
|
result = args.value_at(0).value(moment);
|
||||||
|
|
||||||
if (! result.is_null())
|
if (! result.is_null())
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -1401,8 +1401,7 @@ bool value_t::is_zero() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t value_t::value(const bool primary_only,
|
value_t value_t::value(const optional<datetime_t>& moment,
|
||||||
const optional<datetime_t>& moment,
|
|
||||||
const optional<commodity_t&>& in_terms_of) const
|
const optional<commodity_t&>& in_terms_of) const
|
||||||
{
|
{
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
|
|
@ -1411,13 +1410,13 @@ value_t value_t::value(const bool primary_only,
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
if (optional<amount_t> val =
|
if (optional<amount_t> val =
|
||||||
as_amount().value(primary_only, moment, in_terms_of))
|
as_amount().value(moment, in_terms_of))
|
||||||
return *val;
|
return *val;
|
||||||
return NULL_VALUE;
|
return NULL_VALUE;
|
||||||
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
if (optional<balance_t> bal =
|
if (optional<balance_t> bal =
|
||||||
as_balance().value(primary_only, moment, in_terms_of))
|
as_balance().value(moment, in_terms_of))
|
||||||
return *bal;
|
return *bal;
|
||||||
return NULL_VALUE;
|
return NULL_VALUE;
|
||||||
|
|
||||||
|
|
@ -1455,7 +1454,7 @@ value_t value_t::exchange_commodities(const std::string& commodities,
|
||||||
if (commodity_t * commodity =
|
if (commodity_t * commodity =
|
||||||
commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
|
commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
|
||||||
moment)) {
|
moment)) {
|
||||||
value_t result = value(false, moment, *commodity);
|
value_t result = value(moment, *commodity);
|
||||||
if (! result.is_null())
|
if (! result.is_null())
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -476,8 +476,7 @@ public:
|
||||||
void in_place_unreduce(); // exists for efficiency's sake
|
void in_place_unreduce(); // exists for efficiency's sake
|
||||||
|
|
||||||
// Return the "market value" of a given value at a specific time.
|
// Return the "market value" of a given value at a specific time.
|
||||||
value_t value(const bool primary_only = false,
|
value_t value(const optional<datetime_t>& moment = none,
|
||||||
const optional<datetime_t>& moment = none,
|
|
||||||
const optional<commodity_t&>& in_terms_of = none) const;
|
const optional<commodity_t&>& in_terms_of = none) const;
|
||||||
|
|
||||||
value_t price() const;
|
value_t price() const;
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
>>>2
|
>>>2
|
||||||
While parsing file "$sourcepath/src/amount.h", line 66:
|
While parsing file "$sourcepath/src/amount.h", line 66:
|
||||||
Error: No quantity specified for amount
|
Error: No quantity specified for amount
|
||||||
While parsing file "$sourcepath/src/amount.h", line 726:
|
While parsing file "$sourcepath/src/amount.h", line 725:
|
||||||
Error: Invalid date/time: line amount_t amoun
|
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 731:
|
||||||
Error: Invalid date/time: line string amount_
|
Error: Invalid date/time: line string amount_
|
||||||
While parsing file "$sourcepath/src/amount.h", line 738:
|
While parsing file "$sourcepath/src/amount.h", line 737:
|
||||||
Error: Invalid date/time: line string amount_
|
Error: Invalid date/time: line string amount_
|
||||||
While parsing file "$sourcepath/src/amount.h", line 744:
|
While parsing file "$sourcepath/src/amount.h", line 743:
|
||||||
Error: Invalid date/time: line string amount_
|
Error: Invalid date/time: line string amount_
|
||||||
While parsing file "$sourcepath/src/amount.h", line 750:
|
While parsing file "$sourcepath/src/amount.h", line 749:
|
||||||
Error: Invalid date/time: line std::ostream&
|
Error: Invalid date/time: line std::ostream&
|
||||||
While parsing file "$sourcepath/src/amount.h", line 757:
|
While parsing file "$sourcepath/src/amount.h", line 756:
|
||||||
Error: Invalid date/time: line std::istream&
|
Error: Invalid date/time: line std::istream&
|
||||||
=== 7
|
=== 7
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,11 @@ void CommodityTestCase::testPriceHistory()
|
||||||
cad.add_price(jan17_06, amount_t("$1.11"));
|
cad.add_price(jan17_06, amount_t("$1.11"));
|
||||||
|
|
||||||
#ifndef NOT_FOR_PYTHON
|
#ifndef NOT_FOR_PYTHON
|
||||||
optional<amount_t> amt = x1.value(false, feb28_07sbm);
|
optional<amount_t> amt = x1.value(feb28_07sbm);
|
||||||
assertTrue(amt);
|
assertTrue(amt);
|
||||||
assertEqual(amount_t("$1831.83"), *amt);
|
assertEqual(amount_t("$1831.83"), *amt);
|
||||||
|
|
||||||
amt = x1.value(false, CURRENT_TIME());
|
amt = x1.value(CURRENT_TIME());
|
||||||
assertTrue(amt);
|
assertTrue(amt);
|
||||||
assertEqual(string("$2124.12"), amt->to_string());
|
assertEqual(string("$2124.12"), amt->to_string());
|
||||||
#ifdef INTEGER_MATH
|
#ifdef INTEGER_MATH
|
||||||
|
|
@ -86,18 +86,18 @@ void CommodityTestCase::testPriceHistory()
|
||||||
assertEqual(string("$2124.122"), amt->to_fullstring());
|
assertEqual(string("$2124.122"), amt->to_fullstring());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
amt = x1.value(false, CURRENT_TIME(), euro);
|
amt = x1.value(CURRENT_TIME(), euro);
|
||||||
assertTrue(amt);
|
assertTrue(amt);
|
||||||
assertEqual(string("EUR 1366.87"), amt->rounded().to_string());
|
assertEqual(string("EUR 1366.87"), amt->rounded().to_string());
|
||||||
|
|
||||||
// Add a newer Euro pricing
|
// Add a newer Euro pricing
|
||||||
aapl.add_price(jan17_07, amount_t("EUR 23.00"));
|
aapl.add_price(jan17_07, amount_t("EUR 23.00"));
|
||||||
|
|
||||||
amt = x1.value(false, CURRENT_TIME(), euro);
|
amt = x1.value(CURRENT_TIME(), euro);
|
||||||
assertTrue(amt);
|
assertTrue(amt);
|
||||||
assertEqual(string("EUR 2302.30"), amt->to_string());
|
assertEqual(string("EUR 2302.30"), amt->to_string());
|
||||||
|
|
||||||
amt = x1.value(false, CURRENT_TIME(), cad);
|
amt = x1.value(CURRENT_TIME(), cad);
|
||||||
assertTrue(amt);
|
assertTrue(amt);
|
||||||
assertEqual(string("CAD 3223.22"), amt->to_string());
|
assertEqual(string("CAD 3223.22"), amt->to_string());
|
||||||
#endif // NOT_FOR_PYTHON
|
#endif // NOT_FOR_PYTHON
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue