Class: Currency::Exchange::Rate

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

Overview

Represents a convertion rate between two currencies at a given period of time.

Direct Known Subclasses

Writable

Defined Under Namespace

Modules: Source Classes: Deriver, Writable

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(c1, c2, c1_to_c2_rate, source = "UNKNOWN", date = nil, derived = nil, reciprocal = nil, opts = nil) ⇒ Rate

Returns a new instance of Rate.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/currency/exchange/rate.rb', line 56

def initialize(c1, c2, c1_to_c2_rate, source = "UNKNOWN", date = nil, derived = nil, reciprocal = nil, opts = nil)
  @c1 = c1
  @c2 = c2
  @rate = c1_to_c2_rate
  raise ::Currency::Exception::InvalidRate, 
  [ 
   "rate is not positive",
   :rate, @rate,
   :c1, c1,
   :c2, c2,
  ] unless @rate && @rate >= 0.0
  @source = source
  @date = date
  @derived = derived
  @reciprocal = reciprocal
  
  #
  @rate_avg =
    @rate_samples =
    @rate_lo =
    @rate_hi =
    @rate_date_0 =
    @rate_date_1 =
    @date_0 =
    @date_1 =
    nil

  if opts
    opts.each_pair do | k, v |
      self.instance_variable_set("@#{k}", v)
    end
  end
end

Instance Attribute Details

#c1Object (readonly)

The first Currency.



9
10
11
# File 'lib/currency/exchange/rate.rb', line 9

def c1
  @c1
end

#c2Object (readonly)

The second Currency.



12
13
14
# File 'lib/currency/exchange/rate.rb', line 12

def c2
  @c2
end

#dateObject (readonly)

The Time of the rate.



25
26
27
# File 'lib/currency/exchange/rate.rb', line 25

def date
  @date
end

#date_0Object (readonly)

The lowest date of sampled rates.



49
50
51
# File 'lib/currency/exchange/rate.rb', line 49

def date_0
  @date_0
end

#date_1Object (readonly)

The highest date of sampled rates. This is non-inclusive during searches to allow seamless tileings of time with rate buckets.



54
55
56
# File 'lib/currency/exchange/rate.rb', line 54

def date_1
  @date_1
end

#derivedObject (readonly)

If the rate is derived from other rates, this describes from where it was derived.



28
29
30
# File 'lib/currency/exchange/rate.rb', line 28

def derived
  @derived
end

#rateObject (readonly)

The rate between c1 and c2.

To convert between m1 in c1 and m2 in c2:

m2 = m1 * rate.


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

def rate
  @rate
end

#rate_avgObject (readonly)

Average rate over rate samples in a time range.



31
32
33
# File 'lib/currency/exchange/rate.rb', line 31

def rate_avg
  @rate_avg
end

#rate_date_0Object (readonly)

The rate at date_0.



43
44
45
# File 'lib/currency/exchange/rate.rb', line 43

def rate_date_0
  @rate_date_0
end

#rate_date_1Object (readonly)

The rate at date_1.



46
47
48
# File 'lib/currency/exchange/rate.rb', line 46

def rate_date_1
  @rate_date_1
end

#rate_hiObject (readonly)

The rate high between date_0 and date_1.



40
41
42
# File 'lib/currency/exchange/rate.rb', line 40

def rate_hi
  @rate_hi
end

#rate_loObject (readonly)

The rate low between date_0 and date_1.



37
38
39
# File 'lib/currency/exchange/rate.rb', line 37

def rate_lo
  @rate_lo
end

#rate_samplesObject (readonly)

Number of rate samples used to calcuate rate_avg.



34
35
36
# File 'lib/currency/exchange/rate.rb', line 34

def rate_samples
  @rate_samples
end

#sourceObject (readonly)

The source of the rate.



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

def source
  @source
end

Instance Method Details

#collect_rate(rate) ⇒ Object

Collect rates samples in to this Rate.



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
# File 'lib/currency/exchange/rate.rb', line 136

def collect_rate(rate)
  # Initial.
  @rate_samples ||= 0
  @rate_sum ||= 0
  @source ||= rate.source
  @c1 ||= rate.c1
  @c2 ||= rate.c2
 
  # Reciprocal?
  if @c1 == rate.c2 && @c2 == rate.c1
    collect_rate(rate.reciprocal)
  elsif ! (@c1 == rate.c1 && @c2 == rate.c2)
    raise ::Currency::Exception::InvalidRate,
    [ 
     "Cannot collect rates between different currency pairs",
      :rate1, self,
      :rate2, rate,
    ]
  else
    # Multisource?
    @source = "<<multiple-sources>>" unless @source == rate.source

    # Calculate rate average.
    @rate_samples += 1
    @rate_sum += rate.rate || (rate.rate_lo + rate.rate_hi) * 0.5
    @rate_avg = @rate_sum / @rate_samples

    # Calculate rates ranges.
    r = rate.rate_lo || rate.rate
    unless @rate_lo && @rate_lo < r
      @rate_lo = r
    end
    r = rate.rate_hi || rate.rate
    unless @rate_hi && @rate_hi > r
      @rate_hi = r
    end

    # Calculate rates on date range boundaries
    r = rate.rate_date_0 || rate.rate
    d = rate.date_0 || rate.date
    unless @date_0 && @date_0 < d
      @date_0 = d
      @rate_date_0 = r
    end

    r = rate.rate_date_1 || rate.rate
    d = rate.date_1 || rate.date
    unless @date_1 && @date_1 > d
      @date_1 = d 
      @rate_date_1 = r
    end

    @date ||= rate.date || rate.date0 || rate.date1
  end
  self
end

#collect_rates(rates) ⇒ Object

Collect rate samples into rate_avg, rate_hi, rate_lo, rate_date_0, rate_date_1, date_0, date_1.



127
128
129
130
131
132
133
# File 'lib/currency/exchange/rate.rb', line 127

def collect_rates(rates)
  rates = [ rates ] unless rates.kind_of?(Enumerable)
  rates.each do | r |
    collect_rate(r)
  end
  self
end

#convert(m, c1) ⇒ Object

Converts from m in Currency c1 to the opposite currency.



114
115
116
117
118
119
120
121
122
123
# File 'lib/currency/exchange/rate.rb', line 114

def convert(m, c1)
  m = m.to_f	
  if @c1 == c1
    # $stderr.puts "Converting #{@c1} #{m} to #{@c2} #{m * @rate} using #{@rate}"
    m * @rate
  else
    # $stderr.puts "Converting #{@c2} #{m} to #{@c1} #{m / @rate} using #{1.0 / @rate}; recip"
    m / @rate
  end
end

#inspectObject



200
# File 'lib/currency/exchange/rate.rb', line 200

def inspect; to_s; end

#reciprocalObject

Returns a cached reciprocal Rate object from c2 to c1.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/currency/exchange/rate.rb', line 92

def reciprocal
  @reciprocal ||= @rate == 1.0 ? self :
    self.class.new(@c2, @c1, 
                   1.0 / @rate, 
                   @source, 
                   @date, 
                   "reciprocal(#{derived || "#{c1.code}#{c2.code}"})", self,
                   { 
                     :rate_avg     => @rate_avg    && 1.0 / @rate_avg,
                     :rate_samples => @rate_samples,                            
                     :rate_lo      => @rate_lo     && 1.0 / @rate_lo,
                     :rate_hi      => @rate_hi     && 1.0 / @rate_hi,
                     :rate_date_0  => @rate_date_0 && 1.0 / @rate_date_0,
                     :rate_date_1  => @rate_date_1 && 1.0 / @rate_date_1,
                     :date_0       => @date_0,
                     :date_1       => @date_1,
                   }
                   )
end

#to_s(extended = false) ⇒ Object



194
195
196
197
198
# File 'lib/currency/exchange/rate.rb', line 194

def to_s(extended = false)
  extended = "#{date_0} #{rate_date_0} |< #{rate_lo} #{rate} #{rate_hi} >| #{rate_date_1} #{date_1}" if extended
  extended ||= ''
  "#<#{self.class.name} #{c1.code} #{c2.code} #{rate} #{source.inspect} #{date ? date.strftime('%Y/%m/%d-%H:%M:%S') : 'nil'} #{derived && derived.inspect} #{extended}>"
end