class GoogleFinance::Prices

Public Class Methods

get(symbol, params = {}) click to toggle source
# File lib/google-finance/prices.rb, line 12
def self.get(symbol, params = {})
  query = {}
  params.each_pair do |k, v|
    case k
    when :exchange, :x then
      query[:x] = v
    when :interval, :i then
      query[:i] = v
    when :period, :p then
      query[:p] = v
    when :df then
      query[:df] = v
    when :auto then
      query[:auto] = v
    when :ei then
      query[:ei] = v
    when :fields, :f then
      query[:f] = (v.is_a?(String) ? v.split(',').map(&:to_sym) : v).map do |f|
        case f
        when :date, :d then :d
        when :open, :o then :o
        when :close, :c then :c
        when :volume, :v then :v
        when :low, :l then :l
        when :high, :h then :h
        when :k then :k
        else
          raise ArgumentError, "Invalid fields: #{v}."
        end
      end.join(',')
    else
      raise ArgumentError, "Invalid parameter: #{k}."
    end
  end
  data = GoogleFinance::Api::GetPrices.fetch({ q: symbol }.merge(query))
  headers = {}
  rows = []
  start_ts = Time.at(0)
  timezone_offset = 0
  data.each_line do |line|
    line = CGI.unescape(line)
    if line =~ /(?<k>.+)\=(?<v>.*)/
      k = Regexp.last_match[:k].downcase.to_sym
      case k
      when :columns then
        headers[k] = Regexp.last_match[:v].split(',').map(&:downcase)
      when :market_open_minute, :market_close_minute, :interval then
        headers[k] = Regexp.last_match[:v].to_i
      when :timezone_offset then
        timezone_offset = Regexp.last_match[:v].to_i
      else
        headers[k] = Regexp.last_match[:v]
      end
    else
      values = line.split(',')
      raise "Unexpected number of columns, #{values.count} vs. #{headers[:columns].size}." if (headers[:columns] || []).size != values.count
      row = {}
      if headers[:columns]
        headers[:columns].each_with_index do |name, ndx|
          row[name] = case name
                      when 'date' then
                        if values[ndx] =~ /^a(?<ts>.*)/
                          # https://stackoverflow.com/questions/45897894/convert-timestamps-in-google-finance-stock-data-to-proper-datetime
                          #
                          # The full timestamps are denoted by the leading 'a'. Like this: a1092945600. The number after the 'a' is a Unix timestamp.
                          # The numbers without a leading 'a' are "intervals".
                          #
                          start_ts = Time.at(Regexp.last_match[:ts].to_i)
                        else
                          start_ts + (headers[:interval] || 1) * values[ndx].to_i
                        end
                      when 'volume' then
                        values[ndx].to_i
                      else
                        values[ndx].to_f
          end
        end
      end
      rows << GoogleFinance::Price.new({ 'timezone_offset' => timezone_offset }.merge(row))
    end
  end
  raise GoogleFinance::Errors::SymbolNotFoundError.new(symbol, data) if rows.count == 0 && headers[:exchange] == 'UNKNOWN EXCHANGE'
  new headers, rows
end
new(headers, values = []) click to toggle source
Calls superclass method
# File lib/google-finance/prices.rb, line 7
def initialize(headers, values = [])
  @headers = OpenStruct.new(headers)
  super values
end