frankfurter/lib/provider/adapters/sbi.rb

122 lines
3.2 KiB
Ruby
Raw Permalink Normal View History

2026-05-21 01:38:14 -06:00
# frozen_string_literal: true
require "net/http"
require "ox"
require "provider/adapters/adapter"
class Provider
module Adapters
# Seðlabanki Íslands (Central Bank of Iceland). Publishes daily reference
# exchange rates for 30+ currencies against the Icelandic króna (ISK).
# Two GroupIDs are needed: 9 (official reference, 10 currencies from 1981)
# and 7 (registered mid-rate, 22 currencies from 2006).
class SBI < Adapter
BASE_URL = "https://sedlabanki.is/xmltimeseries/Default.aspx"
# TimeSeries ID to ISO currency code mapping
# GroupID=9 (official reference rates)
GROUP9_CURRENCIES = {
"4055" => "USD",
"4061" => "DKK",
"4064" => "EUR",
"4085" => "JPY",
"4088" => "CAD",
"4091" => "NOK",
"4097" => "XDR",
"4103" => "GBP",
"4106" => "CHF",
"4109" => "SEK",
}.freeze
# GroupID=7 (registered mid-rates)
GROUP7_CURRENCIES = {
"29" => "CNY",
"31" => "PLN",
"35" => "NGN",
"36" => "TWD",
"37" => "KRW",
"38" => "SRD",
"39" => "AUD",
"40" => "NZD",
"41" => "HKD",
"42" => "HUF",
"43" => "ILS",
"44" => "ZAR",
"45" => "SGD",
"46" => "MXN",
"48" => "TRY",
"50" => "INR",
"52" => "CZK",
"53" => "BRL",
"74" => "THB",
"288" => "JMD",
"3503" => "SAR",
"19254" => "KWD",
}.freeze
class << self
def backfill_range = 365
end
def fetch(after: nil, upto: nil)
end_date = upto || Date.today
xml9 = fetch_group(after, end_date, 9)
xml7 = fetch_group(after, end_date, 7)
parse(xml9, GROUP9_CURRENCIES) + parse(xml7, GROUP7_CURRENCIES)
end
def parse(xml, currency_map = GROUP9_CURRENCIES.merge(GROUP7_CURRENCIES))
doc = Ox.load(xml, mode: :generic)
records = []
doc.locate("*/TimeSeries").each do |ts|
id = ts.attributes[:ID]
currency = currency_map[id]
next unless currency
ts.locate("TimeSeriesData/Entry").each do |entry|
date_node = entry.locate("Date").first
value_node = entry.locate("Value").first
next unless date_node && value_node
date_str = date_node.text
rate_str = value_node.text
next unless date_str && rate_str
rate = Float(rate_str)
next if rate.zero?
date = parse_date(date_str)
records << { date:, base: currency, quote: "ISK", rate: }
end
end
records
end
private
def fetch_group(start_date, end_date, group_id)
url = URI(BASE_URL)
url.query = URI.encode_www_form(
"DagsFra" => start_date.to_s,
"DagsTil" => end_date.to_s,
"GroupID" => group_id,
"Type" => "xml",
)
Net::HTTP.get(url)
end
def parse_date(str)
# Format: "M/D/YYYY 12:00:00 AM"
date_part = str.split(" ").first
month, day, year = date_part.split("/").map(&:to_i)
Date.new(year, month, day)
end
end
end
end