67 lines
1.9 KiB
Ruby
67 lines
1.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "json"
|
|
require "net/http"
|
|
|
|
require "provider/adapters/adapter"
|
|
|
|
class Provider
|
|
module Adapters
|
|
# Bank of Japan. Fetches daily spot exchange rates for USD/JPY and EUR/USD
|
|
# from the Tokyo market via the BOJ Statistics API. No authentication required.
|
|
# Only 2 pairs — this is the full extent of what BOJ publishes via this API.
|
|
class BOJ < Adapter
|
|
API_URL = "https://www.stat-search.boj.or.jp/api/v1/getDataCode"
|
|
|
|
# series_code => { base:, quote: }
|
|
SERIES = {
|
|
"FXERD04" => { base: "USD", quote: "JPY" },
|
|
"FXERD34" => { base: "EUR", quote: "USD" },
|
|
}.freeze
|
|
|
|
def fetch(after: nil, upto: nil)
|
|
effective_after = after
|
|
effective_upto = upto || Date.today
|
|
|
|
url = URI(API_URL)
|
|
params = {
|
|
format: "json",
|
|
lang: "en",
|
|
db: "FM08",
|
|
code: SERIES.keys.join(","),
|
|
startDate: effective_after.strftime("%Y%m"),
|
|
endDate: effective_upto.strftime("%Y%m"),
|
|
}
|
|
url.query = URI.encode_www_form(params)
|
|
|
|
response = Net::HTTP.get(url)
|
|
raw = parse(response)
|
|
raw.select { |r| r[:date].between?(effective_after, effective_upto) }
|
|
end
|
|
|
|
def parse(json)
|
|
data = JSON.parse(json)
|
|
resultset = data["RESULTSET"] || []
|
|
|
|
resultset.flat_map do |series|
|
|
meta = SERIES[series["SERIES_CODE"]]
|
|
next [] unless meta
|
|
|
|
values_data = series.dig("VALUES") || {}
|
|
dates = values_data["SURVEY_DATES"] || []
|
|
rates = values_data["VALUES"] || []
|
|
|
|
dates.zip(rates).filter_map do |raw_date, value|
|
|
next if value.nil?
|
|
|
|
rate = Float(value)
|
|
next if rate.zero?
|
|
|
|
date = Date.strptime(raw_date.to_s, "%Y%m%d")
|
|
{ date:, base: meta[:base], quote: meta[:quote], rate: }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|