Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
scottjbarr committed Oct 7, 2011
0 parents commit ac1a45d
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.gem
.bundle
Gemfile.lock
pkg/*
48 changes: 48 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require "bundler/gem_tasks"
# require 'rake'
require 'rake/testtask'

# Host or location to copy gem to. At the moment this is only a local copy
# operation
GEM_LOCAL = "/Users/scott/.gems-repository"

# Details of theremote server to upload the gem to
GEM_HOST = "gems.signalvsnoise.com"
GEM_HOST_USER = "root"
SSH_KEY = "#{ENV['HOME']}/.ssh/scott-signalvsnoise.key"

Rake::TestTask.new("test:units") { |test|
%w{. lib test}.each { |dir| test.libs << dir }
test.test_files = FileList["test/unit/*_test.rb"].exclude("test/test_helper.rb", "test/vendor")
test.verbose = false
# test.warning = true
}

Rake::TestTask.new("test:functionals") { |test|
%w{. lib test}.each { |dir| test.libs << dir }
test.test_files = FileList["test/functional/*_test.rb"].exclude("test/test_helper.rb", "test/vendor")
test.verbose = false
# test.warning = true
}

task :test => ["test:units", "test:functionals"]

def get_version
DividendPredictor::VERSION
end

task :upload_local do
# place the gem in the local repository
gem_file = "pkg/#{APP_NAME}-#{get_version}.gem"
system "cp #{gem_file} #{GEM_LOCAL}/gems/"

# update the gem index
system "cd #{GEM_LOCAL} && gem generate_index -d ."
end

task :sync_remote do
system "cd #{GEM_LOCAL} && rsync -auvz -e 'ssh -i #{SSH_KEY}' . #{GEM_HOST_USER}@#{GEM_HOST}:/var/www/gems/"
end

task :publish => [ :test, :build, :upload_local, :sync_remote ]

161 changes: 161 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
= How to query the nasdaq.com for prices

Let's check the price for Altria (MO) because everyone loves smoking, right?

== Query

$ curl -i "http://www.nasdaq.com/quote.dll?page=dynamic&mode=data&symbol=MO&random=0.7634591432288283"

== Response

HTTP/1.1 200 ok
Content-Length: 113
Content-Type: text/plain
Server: Microsoft-IIS/7.5
Date: Thu, 18 Aug 2011 06:01:43 GMT
Connection: close

*MO|26|0.32|1.25%|13,603,764|up|Y|$&nbsp;26.17|$&nbsp;25.79|MO|Dec. 31, 1969|N/A|N/A|N|NYSE|N|Altria Group|

What fields are returned in the data?

*MO - Symbol
26 - Price in $US. The price here is $26.00 even
0.32 - Change in $US, from
1.25% - Change in %
13,603,764 - Volume of shares traded
up - Direction of movement. Values (up, down)
Y - Unknown. Values (Y, A, N)
$&nbsp;26.17 - Day high. Unescaped value would be "$ 26.17"
$&nbsp;25.79 - Day low. Unescaped value would be "$ 25.79"
MO - Symbol
Dec. 31, 1969 - Unknown
N/A - Unknown
N/A - Unknown
N - Unknown
NYSE - Stock exchange
N - Unknown
Altria Group - Company name

OK, so after we smoke that tasty (oh so tasty!) tobacco, it's time for a Coke :)

$ curl -i "http://www.nasdaq.com/quote.dll?page=dynamic&mode=data&symbol=KO&random=0.7634591432288283"
HTTP/1.1 200 ok
Content-Length: 127
Content-Type: text/plain
Server: Microsoft-IIS/7.5
Date: Thu, 18 Aug 2011 06:01:57 GMT
Connection: close

*KO|69.28|1.11|1.63%|11,587,911|up|Y|$&nbsp;69.35|$&nbsp;68.16|KO|Dec. 31, 1969|N/A|N/A|N|NYSE|N|Coca-Cola Company (The)|

= Price History

Lets find the price history for KO.

See the "5120" in the URL? The "5" means nothing to us, but the 120 is the
number of months of data to return. 120 months is 10 years. But you can
specify longer in the URL. Nasdaq only makes prices back to 2 Jan 1990
though.

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0|0,0,0,0,0-5120-03NA000000KO-&SF:4|5-WD=539-HT=395--XXCL-

All of the pipe delimited "0,0,0,0,0" sets can be eliminated with no change
to the output. Sweet.

Here is 3 months of Altria price data

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0,0,0,0,00,0,0,0,0-5003-03NA000000MO-&SF:4|5-WD=539-HT=395--XCL-

= Realtime Quotes

Quote for KO

== Request

GET http://www.nasdaq.com/aspx/NLS/NLSHandler.ashx?msg=Last&Symbol=KO&QESymbol=KO

== Response

<DocumentElement>
<Last>
<totVol>1711</totVol>
<high>67.8200</high>
<low>67.2800</low>
<Price>67.8200</Price>
<ConsolidatedShares>2715</ConsolidatedShares>
<ServerTime>9/23/2011 8:06:41 AM</ServerTime>
<RefreshTime>35000</RefreshTime>
<MarketStatus>C</MarketStatus>
<MarketCloseTime>16:0</MarketCloseTime>
<previousclose>67.82</previousclose>
<tradedate>9/23/2011 8:06:41 AM</tradedate>
</Last>
</DocumentElement>


= Charts

The charts are rendered by URL's like this...

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:1|8|5-SH:8=20-WD=539-HT=395-

The SF:X parameter changes the type of chart.

SF:1 | Mountain
SF:4 | OHLC
SF:6 | Candlestick
SF:7 | Line
SF:43 | Bar

Other parameters

WD | Width
HT | Height

Lower Studies

The "5-SH" means that volume is rendered in the "lower studies" section at
the bottom of the chart.

"8=20" | Render the 20 day moving average
"8=50" | Render the 50 day moving average

50 day moving average

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:1|8|5-SH:8=50-WD=539-HT=395-

MACD

The parameters "15=12,26,9" causes the lower studies section to show
the MACD.

Note that parameters are pipe delimited in the url in some places.

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:1|8|15-SH:8=20|15=12,26,9-WD=539-HT=395-

The "27=10" causes the rendering of the RSI (Relative Strength Index)

http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:1|8|27-SH:8=20|27=10-WD=539-HT=395-

== Examples

Mountain

curl "http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:1|8|5-SH:8=20-WD=539-HT=395-" > ko-mountain-1.gif

OHLC

curl "http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:4|8|5-SH:8=20-WD=539-HT=395-" > ko-ohlc-1.gif

Candlestick

curl "http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:6|8|5-SH:8=20-WD=539-HT=395-" > ko-candlestick-1.gif

Line

curl "http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:7|8|5-SH:8=20-WD=539-HT=395-" > ko-line-1.gif

Bar

curl "http://charting.nasdaq.com/ext/charts.dll?2-1-14-0-0-51-03NA000000KO-&SF:43|8|5-SH:8=20-WD=539-HT=395-" > ko-bar-1.gif
41 changes: 41 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require "bundler/gem_tasks"
require 'rake/testtask'

# Host or location to copy gem to. At the moment this is only a local copy
# operation
GEM_LOCAL = "/Users/scott/.gems-repository"

# Details of theremote server to upload the gem to
GEM_HOST = "gems.signalvsnoise.com"
GEM_HOST_USER = "root"
SSH_KEY = "#{ENV['HOME']}/.ssh/scott-signalvsnoise.key"

Rake::TestTask.new("test:units") { |test|
%w{. lib test}.each { |dir| test.libs << dir }
test.test_files = FileList["test/test_*.rb"].exclude("test/test_helper.rb", "test/vendor")
test.verbose = false
# test.warning = true
}


task :test => ["test:units"]

def get_version
Scottjbarr::Nasdaq::VERSION
end

task :upload_local do
# place the gem in the local repository
gem_file = "pkg/#{APP_NAME}-#{get_version}.gem"
system "cp #{gem_file} #{GEM_LOCAL}/gems/"

# update the gem index
system "cd #{GEM_LOCAL} && gem generate_index -d ."
end

task :sync_remote do
system "cd #{GEM_LOCAL} && rsync -auvz -e 'ssh -i #{SSH_KEY}' . #{GEM_HOST_USER}@#{GEM_HOST}:/var/www/gems/"
end

task :publish => [ :test, :build, :upload_local, :sync_remote ]

7 changes: 7 additions & 0 deletions lib/scottjbarr-nasdaq.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "scottjbarr-nasdaq/version"

Dir.glob(File.dirname(__FILE__) + '/scottjbarr-nasdaq/*') { |file| require file }

module Nasdaq
SERVER = "www.nasdaq.com"
end
104 changes: 104 additions & 0 deletions lib/scottjbarr-nasdaq/quote.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require 'net/http'
require 'cgi'
require 'uri'
require 'nokogiri'
require 'hashie'
require 'active_support/core_ext/string/inflections'

module Nasdaq

class Quote < Hashie::Dash

property :symbol
property :tot_vol
property :high
property :low
property :price
property :consolidated_shares
property :server_time
property :refresh_time
property :market_status
property :market_close_time
property :previous_close
property :trade_date

INTEGER_FIELDS = %w(consolidated_shares refresh_time tot_vol)
DECIMAL_FIELDS = %w(high low previous_close price)
# DATE_FIELDS = %w(server_time trade_date)

def market_open?
market_status == "O"
end

def self.path(symbol)
data = {
:msg => "Last",
:Symbol => symbol.upcase,
:QESymbol => symbol.upcase
}
path = "/aspx/NLS/NLSHandler.ashx?#{get_form_data(data)}"
end

def self.uri(symbol)
URI.parse("http://#{SERVER}#{path(symbol)}")
end

def self.for(symbol)
uri = uri(symbol)
http = Net::HTTP.new(uri.host, uri.port)
response = http.get(uri.to_s)

# p resp.status
hash = parse(response.body)
hash[:symbol] = symbol

hash = cast_values(hash)
Quote.new(hash)
end

def self.cast_values(hash)
hash.each_pair do |k, v|
if INTEGER_FIELDS.include?(k)
hash[k] = v.to_i
elsif DECIMAL_FIELDS.include?(k)
hash[k] = v.to_f
end
end

hash
end

# Convert a hash to an escaped query string
def self.get_form_data(params)
params.reduce("") { |m, v| m += "#{v[0]}=#{CGI.escape(v[1].to_s)}&" }.chop
end

def self.parse(body)
xml = Nokogiri::XML(body) do |config|
config.options = Nokogiri::XML::ParseOptions::STRICT | Nokogiri::XML::ParseOptions::NOENT | Nokogiri::XML::ParseOptions::NOBLANKS
end

hash = {}

xml.xpath('//DocumentElement/Last').children.each do |node|
hash[convert_name(node.name)] = node.text
end

hash
end

def self.convert_name(name)
name = name.underscore

if name == "previousclose"
name = "previous_close"
elsif name == "tradedate"
name = "trade_date"
end

name
end

end

end
3 changes: 3 additions & 0 deletions lib/scottjbarr-nasdaq/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Nasdaq
VERSION = "0.0.1"
end
24 changes: 24 additions & 0 deletions scottjbarr-nasdaq.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "scottjbarr-nasdaq/version"

Gem::Specification.new do |s|
s.name = "scottjbarr-nasdaq"
s.version = Nasdaq::VERSION
s.authors = ["Scott Barr"]
s.email = ["[email protected]"]
s.homepage = ""
s.summary = %q{Scrape quotes from NASDAQ}
s.description = %q{Scrape quotes from NASDAQ}

s.rubyforge_project = "scottjbarr-nasdaq"

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

# specify any dependencies here; for example:
# s.add_development_dependency "rspec"
# s.add_runtime_dependency "rest-client"
end
Loading

0 comments on commit ac1a45d

Please sign in to comment.