Drop price-quotes.scm, gnc-fq-helper.in and gnc-fq-check.in - no longer used

This commit is contained in:
Geert Janssens 2021-03-16 14:18:01 +01:00 committed by John Ralls
parent bf357315fd
commit e97fc3e408
11 changed files with 10 additions and 1066 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Test file for price database stuff
# To update the price database call
# $PATH/gnucash --add-price-quotes $PATHTOFILE
# $PATH/gnucash-cli --quotes get $PATHTOFILE
# before running this.
# Adding to a calling bash script would be better
# Although calling it from here would be even better!

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Another test file for price database stuff
# To update the price database call
# $PATH/gnucash --add-price-quotes $PATHTOFILE
# $PATH/gnucash-cli --quotes get $PATHTOFILE
# before running this.
# Adding to a calling bash script would be better
# Although calling it from here would be even better!

View File

@ -267,15 +267,10 @@ foreach(gres_file ${gresource_files})
endforeach()
gnc_add_scheme_targets(price-quotes
SOURCES price-quotes.scm
OUTPUT_DIR gnucash
DEPENDS "scm-engine;scm-app-utils;scm-gnome-utils")
set_local_dist(gnucash_DIST_local CMakeLists.txt environment.in generate-gnc-script
gnucash.cpp gnucash-commands.cpp gnucash-cli.cpp gnucash-core-app.cpp
gnucash-locale-macos.mm gnucash-locale-windows.c gnucash.rc.in gnucash-valgrind.in
gnucash-gresources.xml ${gresource_files} price-quotes.scm
gnucash-gresources.xml ${gresource_files}
${gnucash_noinst_HEADERS} ${gnucash_EXTRA_DIST})
set (gnucash_DIST ${gnucash_DIST_local} ${gnome_DIST} ${gnome_search_DIST} ${gnome_utils_DIST}

View File

@ -183,7 +183,6 @@ scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **
auto quote_sources = quotes.sources_as_glist();
gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources);
g_list_free (quote_sources);
scm_c_use_module("gnucash price-quotes");
}
else
{

View File

@ -1,504 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; price-quotes.scm - manage sub-processes.
;;; Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
;;;
;;; 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 price-quotes))
(export gnc:book-add-quotes) ;; called from gnome/dialog-price-edit-db.c
(use-modules (gnucash engine))
(use-modules (gnucash utilities))
(use-modules (gnucash core-utils))
(use-modules (gnucash app-utils))
(use-modules (gnucash gnome-utils))
(use-modules (srfi srfi-11)
(srfi srfi-1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Finance::Quote based instantaneous quotes -- used by the
;; --add-price-quotes command line option, etc.
;;
;; Note From: Dave Peticolas <dave@krondo.com> Date: Sun, 01 Apr 2001
;; Those aren't pricedb functions, those are online quote functions,
;; i.e., low-level functions for getting online-quotes and putting
;; them into the price db. Reports should not be using those
;; functions, they should be using the price db. See
;; src/engine/gnc-pricedb.h
(define gnc:*finance-quote-helper*
(string-append (gnc-path-get-bindir) "/gnc-fq-helper"))
(define (gnc:fq-get-quotes requests)
;; requests should be a list where each item is of the form
;;
;; (<fq-method> sym sym ...)
;;
;; i.e. (alphavantage "RHAT" "LNUX" "IBM")
;;
;; for currencies, we have
;;
;; (currency "USD" "AUD") for the conversion from USD to AUD,
;; i.e., the price of USD in AUD.
;;
;; This function will return #f on catastrophic failure or a list
;; where, for each element in requests, the output list will contain
;; a quote-result element. This element will be #f or an error
;; symbol if the corresponding method call fails, or a list
;; otherwise. A quote-result list will contain the symbol
;; representing the item being quoted, followed by an alist
;; detailing the quote data from gnc-fq-helper.
;;
;; Possible error symbols and their meanings are:
;; missing-lib One of the required perl libs is missing
;;
;; So for the example method call above, the resulting item in the
;; output list might look like this:
;;
;; (("RHAT" (symbol . "RHAT") (gnc:time-no-zone . "...")
;; (last . 6.59375) (currency . "USD"))
;; ("LNUX" (symbol . "LNUX") (gnc:time-no-zone . "...")
;; (last . 3.5) (currency . "USD"))
;; ("IBM" (symbol . "IBM") (gnc:time-no-zone . "...")
;; (last . 104.42) (currency . "USD")))
;;
;; Also note that any given value in the alist might be
;; 'failed-conversion if the Finance::Quote result for that field
;; was unparsable. See the gnc-fq-helper for more details
;; about it's output.
(let ((quoter #f))
(define (start-quoter)
(set! quoter
(gnc-spawn-process-async (list "perl" "-w" gnc:*finance-quote-helper*) #t)))
(define (get-quotes)
(when quoter
(map
(lambda (request)
(catch #t
(lambda ()
(gnc:debug "handling-request: " request)
(and (member (car request) '("currency" "alphavantage" "vanguard"))
(not (getenv "ALPHAVANTAGE_API_KEY"))
(throw 'need-alphavantage-key))
;; we need to display the first element (the method,
;; so it won't be quoted) and then write the rest
(with-output-to-port (fdes->outport (gnc-process-get-fd quoter 0))
(lambda ()
(display #\()
(display (car request))
(display " ")
(for-each write (cdr request))
(display #\))
(newline)
(force-output)))
(let ((results (read (fdes->inport (gnc-process-get-fd quoter 1)))))
(gnc:debug "results: " results)
results))
(lambda (key . args) key)))
requests)))
(define (kill-quoter)
(when quoter
(gnc-detach-process quoter #t)
(set! quoter #f)))
(dynamic-wind start-quoter get-quotes kill-quoter)))
(define (gnc:book-add-quotes window book)
(define (book->commodity->fq-call-data book)
;; Call helper that walks all of the defined commodities to see if
;; any are marked for quote retrieval. This function returns a
;; list of info needed for the relevant Finance::Quote calls, and
;; a list of the corresponding commodities. Also perform a bit of
;; optimization, merging calls for symbols to the same
;; Finance::Quote method.
;;
;; Returns a list of the info needed for a set of calls to
;; gnc-fq-helper. Each item will of the list will be of the
;; form:
;;
;; (("alphavantage" (commodity-1 currency-1 tz-1)
;; (commodity-2 currency-2 tz-2) ...)
;; ("fidelity_direct" (commodity-3 currency-3 tz-3)
;; (commodity-4 currency-4 tz-4) ...)
;; ("currency" curr-1 curr-2 tz)
;; ("currency" curr-3 curr-4 tz) ...)
(let-values (((currency-list commodity-list)
(partition (lambda (a) (string=? (car a) "currency"))
(gnc-commodity-table-get-quotable-commodities
(gnc-commodity-table-get-table book)))))
(let ((commodity-hash (make-hash-table))
(currency-list-filtered
(filter
(lambda (a)
(and (not (gnc-commodity-equiv (cadr a) (caddr a)))
(not (string=? (gnc-commodity-get-mnemonic (cadr a)) "XXX"))))
currency-list)))
;; Now collect symbols going to the same backend.
(for-each
(lambda (item)
(let ((key (car item))
(val (cdr item)))
(hash-set! commodity-hash key
(cons val (hash-ref commodity-hash key '())))))
commodity-list)
;; Now translate to just what gnc-fq-helper expects.
(and (or (pair? currency-list-filtered) (pair? commodity-list))
(append
(hash-map->list cons commodity-hash)
(map (lambda (cmd) (cons (car cmd) (list (cdr cmd))))
currency-list-filtered))))))
(define (fq-call-data->fq-calls fq-call-data)
;; take an output element from book->commodity->fq-call-data and
;; return a list where the gnc_commodities have been converted to
;; their fq-suitable symbol strings. i.e. turn the former into
;; the latter:
;;
;; ("alphavantage" (commodity-1 currency-1 tz-1)
;; (commodity-2 currency-2 tz-2) ...)
;;
;; ("alphavantage" "IBM" "AMD" ...)
;;
(if (equal? (car fq-call-data) "currency")
(map (lambda (quote-item-info)
(list (car fq-call-data)
(gnc-commodity-get-mnemonic (car quote-item-info))
(gnc-commodity-get-mnemonic (cadr quote-item-info))))
(cdr fq-call-data))
(list
(cons (car fq-call-data)
(map
(lambda (quote-item-info)
(gnc-commodity-get-mnemonic (car quote-item-info)))
(cdr fq-call-data))))))
(define (fq-results->commod-tz-quote-triples fq-call-data fq-results)
;; Change output of gnc:fq-get-quotes to a list of (commod
;; timezone quote) triples using the matching commodity items from
;; fq-call-data.
;;
;; This function presumes that fq-call-data is "correct" -- it
;; contains the correct number of calls, and has the commodity
;; pointers in all the right places. If not, then the results of
;; this function are undefined.
;;
;; If there's a catatstrophic error, this function might return
;; #f. If there's an error for any given input element, there
;; will be a pair like this in the output (#f . <commodity>)
;; indicating the commodity for which the quote failed.
;;
;; If this function doesn't return #f, it will return a list with
;; as many elements as there were commodities in the fq-call-data.
;;
;; We might want more sophisticated error handling later, but this
;; will do for now .
(let ((result-list '()))
(define (process-a-quote call-data call-result)
;; data -> (commod-1 currency-1 tz-1)
;; result -> (commod-1-sym . result-alist) or some kind of garbage.
(if (and (list? call-result)
(not (null? call-result))
(list? (cdr call-result))
(every
(lambda (alist-item)
(and (pair? alist-item)
(not (eq? 'failed-conversion (cdr alist-item)))))
(cdr call-result)))
;; OK, data is good (as far as we can tell).
(set! result-list
(cons (list (car call-data)
(caddr call-data)
(cdr call-result))
result-list))
(set! result-list
(cons (cons #f (car call-data))
result-list))))
(define (process-call-result-pair call-data call-result)
(if (and (list? call-result)
(= (length call-data) (+ 1 (length call-result))))
;; OK, continue.
(for-each
(lambda (call-data-item call-result-item)
(if (and (list? call-result-item) (list? (car call-result-item)))
(for-each
(lambda (result-subitem)
(gnc:debug "call-data-item: " call-data-item)
(gnc:debug "result-subitem: " result-subitem)
(process-a-quote call-data-item result-subitem))
call-result-item)
(process-a-quote call-data-item call-result-item)))
(cdr call-data) call-result)
;; else badly formed result, must assume all garbage.
(for-each
(lambda (call-item)
(set! result-list (cons (cons #f (car call-item)) result-list)))
(cdr call-data))))
(and (list? fq-call-data)
(list? fq-results)
(= (length fq-call-data) (length fq-results))
(begin
(for-each process-call-result-pair
fq-call-data
fq-results)
(reverse result-list)))))
(define (timestr->time64 timestr time-zone)
;; time-zone is ignored currently
(gnc-parse-time-to-time64 timestr "%Y-%m-%d %H:%M:%S"))
(define (commodity-tz-quote-triple->price book c-tz-quote-triple)
;; return a string like "NASDAQ:CSCO" on error, or a price on
;; success. Presume that F::Q currencies are ISO4217 currencies.
(let* ((commodity (first c-tz-quote-triple))
(time-zone (second c-tz-quote-triple))
(quote-data (third c-tz-quote-triple))
(gnc-time (assq-ref quote-data 'gnc:time-no-zone))
(price #f)
(price-type #f)
(currency-str (assq-ref quote-data 'currency))
(commodity-table (gnc-commodity-table-get-table book))
(currency
(and commodity-table
(string? currency-str)
(gnc-commodity-table-lookup commodity-table
"ISO4217"
(string-upcase currency-str))))
(pricedb (gnc-pricedb-get-db book))
(saved-price #f)
(commodity-str (gnc-commodity-get-printname commodity))
)
(if (equal? (gnc-commodity-get-printname currency) commodity-str)
(let* ((symbol (assq-ref quote-data 'symbol))
(other-curr
(and commodity-table
(string? symbol)
(gnc-commodity-table-lookup commodity-table "ISO4217"
(string-upcase symbol)))))
(set! commodity other-curr)))
(let lp ((price-syms '(last nav price))
(price-types '("last" "nav" "unknown")))
(unless (null? price-syms)
(cond
((assq-ref quote-data (car price-syms)) =>
(lambda (p)
;; The OpenExchange exchange rate source in Finance::Quote produces
;; some ridiculously precise prices like #e6.95253159056541e-5 which
;; produce a denominator greater than INT64_MAX. Use the rationalize
;; function to bring them back to reality. The precision parameter is
;; chosen empirically to give the best results.
(set! price (gnc-scm-to-numeric
(rationalize p 1/100000000000000)))
(set! price-type (car price-types))))
(else (lp (cdr price-syms) (cdr price-types))))))
(if gnc-time
(set! gnc-time (timestr->time64 gnc-time time-zone))
(set! gnc-time (gnc:get-today)))
(if (not (and commodity currency gnc-time price price-type))
(string-append
currency-str ":" (gnc-commodity-get-mnemonic commodity))
(begin
(set! saved-price (gnc-pricedb-lookup-day-t64 pricedb
commodity currency
gnc-time))
(if (not (null? saved-price))
(begin
(if (gnc-commodity-equiv (gnc-price-get-currency saved-price)
commodity)
(set! price (gnc-numeric-invert price)))
(if (>= (gnc-price-get-source saved-price) PRICE-SOURCE-FQ)
(begin
(gnc-price-begin-edit saved-price)
(gnc-price-set-time64 saved-price gnc-time)
(gnc-price-set-source saved-price PRICE-SOURCE-FQ)
(gnc-price-set-typestr saved-price price-type)
(gnc-price-set-value saved-price price)
(gnc-price-commit-edit saved-price)
#f)
#f))
(let ((gnc-price (gnc-price-create book)))
(if (not gnc-price)
(string-append
currency-str ":" (gnc-commodity-get-mnemonic commodity))
(begin
(gnc-price-begin-edit gnc-price)
(gnc-price-set-commodity gnc-price commodity)
(gnc-price-set-currency gnc-price currency)
(gnc-price-set-time64 gnc-price gnc-time)
(gnc-price-set-source gnc-price PRICE-SOURCE-FQ)
(gnc-price-set-typestr gnc-price price-type)
(gnc-price-set-value gnc-price price)
(gnc-price-commit-edit gnc-price)
gnc-price))))
))
))
(define (book-add-prices! book prices)
(let ((pricedb (gnc-pricedb-get-db book)))
(for-each
(lambda (price)
(when price
(gnc-pricedb-add-price pricedb price)
(gnc-price-unref price)))
prices)))
(define (show-error msg)
(gnc:gui-error msg (G_ msg)))
;; Add the alphavantage api key to the environment. This value is taken from
;; the Online Quotes preference tab
(let ((alphavantage-api-key
(gnc-prefs-get-string "general.finance-quote" "alphavantage-api-key")))
(gnc:debug "ALPHAVANTAGE_API_KEY=" alphavantage-api-key)
(unless (string-null? alphavantage-api-key)
(setenv "ALPHAVANTAGE_API_KEY" alphavantage-api-key)))
(let* ((fq-call-data (book->commodity->fq-call-data book))
(fq-calls (and fq-call-data
(append-map fq-call-data->fq-calls fq-call-data)))
(fq-results (and fq-calls (gnc:fq-get-quotes fq-calls)))
(commod-tz-quote-triples (and fq-results (list? (car fq-results))
(fq-results->commod-tz-quote-triples
fq-call-data fq-results)))
;; At this point commod-tz-quote-triples will either be #f or a
;; list of items. Each item will either be (commodity
;; timezone quote-data) or (#f . problem-commodity)
(problem-syms (and commod-tz-quote-triples
(filter-map
(lambda (cq-pair)
(and (not (car cq-pair))
(string-append
(gnc-commodity-get-namespace (cdr cq-pair))
":"
(gnc-commodity-get-mnemonic (cdr cq-pair)))))
commod-tz-quote-triples)))
;; strip out the "bad" ones from above.
(ok-syms (and commod-tz-quote-triples (filter car commod-tz-quote-triples)))
(keep-going? #t))
(cond
((not fq-call-data)
(set! keep-going? #f)
(show-error (N_ "No commodities marked for quote retrieval.")))
((not fq-results)
(set! keep-going? #f)
(show-error (N_ "Unable to get quotes or diagnose the problem.")))
((memq 'missing-lib fq-results)
(set! keep-going? #f)
(show-error (N_ "You are missing some needed Perl libraries.
Run 'gnc-fq-update' as root to install them.")))
((memq 'need-alphavantage-key fq-results)
(set! keep-going? #f)
(show-error (format #f (G_ "ERROR: ALPHAVANTAGE_API_KEY must be set for currency and quotes; see ~A")
"https://wiki.gnucash.org/wiki/Online_Quotes#Source_Alphavantage.2C_US")))
((memq 'system-error fq-results)
(set! keep-going? #f)
(show-error (N_ "There was a system error while retrieving the price quotes.")))
((not (list? (car fq-results)))
(set! keep-going? #f)
(show-error (N_ "There was an unknown error while retrieving the price quotes.")))
((not commod-tz-quote-triples)
(set! keep-going? #f)
(show-error (N_ "Unable to get quotes or diagnose the problem.")))
((pair? problem-syms)
(cond
((not (gnucash-ui-is-running))
(gnc:warn
(with-output-to-string
(lambda ()
(display "Unable to retrieve quotes for these items:\n")
(display (string-join problem-syms "\n "))
(newline)
(display "Continuing with good quotes.")
(newline)))))
((and ok-syms (not (null? ok-syms)))
(set! keep-going?
(gnc-verify-dialog
window #t (with-output-to-string
(lambda ()
(display (G_ "Unable to retrieve quotes for these items:"))
(display "\n ")
(display (string-join problem-syms "\n "))
(newline)
(display (G_ "Continue using only the good quotes?")))))))
(else
(set! keep-going? #f)
(gnc-error-dialog
window (with-output-to-string
(lambda ()
(display (G_ "Unable to retrieve quotes for these items:"))
(display "\n ")
(display (string-join problem-syms "\n ")))))))))
(when keep-going?
(let ((prices (map (lambda (triple)
(commodity-tz-quote-triple->price book triple))
ok-syms)))
(when (any string? prices)
(if (gnucash-ui-is-running)
(set! keep-going?
(gnc-verify-dialog
window #t
(with-output-to-string
(lambda ()
(display (G_ "Unable to create prices for these items:"))
(display "\n ")
(display (string-join (filter string? prices) "\n "))
(newline)
(display (G_ "Add remaining good quotes?"))))))
(gnc:warn
(with-output-to-string
(lambda ()
(display "Unable to create prices for these items:\n ")
(display (string-join (filter string? prices) "\n "))
(newline)
(display "Adding remaining good quotes.")
(newline))))))
(when keep-going?
(book-add-prices! book (filter (negate string?) prices)))))))

View File

@ -118,7 +118,6 @@ static const char* source_names[(size_t)PRICE_SOURCE_INVALID + 1] =
{
/* sync with price_to_gui in dialog-price-editor.c */
"user:price-editor",
/* sync with commidity-tz-quote->price in price-quotes.scm */
"Finance::Quote",
"user:price",
/* String retained for backwards compatibility. */

View File

@ -1,6 +1,6 @@
set(_BIN_FILES "")
foreach(file gnc-fq-check.in gnc-fq-helper.in gnc-fq-update.in gnc-fq-dump.in finance-quote-wrapper.in)
foreach(file gnc-fq-update.in gnc-fq-dump.in finance-quote-wrapper.in)
string(REPLACE ".in" "" _OUTPUT_FILE_NAME ${file})
set(_ABS_OUTPUT_FILE ${BINDIR_BUILD}/${_OUTPUT_FILE_NAME})
configure_file( ${file} ${_ABS_OUTPUT_FILE} @ONLY)
@ -9,7 +9,7 @@ endforeach(file)
set(_MAN_FILES "")
foreach(file gnc-fq-dump gnc-fq-helper)
foreach(file gnc-fq-dump finance-quote-wrapper)
set(_POD_INPUT ${BINDIR_BUILD}/${file})
set(_MAN_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${file}.1)
list(APPEND _MAN_FILES ${_MAN_OUTPUT})
@ -26,4 +26,4 @@ add_custom_target(quotes-bin ALL DEPENDS ${_BIN_FILES})
install(FILES ${_MAN_FILES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(PROGRAMS ${_BIN_FILES} DESTINATION ${CMAKE_INSTALL_BINDIR})
set_dist_list(quotes_DIST CMakeLists.txt gnc-fq-check.in gnc-fq-dump.in gnc-fq-helper.in gnc-fq-update.in finance-quote-wrapper.in Quote_example.pl README)
set_dist_list(quotes_DIST CMakeLists.txt gnc-fq-dump.in gnc-fq-update.in finance-quote-wrapper.in Quote_example.pl README)

View File

@ -2,11 +2,11 @@
This directory contains assorted stock quote scripts.
gnc-fq-check.in:
finance-quote-wrapper.in:
Source file for gnc-fq-check which is a perl script that allows
gnucash to determine if Finance::Quote is installed properly. The
responses is a scheme form.
Source file for finance-quote-wrapper which is a perl script that
allows gnucash to communicate with Finance::Quote.
The requests and responses are in json format.
gnc-fq-dump.in:
@ -14,12 +14,6 @@ gnc-fq-dump.in:
a quote from Finance::Quote and dumps the response to the terminal.
Its useful for determining problems with F::Q.
gnc-fq-helper.in:
Source file for gnc-fq-helper which is a perl script that
allows gnucash to communicate with Finance::Quote over pipes from
guile. The requests and responses are scheme forms.
gnc-fq-update.in:
Source file for gnc-fq-update which is a perl script that updates

View File

@ -1,103 +0,0 @@
#!@PERL@ -w
######################################################################
### gnc-fq-check - check for the presence of Finance::Quote
### From gnc-fq-helper.
### Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
###
### 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
######################################################################
use strict;
use English;
use FileHandle;
=head1 NAME
gnc-fq-check - check for the presence of Finance::Quote
From gnc-fq-helper
=head1 SYNOPSIS
gnc-fq-check
=head1 DESCRIPTION
Input: <none>
Output (on standard output, one output form per input line):
A list of quote sources supported by Finance::Quote, or the single
term missing-lib if finance quote could not be executed.
Exit status
0 - success
non-zero - failure
=cut
sub check_modules {
my @modules = qw(Finance::Quote);
my @missing;
foreach my $mod (@modules) {
if (eval "require $mod") {
$mod->import();
}
else {
push (@missing, $mod);
}
}
return unless @missing;
print STDERR "\n";
print STDERR "You need to install the following Perl modules:\n";
foreach my $mod (@missing) {
print STDERR " ".$mod."\n";
}
print STDERR "\n";
print STDERR "Use your system's package manager to install them,\n";
print STDERR "or run 'gnc-fq-update' as root.\n";
print "missing-lib\n";
exit 1;
}
#---------------------------------------------------------------------------
# Runtime.
# Check for and load non-standard modules
check_modules ();
# Create a stockquote object.
my $quoter = Finance::Quote->new();
my $prgnam = "gnc-fq-check";
print "$Finance::Quote::VERSION\n";
my @qsources;
my @sources = $quoter->sources();
foreach my $source (@sources) {
print "$source\n";
}
## Local Variables:
## mode: perl
## End:

View File

@ -1,435 +0,0 @@
#!@PERL@ -w
######################################################################
### gnc-fq-helper - present a scheme interface to Finance::Quote
### Copyright 2001 Rob Browning <rlb@cs.utexas.edu>
###
### 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
######################################################################
use strict;
use English;
=head1 NAME
gnc-fq-helper - allows gnucash to communicate with Finance::Quote
over pipes from guile. The requests and responses
are scheme forms.
=head1 SYNOPSIS
gnc-fq-helper
=head1 DESCRIPTION
Input: (on standard input - one entry per line and one line per
entry, and double quotes must only be delimiters, not string
content -- remember, we don't have a real scheme parser on the perl
side :>).
(<method-name> symbol symbol symbol ...)
where <method-name> indicates the desired Finance::Quote method.
One can list the many methods by running gnc-fq-check.
For currency quotes, the symbols alternate between the 'from'
and 'to' currencies.
For example:
(alphavantage "IBM" "LNUX")
(fidelity_direct "FBIOX" "FSELX")
(currency "USD" "AUD")
Output (on standard output, one output form per input line):
Schemified version of gnc-fq's output, basically an alist of
alists, as in the example below. Right now, only the fields that
this script knows about (and knows how to convert to scheme) are
returned, so the conversion function will have to be updated
whenever Finance::Quote changes. Currently you'll get symbol,
gnc:time-no-zone, and currency, and either last, nav, or price.
Fields with gnc: prefixes are non-Finance::Quote fields.
gnc:time-no-zone is returned as a string of the form "YYYY-MM-DD
HH:MM:SS", basically the unmolested (and underspecified) output of
the quote source. It's up to you to know what it's proper timezone
really is. i.e. if you know the time was in America/Chicago, you'll
need to convert it to that.
For example:
$ echo '(alphavantage "CSCO" "JDSU" "^IXIC")' | ./gnc-fq-helper
(("CSCO" (symbol . "CSCO")
(gnc:time-no-zone . "2001-03-13 19:27:00")
(last . 20.375)
(currency . "USD"))
("JDSU" (symbol . "JDSU")
(gnc:time-no-zone . "2001-03-13 19:27:00")
(last . 23.5625)
(currency . "USD"))
("^IXIC" (symbol . ^IXIC)
(gnc:time-no-zone . 2002-12-04 17:16:00)
(last . 1430.35)
(currency . failed-conversion)))
On error, the overall result may be #f, or on individual errors, the
list sub-item for a given symbol may be #f, like this:
$ echo '(alphavantage "CSCO" "JDSU")' | ./gnc-fq-helper
(#f
("JDSU" (symbol . "JDSU")
(gnc:time-no-zone . "2001-03-13 19:27:00")
(last . 23.5625)
(currency . "USD")))
further, errors may be stored with each quote as indicated in
Finance::Quote, and whenever the conversion to scheme data fails,
the field will have the value 'failed-conversion, and accordingly
this symbol will never be a legitimate conversion.
Exit status
0 - success
non-zero - failure
=cut
# The methods we know about. For now we assume they all have the same
# signature so this works OK.
sub check_modules {
# Date::Manip provides ParseDate, ParseDateString, and UnixTime.
my @modules = qw(FileHandle Finance::Quote Date::Manip);
my @missing;
foreach my $mod (@modules) {
if (eval "require $mod") {
$mod->import();
}
else {
push (@missing, $mod);
}
}
return unless @missing;
print STDERR "\n";
print STDERR "You need to install the following Perl modules:\n";
foreach my $mod (@missing) {
print STDERR " ".$mod."\n";
}
print STDERR "\n";
print STDERR "Use your system's package manager to install them,\n";
print STDERR "or run 'gnc-fq-update' as root.\n";
print "missing-lib";
exit 1;
}
# Check for and load non-standard modules
check_modules ();
# Set a base date with the current time in the current TZ:
my $base_date = new Date::Manip::Date;
$base_date->parse("now");
sub schemify_string {
my($str) = @_;
if(!$str) { return "failed-conversion"; }
# FIXME: Is this safe? Can we just double all backslashes and backslash
# escape all double quotes and get the right answer?
# double all backslashes.
my $bs = "\\";
$str =~ s/$bs$bs/$bs$bs/gmo;
# escape all double quotes.
# Have to do this because the perl-mode parser freaks out otherwise.
my $dq = '"';
$str =~ s/$dq/$bs$dq/gmo;
return '"' . $str . '"';
}
sub schemify_boolean {
my($bool) = @_;
if($bool) {
return "#t";
} else {
return "#f";
}
}
sub schemify_num {
my($numstr) = @_;
# This is for normal numbers, not the funny ones like "2.346B".
# For now we don't need to do anything.
if(!$numstr) { return "failed-conversion"; }
if($numstr =~ /^\s*(\d+(\.\d+)?([eE][+-]?\d+)?)$/o) {
return "#e" . $1;
} else {
return "failed-conversion";
}
}
# sub schemify_range {
# #convert range in form ``num1 - num2'' to ``(num1 num2)''.
# }
sub get_quote_time {
# return the date.
my ($item, $quotehash) = @_;
my $datestr = $$quotehash{$item, 'date'};
my $timestr = $$quotehash{$item, 'time'};
my $format = "%Y-%m-%d %H:%M:%S";
my $result;
if ($datestr) {
my $parsestr = $datestr . " " . ($timestr ? $timestr : "12:00:00");
my $date = $base_date->new();
my $err = $date->parse($parsestr);
if ($err) {
print $date->err(), " $parsestr\n";
$result = $base_date->printf($format);
}
else {
$result = $date->printf($format);
}
} else {
$result = $base_date->printf($format);
}
return("\"$result\"");
}
sub schemify_quote {
my($itemname, $quotehash, $indentlevel) = @_;
my $scmname = schemify_string($itemname);
my $quotedata = "";
my $field;
my $data;
if (!$$quotehash{$itemname, "success"}) {
return schemify_boolean(0);
}
$field = 'symbol';
if (($$quotehash{$itemname, $field})) {
$data = schemify_string($$quotehash{$itemname, $field});
} else {
# VWD and a few others don't set the symbol field
$data = schemify_string($itemname);
}
$quotedata .= "($field . $data)";
$field = 'gnc:time-no-zone';
$data = get_quote_time($itemname, $quotehash);
$quotedata .= " ($field . $data)" if $data;
$field = 'last';
if (!($$quotehash{$itemname, $field})) {
$field = 'nav';
}
if (!($$quotehash{$itemname, $field})) {
$field = 'price';
}
$data = schemify_num($$quotehash{$itemname, $field});
$quotedata .= " ($field . $data)";
$field = 'currency';
$data = schemify_string($$quotehash{$itemname, $field});
$quotedata .= " ($field . $data)";
return "($scmname $quotedata)";
}
sub schemify_quotes {
my($symbols, $quotehash) = @_;
my $resultstr = "";
my $sym;
my $separator = "";
# we have to pass in @$items because Finance::Quote just uses the
# mangled "$name$field string as the key, so there's no way (I know
# of) to find out which stocks are in a given quotehash, just given
# the quotehash.
foreach $sym (@$symbols) {
$resultstr .= $separator . schemify_quote($sym, $quotehash, 2);
if(!$separator) { $separator = "\n "; }
}
return "($resultstr)\n";
}
sub parse_input_line {
# FIXME: we need to rewrite parsing to handle commands modularly.
# Right now all we do is hard-code "fetch".
my($input) = @_;
# Have to do this because the perl-mode parser freaks out otherwise.
my $dq = '"';
my @symbols;
# Make sure we have an opening ( preceded only by whitespace.
# and followed by a one word method name composed of [a-z_]+.
# Also allow the '.' and '^' characters for stock indices.
# Kill off the whitespace if we do and grab the command.
if($input !~ s/^\s*\(\s*([\.\^a-z_]+)\s+//o) { return 0; }
my $quote_method_name = $1;
# Make sure we have an ending ) followed only by whitespace
# and kill it off if we do...
if($input !~ s/\s*\)\s*$//o) { return 0; }
while($input) {
# Items should look like "RHAT"
# Grab RHAT and delete "RHAT"\s*
if($input !~ s/^$dq([^$dq]+)$dq\s*//o) { return 0; }
my $symbol = $1;
push @symbols, $symbol;
}
my @result = ($quote_method_name, \@symbols);
return \@result;
}
#---------------------------------------------------------------------------
# Runtime.
# Create a stockquote object.
my $quoter = Finance::Quote->new();
my $prgnam = "gnc-fq-helper";
# Disable default currency conversions.
$quoter->set_currency();
while(<>) {
my $result = parse_input_line($_);
if(!$result) {
print STDERR "$prgnam: bad input line ($_)\n";
exit 1;
}
my($quote_method_name, $symbols) = @$result;
my %quote_data;
if($quote_method_name =~ m/^currency$/) {
my ($from_currency, $to_currency) = @$symbols;
last unless $from_currency;
last unless $to_currency;
my $price = $quoter->currency($from_currency, $to_currency);
my $inv_price = undef;
# Sometimes price quotes are available in only one direction.
unless (defined($price)) {
$inv_price = $quoter->currency($to_currency, $from_currency);
if (defined($inv_price)) {
my $tmp = $to_currency;
$to_currency = $from_currency;
$from_currency = $tmp;
$price = $inv_price;
}
}
$quote_data{$from_currency, "success"} = defined($price);
$quote_data{$from_currency, "symbol"} = $from_currency;
$quote_data{$from_currency, "currency"} = $to_currency;
$quote_data{$from_currency, "last"} = $price;
my @new_symbols = ($from_currency);
$symbols = \@new_symbols;
} else {
%quote_data = $quoter->fetch($quote_method_name, @$symbols);
}
if (%quote_data) {
print schemify_quotes($symbols, \%quote_data);
} else {
print "#f\n";
}
STDOUT->flush();
}
exit 0;
__END__
# Keep this around in case we need to go back to complex per-symbol args.
#
# while($input) {
# # Items should look like "RHAT" "EST")
# # Grab RHAT and delete ("RHAT"\s*
# if($input !~ s/^\(\s*$dq([^$dq]+)$dq\s*//o) { return 0; }
# my $symbol = $1;
# my $timezone;
# # Now grab EST or #f and delete \s*"EST") or #f)
# if($input =~ s/^\s*$dq([^$dq]+)$dq\)\s*//o) {
# $timezone = $1;
# } else {
# if($input =~ s/^\s*(\#f)\)\s*//o) {
# $timezone = 0;
# } else {
# return 0;
# }
# }
# sub get_quote_utc {
# # return the date in utc epoch seconds, using $timezone if specified.
# my ($item, $timezone, $quotehash) = @_;
# if(!defined($timezone)) { return "failed-conversion"; }
# my $datestr = $$quotehash{$item, 'date'};
# my $timestr = $$quotehash{$item, 'time'};
# if(!$datestr) {
# return "failed-conversion";
# }
# my $parsestr = $datestr;
# if($timestr) {
# $parsestr .= " $timestr";
# }
# if($timezone) {
# # Perform a conversion.
# $parsestr = Date_ConvTZ(ParseDate($parsestr), $timezone, 'UTC');
# }
# my $result = UnixDate($parsestr, "%s");
# if($result !~ /^(\+|-)?\d+$/) {
# $result = "failed-conversion";
# }
# return $result;
# }
## Local Variables:
## mode: perl
## End:

View File

@ -374,7 +374,6 @@ gnucash/import-export/qif-imp/qif-parse.scm
gnucash/import-export/qif-imp/qif-to-gnc.scm
gnucash/import-export/qif-imp/qif-utils.scm
gnucash/import-export/qif-imp/string.scm
gnucash/price-quotes.scm
gnucash/python/gncmod-python.c
gnucash/python/init.py
gnucash/python/pycons/console.py