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.

Defined Under Namespace

Modules: Source Classes: Deriver

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.



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

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.new(@rate) 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.



7
8
9
# File 'lib/currency/exchange/rate.rb', line 7

def c1
  @c1
end

#c2Object (readonly)

The second Currency.



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

def c2
  @c2
end

#dateObject (readonly)

The Time of the rate.



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

def date
  @date
end

#date_0Object (readonly)

The lowest date of sampled rates.



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

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.



52
53
54
# File 'lib/currency/exchange/rate.rb', line 52

def date_1
  @date_1
end

#derivedObject (readonly)

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



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

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.


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

def rate
  @rate
end

#rate_avgObject (readonly)

Average rate over rate samples in a time range.



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

def rate_avg
  @rate_avg
end

#rate_date_0Object (readonly)

The rate at date_0.



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

def rate_date_0
  @rate_date_0
end

#rate_date_1Object (readonly)

The rate at date_1.



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

def rate_date_1
  @rate_date_1
end

#rate_hiObject (readonly)

The rate high between date_0 and date_1.



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

def rate_hi
  @rate_hi
end

#rate_loObject (readonly)

The rate low between date_0 and date_1.



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

def rate_lo
  @rate_lo
end

#rate_samplesObject (readonly)

Number of rate samples used to calcuate rate_avg.



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

def rate_samples
  @rate_samples
end

#sourceObject (readonly)

The source of the rate.



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

def source
  @source
end

Instance Method Details

#collect_rate(rate) ⇒ Object

Collect rates samples in to this Rate.



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

def collect_rate(rate)
  # Initial.
  @rate_samples ||= 0
  @rate_sum ||= 0
  @source ||= rate.source
  @c1 ||= rate.c1
  @c2 ||= rate.c2
  @date ||= rate.date
 
  # Reciprocal?
  if @c1 == rate.c2 && @c2 == rate.c1
    collect_rate(rate.reciprocal)
  elsif ! (@c1 == rate.c1 && @c2 == rate.c2)
    raise("Cannot collect rates between different currency pairs")
  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_0 = 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.



119
120
121
122
123
124
125
# File 'lib/currency/exchange/rate.rb', line 119

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.



106
107
108
109
110
111
112
113
114
115
# File 'lib/currency/exchange/rate.rb', line 106

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



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

def inspect; to_s; end

#reciprocalObject

Returns a cached reciprocal Rate object from c2 to c1.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/currency/exchange/rate.rb', line 84

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



182
183
184
185
186
# File 'lib/currency/exchange/rate.rb', line 182

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