69 lines
1.9 KiB
Ruby
69 lines
1.9 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require "json"
|
||
|
|
require "net/http"
|
||
|
|
|
||
|
|
require "provider/adapters/adapter"
|
||
|
|
|
||
|
|
class Provider
|
||
|
|
module Adapters
|
||
|
|
# Bank of Thailand. Fetches daily average commercial bank exchange rates
|
||
|
|
# for 19 currencies against the Thai baht (THB). Uses mid_rate (midpoint
|
||
|
|
# of buying transfer and selling). Some currencies are quoted per 100 or
|
||
|
|
# 1,000 units — the adapter normalises to per-unit rates.
|
||
|
|
# Requires BOT_API_KEY environment variable.
|
||
|
|
class BOT < Adapter
|
||
|
|
BASE_URL = "https://gateway.api.bot.or.th/Stat-ExchangeRate/v2/DAILY_AVG_EXG_RATE/"
|
||
|
|
|
||
|
|
class << self
|
||
|
|
def api_key = ENV["BOT_API_KEY"] || raise(Adapter::Unavailable, "no API key")
|
||
|
|
def backfill_range = 30 # API enforces max 31-day period per request
|
||
|
|
end
|
||
|
|
|
||
|
|
def fetch(after: nil, upto: nil)
|
||
|
|
uri = URI(BASE_URL)
|
||
|
|
uri.query = URI.encode_www_form(
|
||
|
|
start_period: after.strftime("%Y-%m-%d"),
|
||
|
|
end_period: (upto || Date.today).strftime("%Y-%m-%d"),
|
||
|
|
)
|
||
|
|
|
||
|
|
response = Net::HTTP.get_response(uri, {
|
||
|
|
"Authorization" => self.class.api_key,
|
||
|
|
"Accept" => "application/json",
|
||
|
|
})
|
||
|
|
|
||
|
|
parse(response.body)
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse(body)
|
||
|
|
data = JSON.parse(body).dig("result", "data", "data_detail")
|
||
|
|
return [] unless data
|
||
|
|
|
||
|
|
data.filter_map do |record|
|
||
|
|
mid = record["mid_rate"]
|
||
|
|
next if mid.nil? || mid.to_s.empty?
|
||
|
|
|
||
|
|
rate = Float(mid)
|
||
|
|
next if rate.zero?
|
||
|
|
|
||
|
|
currency = record["currency_id"]
|
||
|
|
unit = extract_unit(record["currency_name_eng"])
|
||
|
|
rate /= unit if unit > 1
|
||
|
|
|
||
|
|
{ date: Date.parse(record["period"]), base: currency, quote: "THB", rate: }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def extract_unit(name)
|
||
|
|
case name
|
||
|
|
when /\(100 /i then 100
|
||
|
|
when /\(1,000 /i then 1_000
|
||
|
|
else 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|