racket/collects/frtime/demos/spreadsheet/quotes.ss
2005-05-27 18:56:37 +00:00

76 lines
2.2 KiB
Scheme

(module quotes mzscheme
(require (lib "url.ss" "net"))
(require (lib "list.ss"))
(provide no-quote? stock-quote no-quote-reason)
(define-struct no-quote (company reason))
#| ----------------------------------------------------------------------------
Stock and Fund Quotes
---------------------
procedures:
stock-quote : String -> Number
exceptions:
no-quote : (structure:no-quote String Symbol)
The goal is to send a request to some quote server,
read the page line by line, and identify the quote.
-----------------------------------------------------
First: where the information comes from and
how to indentify it within the page:
- the current source is Yahoo's page
- we look for a table cell that looks like
this: <td nowrap><b>DIGIT*.DIGITDIGIT</b></td>
|#
; String[format: String[company name]]
(define SOURCE "http://finance.yahoo.com/q?s=~a&d=v1")
; String -> (union (list String String) #f)
(define (find x)
(regexp-match "<b>([0-9\\.]*)</b></big></td>" x))
; String -> Number
(define (stock-quote company)
(let* ([URL (string->url (format SOURCE company))]
[PG (call/input-url URL get-pure-port read-a-page)]
; [_ (printf "~s~n" PG)] ; for debugging
[LN (filter find PG)]
[QT (if (pair? LN)
(cadr (find (car LN)))
(raise (make-no-quote company 'find)))])
(cond
[(string->number QT)]
[else (raise (make-no-quote company 'no-number))])))
;; Iport -> (listof String)
;; reading a page as a list of lines
(define (read-a-page ip)
(letrec ([reader (lambda ()
(let ([next (read-line)])
(cond
[(eof-object? next) '()]
[else (cons next (reader))])))])
(parameterize ([current-input-port ip])
(reader))))
#| TESTS:
(map stock-quote '(; companies
"BAC" "DELL" "IBM"
; funds
"PRSCX" "NAESX" "FRBAX"))
(with-handlers ([no-quote? (lambda (x) (eq? (no-quote-reason x) 'find))])
(stock-quote "XXX"))
|#
)