Here you go, a prices-report.scm which can be dropped into standard-reports
folder and adds a rudimentary forex analysis. If rebuilding you'll need to
add onto CMakeLists.txt as well.

It scans *only* transactions which involve 2 different commodities. eg
GBP<->EUR or AAPL<->USD.

It calculates and displays the exact price ratio achieved in the particular
transaction, and also finds the nearest pricedb entry applicable for that
date between the two commodities.

It does not modify the datafile, nor pricedb. It ignores any brokerage fees.

For illustration/entertainment only.
(define-module (gnucash report standard-reports prices-report))

(use-modules (gnucash utilities))
(use-modules (srfi srfi-1))
(use-modules (srfi srfi-11))
(use-modules (srfi srfi-13))
(use-modules (gnucash gnc-module))
(use-modules (gnucash gettext))

(gnc:module-load "gnucash/report/report-system" 0)

(define reportname (N_ "Prices Report"))

(define (options-generator)
  (let ((options (gnc:new-options)))
    options))

(define (gnc-account-child-accounts-recursive account)
  (let loop ((account account)
             (initial '()))
    (fold (lambda (child-account accumulator)
            (append (loop child-account (list child-account))
                    accumulator))
          initial
          (gnc-account-get-children account))))

(define (split->splits split)
  (xaccTransGetSplitList
   (xaccSplitGetParent split)))

(define (split->commodities split)
  (delete-duplicates
   (map split->commodity (split->splits split))
   gnc-commodity-equal))

(define (split->commodity split)
  (xaccAccountGetCommodity (xaccSplitGetAccount split)))

(define (split-get-exact-ratio split)
  (let* ((splits (split->splits split))
         (split-1 (car splits))
         (split-2 (cadr splits)))
    (/ (xaccSplitGetAmount split-1)
       (xaccSplitGetAmount split-2))))

(define (split-describe split op)
  (let* ((sp (op (split->splits split))))
    (gnc:make-gnc-monetary (split->commodity sp) (xaccSplitGetAmount sp))))
                  
(define (prices-renderer report-obj)
  ;; (define options (gnc:report-options report-obj))
  (gnc:report-starting reportname)
  (let* ((document (gnc:make-html-document))
         (accounts (gnc-account-child-accounts-recursive
                    (gnc-get-current-root-account)))
         (query (qof-query-create-for-splits)))
    (qof-query-set-book query (gnc-get-current-book))
    (xaccQueryAddAccountMatch query accounts QOF-GUID-MATCH-ANY QOF-QUERY-AND)
    (xaccQueryAddDateMatchTT query #f 0 #f 0 QOF-QUERY-AND)
    (gnc:query-set-match-non-voids-only! query (gnc-get-current-book))
    (qof-query-set-sort-order query (list SPLIT-TRANS TRANS-DATE-POSTED) '() '())
    (qof-query-set-sort-increasing query #t #t #t)

    (let ((splits (xaccQueryGetSplitsUniqueTrans query)))
      (qof-query-destroy query)

      (if (null? splits)

          (gnc:html-document-add-object!
           document
           (gnc:html-make-generic-warning
            reportname (gnc:report-id report-obj)
            "Empty Book" "Cannot find any transactions"))

          (let ((rep (gnc:make-html-table))
                (splits-with-prices (filter
                                     (lambda (split)
                                       (= 2 (length
                                             (split->commodities split))))
                                     splits)))

            (gnc:html-document-set-title! document reportname)

            (for-each
             (lambda (split)
               (gnc:html-table-append-row!
                rep
                (list

                 (qof-print-date (xaccTransGetDate (xaccSplitGetParent split)))

                 (gnc:html-transaction-anchor (xaccSplitGetParent split) "Transferring")

                 (split-describe split car)
                 "and"
                 (split-describe split cadr)

                 "exact price is"
                 (split-get-exact-ratio split)

                 (string-join (map gnc-commodity-get-mnemonic (split->commodities split)) "/")

                 "and nearest pricedb is"
                 (let ((price (gnc-pricedb-lookup-nearest-in-time64 (gnc-pricedb-get-db (gnc-get-current-book))
                                                                    (cadr (split->commodities split))
                                                                    (car (split->commodities split))
                                                                    (xaccTransGetDate (xaccSplitGetParent split))))

                       (val (gnc:exchange-by-pricedb-nearest (gnc:make-gnc-monetary (cadr (split->commodities split)) 1)
                                                               (car (split->commodities split))
                                                               (xaccTransGetDate (xaccSplitGetParent split)))))
                   (if (null? price)
                       "missing"
                       (gnc:html-price-anchor price val))))))
             splits-with-prices)

            (gnc:html-document-add-object! document rep))))

    (gnc:report-finished)

    document))

;; Define the report.
(gnc:define-report
 'version 1
 'name reportname
 'report-guid "bdebf90bde524f7a9b11a78cced599f2"
 'options-generator options-generator
 'renderer prices-renderer)
_______________________________________________
gnucash-devel mailing list
[email protected]
https://lists.gnucash.org/mailman/listinfo/gnucash-devel

Reply via email to