diff --git a/bin/constituents b/bin/constituents new file mode 100755 index 0000000..b609596 --- /dev/null +++ b/bin/constituents @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +abort "usage: #{File.basename($0)} [index]" unless ARGV[0] + +LIB_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) +$LOAD_PATH << LIB_DIR + +require 'lib/penfold' + +puts "# Generated at #{Time.now}" +puts Market.constituents(ARGV[0]).join("\n") diff --git a/lib/market.rb b/lib/market.rb index 72a9fc8..b95a940 100644 --- a/lib/market.rb +++ b/lib/market.rb @@ -2,6 +2,7 @@ require 'nokogiri' require 'open-uri' require 'date' +require 'cgi' class Market class Quote @@ -155,6 +156,26 @@ def historical_prices(ticker, from = Date.today - 365) csv.scan(/\d+\.\d+$/).map { |p| p.to_f } end + def constituents(ticker, offset = 0, traverse = true) + ticker = "^#{ticker}" unless ticker =~ /^\^/ + + url = "http://finance.yahoo.com/q/cp?s=%s&c=%s" % [CGI.escape(ticker), offset] + print "Fetching #{url}..." if $VERBOSE + + doc = with_retry do + Nokogiri::HTML.parse(open(url).read) + end + + symbols = doc.at("#yfncsumtab").search("tr td:first-child.yfnc_tabledata1").map{ |td| td.text } + next_link = doc.at("#yfncsumtab").at("//a[text()='Next']") + + if next_link && traverse + return symbols + constituents(ticker, offset + 1) + end + + return symbols + end + def with_retry(&block) retries = 5