74 lines
2.3 KiB
Ruby
74 lines
2.3 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require "net/http"
|
||
|
|
require "oj"
|
||
|
|
|
||
|
|
require "provider/adapters/adapter"
|
||
|
|
|
||
|
|
class Provider
|
||
|
|
module Adapters
|
||
|
|
# National Bank of the Republic of Belarus. Publishes daily rates for ~30 currencies against BYN.
|
||
|
|
# BYN was redenominated on 2016-07-01; earlier data uses different currency IDs.
|
||
|
|
class NBRB < Adapter
|
||
|
|
RATES_URL = "https://api.nbrb.by/exrates/rates"
|
||
|
|
CHUNK_DAYS = 365
|
||
|
|
|
||
|
|
def fetch(after: nil, upto: nil)
|
||
|
|
currencies = current_currencies
|
||
|
|
currencies.flat_map do |cur_id, iso, scale|
|
||
|
|
chunked_dynamics(cur_id, iso, scale, after, upto || Date.today)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def parse_daily(data)
|
||
|
|
data.filter_map do |row|
|
||
|
|
date = Date.parse(row.fetch("Date"))
|
||
|
|
next if date.saturday? || date.sunday?
|
||
|
|
|
||
|
|
iso = row.fetch("Cur_Abbreviation")
|
||
|
|
scale = Integer(row.fetch("Cur_Scale"))
|
||
|
|
rate = Float(row.fetch("Cur_OfficialRate"))
|
||
|
|
next if scale.zero?
|
||
|
|
|
||
|
|
{ date:, base: iso, quote: "BYN", rate: rate / scale }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def current_currencies
|
||
|
|
data = Oj.load(Net::HTTP.get(URI("#{RATES_URL}?periodicity=0")), mode: :strict)
|
||
|
|
data.map { |row| [row.fetch("Cur_ID"), row.fetch("Cur_Abbreviation"), Integer(row.fetch("Cur_Scale"))] }
|
||
|
|
end
|
||
|
|
|
||
|
|
def chunked_dynamics(cur_id, iso, scale, start_date, end_date)
|
||
|
|
records = []
|
||
|
|
chunk_start = start_date
|
||
|
|
|
||
|
|
while chunk_start <= end_date
|
||
|
|
chunk_end = [chunk_start + CHUNK_DAYS - 1, end_date].min
|
||
|
|
records.concat(fetch_dynamics(cur_id, iso, scale, chunk_start, chunk_end))
|
||
|
|
chunk_start = chunk_end + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
records
|
||
|
|
end
|
||
|
|
|
||
|
|
def fetch_dynamics(cur_id, iso, scale, start_date, end_date)
|
||
|
|
url = URI("#{RATES_URL}/dynamics/#{cur_id}")
|
||
|
|
url.query = URI.encode_www_form(startDate: start_date.to_s, endDate: end_date.to_s)
|
||
|
|
data = Oj.load(Net::HTTP.get(url), mode: :strict)
|
||
|
|
return [] unless data.is_a?(Array)
|
||
|
|
|
||
|
|
data.filter_map do |row|
|
||
|
|
date = Date.parse(row.fetch("Date"))
|
||
|
|
next if date.saturday? || date.sunday?
|
||
|
|
|
||
|
|
rate = Float(row.fetch("Cur_OfficialRate"))
|
||
|
|
{ date:, base: iso, quote: "BYN", rate: rate / scale }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|