mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
354 lines
13 KiB
Scheme
354 lines
13 KiB
Scheme
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; price-scatter.scm: A scatter plot report about some price.
|
|
;;
|
|
;; By Christian Stimming <stimming@tuhh.de>
|
|
;;
|
|
;; This program is free software; you can redistribute it and/or
|
|
;; modify it under the terms of the GNU General Public License as
|
|
;; published by the Free Software Foundation; either version 2 of
|
|
;; the License, or (at your option) any later version.
|
|
;;
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; if not, contact:
|
|
;;
|
|
;; Free Software Foundation Voice: +1-617-542-5942
|
|
;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
|
|
;; Boston, MA 02110-1301, USA gnu@gnu.org
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define-module (gnucash report standard-reports price-scatter))
|
|
|
|
(use-modules (gnucash main)) ;; FIXME: delete after we finish modularizing.
|
|
(use-modules (srfi srfi-1))
|
|
(use-modules (gnucash gnc-module))
|
|
(use-modules (gnucash core-utils))
|
|
(use-modules (gnucash gettext))
|
|
|
|
(use-modules (gnucash printf))
|
|
|
|
(gnc:module-load "gnucash/report/report-system" 0)
|
|
|
|
(define optname-from-date (N_ "Start Date"))
|
|
(define optname-to-date (N_ "End Date"))
|
|
(define optname-stepsize (N_ "Step Size"))
|
|
|
|
(define pagename-price (N_ "Price"))
|
|
(define optname-report-currency (N_ "Report's currency"))
|
|
(define optname-price-commodity (N_ "Price of Commodity"))
|
|
(define optname-price-source (N_ "Price Source"))
|
|
(define optname-invert (N_ "Invert prices"))
|
|
|
|
;; (optname-accounts (N_ "Accounts"))
|
|
;; The line break in the next expression will suppress above comment as translator comment.
|
|
|
|
(define optname-inc-exp
|
|
(N_ "Show Income/Expense"))
|
|
(define optname-show-profit (N_ "Show Net Profit"))
|
|
|
|
(define optname-sep-bars (N_ "Show Asset & Liability bars"))
|
|
(define optname-net-bars (N_ "Show Net Worth bars"))
|
|
|
|
(define optname-marker (N_ "Marker"))
|
|
(define optname-markercolor (N_ "Marker Color"))
|
|
(define optname-plot-width (N_ "Plot Width"))
|
|
(define optname-plot-height (N_ "Plot Height"))
|
|
|
|
(define (options-generator)
|
|
(let* ((options (gnc:new-options))
|
|
;; This is just a helper function for making options.
|
|
(add-option
|
|
(lambda (new-option)
|
|
(gnc:register-option options new-option))))
|
|
|
|
(gnc:options-add-date-interval!
|
|
options gnc:pagename-general
|
|
optname-from-date optname-to-date "a")
|
|
|
|
(gnc:options-add-interval-choice!
|
|
options gnc:pagename-general optname-stepsize "b" 'MonthDelta)
|
|
|
|
(gnc:options-add-currency!
|
|
options pagename-price optname-report-currency "d")
|
|
|
|
(add-option
|
|
(gnc:make-commodity-option
|
|
pagename-price optname-price-commodity
|
|
"e"
|
|
(N_ "Calculate the price of this commodity.")
|
|
(gnc-locale-default-iso-currency-code)))
|
|
|
|
(add-option
|
|
(gnc:make-multichoice-option
|
|
pagename-price optname-price-source
|
|
"f" (N_ "The source of price information.")
|
|
'actual-transactions
|
|
(list (vector 'weighted-average
|
|
(N_ "Weighted Average")
|
|
(N_ "The weighted average of all currency transactions of the past."))
|
|
(vector 'actual-transactions
|
|
(N_ "Actual Transactions")
|
|
(N_ "The instantaneous price of actual currency transactions in the past."))
|
|
(vector 'pricedb
|
|
(N_ "Price Database")
|
|
(N_ "The recorded prices."))
|
|
)))
|
|
|
|
(add-option
|
|
(gnc:make-simple-boolean-option
|
|
pagename-price optname-invert
|
|
"g"
|
|
(N_ "Plot commodity per currency rather than currency per commodity.")
|
|
#f))
|
|
|
|
|
|
(gnc:options-add-plot-size!
|
|
options gnc:pagename-display
|
|
optname-plot-width optname-plot-height "c" 500 400)
|
|
|
|
(gnc:options-add-marker-choice!
|
|
options gnc:pagename-display
|
|
optname-marker "a" 'filledsquare)
|
|
|
|
(add-option
|
|
(gnc:make-color-option
|
|
gnc:pagename-display optname-markercolor
|
|
"b"
|
|
(N_ "Color of the marker.")
|
|
(list #xb2 #x22 #x22 0)
|
|
255 #f))
|
|
|
|
(gnc:options-set-default-section options gnc:pagename-general)
|
|
|
|
options))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; The renderer function
|
|
(define (renderer report-obj)
|
|
|
|
;; This is a helper function for looking up option values.
|
|
(define (get-option section name)
|
|
(gnc:option-value
|
|
(gnc:lookup-option (gnc:report-options report-obj) section name)))
|
|
|
|
;; small helper for the warnings below
|
|
(define (commodity-numeric->string c n)
|
|
(gnc:monetary->string
|
|
(gnc:make-gnc-monetary c n)))
|
|
|
|
|
|
(let* ((to-date-tp (gnc:timepair-end-day-time
|
|
(gnc:date-option-absolute-time
|
|
(get-option gnc:pagename-general
|
|
optname-to-date))))
|
|
(from-date-tp (gnc:timepair-start-day-time
|
|
(gnc:date-option-absolute-time
|
|
(get-option gnc:pagename-general
|
|
optname-from-date))))
|
|
(interval (get-option gnc:pagename-general optname-stepsize))
|
|
(report-title (get-option gnc:pagename-general
|
|
gnc:optname-reportname))
|
|
|
|
(height (get-option gnc:pagename-display optname-plot-height))
|
|
(width (get-option gnc:pagename-display optname-plot-width))
|
|
(marker (get-option gnc:pagename-display optname-marker))
|
|
(mcolor
|
|
(gnc:color-option->hex-string
|
|
(gnc:lookup-option (gnc:report-options report-obj)
|
|
gnc:pagename-display optname-markercolor)))
|
|
|
|
(report-currency (get-option pagename-price
|
|
optname-report-currency))
|
|
(price-commodity (get-option pagename-price
|
|
optname-price-commodity))
|
|
(price-source (get-option pagename-price
|
|
optname-price-source))
|
|
|
|
(dates-list (gnc:make-date-list
|
|
(gnc:timepair-end-day-time from-date-tp)
|
|
(gnc:timepair-end-day-time to-date-tp)
|
|
(gnc:deltasym-to-delta interval)))
|
|
|
|
(document (gnc:make-html-document))
|
|
(chart (gnc:make-html-scatter))
|
|
(currency-accounts
|
|
(filter gnc:account-has-shares? (gnc-account-get-descendants-sorted
|
|
(gnc-get-current-root-account))))
|
|
(invert (get-option pagename-price optname-invert))
|
|
(data '()))
|
|
|
|
;; Short helper for all the warnings below
|
|
(define (make-warning title text)
|
|
(gnc:html-document-add-object!
|
|
document
|
|
(gnc:make-html-text
|
|
(gnc:html-markup-h2 title)
|
|
(gnc:html-markup-p text))))
|
|
|
|
(gnc:html-scatter-set-title!
|
|
chart report-title)
|
|
(gnc:html-scatter-set-subtitle!
|
|
chart (string-append
|
|
;; Check for whether it is commodity against currency or
|
|
;; the other way round.
|
|
(if invert
|
|
(gnc-commodity-get-mnemonic report-currency)
|
|
(gnc-commodity-get-mnemonic price-commodity))
|
|
" - "
|
|
(sprintf #f
|
|
(_ "%s to %s")
|
|
(gnc-print-date from-date-tp)
|
|
(gnc-print-date to-date-tp))))
|
|
(gnc:html-scatter-set-width! chart width)
|
|
(gnc:html-scatter-set-height! chart height)
|
|
(gnc:html-scatter-set-marker! chart
|
|
(case marker
|
|
((diamond) "diamond")
|
|
((circle) "circle")
|
|
((square) "square")
|
|
((cross) "x")
|
|
((plus) "plus")
|
|
((dash) "dash")
|
|
((filleddiamond) "filledDiamond")
|
|
((filledcircle) "filledCircle")
|
|
((filledsquare) "filledSquare")))
|
|
(gnc:html-scatter-set-markercolor! chart mcolor)
|
|
(gnc:html-scatter-set-y-axis-label!
|
|
chart
|
|
;; Check for whether it is commodity against currency or
|
|
;; the other way round.
|
|
(if invert
|
|
(gnc-commodity-get-mnemonic price-commodity)
|
|
(gnc-commodity-get-mnemonic report-currency)))
|
|
(gnc:html-scatter-set-x-axis-label!
|
|
chart (case interval
|
|
((DayDelta) (_ "Days"))
|
|
((WeekDelta) (_ "Weeks"))
|
|
((TwoWeekDelta) (_ "Double-Weeks"))
|
|
((MonthDelta) (_ "Months"))
|
|
((YearDelta) (_ "Years"))))
|
|
|
|
(if
|
|
(not (gnc-commodity-equiv report-currency price-commodity))
|
|
(begin
|
|
(if (or (not (null? currency-accounts))
|
|
(eq? price-source 'pricedb))
|
|
(set!
|
|
data
|
|
(case price-source
|
|
((actual-transactions)
|
|
(gnc:get-commodity-inst-prices
|
|
currency-accounts to-date-tp
|
|
price-commodity report-currency))
|
|
((weighted-average)
|
|
(gnc:get-commodity-totalavg-prices
|
|
currency-accounts to-date-tp
|
|
price-commodity report-currency))
|
|
((pricedb)
|
|
(map (lambda (p)
|
|
(list (gnc-price-get-time p)
|
|
(gnc-price-get-value p)))
|
|
(gnc-pricedb-get-prices
|
|
(gnc-pricedb-get-db (gnc-get-current-book))
|
|
price-commodity report-currency)))
|
|
)))
|
|
|
|
(set! data (filter
|
|
(lambda (x)
|
|
(and
|
|
(gnc:timepair-ge to-date-tp (first x))
|
|
(gnc:timepair-ge (first x) from-date-tp)))
|
|
data))
|
|
|
|
;; some output
|
|
;;(warn "data" (map (lambda (x) (list
|
|
;; (gnc-print-date (car x))
|
|
;; (gnc-numeric-to-double (second x))))
|
|
;; data))
|
|
|
|
;; convert the gnc:numeric's to doubles
|
|
(if invert
|
|
(set! data (map (lambda (x)
|
|
(list (first x)
|
|
(/ 1 (gnc-numeric-to-double (second x)))))
|
|
data))
|
|
(set! data (map (lambda (x)
|
|
(list (first x)
|
|
(gnc-numeric-to-double (second x))))
|
|
data)))
|
|
|
|
;; convert the dates to the weird x-axis scaling of the
|
|
;; scatterplot
|
|
(set! data
|
|
(map (lambda (x)
|
|
(list
|
|
(/ (- (car (first x))
|
|
(car from-date-tp))
|
|
;; FIXME: These hard-coded values are more
|
|
;; or less totally bogus. OTOH this whole
|
|
;; scaling thing is totally bogus as well,
|
|
;; so this doesn't matter too much.
|
|
(case interval
|
|
((DayDelta) 86400)
|
|
((WeekDelta) 604800)
|
|
((TwoWeekDelta) 1209600)
|
|
((MonthDelta) 2628000)
|
|
((YearDelta) 31536000)))
|
|
(second x)))
|
|
data))
|
|
|
|
(gnc:html-scatter-set-data!
|
|
chart data)
|
|
|
|
;; Make tons of tests so that Guppi won't barf
|
|
(if (not (null? data))
|
|
(if (> (length data) 1)
|
|
(if (apply equal? (map second data))
|
|
(make-warning
|
|
(_ "All Prices equal")
|
|
(_ "All the prices found are equal. \
|
|
This would result in a plot with one straight line. \
|
|
Unfortunately, the plotting tool can't handle that."))
|
|
(if (apply equal? (map first data))
|
|
(make-warning
|
|
(_ "All Prices at the same date")
|
|
(_ "All the prices found are from the same date. \
|
|
This would result in a plot with one straight line. \
|
|
Unfortunately, the plotting tool can't handle that."))
|
|
|
|
(gnc:html-document-add-object! document chart)))
|
|
|
|
(make-warning
|
|
(_ "Only one price")
|
|
(_ "There was only one single price found for the \
|
|
selected commodities in the selected time period. This doesn't give \
|
|
a useful plot.")))
|
|
(make-warning
|
|
(_ "No data")
|
|
(_ "There is no price information available for the \
|
|
selected commodities in the selected time period."))))
|
|
|
|
;; warning if report-currency == price-commodity
|
|
(make-warning
|
|
(_ "Identical commodities")
|
|
(_ "Your selected commodity and the currency of the report \
|
|
are identical. It doesn't make sense to show prices for identical \
|
|
commodities.")))
|
|
|
|
document))
|
|
|
|
;; Here we define the actual report
|
|
(gnc:define-report
|
|
'version 1
|
|
'name (N_ "Price")
|
|
'report-guid "1d241609fd4644caad765c95be20ff4c"
|
|
'menu-path (list gnc:menuname-asset-liability)
|
|
'menu-name (N_ "Price Scatterplot")
|
|
'options-generator options-generator
|
|
'renderer renderer)
|