From 9e1c9090190c7452db9bd52bd6ae217d11c3f2e6 Mon Sep 17 00:00:00 2001 From: Derek Atkins Date: Sun, 20 Apr 2003 23:50:39 +0000 Subject: [PATCH] Herbert Thoma's multi-currency patch (#3): * src/engine/Account.c: move currency conversion to gnc-pricedb.c * src/engine/gnc-pricedb.c * src/engine/gnc-pricedb.h: add functions gnc_pricedb_convert_balance_latest_price and gnc_pricedb_convert_balance_nearest_price * src/engine/gw-engine-spec.scm: wrap functions gnc_price_list_destroy, gnc_pricedb_lookup_latest_any_currency, gnc_pricedb_lookup_nearest_in_time_any_currency, gnc_pricedb_convert_balance_latest_price and gnc_pricedb_convert_balance_nearest_price * src/report/report-system/commodity-utilities.scm: use gnc:pricedb-convert-balance-latest-price and gnc:pricedb-convert-balance-nearest-price to improve multiple currency reports * src/report/standard-reports/advanced-portfolio.scm: improve report for stocks and funds not denominated in report currency git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8234 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 23 +++ src/engine/Account.c | 61 +------ src/engine/gnc-pricedb.c | 160 ++++++++++++++++++ src/engine/gnc-pricedb.h | 17 ++ src/engine/gw-engine-spec.scm | 48 ++++++ .../report-system/commodity-utilities.scm | 18 +- .../standard-reports/advanced-portfolio.scm | 102 +++++------ 7 files changed, 305 insertions(+), 124 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0222ff3f4..87fdbddffc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2003-04-18 Herbert Thoma + + * src/engine/Account.c: move currency conversion to gnc-pricedb.c + + * src/engine/gnc-pricedb.c + * src/engine/gnc-pricedb.h: add functions + gnc_pricedb_convert_balance_latest_price and + gnc_pricedb_convert_balance_nearest_price + + * src/engine/gw-engine-spec.scm: wrap functions + gnc_price_list_destroy, gnc_pricedb_lookup_latest_any_currency, + gnc_pricedb_lookup_nearest_in_time_any_currency, + gnc_pricedb_convert_balance_latest_price and + gnc_pricedb_convert_balance_nearest_price + + * src/report/report-system/commodity-utilities.scm: use + gnc:pricedb-convert-balance-latest-price and + gnc:pricedb-convert-balance-nearest-price to improve + multiple currency reports + + * src/report/standard-reports/advanced-portfolio.scm: + improve report for stocks and funds not denominated in report currency + 2003-04-16 Christian Stimming * src/import-export/hbci/druid-hbci-initial.c, diff --git a/src/engine/Account.c b/src/engine/Account.c index 09abb9a1d3..5125d5be71 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -1988,10 +1988,6 @@ xaccAccountConvertBalanceToCurrency(Account *account, /* for book */ { GNCBook *book; GNCPriceDB *pdb; - 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)) @@ -2000,63 +1996,8 @@ xaccAccountConvertBalanceToCurrency(Account *account, /* for book */ book = xaccGroupGetBook (xaccAccountGetRoot (account)); pdb = gnc_book_get_pricedb (book); - /* Look for a direct price. */ - price = gnc_pricedb_lookup_latest (pdb, balance_currency, new_currency); - if (price) { - balance = gnc_numeric_mul (balance, gnc_price_get_value (price), - gnc_commodity_get_fraction (new_currency), - GNC_RND_ROUND); - gnc_price_unref (price); - return balance; - } + balance = gnc_pricedb_convert_balance_latest_price(pdb, balance, balance_currency, new_currency); - /* - * no direct price found, try if we find a price in another currency - * and convert in two stages - */ - price_list = gnc_pricedb_lookup_latest_any_currency(pdb, balance_currency); - 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(pdb, intermediate_currency, - new_currency); - if(currency_price) { - currency_price_value = gnc_price_get_value(currency_price); - gnc_price_unref(currency_price); - } else { - currency_price = gnc_pricedb_lookup_latest(pdb, new_currency, - intermediate_currency); - 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_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_RND_ROUND); - balance = gnc_numeric_mul (balance, gnc_price_get_value (price), - gnc_commodity_get_fraction (new_currency), - GNC_RND_ROUND); - - gnc_price_list_destroy(price_list); return balance; } diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c index 5f0c330747..76911b25b8 100644 --- a/src/engine/gnc-pricedb.c +++ b/src/engine/gnc-pricedb.c @@ -1021,6 +1021,7 @@ gnc_pricedb_lookup_latest_any_currency(GNCPriceDB *db, pl.type = LOOKUP_LATEST; pl.prdb = db; pl.commodity = commodity; + pl.currency = NULL; /* can the backend handle this??? */ (db->book->backend->price_lookup) (db->book->backend, &pl); } @@ -1167,6 +1168,7 @@ gnc_pricedb_lookup_day_any_currency(GNCPriceDB *db, pl.type = LOOKUP_AT_TIME; pl.prdb = db; pl.commodity = c; + pl.currency = NULL; /* can the backend handle this??? */ pl.date = t; (db->book->backend->price_lookup) (db->book->backend, &pl); } @@ -1271,6 +1273,7 @@ gnc_pricedb_lookup_at_time_any_currency(GNCPriceDB *db, pl.type = LOOKUP_AT_TIME; pl.prdb = db; pl.commodity = c; + pl.currency = NULL; /* can the backend handle this??? */ pl.date = t; (db->book->backend->price_lookup) (db->book->backend, &pl); } @@ -1437,6 +1440,7 @@ gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, pl.type = LOOKUP_NEAREST_IN_TIME; pl.prdb = db; pl.commodity = c; + pl.currency = NULL; /* can the backend handle this??? */ pl.date = t; (db->book->backend->price_lookup) (db->book->backend, &pl); } @@ -1456,6 +1460,162 @@ gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, return result; } + +/* + * Convert a balance from one currency to another. + */ +gnc_numeric +gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, + gnc_numeric balance, + gnc_commodity *balance_currency, + gnc_commodity *new_currency) +{ + 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 (pdb, balance_currency, new_currency); + if (price) { + balance = gnc_numeric_mul (balance, gnc_price_get_value (price), + gnc_commodity_get_fraction (new_currency), + GNC_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_any_currency(pdb, balance_currency); + 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(pdb, intermediate_currency, + new_currency); + if(currency_price) { + currency_price_value = gnc_price_get_value(currency_price); + gnc_price_unref(currency_price); + } else { + currency_price = gnc_pricedb_lookup_latest(pdb, new_currency, + intermediate_currency); + 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_DENOM_AUTO, + GNC_DENOM_EXACT | GNC_RND_NEVER); + 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_RND_ROUND); + balance = gnc_numeric_mul (balance, gnc_price_get_value (price), + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + + gnc_price_list_destroy(price_list); + return balance; +} + +gnc_numeric +gnc_pricedb_convert_balance_nearest_price(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_nearest_in_time (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_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_nearest_in_time_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_nearest_in_time(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_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_RND_ROUND); + balance = gnc_numeric_mul (balance, gnc_price_get_value (price), + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + + gnc_price_list_destroy(price_list); + return balance; +} + + /* ==================================================================== */ /* gnc_pricedb_foreach_price infrastructure */ diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h index 45b9a2c0f3..77d97b2019 100644 --- a/src/engine/gnc-pricedb.h +++ b/src/engine/gnc-pricedb.h @@ -308,6 +308,23 @@ GList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, gnc_commodity *c, Timespec t); +/** gnc_pricedb_convert_balance_latest_price - Convert a balance + from one currency to another. */ +gnc_numeric +gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, + gnc_numeric balance, + gnc_commodity *balance_currency, + gnc_commodity *new_currency); + +/** gnc_pricedb_convert_balance_nearest_price - Convert a balance + from one currency to another. */ +gnc_numeric +gnc_pricedb_convert_balance_nearest_price(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 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 diff --git a/src/engine/gw-engine-spec.scm b/src/engine/gw-engine-spec.scm index 605c694eb0..0b1df3d197 100644 --- a/src/engine/gw-engine-spec.scm +++ b/src/engine/gw-engine-spec.scm @@ -1283,6 +1283,14 @@ when no longer needed.") '(( db) ( p)) "Add a price to the DB. Unref the price when you're finished with it.") +(gw:wrap-function + ws + 'gnc:price-list-destroy + ' + "gnc_price_list_destroy" + '(((gw:glist-of callee-owned) prices)) + "Destroys a gnc price list unrefing the prices included in the list") + (gw:wrap-function ws 'gnc:pricedb-lookup-latest @@ -1292,6 +1300,15 @@ when no longer needed.") ( commodity) ( currency)) "Returns the latest price. Unref the price when you're finished with it.") +(gw:wrap-function + ws + 'gnc:pricedb-lookup-latest-any-currency + '(gw:glist-of caller-owned) + "gnc_pricedb_lookup_latest_any_currency" + '(( db) + ( commodity)) + "Returns the latest price(s) in any currency available.") + (gw:wrap-function ws 'gnc:pricedb-lookup-nearest-in-time @@ -1302,6 +1319,15 @@ when no longer needed.") ( t)) "Returns the price quote nearest to t. Unref price when finished with it.") +(gw:wrap-function + ws + 'gnc:pricedb-lookup-nearest-in-time-any-currency + '(gw:glist-of caller-owned) + "gnc_pricedb_lookup_nearest_in_time_any_currency" + '(( db) + ( commodity) ( t)) + "Returns the price(s) nearest to t in any currency available.") + (gw:wrap-function ws 'gnc:pricedb-get-prices @@ -1332,6 +1358,28 @@ when no longer needed.") ( t)) "Lookup a price on the day specified by time t.") +(gw:wrap-function + ws + 'gnc:pricedb-convert-balance-latest-price + ' + "gnc_pricedb_convert_balance_latest_price" + '(( db) + ( balance) + ( balance_commodity) ( new_currency)) + "convert balance in commodity balance_commodity to new_currency using latest price.") + +(gw:wrap-function + ws + 'gnc:pricedb-convert-balance-nearest-price + ' + "gnc_pricedb_convert_balance_nearest_price" + '(( db) + ( balance) + ( balance_commodity) ( new_currency) + ( t)) + "convert balance in commodity balance_commodity to new_currency using nearest price +to time t.") + ;;=========== ;; GNCSession diff --git a/src/report/report-system/commodity-utilities.scm b/src/report/report-system/commodity-utilities.scm index 554c594372..00d47be0ef 100644 --- a/src/report/report-system/commodity-utilities.scm +++ b/src/report/report-system/commodity-utilities.scm @@ -736,10 +736,11 @@ (if (and (record? foreign) (gnc:gnc-monetary? foreign)) (or (gnc:exchange-by-euro foreign domestic #f) (gnc:exchange-if-same foreign domestic) - (gnc:exchange-by-pricedb-helper - foreign domestic - (gnc:pricedb-lookup-latest - (gnc:book-get-pricedb (gnc:get-current-book)) + (gnc:make-gnc-monetary + domestic + (gnc:pricedb-convert-balance-latest-price + (gnc:book-get-pricedb (gnc:get-current-book)) + (gnc:gnc-monetary-amount foreign) (gnc:gnc-monetary-commodity foreign) domestic))) #f)) @@ -758,10 +759,11 @@ date) (or (gnc:exchange-by-euro foreign domestic date) (gnc:exchange-if-same foreign domestic) - (gnc:exchange-by-pricedb-helper - foreign domestic - (gnc:pricedb-lookup-nearest-in-time - (gnc:book-get-pricedb (gnc:get-current-book)) + (gnc:make-gnc-monetary + domestic + (gnc:pricedb-convert-balance-nearest-price + (gnc:book-get-pricedb (gnc:get-current-book)) + (gnc:gnc-monetary-amount foreign) (gnc:gnc-monetary-commodity foreign) domestic date))) #f)) diff --git a/src/report/standard-reports/advanced-portfolio.scm b/src/report/standard-reports/advanced-portfolio.scm index 8196aa6a5d..e5b4fca59f 100644 --- a/src/report/standard-reports/advanced-portfolio.scm +++ b/src/report/standard-reports/advanced-portfolio.scm @@ -59,9 +59,18 @@ (gnc:options-add-currency! options gnc:pagename-general (N_ "Report Currency") "c") - (gnc:options-add-price-source! - options gnc:pagename-general - optname-price-source "d" 'pricedb-latest) + (add-option + (gnc:make-multichoice-option + gnc:pagename-general optname-price-source + "d" (N_ "The source of price information") 'pricedb-nearest + (list (vector 'pricedb-latest + (N_ "Most recent") + (N_ "The most recent recorded price")) + (vector 'pricedb-nearest + (N_ "Nearest in time") + (N_ "The price recorded nearest in time to the report date")) + ))) + (add-option (gnc:make-number-range-option @@ -118,7 +127,7 @@ (string=? (gnc:split-get-guid s1) (gnc:split-get-guid s2))) (define (table-add-stock-rows table accounts to-date - currency price-fn include-empty + currency price-fn exchange-fn include-empty total-value total-moneyin total-moneyout total-gain) @@ -149,15 +158,10 @@ (moneyoutcoll (gnc:make-commodity-collector)) (gaincoll (gnc:make-commodity-collector)) - (price-info (price-fn commodity currency to-date)) + (price-list (price-fn commodity to-date)) + (price (car price-list)) - (value-num (gnc:numeric-mul - units - (cdr price-info) - (gnc:commodity-get-fraction currency) - GNC-RND-ROUND)) - - (value (gnc:make-gnc-monetary currency value-num)) + (value (exchange-fn (gnc:make-gnc-monetary commodity units) currency to-date)) ) ;; (gnc:debug "---" name "---") @@ -211,11 +215,11 @@ ;; (gnc:debug "totalunityears" totalunityears) (gaincoll 'merge moneyoutcoll #f) - (gaincoll 'add currency value-num) + (gaincoll 'add (gnc:gnc-monetary-commodity value) (gnc:gnc-monetary-amount value)) (gaincoll 'merge moneyincoll #f) (if (or include-empty (not (gnc:numeric-zero-p units))) - (begin (total-value 'add currency value-num) + (begin (total-value 'add (gnc:gnc-monetary-commodity value) (gnc:gnc-monetary-amount value)) (total-moneyin 'merge moneyincoll #f) (total-moneyout 'merge moneyoutcoll #f) (total-gain 'merge gaincoll #f) @@ -230,17 +234,17 @@ (gnc:make-html-table-header-cell/markup "number-cell" (gnc:html-price-anchor - (car price-info) - (gnc:make-gnc-monetary currency - (cdr price-info)))) + price + (gnc:make-gnc-monetary (gnc:price-get-currency price) + (gnc:price-get-value price)))) (gnc:make-html-table-header-cell/markup "number-cell" value) (gnc:make-html-table-header-cell/markup - "number-cell" (gnc:monetary-neg (gnc:sum-collector-commodity moneyincoll currency price-fn))) + "number-cell" (gnc:monetary-neg (gnc:sum-collector-commodity moneyincoll currency exchange-fn))) (gnc:make-html-table-header-cell/markup - "number-cell" (gnc:sum-collector-commodity moneyoutcoll currency price-fn)) + "number-cell" (gnc:sum-collector-commodity moneyoutcoll currency exchange-fn)) (gnc:make-html-table-header-cell/markup - "number-cell" (gnc:sum-collector-commodity gaincoll currency price-fn)) + "number-cell" (gnc:sum-collector-commodity gaincoll currency exchange-fn)) (gnc:make-html-table-header-cell/markup "number-cell" (sprintf #f "%.2f%%" (* 100 (/ (gnc:numeric-to-double (cadr (gaincoll 'getpair currency #f))) (gnc:numeric-to-double (cadr (moneyincoll 'getpair currency #t))))))) @@ -248,7 +252,10 @@ ) (table-add-stock-rows-internal rest (not odd-row?)) ) - (table-add-stock-rows-internal rest odd-row?))))) + (table-add-stock-rows-internal rest odd-row?) + ) + (gnc:price-list-destroy price-list) + ))) (set! work-to-do (gnc:accounts-count-splits accounts)) (table-add-stock-rows-internal accounts #t))) @@ -263,10 +270,10 @@ (get-option gnc:pagename-general "Date"))) (accounts (get-option gnc:pagename-accounts "Accounts")) (currency (get-option gnc:pagename-general "Report Currency")) - (report-title (get-option gnc:pagename-general - gnc:optname-reportname)) (price-source (get-option gnc:pagename-general optname-price-source)) + (report-title (get-option gnc:pagename-general + gnc:optname-reportname)) (include-empty (get-option gnc:pagename-accounts optname-zero-shares)) @@ -286,38 +293,21 @@ ;; (gnc:debug "accounts" accounts) (if (not (null? accounts)) ; at least 1 account selected - (let* ((commodity-list (gnc:accounts-get-commodities - (append - (gnc:acccounts-get-all-subaccounts - accounts) accounts) currency)) + (let* ((exchange-fn + (case price-source + ('pricedb-latest + (lambda (foreign domestic date) + (gnc:exchange-by-pricedb-latest foreign domestic))) + ('pricedb-nearest gnc:exchange-by-pricedb-nearest))) (pricedb (gnc:book-get-pricedb (gnc:get-current-book))) (price-fn (case price-source - ('weighted-average - (let ((pricealist - (gnc:get-commoditylist-totalavg-prices - commodity-list currency to-date #f #f))) - (lambda (foreign domestic date) - (cons #f (gnc:pricealist-lookup-nearest-in-time - pricealist foreign date))))) ('pricedb-latest - (lambda (foreign domestic date) - (let ((price - (gnc:pricedb-lookup-latest - pricedb foreign domestic))) - (if price - (let ((v (gnc:price-get-value price))) - (cons price v)) - (cons #f (gnc:numeric-zero)))))) + (lambda (foreign date) + (gnc:pricedb-lookup-latest-any-currency pricedb foreign))) ('pricedb-nearest - (lambda (foreign domestic date) - (let ((price - (gnc:pricedb-lookup-nearest-in-time - pricedb foreign domestic date))) - (if price - (let ((v (gnc:price-get-value price))) - (cons price v)) - (cons #f (gnc:numeric-zero))))))))) + (lambda (foreign date) + (gnc:pricedb-lookup-nearest-in-time-any-currency pricedb foreign date)))))) (gnc:html-table-set-col-headers! table @@ -333,8 +323,8 @@ (_ "Total Return"))) (table-add-stock-rows - table accounts to-date currency - price-fn include-empty total-value total-moneyin total-moneyout total-gain) + table accounts to-date currency price-fn exchange-fn + include-empty total-value total-moneyin total-moneyout total-gain) (gnc:html-table-append-row/markup! table @@ -353,13 +343,13 @@ "" "" (gnc:make-html-table-cell/markup - "total-number-cell" (gnc:sum-collector-commodity total-value currency price-fn)) + "total-number-cell" (gnc:sum-collector-commodity total-value currency exchange-fn)) (gnc:make-html-table-cell/markup - "total-number-cell" (gnc:monetary-neg (gnc:sum-collector-commodity total-moneyin currency price-fn))) + "total-number-cell" (gnc:monetary-neg (gnc:sum-collector-commodity total-moneyin currency exchange-fn))) (gnc:make-html-table-cell/markup - "total-number-cell" (gnc:sum-collector-commodity total-moneyout currency price-fn)) + "total-number-cell" (gnc:sum-collector-commodity total-moneyout currency exchange-fn)) (gnc:make-html-table-cell/markup - "total-number-cell" (gnc:sum-collector-commodity total-gain currency price-fn)) + "total-number-cell" (gnc:sum-collector-commodity total-gain currency exchange-fn)) (gnc:make-html-table-cell/markup "total-number-cell" (sprintf #f "%.2f%%" (* 100 (/ (gnc:numeric-to-double (cadr (total-gain 'getpair currency #f))) (gnc:numeric-to-double (cadr (total-moneyin 'getpair currency #t)))))))