Class: Money::Bank::Historical

Inherits:
Bank::Base
  • Object
show all
Defined in:
lib/money/bank/historical.rb

Overview

Bank that serves historical exchange rates. Inherits from Money::Bank::Base

Defined Under Namespace

Classes: Configuration

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.configurationObject

Returns the configuration (Money::Bank::Historical::Configuration)



55
56
57
# File 'lib/money/bank/historical.rb', line 55

def self.configuration
  @configuration ||= Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Configures the bank. Parameters that can be configured:

  • oer_app_id - (required) your OpenExchangeRates App ID

  • oer_account_type - (optional) your OpenExchangeRates account type. Choose one of the values in the Money::RatesProvider::OpenExchangeRates::AccountType module (default: Money::RatesProvider::OpenExchangeRates::AccountType::ENTERPRISE)

  • base_currency - (optional) Money::Currency relative to which all the rates are stored (default: EUR)

  • redis_url - (optional) the URL of the Redis server (default: redis://localhost:6379)

  • redis_namespace - (optional) Redis namespace to prefix all keys (default: currency)

  • timeout - (optional) set a timeout for the OER calls (default: 15 seconds)

Examples

Money::Bank::Historical.configure do |config|
  config.oer_app_id = 'XXXXXXXXXXXXXXXXXXXXX'
  config. = Money::RatesProvider::OpenExchangeRates::AccountType::FREE
  config.base_currency = Money::Currency.new('USD')
  config.redis_url = 'redis://localhost:6379'
  config.redis_namespace = 'currency'
  config.timeout = 20
end

Yields:



77
78
79
80
# File 'lib/money/bank/historical.rb', line 77

def self.configure
  yield(configuration)
  instance.setup
end

Instance Method Details

#add_rate(from_currency, to_currency, rate, datetime = yesterday_utc) ⇒ Object

Adds a single rate for a specific date to the Redis cache. If no datetime is passed, it defaults to yesterday (UTC). One of the passed currencies should match the base currency.

Parameters

  • from_currency - Fixed currency of the rate (en.wikipedia.org/wiki/Exchange_rate#Quotations). Accepts ISO String and Money::Currency objects.

  • to_currency - Variable currency of the rate (en.wikipedia.org/wiki/Exchange_rate#Quotations). Accepts ISO String and Money::Currency objects.

  • rate - The price of 1 unit of from_currency in to_currency.

  • datetime - The Date this rate was observed. If Time is passed instead, it’s converted to the UTC Date. If no datetime is passed, it defaults to yesterday (UTC).

Errors

  • Raises ArgumentError when neither from_currency, nor to_currency match the base_currency given in the configuration.

Examples

Assuming USD is the base currency

from_money = Money.new(100_00, 'EUR')
to_currency = 'GBP'

date = Date.new(2016, 5, 18)

# 1 EUR = 1.2 USD on May 18th 2016
bank.add_rate('EUR', 'USD', 1.2, date)
# 1 USD = 0.8 GBP on May 18th 2016
bank.add_rate(Money::Currency.new('USD'), Money::Currency.new('GBP'), 0.8, date)

# 100 EUR = 100 * 1.2 USD = 100 * 1.2 * 0.8 GBP = 96 GBP
bank.exchange_with_historical(from_money, to_currency, date)
# => #<Money fractional:9600 currency:GBP>


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
# File 'lib/money/bank/historical.rb', line 158

def add_rate(from_currency, to_currency, rate, datetime = yesterday_utc)
  from_currency = Currency.wrap(from_currency)
  to_currency = Currency.wrap(to_currency)

  if from_currency != @base_currency && to_currency != @base_currency
    raise ArgumentError, "`from_currency` (#{from_currency.iso_code}) or "\
                         "`to_currency` (#{to_currency.iso_code}) should "\
                         "match the base currency #{@base_currency.iso_code}"
  end

  date = datetime_to_date(datetime)

  currency_date_rate_hash = if from_currency == @base_currency
                              {
                                to_currency.iso_code => {
                                  date.iso8601 => rate
                                }
                              }
                            else
                              {
                                from_currency.iso_code => {
                                  date.iso8601 => 1 / rate
                                }
                              }
                            end

  add_rates(currency_date_rate_hash)
end

#add_rates(currency_date_rate_hash) ⇒ Object

Adds historical rates in bulk to the Redis cache.

Parameters

currency_date_rate_hash - A Hash of exchange rates, broken down by currency and date. See the example for details.

Examples

Assuming USD is the base currency

rates = {
  'EUR' => {
    '2015-09-10' => 0.11, # 1 USD = 0.11 EUR
    '2015-09-11' => 0.22
  },
  'GBP' => {
    '2015-09-10' => 0.44, # 1 USD = 0.44 GBP
    '2015-09-11' => 0.55
  }
}
bank.add_rates(rates)


121
122
123
# File 'lib/money/bank/historical.rb', line 121

def add_rates(currency_date_rate_hash)
  @store.add_rates(currency_date_rate_hash)
end

#exchange_with(from_money, to_currency) ⇒ Object

Exchanges from_money to to_currency using yesterday’s closing rates and returns a new Money object.

Parameters

  • from_money - The Money object to exchange

  • to_currency - The currency to exchange from_money to. Accepts ISO String and Money::Currency objects.



221
222
223
# File 'lib/money/bank/historical.rb', line 221

def exchange_with(from_money, to_currency)
  exchange_with_historical(from_money, to_currency, yesterday_utc)
end

#exchange_with_historical(from_money, to_currency, datetime) ⇒ Object

Exchanges from_money to to_currency using datetime‘s closing rates and returns a new Money object.

Parameters

  • from_money - The Money object to exchange

  • to_currency - The currency to exchange from_money to. Accepts ISO String and Money::Currency objects.

  • datetime - The Date to get the exchange rate from. If Time is passed instead, it’s converted to the UTC Date.



233
234
235
236
237
238
239
240
241
242
243
# File 'lib/money/bank/historical.rb', line 233

def exchange_with_historical(from_money, to_currency, datetime)
  date = datetime_to_date(datetime)

  from_currency = from_money.currency
  to_currency = Currency.wrap(to_currency)

  rate = rate_on_date(from_currency, to_currency, date)
  to_amount = from_money.amount * rate

  Money.from_amount(to_amount, to_currency)
end

#get_rate(from_currency, to_currency, datetime = yesterday_utc) ⇒ Object

Returns the BigDecimal rate for converting from_currency to to_currency on a specific date. This is the price of 1 unit of from_currency in to_currency on that date. If rate is not found in the Redis cache, it is fetched from OpenExchangeRates. If no datetime is passed, it defaults to yesterday (UTC).

Parameters

  • from_currency - Fixed currency of the returned rate (en.wikipedia.org/wiki/Exchange_rate#Quotations). Accepts ISO String and Money::Currency objects.

  • to_currency - Variable currency of the returned rate (en.wikipedia.org/wiki/Exchange_rate#Quotations). Accepts ISO String and Money::Currency objects.

  • datetime - The Date the returned rate was observed. If Time is passed instead, it’s converted to the UTC Date. If no datetime is passed, it defaults to yesterday (UTC).

Examples

bank.get_rate(Money::Currency.new('GBP'), 'CAD', Date.new(2016, 10, 1))
# => #<BigDecimal:7fd39fd2cb78,'0.1703941289 451827243E1',27(45)>


205
206
207
208
209
210
211
212
# File 'lib/money/bank/historical.rb', line 205

def get_rate(from_currency, to_currency, datetime = yesterday_utc)
  from_currency = Currency.wrap(from_currency)
  to_currency = Currency.wrap(to_currency)

  date = datetime_to_date(datetime)

  rate_on_date(from_currency, to_currency, date)
end

#setupObject

Called at the end of the superclass’ initialize and also when configuration changes. It initializes/resets all the instance variables.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/money/bank/historical.rb', line 84

def setup
  @base_currency = Historical.configuration.base_currency
  # Hash[iso_currency][iso_date]
  @rates = {}
  @store = RatesStore::HistoricalRedis.new(@base_currency,
                                           Historical.configuration.redis_url,
                                           Historical.configuration.redis_namespace)
  @provider = RatesProvider::OpenExchangeRates.new(Historical.configuration.oer_app_id,
                                                   @base_currency,
                                                   Historical.configuration.timeout,
                                                   Historical.configuration.)
  # for controlling access to @rates
  @mutex = Mutex.new
end