Problem in Trial Balance report with stocks and multiple currencies

Sherlock Holmes sh025622 at gmail.com
Sat Aug 23 23:18:56 EDT 2025


I concur.

There are significant differences in the implementation between 
gnc:get-exchange-totals and gnc:get-exchange-cost-totals that I believe 
are the root cause of the issue.  These differences appear to date back 
to May 3, 2019.    As a WAG, I modified gnc:get-exchange-cost-totals to 
match gnc:get-exchange-totals in the attached patch and the issue you've 
raised appears to be resolved.  I have not done any further testing,

Regards,

Sherlock


On 8/23/25 2:20 PM, Chang Wang wrote:
> Thanks for the reminder. I'll post to the user list in the future.
> However, in the above example, there is no gain or loss due to 
> currency exchange as the exchange rates are set to 1 so no currency 
> gain/loss needs to be booked. And the price source is set to be Last 
> up through report date instead of average cost. Therefore, I think 
> these are different issues.
>
> On Sat, Aug 23, 2025 at 3:51 PM John Ralls <jralls at ceridwen.us> wrote:
>
>     Oddly I just told somebody on IRC the same answer:
>     https://bugs.gnucash.org/show_bug.cgi?id=797796
>
>     Unless you’re willing to submit a PR, this is a user-list topic,
>     so in the future please use gnucash-user instead of gnucash-devel.
>
>     Regards,
>     John Ralls
>
>     > On Aug 23, 2025, at 1:43 PM, Chang Wang <wangchang327 at gmail.com>
>     wrote:
>     >
>     > Hi all,
>     > I noticed an issue with the Trial Balance report when using
>     stock trading and multiple currencies. Even when transactions are
>     balanced, the Trial Balance report appears to break due to
>     incorrect calculation of unrealized gains.
>     >
>     > I've attached an uncompressed minimal example to illustrate the
>     problem.
>     >
>     > Steps to reproduce:
>     > Open the attached book.
>     > Generate a Trial Balance report with reporting currency set to
>     USD, price source set to Last up through report date, and enable
>     Show Foreign Currencies and Exchange Rates.
>     >
>     > Observed behavior:
>     > The report shows an Unrealized Gain of $20,800, which is incorrect.
>     >
>     > Expected behavior:
>     > The Unrealized Gain should be $200.
>     >
>     > Explanation:
>     > The example contains three transactions:
>     > 1) 08/02/2025 - Buy one stock for 10,200 JPY.
>     > 2) 08/03/2025 - Exchange 100,000 JPY for 100,000 USD.
>     > 3) 08/04/2025 - Buy one stock for 10,400 JPY.
>     >
>     > The JPY/USD rate is fixed at 1 on all days, so there should be
>     no realized or unrealized currency gains. Stock prices are set at
>     10X00 JPY on 08/0X/2025, where X = 1, 2, 3, 4.
>     >
>     > Therefore, in USD reporting currency, the Trial Balance should
>     show unrealized gains as:
>     > (10,400 * 2) - 10,200 - 10,400 = 200 JPY = 200 USD
>     >
>     > Notably, the Balance Sheet report does display the correct
>     unrealized gain. And if transaction 3) or transaction 2) is
>     removed, the Trial Balance turns out to be correct.
>     >
>     > I'm not familiar with Scheme, so I wasn't able to locate the
>     problem in the source code. I also wasn't able to file a bug on
>     Bugzilla, since the registration function appears to be broken.
>     >
>     > Thanks for your attention,
>     > Chang
>     > <tb.gnucash>_______________________________________________
>
> _______________________________________________
> gnucash-devel mailing list
> gnucash-devel at gnucash.org
> https://lists.gnucash.org/mailman/listinfo/gnucash-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20250823/c59e7092/attachment-0001.htm>
-------------- next part --------------
--- commodity-utilities.scm.orig	2025-08-23 19:49:25
+++ commodity-utilities.scm	2025-08-23 19:23:32
@@ -526,13 +526,6 @@
       (cond
        ((null? comm-splits)
         (gnc:resolve-unknown-comm sumlist report-commodity #:hide-warnings? hide-warnings?))
-
-       ;; However skip splits in trading accounts as these counterbalance
-       ;; the actual value and share amounts back to zero
-       ((eqv? (xaccAccountGetType (xaccSplitGetAccount (car comm-splits)))
-              ACCT-TYPE-TRADING)
-        (loop (cdr comm-splits)
-              sumlist))
 
        ;; Go through all splits and add up all value-amounts
        ;; and share-amounts
@@ -540,10 +533,15 @@
         (let* ((a (car comm-splits))
                (txn-comm (xaccTransGetCurrency (xaccSplitGetParent a)))
                (acc-comm (xaccAccountGetCommodity (xaccSplitGetAccount a)))
-               (share-amt (xaccSplitGetAmount a))
-               (value-amt (xaccSplitGetValue a)))
+               (share-amt (abs (xaccSplitGetAmount a)))
+               (value-amt (abs (xaccSplitGetValue a))))
 
           (cond
+           ;; Without shares this is not a buy or sell; ignore it.
+           ((zero? share-amt)
+            (loop (cdr comm-splits)
+                  sumlist))
+
            ((assoc txn-comm sumlist)
             => (lambda (comm-list)
                  (cond
@@ -571,16 +569,16 @@
                   ;; other commodity already exists in comm-list?
                   ((assoc txn-comm (cadr comm-list))
                    => (lambda (pair)
-                        ((caadr pair) 'add (- value-amt))
-                        ((cdadr pair) 'add (- share-amt))
+                        ((caadr pair) 'add value-amt)
+                        ((cdadr pair) 'add share-amt)
                         (loop (cdr comm-splits)
                               sumlist)))
                   (else
                    (let ((pair (list txn-comm (cons (gnc:make-value-collector)
                                                     (gnc:make-value-collector)))))
                      ;; And add the balances to the comm-list entry.
-                     ((caadr pair) 'add (- value-amt))
-                     ((cdadr pair) 'add (- share-amt))
+                     ((caadr pair) 'add value-amt)
+                     ((cdadr pair) 'add share-amt)
                      (loop (cdr comm-splits)
                            (cons (list (car comm-list) (cons pair (cadr comm-list)))
                                  (alist-delete


More information about the gnucash-devel mailing list