Class: Currency::Exchange::Rate::Source::Historical::RateLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/currency/exchange/rate/source/historical/rate_loader.rb

Overview

Loads rates from multiple sources and will store them as historical rates in a database.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = { }) ⇒ RateLoader

Returns a new instance of RateLoader.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 24

def initialize(opts = { })
  self.summary_rate_src = 'summary'
  self.source_options = { }
  self.options = opts.dup.freeze
  self.base_currencies = [ :USD ]
  self.required_currencies =
    [
     :USD,
     :GBP,
     :CAD,
     :EUR,
     #   :MXP,
    ]
  self.verbose = ! ! ENV['CURRENCY_VERBOSE']
  opts.each do | k, v | 
    setter = "#{k}="
    send(setter, v) if respond_to?(setter)
  end
end

Instance Attribute Details

#base_currenciesObject

Returns the value of attribute base_currencies.



20
21
22
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 20

def base_currencies
  @base_currencies
end

#optionsObject

Returns the value of attribute options.



13
14
15
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 13

def options
  @options
end

#preferred_summary_sourceObject

Returns the value of attribute preferred_summary_source.



19
20
21
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 19

def preferred_summary_source
  @preferred_summary_source
end

#rate_source_optionsObject

Returns the value of attribute rate_source_options.



17
18
19
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 17

def rate_source_options
  @rate_source_options
end

#rate_sourcesObject

Returns the value of attribute rate_sources.



16
17
18
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 16

def rate_sources
  @rate_sources
end

#required_currenciesObject

Returns the value of attribute required_currencies.



15
16
17
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 15

def required_currencies
  @required_currencies
end

#source_optionsObject

Returns the value of attribute source_options.



14
15
16
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 14

def source_options
  @source_options
end

#summary_rate_srcObject

Returns the value of attribute summary_rate_src.



21
22
23
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 21

def summary_rate_src
  @summary_rate_src
end

#verboseObject

Returns the value of attribute verbose.



18
19
20
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 18

def verbose
  @verbose
end

#writerObject (readonly)

Returns the value of attribute writer.



22
23
24
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 22

def writer
  @writer
end

Instance Method Details

#initialize_writer(writer = Currency::Exchange::Rate::Source::Historical::Writer.new) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 45

def initialize_writer(writer = Currency::Exchange::Rate::Source::Historical::Writer.new)
  @writer = writer

  writer.time_quantitizer = :current
  writer.required_currencies = required_currencies
  writer.base_currencies = base_currencies
  writer.preferred_currencies = writer.required_currencies
  writer.reciprocal_rates = true
  writer.all_rates = true
  writer.identity_rates = false 
 
  options.each do | k, v |
    setter = "#{k}="
    writer.send(setter, v) if writer.respond_to?(setter)
  end

  writer
end

#runObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 65

def run
  rate_sources.each do | src |
    # Create a historical rate writer.
    initialize_writer

    # Handle creating a summary rates called 'summary'.
    if src == summary_rate_src
      summary_rates(src)
    else
      require "currency/exchange/rate/source/#{src}"
      src_cls_name = src.gsub(/(^|_)([a-z])/) { | m | $2.upcase }
      src_cls = Currency::Exchange::Rate::Source.const_get(src_cls_name)
      src = src_cls.new(source_options)
      
      writer.source = src  
      
      writer.write_rates
    end
  end
ensure
  @writer = nil
end

#summary_rates(src) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
# File 'lib/currency/exchange/rate/source/historical/rate_loader.rb', line 89

def summary_rates(src)
  # A list of summary rates.
  summary_rates = [ ]
  
  # Get a list of all rate time ranges before today,
  # that do not have a 'cnu' summary rate.
  h_rate_cls = Currency::Exchange::Rate::Source::Historical::Rate
  conn = h_rate_cls.connection
  
  # Select only rates from yesterday or before back till 30 days.
  date_1 = Time.now - (0 * 24 * 60 * 60)
  date_0 = date_1 - (30 * 24 * 60 * 60)
  
  date_0 = conn.quote(date_0)
  date_1 = conn.quote(date_1)
  
  query = 
"SELECT 
DISTINCT a.date_0, a.date_1 
FROM 
#{h_rate_cls.table_name} AS a 
WHERE 
    a.source <> '#{src}' 
AND a.date_1 >= #{date_0} AND a.date_1 < #{date_1} 
AND (SELECT COUNT(b.id) FROM #{h_rate_cls.table_name} AS b 
     WHERE 
           b.c1 = a.c1 AND b.c2 = a.c2 
       AND b.date_0 = a.date_0 AND b.date_1 = a.date_1 
       AND b.source = '#{src}') = 0 
ORDER BY
 date_0"
  STDERR.puts "query = \n#{query.split("\n").join(' ')}" if verbose
    
  dates = conn.query(query)
    
  dates.each do | date_range |
    STDERR.puts "\n=============================================\n" if verbose
    STDERR.puts "date_range = #{date_range.inspect}"                if verbose
    
    # Query for all rates that have the same date range.
    q_rate = h_rate_cls.new(:date_0 => date_range[0], :date_1 => date_range[1])
    available_rates = q_rate.find_matching_this(:all)
    
    # Collect all the currency pairs and rates.
    currency_pair = { }
    available_rates.each do | h_rate |
      rate = h_rate.to_rate
      (currency_pair[ [ rate.c1, rate.c2 ] ] ||= [ ]) << [ h_rate, rate ]
      # STDERR.puts "rate = #{rate} #{h_rate.date_0} #{h_rate.date_1}" if verbose
    end
    
    currency_pair.each_pair do | currency_pair, rates |
      STDERR.puts "\n  =============================================\n" if verbose
      STDERR.puts "  currency_pair = #{currency_pair}"                  if verbose
      
      # Create a summary rate for the currency pair.
      selected_rates = [ ]
      
      rates.each do | h_rates |
        h_rate, rate = *h_rates
        
        # Sanity check!
        next if h_rate.source == src
        
        # Found perferred source?
        if h_rate.source == preferred_summary_source
          selected_rates = [ h_rates ]
          break
        end
        
        selected_rates << h_rates
      end
      
      unless selected_rates.empty?
        summary_rate = Currency::Exchange::Rate::Writable.new(currency_pair[0], currency_pair[1], 0.0)
        selected_rates.each do | h_rates |
          h_rate, rate = *h_rates
          STDERR.puts "    rate = #{rate.inspect}" if verbose
          summary_rate.collect_rate(rate)
        end
        
        # Save the rate.
        summary_rate.rate = summary_rate.rate_avg
        summary_rate.source = src
        summary_rate.derived = 'summary(' + selected_rates.collect{|r| r[0].id}.sort.join(',') + ')'
        STDERR.puts "  summary_rate = #{summary_rate} #{summary_rate.rate_samples}" if verbose
        
        summary_rates << summary_rate
      end
    end
  end
  
  writer.write_rates(summary_rates)
end