currency 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,6 +22,7 @@ lib/currency/exchange/rate/deriver.rb
22
22
  lib/currency/exchange/rate/source.rb
23
23
  lib/currency/exchange/rate/source/base.rb
24
24
  lib/currency/exchange/rate/source/failover.rb
25
+ lib/currency/exchange/rate/source/federal_reserve.rb
25
26
  lib/currency/exchange/rate/source/historical.rb
26
27
  lib/currency/exchange/rate/source/historical/rate.rb
27
28
  lib/currency/exchange/rate/source/historical/writer.rb
@@ -42,6 +43,7 @@ test/ar_simple_test.rb
42
43
  test/ar_test_base.rb
43
44
  test/ar_test_core.rb
44
45
  test/config_test.rb
46
+ test/federal_reserve_test.rb
45
47
  test/formatter_test.rb
46
48
  test/historical_writer_test.rb
47
49
  test/macro_test.rb
@@ -1,5 +1,21 @@
1
1
  = Currency Release History
2
2
 
3
+ == Release 0.4.7: 2007/06/25
4
+
5
+ CRITICAL FIXES
6
+
7
+ * NewYorkFed: CRITICAL FIX:
8
+
9
+ Rates for USDAUD, USDEUR, USDNZD and USDGBP were reciprocals.
10
+ See http://www.newyorkfed.org/markets/fxrates/noon.cfm
11
+
12
+ * FederalReserve: Added support for historical rates from http://www.federalreserve.gov/releases/H10/hist
13
+ * Provider#get_rate(): Return first rate immediately.
14
+ * Rate::Writable for rate summary computation support.
15
+ * Rate: collect_rate(): fixed rate_date_1.
16
+ * Historical::Rate: to_rate(): takes optional class.
17
+ * Historical::Rate: from_rate(): fixed rate_samples.
18
+
3
19
  == Release 0.4.6: 2007/05/29
4
20
 
5
21
  * NewYorkFed: changed FEXtime to FEXTIME.
data/TODO.txt CHANGED
@@ -3,3 +3,5 @@
3
3
 
4
4
  * Refactor all configuration class variables into Currency::Config
5
5
  * Refactor all cached values into objects that can be reinstantiated on a per-thread basis
6
+ * Support http://www.xe.com/ucc/full.php rate queries.
7
+
@@ -1,5 +1,5 @@
1
1
  module Currency
2
- CurrencyVersion = '0.4.6'
2
+ CurrencyVersion = '0.4.7'
3
3
  end
4
4
  # DO NOT EDIT
5
5
  # This file is auto-generated by build scripts.
@@ -1,6 +1,8 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
+ require 'currency'
5
+
4
6
  # The Currency::Exchange package is responsible for
5
7
  # the buying and selling of currencies.
6
8
  #
@@ -1,6 +1,8 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
+ require 'currency/exchange'
5
+
4
6
  # Represents a convertion rate between two currencies at a given period of time.
5
7
  class Currency::Exchange::Rate
6
8
  # The first Currency.
@@ -132,7 +134,6 @@ class Currency::Exchange::Rate
132
134
  @source ||= rate.source
133
135
  @c1 ||= rate.c1
134
136
  @c2 ||= rate.c2
135
- @date ||= rate.date
136
137
 
137
138
  # Reciprocal?
138
139
  if @c1 == rate.c2 && @c2 == rate.c1
@@ -170,7 +171,7 @@ class Currency::Exchange::Rate
170
171
  d = rate.date_1 || rate.date
171
172
  unless @date_1 && @date_1 > d
172
173
  @date_1 = d
173
- @rate_date_0 = r
174
+ @rate_date_1 = r
174
175
  end
175
176
 
176
177
  @date ||= rate.date || rate.date0 || rate.date1
@@ -190,3 +191,13 @@ class Currency::Exchange::Rate
190
191
  end # class
191
192
 
192
193
 
194
+ class Currency::Exchange::Rate::Writable < Currency::Exchange::Rate
195
+ attr_writer :source
196
+ attr_writer :derived
197
+ attr_writer :rate
198
+ def initialize(c1 = nil, c2 = nil, rate = nil, *opts)
199
+ super(c1, c2, 0.0, *opts)
200
+ @rate = rate
201
+ end
202
+ end # class
203
+
@@ -0,0 +1,160 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ require 'currency/exchange/rate/source/provider'
5
+
6
+ require 'net/http'
7
+ require 'open-uri'
8
+
9
+
10
+ # Connects to http://www.federalreserve.gov/releases/H10/hist/dat00_<country>.txtb
11
+ # Parses all known currency files.
12
+ #
13
+ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::Rate::Source::Provider
14
+ # Defines the pivot currency for http://www.federalreserve.gov/releases/H10/hist/dat00_#{country_code}.txt data files.
15
+ PIVOT_CURRENCY = :USD
16
+
17
+ # Arbitrary currency code used by www.federalreserve.gov for
18
+ # naming historical data files.
19
+ # Used internally.
20
+ attr_accessor :country_code
21
+
22
+ def initialize(*opt)
23
+ self.uri = 'http://www.federalreserve.gov/releases/H10/hist/dat00_#{country_code}.txt'
24
+ self.country_code = ''
25
+ @raw_rates = nil
26
+ super(*opt)
27
+ end
28
+
29
+
30
+ # Returns 'federalreserve.gov'.
31
+ def name
32
+ 'federalreserve.gov'
33
+ end
34
+
35
+
36
+ # FIXME?
37
+ #def available?(time = nil)
38
+ # time ||= Time.now
39
+ # ! [0, 6].include?(time.wday) ? true : false
40
+ #end
41
+
42
+
43
+ def clear_rates
44
+ @raw_rates = nil
45
+ super
46
+ end
47
+
48
+
49
+ def raw_rates
50
+ rates
51
+ @raw_rates
52
+ end
53
+
54
+ # Maps bizzare federalreserve.gov country codes to ISO currency codes.
55
+ # May only work for the dat00_XX.txt data files.
56
+ # See http://www.jhall.demon.co.uk/currency/by_country.html
57
+ #
58
+ # Some data files list reciprocal rates!
59
+ @@country_to_currency =
60
+ {
61
+ 'al' => [ :AUD, :USD ],
62
+ # 'au' => :ASH, # AUSTRIAN SHILLING: pre-EUR?
63
+ 'bz' => [ :USD, :BRL ],
64
+ 'ca' => [ :USD, :CAD ],
65
+ 'ch' => [ :USD, :CNY ],
66
+ 'dn' => [ :USD, :DKK ],
67
+ 'eu' => [ :EUR, :USD ],
68
+ # 'gr' => :XXX, # Greece Drachma: pre-EUR?
69
+ 'hk' => [ :USD, :HKD ],
70
+ 'in' => [ :USD, :INR ],
71
+ 'ja' => [ :USD, :JPY ],
72
+ 'ma' => [ :USD, :MYR ],
73
+ 'mx' => [ :USD, :MXN ], # OR MXP?
74
+ 'nz' => [ :NZD, :USD ],
75
+ 'no' => [ :USD, :NOK ],
76
+ 'ko' => [ :USD, :KRW ],
77
+ 'sf' => [ :USD, :ZAR ],
78
+ 'sl' => [ :USD, :LKR ],
79
+ 'sd' => [ :USD, :SEK ],
80
+ 'sz' => [ :USD, :CHF ],
81
+ 'ta' => [ :USD, :TWD ], # New Taiwan Dollar.
82
+ 'th' => [ :USD, :THB ],
83
+ 'uk' => [ :GBP, :USD ],
84
+ 've' => [ :USD, :VEB ],
85
+ }
86
+
87
+
88
+ # Parses text file for rates.
89
+ def parse_rates(data = nil)
90
+ data = get_page_content unless data
91
+
92
+ rates = [ ]
93
+
94
+ @raw_rates ||= { }
95
+
96
+ $stderr.puts "#{self}: parse_rates: data =\n#{data}" if @verbose
97
+
98
+ # Rates are USD/currency so
99
+ # c1 = currency
100
+ # c2 = :USD
101
+ c1, c2 = @@country_to_currency[country_code]
102
+
103
+ unless c1 && c2
104
+ raise(::Currency::Exception::UnavailableRates, "Cannot determine currency code for federalreserve.gov country code #{country_code.inspect}")
105
+ end
106
+
107
+ data.split(/\r?\n\r?/).each do | line |
108
+ # day month yy rate
109
+ m = /^\s*(\d\d?)-([A-Z][a-z][a-z])-(\d\d)\s+([\d\.]+)/.match(line)
110
+ next unless m
111
+
112
+ day = m[1].to_i
113
+ month = m[2]
114
+ year = m[3].to_i
115
+ if year >= 50 and year < 100
116
+ year += 1900
117
+ elsif year < 50
118
+ year += 2000
119
+ end
120
+
121
+ date = Time.parse("#{day}-#{month}-#{year} 12:00:00 -05:00") # USA NY => EST
122
+
123
+ rate = m[4].to_f
124
+
125
+ STDERR.puts "#{c1} #{c2} #{rate} #{date}" if @verbose
126
+
127
+ rates << new_rate(c1, c2, rate, date)
128
+
129
+ ((@raw_rates[date] ||= { })[c1] ||= { })[c2] ||= rate
130
+ ((@raw_rates[date] ||= { })[c2] ||= { })[c1] ||= 1.0 / rate
131
+ end
132
+
133
+ # Put most recent rate first.
134
+ # See Provider#get_rate.
135
+ rates.reverse!
136
+
137
+ # $stderr.puts "rates = #{rates.inspect}"
138
+ raise ::Currency::Exception::UnavailableRates, "No rates found in #{get_uri.inspect}" if rates.empty?
139
+
140
+ rates
141
+ end
142
+
143
+
144
+ # Return a list of known base rates.
145
+ def load_rates(time = nil)
146
+ # $stderr.puts "#{self}: load_rates(#{time})" if @verbose
147
+ self.date = time
148
+ rates = [ ]
149
+ @@country_to_currency.keys.each do | cc |
150
+ self.country_code = cc
151
+ rates.push(*parse_rates)
152
+ end
153
+ rates
154
+ end
155
+
156
+
157
+ end # class
158
+
159
+
160
+
@@ -56,6 +56,7 @@ class Currency::Exchange::Rate::Source::Historical::Rate < ::ActiveRecord::Base
56
56
  self.c2 = rate.c2.code.to_s
57
57
  self.rate = rate.rate
58
58
  self.rate_avg = rate.rate_avg
59
+ self.rate_samples = rate.rate_samples
59
60
  self.rate_lo = rate.rate_lo
60
61
  self.rate_hi = rate.rate_hi
61
62
  self.rate_date_0 = rate.rate_date_0
@@ -78,24 +79,25 @@ class Currency::Exchange::Rate::Source::Historical::Rate < ::ActiveRecord::Base
78
79
 
79
80
 
80
81
  # Creates a new Currency::Exchange::Rate object.
81
- def to_rate
82
- Currency::Exchange::Rate.new(
83
- ::Currency::Currency.get(self.c1),
84
- ::Currency::Currency.get(self.c2),
85
- self.rate,
86
- "historical #{self.source}",
87
- self.date,
88
- self.derived,
89
- {
90
- :rate_avg => self.rate_avg,
91
- :rate_samples => self.rate_samples,
92
- :rate_lo => self.rate_lo,
93
- :rate_hi => self.rate_hi,
94
- :rate_date_0 => self.rate_date_0,
95
- :rate_date_1 => self.rate_date_1,
96
- :date_0 => self.date_0,
97
- :date_1 => self.date_1
98
- })
82
+ def to_rate(cls = ::Currency::Exchange::Rate)
83
+ cls.
84
+ new(
85
+ ::Currency::Currency.get(self.c1),
86
+ ::Currency::Currency.get(self.c2),
87
+ self.rate,
88
+ "historical #{self.source}",
89
+ self.date,
90
+ self.derived,
91
+ {
92
+ :rate_avg => self.rate_avg,
93
+ :rate_samples => self.rate_samples,
94
+ :rate_lo => self.rate_lo,
95
+ :rate_hi => self.rate_hi,
96
+ :rate_date_0 => self.rate_date_0,
97
+ :rate_date_1 => self.rate_date_1,
98
+ :date_0 => self.date_0,
99
+ :date_1 => self.date_1
100
+ })
99
101
  end
100
102
 
101
103
 
@@ -47,6 +47,17 @@ class Currency::Exchange::Rate::Source::NewYorkFed < ::Currency::Exchange::Rate:
47
47
  rates
48
48
  @raw_rates
49
49
  end
50
+
51
+
52
+ # The fed swaps rates on some currency pairs!
53
+ # See http://www.newyorkfed.org/markets/fxrates/noon.cfm (LISTS AUD!)
54
+ # http://www.newyorkfed.org/xml/fx.html (DOES NOT LIST AUD!)
55
+ @@swap_units = {
56
+ :AUD => true,
57
+ :EUR => true,
58
+ :NZD => true,
59
+ :GBP => true,
60
+ }
50
61
 
51
62
 
52
63
  # Parses XML for rates.
@@ -80,6 +91,11 @@ class Currency::Exchange::Rate::Source::NewYorkFed < ::Currency::Exchange::Rate:
80
91
  date = date.text
81
92
  date = Time.parse("#{date} 12:00:00 -05:00") # USA NY => EST
82
93
 
94
+ # Handle arbitrary rate reciprocals!
95
+ if @@swap_units[c1] || @@swap_units[c2]
96
+ c1, c2 = c2, c1
97
+ end
98
+
83
99
  rates << new_rate(c1, c2, rate, date)
84
100
 
85
101
  (@raw_rates[c1] ||= { })[c2] ||= rate
@@ -94,14 +94,16 @@ class Currency::Exchange::Rate::Source::Provider < Currency::Exchange::Rate::Sou
94
94
  end
95
95
 
96
96
 
97
- # Return a matching base rate?
97
+ # Return a matching base rate.
98
98
  def get_rate(c1, c2, time)
99
- matching_rates = rates.select do | rate |
100
- rate.c1 == c1 &&
101
- rate.c2 == c2 &&
102
- (! time || normalize_time(rate.date) == time)
99
+ rates.each do | rate |
100
+ return rate if
101
+ rate.c1 == c1 &&
102
+ rate.c2 == c2 &&
103
+ (! time || normalize_time(rate.date) == time)
103
104
  end
104
- matching_rates[0]
105
+
106
+ nil
105
107
  end
106
108
 
107
109
  alias :get_rate_base :get_rate
@@ -0,0 +1,75 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ require 'test/test_base'
5
+
6
+ require 'currency' # For :type => :money
7
+ require 'currency/exchange/rate/source/federal_reserve'
8
+
9
+ module Currency
10
+
11
+ class FederalReserveTest < TestBase
12
+ def setup
13
+ super
14
+ end
15
+
16
+
17
+ @@available = nil
18
+
19
+ # New York Fed rates are not available on Saturday and Sunday.
20
+ def available?
21
+ if @@available == nil
22
+ @@available = @source.available?
23
+ STDERR.puts "Warning: FederalReserve unavailable on Saturday and Sunday, skipping tests." unless @@available
24
+ end
25
+ @@available
26
+ end
27
+
28
+
29
+ def get_rate_source
30
+ # Force FederalReserve Exchange.
31
+ verbose = false
32
+ source = @source = Exchange::Rate::Source::FederalReserve.new(:verbose => verbose)
33
+ deriver = Exchange::Rate::Deriver.new(:source => source, :verbose => source.verbose)
34
+ end
35
+
36
+
37
+
38
+ def test_usd_cad
39
+ return unless available?
40
+
41
+ # yesterday = Time.now.to_date - 1
42
+
43
+ assert_not_nil rates = Exchange::Rate::Source.default.source.raw_rates
44
+ #assert_not_nil rates[:USD]
45
+ #assert_not_nil usd_cad = rates[:USD][:CAD]
46
+
47
+ assert_not_nil usd = Money.new(123.45, :USD)
48
+ assert_not_nil cad = usd.convert(:CAD)
49
+
50
+ # assert_kind_of Numeric, m = (cad.to_f / usd.to_f)
51
+ # $stderr.puts "m = #{m}"
52
+ # assert_equal_float usd_cad, m, 0.001
53
+ end
54
+
55
+
56
+ def test_cad_eur
57
+ return unless available?
58
+
59
+ assert_not_nil rates = Exchange::Rate::Source.default.source.raw_rates
60
+ #assert_not_nil rates[:USD]
61
+ #assert_not_nil usd_cad = rates[:USD][:CAD]
62
+ #assert_not_nil usd_eur = rates[:USD][:EUR]
63
+
64
+ assert_not_nil cad = Money.new(123.45, :CAD)
65
+ assert_not_nil eur = cad.convert(:EUR)
66
+
67
+ #assert_kind_of Numeric, m = (eur.to_f / cad.to_f)
68
+ # $stderr.puts "m = #{m}"
69
+ #assert_equal_float (1.0 / usd_cad) * usd_eur, m, 0.001
70
+ end
71
+
72
+ end
73
+
74
+ end # module
75
+
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: currency
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.6
7
- date: 2007-05-30 00:00:00 -04:00
6
+ version: 0.4.7
7
+ date: 2007-06-25 00:00:00 -04:00
8
8
  summary: "Currency models currencies, monetary values, foreign exchanges rates. Pulls live and historical rates from http://xe.com/, http://newyorkfed.org/, http://thefinancials.com/. Can store/retrieve historical rate data from database using ActiveRecord. Can store/retrieve Money values using ActiveRecord. For more details, see: http://rubyforge.org/projects/currency/ http://currency.rubyforge.org/ http://currency.rubyforge.org/files/README_txt.html"
9
9
  require_paths:
10
10
  - lib
@@ -54,6 +54,7 @@ files:
54
54
  - lib/currency/exchange/rate/source.rb
55
55
  - lib/currency/exchange/rate/source/base.rb
56
56
  - lib/currency/exchange/rate/source/failover.rb
57
+ - lib/currency/exchange/rate/source/federal_reserve.rb
57
58
  - lib/currency/exchange/rate/source/historical.rb
58
59
  - lib/currency/exchange/rate/source/historical/rate.rb
59
60
  - lib/currency/exchange/rate/source/historical/writer.rb
@@ -74,6 +75,7 @@ files:
74
75
  - test/ar_test_base.rb
75
76
  - test/ar_test_core.rb
76
77
  - test/config_test.rb
78
+ - test/federal_reserve_test.rb
77
79
  - test/formatter_test.rb
78
80
  - test/historical_writer_test.rb
79
81
  - test/macro_test.rb