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,287 @@
1
+ =begin
2
+
3
+ Parameter source:
4
+ http://www.gummy-stuff.org/Yahoo-data.htm
5
+ http://finance.yahoo.com/d/quotes.csv?s=XOM+BBDb.TO+JNJ+MSFT&f=snd1l1yr
6
+
7
+ =end
8
+
9
+ module YahooStock
10
+ # ==DESCRIPTION:
11
+ #
12
+ # Class to generate the right url and interface with yahoo to get daily stock data
13
+ #
14
+ class Interface::Quote < Interface
15
+
16
+ class QuoteError < RuntimeError ; end
17
+
18
+ STD_PARAMETERS = {
19
+ :symbol => 's',
20
+ :name => 'n',
21
+ :last_trade_price_only => 'l1',
22
+ :last_trade_date => 'd1',
23
+ :last_trade_time => 't1',
24
+ :change_with_percent_change => 'c',
25
+ :change => 'c1',
26
+ :previous_close => 'p',
27
+ :change_in_percent => 'p2',
28
+ :open => 'o',
29
+ :day_low => 'g',
30
+ :day_high => 'h',
31
+ :volume => 'v',
32
+ :last_trade_with_time => 'l',
33
+ :day_range => 'm',
34
+ :ticker_trend => 't7',
35
+ :ask => 'a',
36
+ :average_daily_volume => 'a2',
37
+ :bid => 'b',
38
+ :bid_size => 'b4'
39
+ } unless defined?(STD_PARAMETERS)
40
+
41
+ EXTENDED_PARAMETERS = {
42
+ :symbol => 's',
43
+ :name => 'n',
44
+ :fifty_two_week_range => 'w',
45
+ :change_from_52_week_low => 'j5',
46
+ :percent_change_from_52_week_low => 'j6',
47
+ :change_from_52_week_high => 'k4',
48
+ :percent_change_from_52_week_high => 'k5',
49
+ :earnings_per_share => 'e',
50
+ :short_ratio => 's7',
51
+ :p_e_ratio => 'r',
52
+ :dividend_pay_date => 'r1',
53
+ :ex_dividend_date => 'q',
54
+ :dividend_per_share => 'd',
55
+ :dividend_yield => 'y',
56
+ :one_yr_target_price => 't8',
57
+ :market_capitalization => 'j1',
58
+ :eps_estimate_current_year => 'e7',
59
+ :eps_estimate_next_year => 'e8',
60
+ :eps_estimate_next_quarter => 'e9',
61
+ :peg_ratio => 'r5',
62
+ :price_eps_estimate_current_year => 'r6',
63
+ :price_eps_estimate_next_year => 'r7',
64
+ :book_value => 'b4',
65
+ :ebitda => 'j4',
66
+ :fifty_day_moving_average => 'm3',
67
+ :two_hundred_day_moving_average => 'm4',
68
+ :change_from_200_day_moving_average => 'm5',
69
+ :percent_change_from_200_day_moving_average => 'm6',
70
+ :change_from_50_day_moving_average => 'm7',
71
+ :percent_change_from_50_day_moving_average => 'm8',
72
+ :shares_owned => 's1',
73
+ :price_paid => 'p1',
74
+ :commission => 'c3',
75
+ :holdings_value => 'v1',
76
+ :day_value_change => 'w1',
77
+ :trade_date => 'd2',
78
+ :holdings_gain_percent => 'g1',
79
+ :annualized_gain => 'g3',
80
+ :holdings_gain => 'g4',
81
+ :stock_exchange => 'x',
82
+ :high_limit => 'l2',
83
+ :low_limit => 'l3',
84
+ :notes => 'n4',
85
+ :fifty_two_week_low => 'j',
86
+ :fifty_two_week_high => 'k',
87
+ :more_info => 'i',
88
+ } unless defined?(EXTENDED_PARAMETERS)
89
+
90
+ REALTIME_PARAMETERS = {
91
+ :symbol => 's',
92
+ :name => 'n',
93
+ :ask_real_time => 'b2',
94
+ :bid_real_time => 'b3',
95
+ :change => 'c1',
96
+ :change_real_time => 'c6',
97
+ :after_hours_change_real_time => 'c8',
98
+ :holdings_gain_percent_real_time => 'g5',
99
+ :holdings_gain_real_time => 'g6',
100
+ :order_book_real_time => 'i5',
101
+ :market_cap_real_time => 'j3',
102
+ :last_trade_real_time_with_time => 'k1',
103
+ :change_percent_real_time => 'k2',
104
+ :day_range_real_time => 'm2',
105
+ :p_e_ratio_real_time => 'r2',
106
+ :holdings_value_real_time => 'v7',
107
+ :day_value_change_real_time => 'w4',
108
+ } unless defined?(REALTIME_PARAMETERS)
109
+
110
+ attr_reader :stock_symbols
111
+
112
+ # The stock_params_hash parameter expects a hash with two key value pairs
113
+ #
114
+ # :stock_symbols => 'Array of stock symbols'
115
+ #
116
+ # e.g. :stock_symbols => ['YHOO']
117
+ #
118
+ # another hash :read_parameters => ['array of values']
119
+ #
120
+ # e.g. :read_parameters => [:last_trade_price_only, :last_trade_date]
121
+ def initialize(stock_params_hash)
122
+ unless stock_params_hash
123
+ raise QuoteError, 'You must pass a hash of stock symbols and the data you would like to see'
124
+ end
125
+ if !stock_params_hash[:stock_symbols] || stock_params_hash[:stock_symbols].length.zero?
126
+ raise(QuoteError, 'No stocks passed')
127
+ end
128
+ if !stock_params_hash[:read_parameters] || stock_params_hash[:read_parameters].length.zero?
129
+ raise QuoteError, 'Read parameters are not provided'
130
+ end
131
+ @stock_symbols = stock_params_hash[:stock_symbols]
132
+ @yahoo_url_parameters = stock_params_hash[:read_parameters]
133
+ @base_url = BASE_URLS[:quote]
134
+ add_observer(self)
135
+ end
136
+
137
+ def stock_symbols=(stock_symbol)
138
+ symbols_on_read = @stock_symbols.dup
139
+ @stock_symbols ||= []
140
+ @stock_symbols << stock_symbol unless @stock_symbols.include?(stock_symbol)
141
+ run_observers if symbols_on_read != @stock_symbols
142
+ end
143
+
144
+ def yahoo_url_parameters
145
+ return [] if !@yahoo_url_parameters || @yahoo_url_parameters.empty?
146
+ @yahoo_url_parameters.map(&:id2name).sort.map(&:to_sym)
147
+ end
148
+
149
+ def yahoo_url_parameters=(yahoo_url_parameter)
150
+ params_on_read = @yahoo_url_parameters.dup
151
+ unless allowed_parameters.include?(yahoo_url_parameter)
152
+ raise QuoteError, "Interface parameter #{yahoo_url_parameter} is not a valid parameter."
153
+ end
154
+ @yahoo_url_parameters ||= []
155
+ @yahoo_url_parameters << yahoo_url_parameter unless @yahoo_url_parameters.include?(yahoo_url_parameter)
156
+ run_observers if params_on_read != @yahoo_url_parameters
157
+ end
158
+
159
+ # Generate full url to be sent to yahoo
160
+ def uri
161
+ @all_stock_symbols = stock_symbols.join('+')
162
+ invalid_params = yahoo_url_parameters-allowed_parameters
163
+ unless invalid_params.length.zero?
164
+ raise QuoteError, "The parameters '#{invalid_params.join(', ')}' are not valid. Please check using YahooStock::Interface::Quote#allowed_parameters or YahooStock::Quote#valid_parameters"
165
+ end
166
+ @parameter_values = yahoo_url_parameters.collect {|v| parameters[v]}.join('')
167
+ if @all_stock_symbols.empty?
168
+ raise QuoteError, "You must add atleast one stock symbol to get stock data"
169
+ end
170
+ if @parameter_values.empty?
171
+ raise QuoteError, "You must add atleast one parameter to get stock data"
172
+ end
173
+ @uri_parameters = {:s => @all_stock_symbols, :f => @parameter_values}
174
+ super()
175
+ end
176
+
177
+ # Read the result using get method in super class
178
+ def get
179
+ uri
180
+ super()
181
+ end
182
+
183
+ # TODO MOVE TO THE HASH CLASS
184
+ # Returns results for the stock symbols as a hash.
185
+ # The hash keys are the stock symbols and the values are a hash of the keys and
186
+ # values asked for that stock.
187
+ def results
188
+ stock = {}
189
+ values.each_with_index do |values, index|
190
+ parsed_values = values.split(',')
191
+ stock[stock_symbols[index]] ||= {}
192
+ parsed_values.each_with_index do |value, i|
193
+ stock[stock_symbols[index]][yahoo_url_parameters[i]] = value
194
+ end
195
+ end
196
+ stock
197
+ end
198
+
199
+ # Add stock symbols to the url.
200
+ def add_symbols(*symbols)
201
+ symbols.each {|symbol| self.stock_symbols = symbol }
202
+ end
203
+
204
+ # Remove stock symbols from the url.
205
+ def remove_symbols(*symbols)
206
+ symbols.each do |symbol|
207
+ unless stock_symbols.include?(symbol)
208
+ raise QuoteError, "Cannot remove stock symbol #{symbol} as it is currently not present."
209
+ end
210
+ if stock_symbols.length == 1
211
+ raise QuoteError, "Symbol #{symbol} is the last symbol. Please add another symbol before removing this."
212
+ end
213
+ stock_symbols.reject!{|stock_sym| stock_sym == symbol}
214
+ run_observers
215
+ end
216
+ end
217
+
218
+ # Add parameters to the url.
219
+ def add_parameters(*parameters)
220
+ parameters.each {|parameter| self.yahoo_url_parameters = parameter }
221
+ end
222
+
223
+ # Remove parameters from the url.
224
+ def remove_parameters(*parameters)
225
+ parameters.each do |parameter|
226
+ unless yahoo_url_parameters.include?(parameter)
227
+ raise QuoteError, "Parameter #{parameter} is not present in current list"
228
+ end
229
+ if yahoo_url_parameters.length == 1
230
+ raise QuoteError, "Parameter #{parameter} is the last parameter. Please add another parameter before removing this."
231
+ end
232
+ @yahoo_url_parameters.reject!{|parameter_key| parameter_key == parameter}
233
+ run_observers
234
+ end
235
+ end
236
+
237
+ # Returns an array of parameters that can be passed to yahoo.
238
+ def allowed_parameters
239
+ parameters.keys
240
+ end
241
+
242
+ # Add standard parameters
243
+ def add_standard_params
244
+ add_grouped_parameters(STD_PARAMETERS.keys)
245
+ end
246
+
247
+ # Add extended parameters
248
+ def add_extended_params
249
+ add_grouped_parameters(EXTENDED_PARAMETERS.keys)
250
+ end
251
+
252
+ # Add realtime parameters
253
+ def add_realtime_params
254
+ add_grouped_parameters(REALTIME_PARAMETERS.keys)
255
+ end
256
+
257
+ # Clear all existing parameters from the current instance.
258
+ def clear_parameters
259
+ @yahoo_url_parameters.clear
260
+ run_observers
261
+ end
262
+
263
+ # Clear all existing symbols from the current instance.
264
+ def clear_symbols
265
+ stock_symbols.clear
266
+ run_observers
267
+ end
268
+
269
+ private
270
+
271
+ def add_grouped_parameters(parameter_group)
272
+ return if (parameter_group - yahoo_url_parameters).empty?
273
+ clear_parameters
274
+ parameter_group.each { |parameter| add_parameters(parameter) }
275
+ end
276
+
277
+ def run_observers
278
+ changed
279
+ notify_observers
280
+ end
281
+
282
+ def parameters
283
+ STD_PARAMETERS.merge(EXTENDED_PARAMETERS).merge(REALTIME_PARAMETERS)
284
+ end
285
+
286
+ end
287
+ end
@@ -0,0 +1,74 @@
1
+ module YahooStock
2
+ # ==DESCRIPTION:
3
+ #
4
+ # Class to generate the right url and interface with yahoo to get Scrip / Stock Symbols
5
+ #
6
+ class Interface::ScripSymbol < Interface
7
+
8
+ class ScripSymbolError < RuntimeError ; end
9
+
10
+ attr_reader :company
11
+ # Scrapes the resulting page and gets data in between two points
12
+ def initialize(company)
13
+ @base_url = BASE_URLS[:scrip_symbol]
14
+ @company = remove_any_space(company)
15
+ @before_element = 'yfi_sym_results'
16
+ @after_element = 'yfi_fp_left_bottom'
17
+ add_observer(self)
18
+ end
19
+
20
+ # Generate full uri with the help of uri method of the superclass
21
+ def uri
22
+ @uri_parameters = {:s => @company}
23
+ super()
24
+ end
25
+
26
+ # Get uri content with the help of get method of the super class
27
+ def get
28
+ uri
29
+ super()
30
+ end
31
+
32
+ def values
33
+ @values ||= get_values
34
+ end
35
+
36
+ def company=(company)
37
+ old_company = @company
38
+ @company = remove_any_space(company)
39
+ old_company != @company ? changed : changed(false)
40
+ notify_observers
41
+ end
42
+
43
+ private
44
+
45
+ def remove_any_space(words)
46
+ words.gsub(/\s/,'+')
47
+ end
48
+ # returns only the text among two points
49
+ def text_range
50
+ body = get.gsub!(/\s*/,'')
51
+ pattern = /#{@before_element}.*#{@after_element}/
52
+ results = pattern.match(body)
53
+ return results[0] if results
54
+ end
55
+
56
+ # Returns all possible values in a single string
57
+ def get_values
58
+ data = []
59
+ rows = text_range.to_s.split(/\<\/tr>/)
60
+ rows.each_with_index do |row, row_i|
61
+ cells = row.split(/\<\/td>/)
62
+ row_data = []
63
+ cells.each_with_index do |cell, cell_i|
64
+ datum = cell.sub('</a>','').gsub(/\<.*\>/,'').strip
65
+ row_data << datum if !datum.nil? || datum.empty?
66
+ end
67
+ data << row_data.join(',') if row_data.length > 1
68
+ end
69
+ data.join("\r\n")
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,158 @@
1
+ module YahooStock
2
+ # == DESCRIPTION:
3
+ #
4
+ # Provides the stock related current data.
5
+ #
6
+ # Uses YahooStock::Interface to connect to yahoo and get relevant data.
7
+ #
8
+ # == USAGE:
9
+ #
10
+ # * Initialize quote object
11
+ #
12
+ # quote = YahooStock::Quote.new(:stock_symbols => ['YHOO', 'GOOG'],
13
+ # :read_parameters => [:last_trade_price_only, :last_trade_date])
14
+ #
15
+ # If read_parameters are not provided then by default the above two parameters are used.
16
+ #
17
+ # * To get data for all stocks
18
+ #
19
+ # quote.get
20
+ #
21
+ # * To get data with real time values
22
+ #
23
+ # quote.realtime
24
+ #
25
+ # * To get data with standard values
26
+ #
27
+ # quote.standard
28
+ #
29
+ # * To get data with extra parameter values
30
+ #
31
+ # quote.extended
32
+ #
33
+ # * To view the valid parameters that can be passed
34
+ #
35
+ # quote.valid_parameters
36
+ #
37
+ # * To view the current parameters used
38
+ #
39
+ # quote.current_parameters
40
+ #
41
+ # * To view the current stock symbols used
42
+ #
43
+ # quote.current_symbols
44
+ #
45
+ # * To add more stocks to the list
46
+ #
47
+ # quote.add_symbols('MSFT', 'AAPL')
48
+ #
49
+ # * To remove stocks from list
50
+ #
51
+ # quote.remove_symbols('MSFT', 'AAPL')
52
+ #
53
+ class Quote < Base
54
+ class QuoteException < RuntimeError; end
55
+
56
+ # The options parameter expects a hash with two key value pairs
57
+ #
58
+ # :stock_symbols => 'Array of stock symbols' or a single symbol
59
+ #
60
+ # e.g. :stock_symbols => ['MSFT','YHOO'] or :stock_symbols => 'YHOO'
61
+ #
62
+ # another hash :read_parameters => 'array of values'
63
+ #
64
+ # e.g. :read_parameters => [:last_trade_price_only, :last_trade_date]
65
+ def initialize(options)
66
+ if options.nil? || !options.is_a?(Hash)
67
+ raise QuoteException, "You must provide a hash of stock symbols to fetch data"
68
+ end
69
+ if options[:stock_symbols].nil? || options[:stock_symbols].empty?
70
+ raise QuoteException, "You must provide atleast one stock symbol to fetch data"
71
+ end
72
+ if !(options[:read_parameters] && options[:read_parameters].any?)
73
+ options[:read_parameters] = [:last_trade_price_only, :last_trade_date]
74
+ end
75
+ options[:stock_symbols] = Array.new << options[:stock_symbols] unless options[:stock_symbols].is_a?(Array)
76
+ @interface = YahooStock::Interface::Quote.new(options)
77
+ end
78
+
79
+ # Create methods:
80
+ # def realtime
81
+ # - To get realtime stock values
82
+ # def extended
83
+ # - To get values for extra parameters
84
+ # def standard
85
+ # - To get standard values for stocks
86
+ %w{realtime extended standard}.each do |quote_type|
87
+ self.send(:define_method, "#{quote_type}".to_sym) do
88
+ @interface.send("add_#{quote_type}_params".to_sym)
89
+ return self
90
+ end
91
+ end
92
+
93
+ # Adds more stock symbols to the existing instance.
94
+ # One or more stock symbols can be passed as parameter.
95
+ def add_symbols(*symbols)
96
+ @interface.add_symbols(*symbols)
97
+ end
98
+
99
+ # Removes stock symbols from the existing instance.
100
+ # One of more stock symbols can be passed to remove.
101
+ def remove_symbols(*symbols)
102
+ @interface.remove_symbols(*symbols)
103
+ end
104
+
105
+ # Clear all existing stock symbols from the current instance.
106
+ def clear_symbols
107
+ @interface.clear_symbols
108
+ end
109
+
110
+ # Show all stock symbols in the current instance that will be used to get results.
111
+ def current_symbols
112
+ @interface.stock_symbols
113
+ end
114
+
115
+ # Adds more parameters for the stock symbols to the existing instance for getting data.
116
+ # One or more parameters can be passed as argument.
117
+ def add_parameters(*parameters)
118
+ @interface.add_parameters(*parameters)
119
+ end
120
+
121
+ # Removes parameters for the stock symbols to get values for from the existing instance.
122
+ # One of more parameters can be passed to remove.
123
+ def remove_parameters(*parameters)
124
+ @interface.remove_parameters(*parameters)
125
+ end
126
+
127
+ # Shows all parameters in the current instance that will be used to get results.
128
+ def current_parameters
129
+ @interface.yahoo_url_parameters
130
+ end
131
+
132
+ alias :data_attributes :current_parameters
133
+
134
+ # Set current instance to use all parameters to fetch values for current symbols.
135
+ def use_all_parameters
136
+ params = valid_parameters.each {|parameter| add_parameters(parameter)}
137
+ sort_symbols(params)
138
+ end
139
+
140
+ # Clear all existing parameters from the current instance.
141
+ def clear_parameters
142
+ @interface.clear_parameters
143
+ current_parameters
144
+ end
145
+
146
+ # Returns an array of all allowed parameters that can be used.
147
+ def valid_parameters
148
+ sort_symbols(@interface.allowed_parameters)
149
+ end
150
+
151
+ private
152
+
153
+ def sort_symbols(array_of_symbols)
154
+ array_of_symbols.map(&:id2name).sort.map(&:to_sym)
155
+ end
156
+
157
+ end
158
+ end