mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Andrew Sackville-West's changes to add the ability to lookup the
latest price before a specific date. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13611 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
872a2cafa8
commit
c9bd69b302
@ -1,5 +1,10 @@
|
|||||||
2006-03-12 David Hampton <hampton@employees.org>
|
2006-03-12 David Hampton <hampton@employees.org>
|
||||||
|
|
||||||
|
* src/engine/gnc-pricedb.[ch]:
|
||||||
|
* src/engine/gw-engine-spec.scm: Andrew Sackville-West's changes
|
||||||
|
to add the ability to lookup the latest price before a specific
|
||||||
|
date.
|
||||||
|
|
||||||
* src/register/register-gnome/gnucash-sheet.[ch]:
|
* src/register/register-gnome/gnucash-sheet.[ch]:
|
||||||
* src/register/ledger-core/split-register.[ch]:
|
* src/register/ledger-core/split-register.[ch]:
|
||||||
* src/register/ledger-core/split-register-control.c:
|
* src/register/ledger-core/split-register-control.c:
|
||||||
|
@ -1575,6 +1575,59 @@ gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GNCPrice *
|
||||||
|
gnc_pricedb_lookup_latest_before (GNCPriceDB *db,
|
||||||
|
gnc_commodity *c,
|
||||||
|
gnc_commodity *currency,
|
||||||
|
Timespec t)
|
||||||
|
{
|
||||||
|
GList *price_list;
|
||||||
|
GNCPrice *current_price = NULL;
|
||||||
|
/* GNCPrice *next_price = NULL;
|
||||||
|
GNCPrice *result = NULL;*/
|
||||||
|
GList *item = NULL;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
QofBook *book;
|
||||||
|
QofBackend *be;
|
||||||
|
Timespec price_time;
|
||||||
|
|
||||||
|
if(!db || !c || !currency) return NULL;
|
||||||
|
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
|
||||||
|
book = qof_instance_get_book(&db->inst);
|
||||||
|
be = qof_book_get_backend(book);
|
||||||
|
#ifdef GNUCASH_MAJOR_VERSION
|
||||||
|
if (be && be->price_lookup)
|
||||||
|
{
|
||||||
|
GNCPriceLookup pl;
|
||||||
|
pl.type = LOOKUP_LATEST_BEFORE;
|
||||||
|
pl.prdb = db;
|
||||||
|
pl.commodity = c;
|
||||||
|
pl.currency = currency;
|
||||||
|
pl.date = t;
|
||||||
|
(be->price_lookup) (be, &pl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
|
||||||
|
if(!currency_hash) { LEAVE ("no currency hash"); return NULL; }
|
||||||
|
|
||||||
|
price_list = g_hash_table_lookup(currency_hash, currency);
|
||||||
|
if(!price_list) { LEAVE ("no price list"); return NULL; }
|
||||||
|
|
||||||
|
item = price_list;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
price_time = gnc_price_get_time (item->data);
|
||||||
|
if (timespec_cmp(&price_time, &t) <= 0)
|
||||||
|
current_price = item->data;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
while (timespec_cmp(&price_time, &t) > 0 && item);
|
||||||
|
gnc_price_ref(current_price);
|
||||||
|
LEAVE (" ");
|
||||||
|
return current_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lookup_nearest(gpointer key, gpointer val, gpointer user_data)
|
lookup_nearest(gpointer key, gpointer val, gpointer user_data)
|
||||||
{
|
{
|
||||||
@ -1628,6 +1681,38 @@ lookup_nearest(gpointer key, gpointer val, gpointer user_data)
|
|||||||
gnc_price_list_insert(return_list, result, FALSE);
|
gnc_price_list_insert(return_list, result, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
lookup_latest_before(gpointer key, gpointer val, gpointer user_data)
|
||||||
|
{
|
||||||
|
//gnc_commodity *currency = (gnc_commodity *)key;
|
||||||
|
GList *price_list = (GList *)val;
|
||||||
|
GNCPrice *current_price = NULL;
|
||||||
|
/* GNCPrice *next_price = NULL;
|
||||||
|
GNCPrice *result = NULL;*/
|
||||||
|
GList *item = NULL;
|
||||||
|
GNCPriceLookupHelper *lookup_helper = (GNCPriceLookupHelper *)user_data;
|
||||||
|
GList **return_list = lookup_helper->return_list;
|
||||||
|
Timespec t = lookup_helper->time;
|
||||||
|
Timespec price_time;
|
||||||
|
|
||||||
|
if (price_list)
|
||||||
|
{
|
||||||
|
item = price_list;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
price_time = gnc_price_get_time (item->data);
|
||||||
|
if (timespec_cmp(&price_time, &t) <= 0)
|
||||||
|
current_price = item->data;
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
while (timespec_cmp(&price_time, &t) > 0 && item);
|
||||||
|
}
|
||||||
|
|
||||||
|
gnc_price_list_insert(return_list, current_price, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GList *
|
GList *
|
||||||
gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
|
gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
|
||||||
const gnc_commodity *c,
|
const gnc_commodity *c,
|
||||||
@ -1671,6 +1756,49 @@ gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GList *
|
||||||
|
gnc_pricedb_lookup_latest_before_any_currency(GNCPriceDB *db,
|
||||||
|
gnc_commodity *c,
|
||||||
|
Timespec t)
|
||||||
|
{
|
||||||
|
GList *result = NULL;
|
||||||
|
GHashTable *currency_hash;
|
||||||
|
GNCPriceLookupHelper lookup_helper;
|
||||||
|
QofBook *book;
|
||||||
|
QofBackend *be;
|
||||||
|
|
||||||
|
if(!db || !c) return NULL;
|
||||||
|
ENTER ("db=%p commodity=%p", db, c);
|
||||||
|
book = qof_instance_get_book(&db->inst);
|
||||||
|
be = qof_book_get_backend(book);
|
||||||
|
#ifdef GNUCASH_MAJOR_VERSION
|
||||||
|
if (be && be->price_lookup)
|
||||||
|
{
|
||||||
|
GNCPriceLookup pl;
|
||||||
|
pl.type = LOOKUP_LATEST_BEFORE;
|
||||||
|
pl.prdb = db;
|
||||||
|
pl.commodity = c;
|
||||||
|
pl.currency = NULL; /* can the backend handle this??? */
|
||||||
|
pl.date = t;
|
||||||
|
(be->price_lookup) (be, &pl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
|
||||||
|
if(!currency_hash) { LEAVE (" no currency hash"); return NULL; }
|
||||||
|
|
||||||
|
lookup_helper.return_list = &result;
|
||||||
|
lookup_helper.time = t;
|
||||||
|
g_hash_table_foreach(currency_hash, lookup_latest_before, &lookup_helper);
|
||||||
|
|
||||||
|
if(!result) { LEAVE (" "); return NULL; }
|
||||||
|
|
||||||
|
result = g_list_sort(result, compare_prices_by_date);
|
||||||
|
|
||||||
|
LEAVE (" ");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a balance from one currency to another.
|
* Convert a balance from one currency to another.
|
||||||
*/
|
*/
|
||||||
@ -1817,6 +1945,7 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
|
|||||||
balance = gnc_numeric_mul (balance, currency_price_value,
|
balance = gnc_numeric_mul (balance, currency_price_value,
|
||||||
gnc_commodity_get_fraction (new_currency),
|
gnc_commodity_get_fraction (new_currency),
|
||||||
GNC_HOW_RND_ROUND);
|
GNC_HOW_RND_ROUND);
|
||||||
|
|
||||||
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
|
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
|
||||||
gnc_commodity_get_fraction (new_currency),
|
gnc_commodity_get_fraction (new_currency),
|
||||||
GNC_HOW_RND_ROUND);
|
GNC_HOW_RND_ROUND);
|
||||||
@ -1826,6 +1955,85 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gnc_numeric
|
||||||
|
gnc_pricedb_convert_balance_latest_before(GNCPriceDB *pdb,
|
||||||
|
gnc_numeric balance,
|
||||||
|
gnc_commodity *balance_currency,
|
||||||
|
gnc_commodity *new_currency,
|
||||||
|
Timespec t)
|
||||||
|
{
|
||||||
|
GNCPrice *price, *currency_price;
|
||||||
|
GList *price_list, *list_helper;
|
||||||
|
gnc_numeric currency_price_value;
|
||||||
|
gnc_commodity *intermediate_currency;
|
||||||
|
|
||||||
|
if (gnc_numeric_zero_p (balance) ||
|
||||||
|
gnc_commodity_equiv (balance_currency, new_currency))
|
||||||
|
return balance;
|
||||||
|
|
||||||
|
/* Look for a direct price. */
|
||||||
|
price = gnc_pricedb_lookup_latest_before (pdb, balance_currency, new_currency, t);
|
||||||
|
|
||||||
|
if (price) {
|
||||||
|
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
|
||||||
|
gnc_commodity_get_fraction (new_currency),
|
||||||
|
GNC_HOW_RND_ROUND);
|
||||||
|
gnc_price_unref (price);
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no direct price found, try if we find a price in another currency
|
||||||
|
* and convert in two stages
|
||||||
|
*/
|
||||||
|
price_list = gnc_pricedb_lookup_latest_before_any_currency(pdb, balance_currency, t);
|
||||||
|
if (!price_list) {
|
||||||
|
balance = gnc_numeric_zero ();
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_helper = price_list;
|
||||||
|
currency_price_value = gnc_numeric_zero();
|
||||||
|
|
||||||
|
do {
|
||||||
|
price = (GNCPrice *)(list_helper->data);
|
||||||
|
|
||||||
|
intermediate_currency = gnc_price_get_currency(price);
|
||||||
|
currency_price = gnc_pricedb_lookup_latest_before(pdb, intermediate_currency,
|
||||||
|
new_currency, t);
|
||||||
|
if(currency_price) {
|
||||||
|
currency_price_value = gnc_price_get_value(currency_price);
|
||||||
|
gnc_price_unref(currency_price);
|
||||||
|
} else {
|
||||||
|
currency_price = gnc_pricedb_lookup_nearest_in_time(pdb, new_currency,
|
||||||
|
intermediate_currency, t);
|
||||||
|
if (currency_price) {
|
||||||
|
/* here we need the reciprocal */
|
||||||
|
currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1),
|
||||||
|
gnc_price_get_value(currency_price),
|
||||||
|
gnc_commodity_get_fraction (new_currency),
|
||||||
|
GNC_HOW_RND_ROUND);
|
||||||
|
gnc_price_unref(currency_price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_helper = list_helper->next;
|
||||||
|
} while((list_helper != NULL) &&
|
||||||
|
(!gnc_numeric_zero_p(currency_price_value)));
|
||||||
|
|
||||||
|
balance = gnc_numeric_mul (balance, currency_price_value,
|
||||||
|
gnc_commodity_get_fraction (new_currency),
|
||||||
|
GNC_HOW_RND_ROUND);
|
||||||
|
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
|
||||||
|
gnc_commodity_get_fraction (new_currency),
|
||||||
|
GNC_HOW_RND_ROUND);
|
||||||
|
|
||||||
|
gnc_price_list_destroy(price_list);
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/* gnc_pricedb_foreach_price infrastructure
|
/* gnc_pricedb_foreach_price infrastructure
|
||||||
*/
|
*/
|
||||||
|
@ -348,6 +348,20 @@ GNCPrice * gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
|
|||||||
GList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
|
GList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
|
||||||
const gnc_commodity *c,
|
const gnc_commodity *c,
|
||||||
Timespec t);
|
Timespec t);
|
||||||
|
/** gnc_pricedb_lookup_latest_before - return the latest price for the given commodity
|
||||||
|
in the given currency up to and including time t. */
|
||||||
|
GNCPrice * gnc_pricedb_lookup_latest_before(GNCPriceDB *db,
|
||||||
|
gnc_commodity *c,
|
||||||
|
gnc_commodity *currency,
|
||||||
|
Timespec t);
|
||||||
|
|
||||||
|
/** gnc_pricedb_lookup_latest_before_any_currency - return recent prices that
|
||||||
|
match the given commodity up to and including time t in any available currency. Prices
|
||||||
|
will be returned as a GNCPrice list (see above). */
|
||||||
|
GList * gnc_pricedb_lookup_latest_before_any_currency(GNCPriceDB *db,
|
||||||
|
gnc_commodity *c,
|
||||||
|
Timespec t);
|
||||||
|
|
||||||
|
|
||||||
/** gnc_pricedb_convert_balance_latest_price - Convert a balance
|
/** gnc_pricedb_convert_balance_latest_price - Convert a balance
|
||||||
from one currency to another. */
|
from one currency to another. */
|
||||||
@ -366,6 +380,16 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
|
|||||||
const gnc_commodity *new_currency,
|
const gnc_commodity *new_currency,
|
||||||
Timespec t);
|
Timespec t);
|
||||||
|
|
||||||
|
/** gnc_pricedb_convert_balance_latest_before - Convert a balance from one currency
|
||||||
|
to another using the lastest price prior to Timespec t. */
|
||||||
|
gnc_numeric
|
||||||
|
gnc_pricedb_convert_balance_latest_before(GNCPriceDB *pdb,
|
||||||
|
gnc_numeric balance,
|
||||||
|
gnc_commodity *balance_currency,
|
||||||
|
gnc_commodity *new_currency,
|
||||||
|
Timespec t);
|
||||||
|
|
||||||
|
|
||||||
/** gnc_pricedb_foreach_price - call f once for each price in db, until
|
/** gnc_pricedb_foreach_price - call f once for each price in db, until
|
||||||
and unless f returns FALSE. If stable_order is not FALSE, make
|
and unless f returns FALSE. If stable_order is not FALSE, make
|
||||||
sure the ordering of the traversal is stable (i.e. the same order
|
sure the ordering of the traversal is stable (i.e. the same order
|
||||||
|
@ -1300,6 +1300,27 @@ when no longer needed.")
|
|||||||
(<gnc:commodity*> commodity) (<gnc:time-pair> t))
|
(<gnc:commodity*> commodity) (<gnc:time-pair> t))
|
||||||
"Returns the price(s) nearest to t in any currency available.")
|
"Returns the price(s) nearest to t in any currency available.")
|
||||||
|
|
||||||
|
|
||||||
|
(gw:wrap-function
|
||||||
|
ws
|
||||||
|
'gnc:pricedb-lookup-latest-before
|
||||||
|
'<gnc:Price*>
|
||||||
|
"gnc_pricedb_lookup_latest_before"
|
||||||
|
'((<gnc:PriceDB*> db)
|
||||||
|
(<gnc:commodity*> commodity) (<gnc:commodity*> currency)
|
||||||
|
(<gnc:time-pair> t))
|
||||||
|
"Returns the latest price quote <= t. Unref price when finished with it.")
|
||||||
|
|
||||||
|
(gw:wrap-function
|
||||||
|
ws
|
||||||
|
'gnc:pricedb-lookup-latest-before-any-currency
|
||||||
|
'(gw:glist-of <gnc:Price*> caller-owned)
|
||||||
|
"gnc_pricedb_lookup_latest_before_any_currency"
|
||||||
|
'((<gnc:PriceDB*> db)
|
||||||
|
(<gnc:commodity*> commodity) (<gnc:time-pair> t))
|
||||||
|
"Returns the latest price quote(s) <= t in any currency available.")
|
||||||
|
|
||||||
|
|
||||||
(gw:wrap-function
|
(gw:wrap-function
|
||||||
ws
|
ws
|
||||||
'gnc:pricedb-get-prices
|
'gnc:pricedb-get-prices
|
||||||
@ -1352,6 +1373,20 @@ when no longer needed.")
|
|||||||
"convert balance in commodity balance_commodity to new_currency using nearest price
|
"convert balance in commodity balance_commodity to new_currency using nearest price
|
||||||
to time t.")
|
to time t.")
|
||||||
|
|
||||||
|
|
||||||
|
(gw:wrap-function
|
||||||
|
ws
|
||||||
|
'gnc:pricedb-convert-balance-latest-before
|
||||||
|
'<gnc:numeric>
|
||||||
|
"gnc_pricedb_convert_balance_latest_before"
|
||||||
|
'((<gnc:PriceDB*> db)
|
||||||
|
(<gnc:numeric> balance)
|
||||||
|
(<gnc:commodity*> balance_commodity) (<gnc:commodity*> new_currency)
|
||||||
|
(<gnc:time-pair> t))
|
||||||
|
"convert balance in commodity balance_commodity to new_currency using latest price
|
||||||
|
prior to time t.")
|
||||||
|
|
||||||
|
|
||||||
;;===========
|
;;===========
|
||||||
;; QofSession
|
;; QofSession
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user