class Money::RatesProvider::OpenExchangeRates

Retrieves exchange rates from OpenExchangeRates.org API, relative to the given base_currency. It is fetching rates for all currencies in one request, as we are charged on a “per date” basis. I.e. one month's data for all currencies counts as 30 calls.

Constants

MIN_DATE

minimum date that OER has data (docs.openexchangerates.org/docs/historical-json)

Public Class Methods

new(oer_app_id, base_currency, timeout, oer_account_type) click to toggle source

Parameters

  • oer_app_id - App ID for the OpenExchangeRates API access

  • base_currency - The base currency that will be used for the OER requests. It should be a Money::Currency object.

  • timeout - The timeout in seconds to set on the requests

  • oer_account_type - The OpenExchangeRates account type. Should be one of AccountType::FREE, DEVELOPER, ENTERPRISE, or UNLIMITED

# File lib/money/rates_provider/open_exchange_rates.rb, line 51
def initialize(oer_app_id, base_currency, timeout, oer_account_type)
  @oer_app_id = oer_app_id
  @base_currency_code = base_currency.iso_code
  @timeout = timeout
  @fetch_rates_method_name = if oer_account_type == AccountType::FREE || oer_account_type == AccountType::DEVELOPER
    :fetch_historical_rates
  else
    :fetch_time_series_rates
  end
end

Public Instance Methods

fetch_rates(date) click to toggle source

Fetches the rates for all available quote currencies (for given date or for a whole month, depending on openexchangerates.org account type). Fetching for all currencies or just one has the same API charge.

It returns a Hash with the rates for each quote currency and date as shown in the example. Rates are BigDecimal.

Parameters

Errors

  • Raises ArgumentError when date is less than January 1st 1999, or greater than yesterday (UTC)

  • Raises Money::RatesProvider::RequestFailed when the OER request fails

Examples

oer.fetch_rates(Date.new(2016, 10, 5))
If Free or Developer account in openexchangerates.org, it will return only for the given date
# => {"AED"=>{"2016-10-05"=>#<BigDecimal:7fa19a188e98,'0.3672682E1',18(36)>}, {"AFN"=>{"2016-10-05"=>#<BigDecimal:7fa19a188e98,'0.3672682E1',18(36)>}, ...
If Enterprise or Unlimited account, it will return for the entire month for the given date 
# => {"AED"=>{"2016-10-01"=>#<BigDecimal:7fa19a188e98,'0.3672682E1',18(36)>, "2016-10-02"=>#<BigDecimal:7fa19b11a5c8,'0.367296E1',18(36)>, ...
# File lib/money/rates_provider/open_exchange_rates.rb, line 85
def fetch_rates(date)
  if date < MIN_DATE || date > max_date
    raise ArgumentError, "Provided date #{date} for OER query should be "\
                         "between #{MIN_DATE} and #{max_date}"
  end

  response = send(@fetch_rates_method_name, date)


  result = Hash.new { |hash, key| hash[key] = {} }

  # sample response can be found in spec/fixtures.
  # we're transforming the response from Hash[iso_date][iso_currency] to
  # Hash[iso_currency][iso_date], as it will allow more efficient caching/retrieving
  response['rates'].each do |iso_date, day_rates|
    day_rates.each do |iso_currency, rate|
      result[iso_currency][iso_date] = rate.to_d
    end
  end

  result
end

Private Instance Methods

fetch_historical_rates(date) click to toggle source
# File lib/money/rates_provider/open_exchange_rates.rb, line 130
def fetch_historical_rates(date)
  date_string = date.iso8601
  options = request_options
  response = self.class.get("/historical/#{date_string}.json", options)

  unless response.success?
    raise RequestFailed, "Historical rates request failed for #{date} - "\
                         "Code: #{response.code} - Body: #{response.body}"
  end

  # Making the return value comply to the same structure returned from the #fetch_month_rates method (/time-series.json API)
  { 
    'start_date' => date_string,
    'end_date' => date_string,
    'base' => response['base'],
    'rates' => {
      date_string => response['rates']
    }
  }
end
fetch_time_series_rates(date) click to toggle source

the API doesn't allow fetching more than a month's data.

# File lib/money/rates_provider/open_exchange_rates.rb, line 112
def fetch_time_series_rates(date)
  options = request_options

  end_of_month = Date.civil(date.year, date.month, -1)
  start_date = Date.civil(date.year, date.month, 1)
  end_date = [end_of_month, max_date].min
  options[:query][:start] = start_date
  options[:query][:end] = end_date

  response = self.class.get('/time-series.json', options)

  unless response.success?
    raise RequestFailed, "Month rates request failed for #{date} - "\
                         "Code: #{response.code} - Body: #{response.body}"
  end
  response        
end
max_date() click to toggle source

A historical day's rates can be obtained when the date changes at 00:00 UTC openexchangerates.org/faq/#timezone

# File lib/money/rates_provider/open_exchange_rates.rb, line 163
def max_date
  Time.now.utc.to_date - 1
end
request_options() click to toggle source
# File lib/money/rates_provider/open_exchange_rates.rb, line 151
def request_options
  options = {
    query: {
      app_id:  @oer_app_id,
      base:    @base_currency_code
    },
    timeout: @timeout
  }
end