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
# 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.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.



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.



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

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("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_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.



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

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.



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

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



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

def inspect; to_s; end

#reciprocalObject

Returns a cached reciprocal Rate object from c2 to c1.



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

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



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

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