yahoo_stock 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,61 @@
1
+ === 0.1.1 2009-08-31
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
5
+
6
+ === 0.1.2 2009-09-01
7
+
8
+ * 1 minor change:
9
+ * changed method name YahooStock::Quote#get_data to get
10
+
11
+ === 0.1.3 2009-09-05
12
+
13
+ * 3 additions:
14
+ * adds a new class called YahooStock::ScripSymbol that allows to
15
+ find out the stock symbol for a company
16
+ * adds specs for previous and new code
17
+ * adds
18
+
19
+ === 0.1.4 2009-09-05
20
+
21
+ * 2 changes related with ruby 1.9:
22
+ * modifies quote class to be compatible with ruby 1.9
23
+ * modifies interface class to be compatible with 1.9
24
+
25
+ === 0.1.5 2009-09-06
26
+
27
+ * 1 changes related with ruby 1.9:
28
+ * modifies ScripSymbol class to be compatible with ruby 1.9
29
+
30
+ === 0.1.6 2009-09-07
31
+
32
+ * 1 addition:
33
+ * adds convenience methods Quote#realtime, standard and extended to
34
+ fetch relevant stock values
35
+
36
+ === 1.0.1 2009-09-10
37
+
38
+ * 1 addition:
39
+ * adds feature to retreive historical stock data
40
+
41
+ === 1.0.2 2009-10-04
42
+ Major changes in the public API. Check the README.rdoc file and individual classes for more information
43
+
44
+ * 8 addition:
45
+ * adds YahooStock::Interface::History
46
+ * adds YahooStock::Interface::Quote
47
+ * adds YahooStock::Interface::ScripSymbol
48
+ * adds YahooStock::Result as a superclass for all formatter classes
49
+ * adds array format, Result::ArrayFormat, to generate results as an array
50
+ * adds hash format, Result::ArrayFormat, to generate results as key value pairs
51
+ * adds base class as parent for public facing classes
52
+ * adds observers to check when it is required to send request to yahoo again to get fresh data
53
+
54
+ * 7 changes:
55
+ * changes YahooStock::Interface to be the main interface class. Other interface classes will inherit from this
56
+ * changes YahooStock::ScripSymbol to use YahooStock::Interface::ScripSymbol
57
+ * removes all history interface logic from YahooStock::History and uses YahooStock::Interface::History
58
+ * changes YahooStock::Quote, YahooStock::History, YahooStock::ScripSymbol to extend from YahooStock::Base
59
+ * sorts url parameters before sending request to yahoo
60
+ * YahooInterface::Quote#realtime, extended, and standard methods should return self to allow calling different format output method calls
61
+ * do not discard any empty values when finding scrip symbol options for a company as this interferes with different format options
@@ -0,0 +1,29 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/yahoo_stock/base.rb
6
+ lib/yahoo_stock/history.rb
7
+ lib/yahoo_stock/interface.rb
8
+ lib/yahoo_stock/interface/history.rb
9
+ lib/yahoo_stock/interface/quote.rb
10
+ lib/yahoo_stock/interface/scrip_symbol.rb
11
+ lib/yahoo_stock/quote.rb
12
+ lib/yahoo_stock/result.rb
13
+ lib/yahoo_stock/result/array_format.rb
14
+ lib/yahoo_stock/result/hash_format.rb
15
+ lib/yahoo_stock/scrip_symbol.rb
16
+ lib/yahoo_stock.rb
17
+ spec/spec_helper.rb
18
+ spec/yahoo_stock/base_spec.rb
19
+ spec/yahoo_stock/interface_spec.rb
20
+ spec/yahoo_stock/interface/history_spec.rb
21
+ spec/yahoo_stock/interface/quote_spec.rb
22
+ spec/yahoo_stock/interface/scrip_symbol_spec.rb
23
+ spec/yahoo_stock/quote_spec.rb
24
+ spec/yahoo_stock/history_spec.rb
25
+ spec/yahoo_stock/result_spec.rb
26
+ spec/yahoo_stock/result/array_format_spec.rb
27
+ spec/yahoo_stock/result/hash_format_spec.rb
28
+ spec/yahoo_stock/scrip_symbol_spec.rb
29
+
@@ -0,0 +1,142 @@
1
+ = yahoo_stock
2
+
3
+ * http://github.com/nas/yahoo_stock
4
+
5
+ == DESCRIPTION:
6
+
7
+ Provides an interface to yahoo finance to get stock related data. For instance, latest trade related data, volume, 50 day moving average, market cap, etc, virtually any thing that yahoo finance provides.
8
+
9
+ If you don't know the stock / scrip symbol of the company then you can find that out by using the YahooStock::ScripSymbol class. The methods are mentioned in the Usage section below. For instance, YHOO for yahoo, GOOG for google, etc.
10
+ The kind of parameters to be passed can be found after initializing the
11
+ YahooStock::Quote object and passing valid_parameters message, example is given below in the USAGE section.
12
+
13
+ == USAGE:
14
+
15
+ require 'rubygems'
16
+
17
+ require 'yahoo_stock'
18
+
19
+ * Initialize quote object
20
+
21
+ quote = YahooStock::Quote.new(:stock_symbols => ['YHOO', 'GOOG'])
22
+
23
+ * To view the valid parameters that can be passed
24
+
25
+ quote.valid_parameters
26
+
27
+ * To view the current parameters used
28
+
29
+ quote.current_parameters
30
+
31
+ * To view the current stock symbols used
32
+
33
+ quote.current_symbols
34
+
35
+ * To add more stocks to the list
36
+
37
+ quote.add_symbols('MSFT', 'AAPL')
38
+
39
+ * To remove stocks from list
40
+
41
+ quote.remove_symbols('MSFT', 'AAPL')
42
+
43
+ * To find data for all stocks, this will give a string containing all values
44
+
45
+ quote.results
46
+
47
+ to return an array instead of a string use:
48
+
49
+ quote.results(:to_array).output
50
+
51
+ to return a hash, use:
52
+
53
+ quote.results(:to_hash).output
54
+
55
+ to store results in a file, use:
56
+
57
+ quote.results.store('filename')
58
+
59
+ * To find out the stock symbol for a company
60
+
61
+ symbol = YahooStock::ScripSymbol.new('Yahoo')
62
+
63
+ * To find all symbols for that company, this will give a string containing all values
64
+
65
+ symbol.results
66
+
67
+ to return an array instead of a string use:
68
+
69
+ symbol.results(:to_array).output
70
+
71
+ to return a hash, use:
72
+
73
+ symbol.results(:to_hash).output
74
+
75
+ to store results in a file, use:
76
+
77
+ symbol.results.store('filename')
78
+
79
+ * To find symbols for multiple companies
80
+
81
+ symbols = YahooStock::ScripSymbol.results('Yahoo', 'Company1', 'Company3')
82
+
83
+ * to get the result in a string
84
+
85
+ symbols.output
86
+
87
+ * to store output in a file
88
+
89
+ symbols.store('filename')
90
+
91
+ * To find historical data for a stock
92
+
93
+ history = YahooStock::History.new(:stock_symbols => 'yhoo', :start_date => Date.today-20, end_date => Date.today -2)
94
+
95
+ to return an array instead of a string use:
96
+
97
+ history.results(:to_array).output
98
+
99
+ to return a hash, use:
100
+
101
+ history.results(:to_hash).output
102
+
103
+ to store results in a file, use:
104
+
105
+ history.results.store('filename')
106
+
107
+ == INSTALL:
108
+
109
+ gem sources -a http://gems.github.com
110
+
111
+ sudo gem install nas-yahoo_stock
112
+
113
+ == TESTS:
114
+
115
+ Tests are written using Rspec 1.2.2
116
+
117
+ To run all tests 'rake spec' from the root directory
118
+
119
+ == LICENSE:
120
+
121
+ (The MIT License)
122
+
123
+ Copyright (c) 2009 Nasir Jamal
124
+
125
+ Permission is hereby granted, free of charge, to any person obtaining
126
+ a copy of this software and associated documentation files (the
127
+ 'Software'), to deal in the Software without restriction, including
128
+ without limitation the rights to use, copy, modify, merge, publish,
129
+ distribute, sublicense, and/or sell copies of the Software, and to
130
+ permit persons to whom the Software is furnished to do so, subject to
131
+ the following conditions:
132
+
133
+ The above copyright notice and this permission notice shall be
134
+ included in all copies or substantial portions of the Software.
135
+
136
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
137
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
138
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
139
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
140
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
141
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
142
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/yahoo_stock'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'yahoo_stock' do
14
+ self.developer 'Nasir Jamal', 'nas35_in@yahoo.com'
15
+ end
16
+
17
+ require 'newgem/tasks'
18
+ Dir['tasks/**/*.rake'].each { |t| load t }
19
+
20
+ # TODO - want other tests/tasks run by default? Add them to the list
21
+ # remove_task :default
22
+ # task :default => [:spec, :features]
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'date'
5
+ require 'yahoo_stock/base.rb'
6
+ require 'yahoo_stock/interface.rb'
7
+ require 'yahoo_stock/history.rb'
8
+ require 'yahoo_stock/scrip_symbol.rb'
9
+ require 'yahoo_stock/quote.rb'
10
+ require 'yahoo_stock/interface/quote.rb'
11
+ require 'yahoo_stock/interface/history.rb'
12
+ require 'yahoo_stock/interface/scrip_symbol.rb'
13
+ require 'yahoo_stock/result.rb'
14
+ require 'yahoo_stock/result/array_format.rb'
15
+ require 'yahoo_stock/result/hash_format.rb'
16
+
17
+ module YahooStock
18
+ VERSION = '1.0.2'
19
+ end
@@ -0,0 +1,37 @@
1
+ # YahooStock::Base class to find and output results.
2
+ module YahooStock
3
+
4
+ class Base
5
+
6
+ def initialize(interface)
7
+ @interface = interface
8
+ end
9
+
10
+ # Uses the values method of the interface used to show results .
11
+ def find
12
+ @interface.values
13
+ end
14
+
15
+ # Method takes one parameter type or a block
16
+ # type uses the existing format classes namespaced in Result::ClassName.output
17
+ # e.g. * results :to_array
18
+ # * results {YourSpecialFormat.method_name}
19
+ # to store
20
+ def results(type=nil, &block)
21
+ if block_given?
22
+ yield
23
+ else
24
+ return YahooStock::Result.new(find) if !type || type.to_s.empty?
25
+ format_type = type.to_s.sub(/^to_/,'').strip
26
+ return YahooStock::Result.const_get("#{format_type.capitalize}Format").new(find){data_attributes}
27
+ end
28
+ end
29
+
30
+ # Abstract method
31
+ def data_attributes
32
+ raise 'Abstract method called. Use the subclass data_attributes method'
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,32 @@
1
+ module YahooStock
2
+ class History < Base
3
+
4
+ class HistoryError < RuntimeError; end
5
+
6
+ def initialize(options)
7
+ unless options.is_a?(Hash)
8
+ raise HistoryError, 'A hash of start_date, end_date and stock_symbol is expected as parameters'
9
+ end
10
+ @interface = YahooStock::Interface::History.new(options)
11
+ end
12
+
13
+ def find
14
+ @find_values = super()
15
+ @find_values.sub(/Date.*\s/,'') if @find_values
16
+ end
17
+
18
+ def values_with_header
19
+ @interface.values
20
+ end
21
+
22
+ def data_attributes
23
+ return unless values_with_header
24
+ data_attributes = /Date.*\s/.match(values_with_header)
25
+ unless data_attributes.nil?
26
+ @data_attributes = data_attributes[0].sub(/\s*$/,'').split(',')
27
+ @data_attributes.map &:strip
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ =begin
2
+ Main class to interface with Yahoo
3
+ =end
4
+
5
+ require 'net/http'
6
+ require 'observer'
7
+ module YahooStock
8
+ # ==DESCRIPTION:
9
+ #
10
+ # Class to generate the right url and interface with yahoo
11
+ #
12
+ class Interface
13
+ include Observable
14
+ class InterfaceError < RuntimeError ; end
15
+
16
+ BASE_URLS = {
17
+ :quote => "http://download.finance.yahoo.com/d/quotes.csv",
18
+ :history => "http://ichart.finance.yahoo.com/table.csv",
19
+ :scrip_symbol => "http://finance.yahoo.com/lookup/all"
20
+ } unless defined?(BASE_URLS)
21
+
22
+ attr_accessor :base_url, :uri_parameters
23
+
24
+ # Send request to the uri and get results
25
+ def get
26
+ begin
27
+ response = Net::HTTP.get_response(URI.parse(uri))
28
+ rescue => e
29
+ raise InterfaceError, "#{e.message}\n\n#{e.backtrace}"
30
+ end
31
+ response.code == '200' ? response.body : response_error(response)
32
+ end
33
+
34
+ # Generates full url to connect to yahoo
35
+ def uri
36
+ raise InterfaceError, 'Base url is require to generate full uri.' unless @base_url
37
+ return @base_url if @uri_parameters.nil? || @uri_parameters.empty?
38
+ params_with_values = []
39
+ @uri_parameters.each {|k,v| params_with_values << "#{k}=#{v}"}
40
+ @base_url+'?'+params_with_values.join('&')
41
+ end
42
+
43
+ # Get result string
44
+ def values
45
+ @values ||= get
46
+ end
47
+
48
+ def update
49
+ @values = nil
50
+ end
51
+
52
+ private
53
+
54
+ # Generate error for debugging when something goes wrong while sending
55
+ # request to yahoo
56
+ def response_error(response)
57
+ trace = "Response \n\nbody : #{response.body}\n\ncode: #{response.code}\n\nmessage: #{response.message}"
58
+ case @base_url
59
+ when BASE_URLS[:quote]
60
+ raise InterfaceError, "Error :: Could not get stock data \n\n#{trace}"
61
+ when BASE_URLS[:history]
62
+ raise InterfaceError, "Error :: Could not get historical data \n\n#{trace}"
63
+ when BASE_URLS[:scrip_symbol]
64
+ raise InterfaceError, "Error :: Could not get stock symbol \n\n#{trace}"
65
+ else
66
+ raise InterfaceError, "Error connecting to #{@base_url} \n\n#{trace}"
67
+ end
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,186 @@
1
+ =begin
2
+ params:
3
+ s=stock symbol
4
+ a=month-1
5
+ b=date
6
+ c=year
7
+ d=month-1
8
+ e=date
9
+ f=year
10
+ g=d or w or m
11
+ ignore=.csv
12
+
13
+ =end
14
+
15
+ module YahooStock
16
+ # ==DESCRIPTION:
17
+ #
18
+ # Class to generate the right url and interface with yahoo to get history of a stock
19
+ #
20
+ class Interface::History < Interface
21
+
22
+ class HistoryError < RuntimeError ; end
23
+
24
+ attr_reader :stock_symbol, :start_date, :end_date, :interval
25
+
26
+ # The options parameter expects a hash with 4 key value pairs
27
+ #
28
+ # :stock_symbol => 'goog', :start_date => Date.today-30,
29
+ # :end_date => Date.today-10, :interval => :weekly
30
+ #
31
+ # The interval option accepts :daily, :monthly and :weekly values
32
+ #
33
+ # The interval key is optional, if not used then by default uses :daily
34
+ #
35
+ # and provides daily history for the specified date range
36
+ #
37
+ def initialize(options)
38
+ @base_url = BASE_URLS[:history]
39
+ validate_keys(options)
40
+
41
+ @stock_symbol = options[:stock_symbol]
42
+ @start_date = options[:start_date]
43
+ @end_date = options[:end_date]
44
+ @interval = options[:interval].nil? ? :daily : options[:interval].to_sym
45
+
46
+ validate_interval_values(options[:interval]) if options[:interval]
47
+ validate_stock_symbol(options)
48
+ validate_start_date(options)
49
+ validate_end_date(options)
50
+ validate_history_range
51
+ end
52
+
53
+ # Make sure that stock symbol is not nil or an empty string before setting it
54
+ def stock_symbol=(stock_symbol)
55
+ validate_stock_symbol_attribute(stock_symbol)
56
+ @stock_symbol = stock_symbol
57
+ end
58
+
59
+ # Before setting start date
60
+ # - Make sure that it is of type date
61
+ # - Make sure that it is before the end date
62
+ def start_date=(start_date)
63
+ validate_start_date_type(start_date)
64
+ validate_history_range(start_date)
65
+ @start_date = start_date
66
+ end
67
+
68
+ # Before setting end date
69
+ # - Make sure that it is of type date
70
+ # - Make sure that it is after the start date
71
+ def end_date=(end_date)
72
+ validate_end_date_type(end_date)
73
+ validate_history_range(start_date, end_date)
74
+ @end_date = end_date
75
+ end
76
+
77
+ # Set interval to specify whether daily, weekly or monthly histroy required
78
+ def interval=(interval)
79
+ validate_interval_values(interval)
80
+ @interval = interval
81
+ end
82
+
83
+ # Generate full uri with the help of uri method of the superclass
84
+ def uri
85
+ frequency = case interval
86
+ when :daily : 'd'
87
+ when :weekly : 'w'
88
+ when :monthly : 'm'
89
+ end
90
+ @uri_parameters = {:a => sprintf("%02d", start_date.month-1), :b => start_date.day,
91
+ :c => start_date.year, :d => sprintf("%02d", end_date.month-1),
92
+ :e => end_date.day, :f => end_date.year, :s => stock_symbol,
93
+ :g => frequency, :ignore => '.csv'}
94
+ super()
95
+ end
96
+
97
+ # Get uri content with the help of get method of the super class
98
+ def get
99
+ if stock_symbol.nil? || start_date.nil? || end_date.nil?
100
+ raise HistoryError, 'Cannot send request unless all parameters, ie stock_symbol, start and end date are present'
101
+ end
102
+ if !(start_date.is_a?(Date) || end_date.is_a?(Date))
103
+ raise HistoryError, 'Start and end date should be of type Date'
104
+ end
105
+ uri
106
+ super()
107
+ end
108
+
109
+ private
110
+
111
+ def validate_interval_values(interval_value=interval)
112
+ valid_values = [:daily, :weekly, :monthly]
113
+ unless valid_values.include?(interval_value)
114
+ raise HistoryError, "Allowed values for interval are #{valid_values.join(', ')}"
115
+ end
116
+ end
117
+
118
+ def validate_stock_symbol(options)
119
+ unless options.keys.include?(:stock_symbol)
120
+ raise HistoryError, ':stock_symbol key is not present in the parameter hash'
121
+ end
122
+ validate_stock_symbol_attribute
123
+ end
124
+
125
+ def validate_stock_symbol_attribute(symbol=stock_symbol)
126
+ if symbol.nil? || symbol.empty?
127
+ raise HistoryError, ':stock_symbol value cannot be nil or blank'
128
+ end
129
+ end
130
+
131
+ def validate_start_date(options)
132
+ validate_date_options(:start_date, options)
133
+ validate_start_date_type
134
+ end
135
+
136
+ def validate_end_date(options)
137
+ validate_date_options(:end_date, options)
138
+ validate_end_date_type
139
+ end
140
+
141
+ def validate_history_range(s_date = start_date, e_date = end_date)
142
+ if s_date >= Date.today
143
+ raise HistoryError, "Start date must be in the past"
144
+ end
145
+ if e_date >= Date.today
146
+ raise HistoryError, "End date must be in the past"
147
+ end
148
+ if e_date < s_date
149
+ raise HistoryError, "End date must be greater than the start date"
150
+ end
151
+ end
152
+
153
+ def validate_end_date_type(e_date=end_date)
154
+ unless e_date.is_a?(Date)
155
+ raise HistoryError, "End date must be of type Date"
156
+ end
157
+ end
158
+
159
+ def validate_start_date_type(s_date=start_date)
160
+ unless s_date.is_a?(Date)
161
+ raise HistoryError, "Start date must be of type Date"
162
+ end
163
+ end
164
+
165
+ def validate_date_options(date_type, options)
166
+ unless options.keys.include?(date_type)
167
+ raise HistoryError, ":#{date_type} key is not present in the parameter hash"
168
+ end
169
+
170
+ if options[date_type].nil? || options[date_type].to_s.empty?
171
+ raise HistoryError, ":#{date_type} value cannot be blank"
172
+ end
173
+ end
174
+
175
+ def validate_keys(options)
176
+ valid_keys = [:stock_symbol, :start_date, :end_date, :interval]
177
+ invalid_keys = []
178
+ options.keys.each{|key| invalid_keys << key unless valid_keys.include?(key) }
179
+ unless invalid_keys.length.zero?
180
+ raise HistoryError, "An invalid key '#{invalid_keys.join(',')}' is passed in the parameters. Allowed keys are #{valid_keys.join(', ')}"
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ end