yahoo_stock 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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