Class: YahooFinance::FinancialStatement::FinancialStatementPage

Inherits:
Object
  • Object
show all
Defined in:
lib/yahoo_finance/financial_statement.rb

Overview

Quarterly Data

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(symbol = nil) ⇒ FinancialStatementPage

Returns a new instance of FinancialStatementPage.



100
101
102
103
104
105
106
107
108
109
# File 'lib/yahoo_finance/financial_statement.rb', line 100

def initialize symbol=nil
  @symbol = symbol
  @term = :quarterly
  @periods = []
  @number_multiplier = 1000.00     # all numbers in the statements are in thousands... I need to verify whether I need to parse that
  @financial_statement = {}
  @data_columns = 4
  @type="is"
  @field_defs = YahooFinance::FinancialStatement::INCOME_STMT_FIELDS
end

Instance Attribute Details

#symbolObject

Returns the value of attribute symbol.



98
99
100
# File 'lib/yahoo_finance/financial_statement.rb', line 98

def symbol
  @symbol
end

Instance Method Details

#available_fieldsObject



117
118
119
# File 'lib/yahoo_finance/financial_statement.rb', line 117

def available_fields 
  return @field_defs.keys;
end

#fetchObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/yahoo_finance/financial_statement.rb', line 121

def fetch
  url = "http://finance.yahoo.com/q/#{@type}?s=#{@symbol}&#{@term.to_s}"
  doc = nil
  tries = 0
  begin
    # SINCE YAHOO HAS SOME TIMES THE TENDENCY TO RETURN AN OOPS PAGE RATHER THAN A HTTP FAILURE
    # WE ARE USING A TEST OF A HEADER FIELD AS A CONDITION OF A CORRECTLY FETCHED PAGE
    fetched_ok = false
    fetch_tries = 1
    while (fetched_ok == false)  && (fetch_tries <= 3)
      open(url) do |stream|
        doc = Nokogiri::HTML(stream)
      end
      search_field = ((@type == "is") ? "Income Statement" : ((@type == "bs") ? "Balance Sheet" : "Cash Flow") )
      fetched_test = doc.xpath("//b[text()[contains(., '" + search_field +"')]]")
      if fetched_test && fetched_test.size > 0
        # THERE IS STILL A CHANCE THAT YAHOO WILL NOT HAVE THE DATA FOR THIS STOCK, IN WHICH CASE, IT WILL DISPLAY
        # a PAGE WITH A STATEMENT LIKE: 'There is no Income Statement data available for AMBR.' --- WE SEARCH FOR THAT AND RETURN NIL IF FOUND
        nodata_path_search_expr = "//p[text()[contains(., 'There is no "+ search_field + " data available for #{symbol}.')]]"
        no_statement = doc.xpath(nodata_path_search_expr)
        # puts "EXPR: #{nodata_path_search_expr}    NO STATEMENT: #{no_statement} AND SIZE: #{no_statement.size}"
        if (no_statement  && (no_statement.size > 0))
          puts "WARNING: FOUND There is no #{search_field} data available for #{symbol}. -- RETURNING NIL"
          return nil        # YAHOO DOESN'T HAVE THE DATA...
        else
          fetched_ok = true
        end
      else
        puts "Fetching URL #{url} again - previous one failed. Trying #{fetch_tries} of 3"
        sleep (1)
        fetch_tries += 1
      end
    end
  rescue
    tries += 1
    if fetch_tries <= 3
      puts "Exception: #{$!.inspect}  -- Retrying symbol #{@symbol} time: #{fetch_tries.to_s} (total 3)"
      sleep(2)
      retry
    end 
    
  end
  #
  # %%% OK, WE MUST MAKE THIS MORE ROBUST TO HANDLE FEWER REPORTING PERIODS, e.g. ACT Actavis has 3 quarters reported
  #
  # let's initialize periods: by finding 'Period Endinng
  got_periods = true
  begin
    row = doc.xpath("//span[text() = 'Period Ending']")[0].parent.parent.parent
    period = []
    1.upto(@data_columns) do |i|
      begin
        pd = Date.parse(row.children[i].text)
        @periods << pd
      rescue
        break;    # end of the line here
      end
    end
    @financial_statement[:statement_periods] = @periods
  rescue
    puts "Exception: #{$!.inspect}  -- Skipping symbol #{@symbol} URL: #{url}"
    # puts "DOC: #{doc}"
    got_periods = false
  end
  
  return nil if !got_periods
  
  # YahooFinance.parse_financial_statement_field field, multiplier
  # let's fetch everything here & store in the income statement
  @field_defs.keys.each do |incst_key|
    next if incst_key == :statement_periods
    path_expr = "//td[text()[contains(., '" + @field_defs[incst_key][0]  + "')]]"
    row = nil
    elem = doc.xpath(path_expr)
    index = 1
    regex = "\\s\*#{@field_defs[incst_key][0]}\\s\*"
    if elem && elem.size == 0
      # this is because we have a strong type; let's try again
      path_expr = "//td/strong[text()[contains(., '" + @field_defs[incst_key][0]  +"')]]"
      elem = doc.xpath(path_expr)
      if elem.size > 0
        elem.each do |e|
          if e.text.match regex
            # we found it
            row = e.parent.parent
          end
        end
        if !row
          # wasn't found
          puts "#{@field_defs[incst_key][0]} was not found!"
          next
        end
        index = row.children.index(elem[0].parent)
      end
    else
      elem.each do |e|
        # puts "Checking #{e}: class #{e.text.class.name} with text <<#{e.text}>> and regex #{regex}"
        if e.text.match regex
          # we found it
          row = e.parent
          break
        end
      end
      if !row
        # wasn't found
        puts "#{@field_defs[incst_key][0]} was not found!"
        next
      end
      index = row.children.index(elem[0])
    end
    if elem && elem.size > 0
      # puts "\tFOUND!!!! PATH EXPRESSION IS #{path_expr} "
      # puts "\t\tROW: #{row}"
      rstbl = []
      1.upto(@periods.size) do |i|
        field = row.children[index+i].text.tr('^[0-9\,\.\-\(\)]', '')
        rs = YahooFinance.parse_financial_statement_field(field, @number_multiplier)
        rstbl << rs
      end
      
      @financial_statement[incst_key] = rstbl
      # puts "\tPARSED #{incst_key}"
    else
      puts "\tNOT FOUND!!!! #{incst_key}"
    end
  end
  @financial_statement
end

#statement_periodsObject



250
251
252
# File 'lib/yahoo_finance/financial_statement.rb', line 250

def statement_periods
  @periods
end

#term=(aValue) ⇒ Object



111
112
113
114
115
# File 'lib/yahoo_finance/financial_statement.rb', line 111

def term= aValue
  if term == :quarterly || term == :annual
    @term = term
  end
end

#value_for(key_stat) ⇒ Object



254
255
256
257
258
259
260
# File 'lib/yahoo_finance/financial_statement.rb', line 254

def value_for key_stat
  begin
    return @financial_statement[key_stat]
  rescue
  end
  return nil
end