frankfurter/lib/provider/adapters/nrb.rb
BadMark d0a43e357a
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / publish (push) Has been cancelled
CI/CD Pipeline / release (push) Has been cancelled
up
2026-05-21 01:38:14 -06:00

78 lines
2 KiB
Ruby

# frozen_string_literal: true
require "json"
require "net/http"
require "provider/adapters/adapter"
class Provider
module Adapters
# Nepal Rastra Bank. Publishes daily buy/sell rates for 22 currencies
# against NPR. Mid-market rate computed as average of buy and sell.
# Rates with unit > 1 (e.g. JPY per 10) are normalized by dividing by unit.
class NRB < Adapter
BASE_URL = "https://www.nrb.org.np/api/forex/v1/rates"
class << self
def backfill_range = 90
end
def fetch(after: nil, upto: nil)
end_date = upto || Date.today
dataset = []
page = 1
loop do
sleep(0.5) if page > 1
url = URI(BASE_URL)
url.query = URI.encode_www_form(
from: after.to_s,
to: end_date.to_s,
page: page,
per_page: 100,
)
response = Net::HTTP.get(url)
data = JSON.parse(response)
payload = data.dig("data", "payload") || []
dataset.concat(parse(payload))
pagination = data["pagination"] || {}
break if page >= (pagination["pages"] || 1)
page += 1
end
dataset
end
def parse(payload)
payload = JSON.parse(payload) if payload.is_a?(String)
return [] unless payload.is_a?(Array)
payload.flat_map do |day|
begin
date = Date.parse(day["date"])
rescue Date::Error
next []
end
rates = day["rates"] || []
rates.filter_map do |entry|
iso = entry.dig("currency", "iso3")
unit = Integer(entry.dig("currency", "unit") || 1)
buy = entry["buy"]
sell = entry["sell"]
next unless buy && sell
mid = (Float(buy) + Float(sell)) / 2.0
rate = mid / unit
next if rate.zero?
{ date:, base: iso, quote: "NPR", rate: }
end
end
end
end
end
end