diff --git a/.gitignore b/.gitignore index d4edbb7..9b0c31b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ autodoc/** /lib/ /classes/ .lein-deps-sum + +.lein-failures diff --git a/project.clj b/project.clj index 8406e4c..d3e7f15 100644 --- a/project.clj +++ b/project.clj @@ -1,10 +1,11 @@ -(defproject com.fxtlabs/stockings "1.1.0-SNAPSHOT" +(defproject com.fxtlabs/stockings "1.2.0-SNAPSHOT" :description "Easy access to financial data: stock quotes, exchange rates, industry sectors, companies, and more." :url "https://github.com/fxtlabs/stockings" - :dependencies [[org.clojure/clojure "1.2.1"] + :dependencies [[org.clojure/clojure "1.4.0"] [joda-time "1.6"] - [clojure-csv "1.2.4"] - [clj-http "0.1.3"]] + [clj-http "0.1.3"] + [org.clojure/data.csv "0.1.2"] + [org.clojure/data.json "0.1.3"]] :dev-dependencies [[com.fxtlabs/autodoc "0.8.0-SNAPSHOT" :exclusions [org.clojure/clojure org.clojure/clojure-contrib]]] diff --git a/src/stockings/alt.clj b/src/stockings/alt.clj index 9f0de3a..403121b 100644 --- a/src/stockings/alt.clj +++ b/src/stockings/alt.clj @@ -3,7 +3,6 @@ from Google Finance." {:author "Filippo Tampieri "} (:use [clojure.string :only (join split-lines)] - [clojure.contrib.def :only (defvar-)] [stockings.utils :only (parse-double parse-int parse-long parse-keyword)] [stockings.core :only (bare-stock-symbol)]) (:require [clojure.xml :as xml] @@ -18,7 +17,7 @@ ;;; Get current quotes ;;; -(defvar- date-time-parser +(def date-time-parser (.withZone (DateTimeFormat/forPattern "yyyyMMddHHmmss") DateTimeZone/UTC)) (defn- parse-date-time @@ -92,14 +91,14 @@ ;;; Get historical quotes ;;; -(defvar- date-parser (DateTimeFormat/forPattern "dd-MMM-yy")) +(def date-parser (DateTimeFormat/forPattern "dd-MMM-yy")) (defn- parse-date "Parse a string representing a date into a `org.joda.time.LocalDate` object." [^String s] (.toLocalDate (.parseDateTime date-parser s))) -(defvar- re-line +(def re-line #"((?:[0-9]|[123][0-9])-\w{3}-[0-9]{2}),([0-9]+(?:\.[0-9]*)?),([0-9]+(?:\.[0-9]*)?),([0-9]+(?:\.[0-9]*)?),([0-9]+(?:\.[0-9]*)?),([0-9]+(?:\.[0-9]*)?)" "The regular expression used to match one line in the CSV-encoded quotes. It matches a line in the form `Date,Open,High,Low,Close,Volume` diff --git a/src/stockings/core.clj b/src/stockings/core.clj index 0f614dd..f081d0c 100644 --- a/src/stockings/core.clj +++ b/src/stockings/core.clj @@ -4,8 +4,7 @@ from Yahoo! Finance." {:author "Filippo Tampieri "} (:use [clojure.string :only (split join lower-case)] - [clojure.contrib.def :only (defvar defvar-)] - [clojure.contrib.json :only (read-json)]) + [clojure.data.json :only (read-json)]) (:require [clj-http.client :as client] [stockings.utils :as yql]) (:import (org.joda.time LocalDate LocalTime DateTimeZone) @@ -78,7 +77,7 @@ ;;; WARNING: use it only for data retrieved from the quotes.csv ;;; service above! -(defvar- nyc-date-time-zone +(def nyc-date-time-zone (DateTimeZone/forTimeZone (TimeZone/getTimeZone "America/New_York"))) (defn get-correct-date-time [^LocalDate date ^LocalTime time] @@ -90,7 +89,10 @@ ;;; Get current quotes ;;; -(defvar- quote-parse-map +(def quote-parse-map + "A map from the keys of a raw stock quote to the parsers used to parse + the corresponding value strings of the raw stock quote into useful + typed values (ints, doubles, dates, etc.)." {:symbol identity :Name identity :PERatio yql/parse-double @@ -143,17 +145,15 @@ :PERatioRealtime yql/parse-double :PriceEPSEstimateNextYear yql/parse-double :EPSEstimateNextQuarter yql/parse-double - :PriceEPSEstimateCurrentYear yql/parse-double} - "A map from the keys of a raw stock quote to the parsers used to parse - the corresponding value strings of the raw stock quote into useful - typed values (ints, doubles, dates, etc.).") + :PriceEPSEstimateCurrentYear yql/parse-double}) -(defvar raw-quote-keys (keys quote-parse-map) +(def raw-quote-keys "A list of all the keys available in a raw stock quote. A custom stock quote can be created by supplying `get-quote` with a parser capable of extracting the value corresponding to a chosen subset of these keys from a raw stock quote and packaging them into the desired result - structure.") + structure." + (keys quote-parse-map)) (defn parse-quote-item "Looks up the value of a supplied key into a raw stock quote and @@ -187,7 +187,7 @@ (apply hash-map (mapcat (fn [[k v]] [k (parse-quote-item raw-quote v)]) key-map)))) -(defvar- default-key-map +(def default-key-map {:symbol :symbol :name :Name :last :LastTradePriceOnly @@ -197,7 +197,7 @@ :low :DaysLow :volume :Volume}) -(defvar- default-quote-parser* (build-quote-parser default-key-map)) +(def default-quote-parser* (build-quote-parser default-key-map)) (defn default-quote-parser "The quote parser used by `get-quote` and `get-quotes` when a custom quote diff --git a/src/stockings/exchanges.clj b/src/stockings/exchanges.clj index 5739b0f..a749dc9 100644 --- a/src/stockings/exchanges.clj +++ b/src/stockings/exchanges.clj @@ -4,8 +4,7 @@ by the NASDAQ at ." {:author "Filippo Tampieri "} (:use [clojure.string :only (split lower-case upper-case)] - [clojure.contrib.def :only (defvar defvar-)] - [clojure-csv.core :only (parse-csv)] + [clojure.data.csv :as csv] [stockings.core :only (explode-stock-symbol)]) (:require [clj-http.client :as client])) @@ -13,29 +12,30 @@ ;;; Stock Exchanges ;;; -(defvar nasdaq - {:name "NASDAQ Stock Market", :symbol "NASDAQ"} - "A map describing the NASDAQ Stock Market (NASDAQ).") +(def nasdaq + "A map describing the NASDAQ Stock Market (NASDAQ)." + {:name "NASDAQ Stock Market", :symbol "NASDAQ"}) -(defvar nyse - {:name "New York Stock Exchange", :symbol "NYSE"} - "A map describing the New York Stock Exchange (NYSE).") +(def nyse + "A map describing the New York Stock Exchange (NYSE)." + {:name "New York Stock Exchange", :symbol "NYSE"}) -(defvar amex - {:name "NYSE Amex Equities", :symbol "AMEX"} - "A map describing the NYSE Amex Equities (AMEX).") +(def amex + "A map describing the NYSE Amex Equities (AMEX)." + {:name "NYSE Amex Equities", :symbol "AMEX"}) -(defvar exchanges +(def exchanges + "A map from stock exchange keywords to stock exchange info maps." {:amex amex, :nasdaq nasdaq - :nyse nyse} - "A map from stock exchange keywords to stock exchange info maps.") + :nyse nyse}) ;;; ;;; Industry Sectors ;;; -(defvar industry-sectors +(def industry-sectors + "A list of the major industry sectors as classified by the NASDAQ." ["Basic Industries" "Capital Goods" "Consumer Durables" @@ -47,14 +47,13 @@ "Miscellaneous" "Public Utilities" "Technology" - "Transportation"] - "A list of the major industry sectors as classified by the NASDAQ.") + "Transportation"]) ;;; ;;; Companies ;;; -(defvar- source-url "http://www.nasdaq.com/screening/companies-by-name.aspx") +(def source-url "http://www.nasdaq.com/screening/companies-by-name.aspx") ;; Use a record instead of a map for efficiency since the lists of ;; companies are pretty long. @@ -68,7 +67,7 @@ [r] (and (vector? r) - (= 9 (count r)) + (= 10 (count r)) (< 0 (count (first r))))) (defn- convert-record @@ -99,7 +98,7 @@ industry for each company." [exchange-key ^String s] (->> s - parse-csv + csv/read-csv rest (filter valid-record?) (map (partial convert-record exchange-key)))) diff --git a/src/stockings/utils.clj b/src/stockings/utils.clj index 161d57e..92afdc4 100644 --- a/src/stockings/utils.clj +++ b/src/stockings/utils.clj @@ -3,13 +3,12 @@ (Yahoo! Query Language) and parse a variety of value types." {:author "Filippo Tampieri "} (:use [clojure.string :only (join lower-case)] - [clojure.contrib.def :only (defvar defvar-)] - [clojure.contrib.json :only (read-json)]) + [clojure.data.json :only (read-json)]) (:require [clj-http.client :as client]) (:import (org.joda.time DateTime LocalDate) (org.joda.time.format DateTimeFormat))) -(defvar- yql-base-url "http://query.yahooapis.com/v1/public/yql") +(def yql-base-url "http://query.yahooapis.com/v1/public/yql") (defn yql-string "String values in a YQL query must be enclosed in double quotes. @@ -51,6 +50,7 @@ (let [payload (-> response :body strip-wrapper read-json)] (if-let [error (:error payload)] (throw (Exception. (:description error)))) + ; (print (:quote (:results (:query payload)))) (:results (:query payload))))) (defn map-parser @@ -91,7 +91,7 @@ (if-let [m (re-matches #"(?:\+|\-)?\d+" s)] (Long/parseLong m 10)))) -(defvar- multipliers +(def multipliers {"B" 1.0e9 "M" 1.0e6 "K" 1.0e3}) @@ -117,7 +117,7 @@ (if-let [m (re-matches #"((?:\+|\-)?\d+(?:\.\d*)?)%" s)] (/ (Double/parseDouble (second m)) 100.0)))) -(defvar- date-parsers +(def date-parsers [(DateTimeFormat/forPattern "yyyy-MM-dd") (DateTimeFormat/forPattern "M/dd/yyyy")]) @@ -133,7 +133,7 @@ :when d] (.toLocalDate d))))) -(defvar- time-parser (DateTimeFormat/forPattern "hh:mmaa")) +(def time-parser (DateTimeFormat/forPattern "hh:mmaa")) (defn parse-time "If the supplied string represents a valid time in the hh:mmaa format