51 lines
1.3 KiB
Ruby
51 lines
1.3 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require "json"
|
||
|
|
require "net/http"
|
||
|
|
|
||
|
|
require "provider/adapters/adapter"
|
||
|
|
|
||
|
|
class Provider
|
||
|
|
module Adapters
|
||
|
|
# Bank of Canada daily indicative rates. Current series starts 2017-01-03.
|
||
|
|
# Legacy noon rates (2007-2017) are available under the LEGACY_NOON_RATES group with ~65 currencies.
|
||
|
|
class BOC < Adapter
|
||
|
|
BASE_URL = "https://www.bankofcanada.ca/valet/observations/group/FX_RATES_DAILY/json"
|
||
|
|
def fetch(after: nil, upto: nil)
|
||
|
|
params = { start_date: after }
|
||
|
|
params[:end_date] = upto if upto
|
||
|
|
fetch_rates(**params)
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse(json)
|
||
|
|
data = json.is_a?(String) ? JSON.parse(json) : json
|
||
|
|
|
||
|
|
data["observations"].flat_map do |obs|
|
||
|
|
date = Date.parse(obs["d"])
|
||
|
|
extract_rates(obs).map do |foreign, rate|
|
||
|
|
{ date:, base: foreign, quote: "CAD", rate: }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def fetch_rates(**params)
|
||
|
|
url = URI(BASE_URL)
|
||
|
|
url.query = URI.encode_www_form(params)
|
||
|
|
|
||
|
|
parse(Net::HTTP.get(url))
|
||
|
|
end
|
||
|
|
|
||
|
|
def extract_rates(observation)
|
||
|
|
observation.each_with_object({}) do |(series, data), rates|
|
||
|
|
next unless series.start_with?("FX")
|
||
|
|
|
||
|
|
iso = series.delete_prefix("FX").delete_suffix("CAD")
|
||
|
|
rates[iso] = Float(data["v"])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|