113 lines
3.1 KiB
Ruby
113 lines
3.1 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require "json"
|
||
|
|
require "net/http"
|
||
|
|
|
||
|
|
require "provider/adapters/adapter"
|
||
|
|
|
||
|
|
class Provider
|
||
|
|
module Adapters
|
||
|
|
# Bank of Jamaica daily counter rates in JMD.
|
||
|
|
# Fetches from a WPDataTables endpoint (table_id=134), which requires a nonce extracted from the page HTML.
|
||
|
|
class BOJA < Adapter
|
||
|
|
PAGE_URL = "https://boj.org.jm/market/foreign-exchange/counter-rates/"
|
||
|
|
BASE_URL = "https://boj.org.jm/wp-admin/admin-ajax.php"
|
||
|
|
TABLE_ID = 134
|
||
|
|
NONCE_PATTERN = /wdtNonceFrontendServerSide_#{TABLE_ID}"\s+value="([^"]+)"/
|
||
|
|
|
||
|
|
CURRENCY_MAP = {
|
||
|
|
"U.S. DOLLAR" => "USD",
|
||
|
|
"GREAT BRITAIN POUND" => "GBP",
|
||
|
|
"CANADA DOLLAR" => "CAD",
|
||
|
|
"EURO" => "EUR",
|
||
|
|
"JAPANESE YEN" => "JPY",
|
||
|
|
"SWISS FRANC" => "CHF",
|
||
|
|
"AUSTRALIAN DOLLAR" => "AUD",
|
||
|
|
"DANISH KRONE" => "DKK",
|
||
|
|
"NORWEGIAN KRONE" => "NOK",
|
||
|
|
"SWEDISH KRONA" => "SEK",
|
||
|
|
"HONG KONG DOLLAR" => "HKD",
|
||
|
|
"BARBADOS DOLLAR" => "BBD",
|
||
|
|
"BELIZE DOLLAR" => "BZD",
|
||
|
|
"T&T DOLLAR" => "TTD",
|
||
|
|
"BAHAMAS DOLLAR" => "BSD",
|
||
|
|
"CAYMAN DOLLAR" => "KYD",
|
||
|
|
"GUYANA DOLLAR" => "GYD",
|
||
|
|
"E. C. DOLLAR" => "XCD",
|
||
|
|
"DOMINICAN REP. PESO" => "DOP",
|
||
|
|
"GIBRALTAR POUND" => "GIP",
|
||
|
|
"NORTHERN IRELAND POUND" => "GBP",
|
||
|
|
}.freeze
|
||
|
|
|
||
|
|
def fetch(after: nil, upto: nil)
|
||
|
|
dataset = fetch_table
|
||
|
|
|
||
|
|
dataset = dataset.select { |r| r[:date] >= after } if after
|
||
|
|
dataset = dataset.select { |r| r[:date] <= upto } if upto
|
||
|
|
|
||
|
|
dataset
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse(json)
|
||
|
|
data = json.is_a?(String) ? JSON.parse(json) : json
|
||
|
|
rows = data["data"]
|
||
|
|
return [] unless rows.is_a?(Array)
|
||
|
|
|
||
|
|
rows.filter_map do |row|
|
||
|
|
parse_row(row)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def fetch_table
|
||
|
|
nonce = fetch_nonce
|
||
|
|
return [] unless nonce
|
||
|
|
|
||
|
|
uri = URI("#{BASE_URL}?action=get_wdtable&table_id=#{TABLE_ID}")
|
||
|
|
request = Net::HTTP::Post.new(uri)
|
||
|
|
request.set_form_data("draw" => "1", "start" => "0", "length" => "-1", "wdtNonce" => nonce)
|
||
|
|
|
||
|
|
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
||
|
|
http.request(request)
|
||
|
|
end
|
||
|
|
|
||
|
|
parse(response.body)
|
||
|
|
end
|
||
|
|
|
||
|
|
def fetch_nonce
|
||
|
|
uri = URI(PAGE_URL)
|
||
|
|
response = Net::HTTP.get(uri)
|
||
|
|
match = response.match(NONCE_PATTERN)
|
||
|
|
match&.captures&.first
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse_row(row)
|
||
|
|
date_str, currency_name, sell_rate, buy_rate, = row
|
||
|
|
return unless date_str && currency_name
|
||
|
|
|
||
|
|
date = Date.strptime(date_str.strip, "%d %b %Y")
|
||
|
|
iso = resolve_currency(currency_name.strip)
|
||
|
|
return unless iso
|
||
|
|
|
||
|
|
rate_value = compute_mid(sell_rate, buy_rate)
|
||
|
|
return unless rate_value && !rate_value.zero?
|
||
|
|
|
||
|
|
{ date:, base: iso, quote: "JMD", rate: rate_value }
|
||
|
|
end
|
||
|
|
|
||
|
|
def compute_mid(sell, buy)
|
||
|
|
s = Float(sell)
|
||
|
|
b = Float(buy)
|
||
|
|
return s if b.zero?
|
||
|
|
|
||
|
|
(s + b) / 2.0
|
||
|
|
end
|
||
|
|
|
||
|
|
def resolve_currency(name)
|
||
|
|
CURRENCY_MAP[name.upcase]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|