Skip to content

Instantly share code, notes, and snippets.

@qoobaa
Last active April 15, 2026 12:33
Show Gist options
  • Select an option

  • Save qoobaa/a1ed534500aba10a7b7da8b8a523b720 to your computer and use it in GitHub Desktop.

Select an option

Save qoobaa/a1ed534500aba10a7b7da8b8a523b720 to your computer and use it in GitHub Desktop.
Fetch FX rates from Banking Circle API - supports both standard and held rates
class FetchBankingCircleFxRateScript < BaseScript
def self.options(args)
{
currency_pair: "GBP/USD",
valid_for_minutes: nil,
amount: "1000.00",
}.tap do |result|
OptionParser.new do |parser|
parser.on("-cPAIR", "--currency-pair=PAIR", String, "Currency pair (e.g., GBP/USD, EUR/PLN)")
parser.on("-vMINUTES", "--valid-for=MINUTES", Integer, "Hold rate for N minutes (optional)")
parser.on("-aAMOUNT", "--amount=AMOUNT", String, "Amount to quote (default: 1000.00)")
end.parse!(args, into: result)
end
end
def call
currency_pair = options[:"currency-pair"] || options[:currency_pair] || "GBP/USD"
valid_for = options[:"valid-for"] || options[:valid_for_minutes]
amount = options[:amount] || "1000.00"
base_ccy, counter_ccy = currency_pair.split("/")
puts "=" * 70
puts "BANKING CIRCLE FX RATE"
puts "=" * 70
puts "Currency Pair: #{base_ccy}/#{counter_ccy}"
puts "Amount: #{amount} #{base_ccy}"
puts "Rate Type: #{valid_for ? "#{valid_for}-minute held" : "Short-lived (standard)"}"
puts "-" * 70
check_credentials!
start_time = Time.current
service = fetch_rate(base_ccy, counter_ccy, amount, valid_for)
response_time = ((Time.current - start_time) * 1000).round(0)
if service.success? && service.is_tradable?
display_rate(service, amount, base_ccy, counter_ccy, response_time, start_time)
else
puts "Error: #{service.quote_type || "Request failed"}"
puts service.response&.body
end
rescue => e
puts "Error: #{e.message}"
end
private
def check_credentials!
["BC_USER_NAME", "BC_PASSWORD", "BC_CERTIFICATE_FILEPATH"].each do |var|
if ENV[var].nil? || ENV[var].empty?
raise "#{var} not set"
end
end
end
def fetch_rate(base_ccy, counter_ccy, amount, valid_for)
if valid_for
fetch_held_rate(base_ccy, counter_ccy, amount, valid_for)
else
fetch_standard_rate(base_ccy, counter_ccy, amount)
end
end
def fetch_standard_rate(base_ccy, counter_ccy, amount)
service = BankingCircleConnector::QuotesService.new(base_ccy, counter_ccy, base_ccy, amount)
service.go!
service
end
def fetch_held_rate(base_ccy, counter_ccy, amount, valid_for)
service = BankingCircleConnector::QuotesService.new(base_ccy, counter_ccy, base_ccy, amount)
service.instance_variable_set(:@base_ccy, base_ccy)
service.instance_variable_set(:@counter_ccy, counter_ccy)
service.instance_variable_set(:@specified_currency, base_ccy)
service.instance_variable_set(:@specified_amount, amount)
service.instance_variable_set(:@valid_for, valid_for)
service.instance_eval do
def go!
initialize_client do |client|
endpoint = "#{base_url}/fx/rates/held-rates/#{@base_ccy}/#{@counter_ccy}"
@response = client.get(endpoint) do |req|
req.headers = { "Content-Type" => "application/json", "Authorization" => "Bearer #{token}" }
req.params = {
"amountCurrency" => @specified_currency,
"amount" => @specified_amount,
"validForMinutes" => @valid_for,
}
end
end
if success?
@quote_type = json_response["quoteType"]
@currency_pair = json_response["currencyPair"]
@rate_bid = json_response["exchangeRateBid"]
@rate_offer = json_response["exchangeRateAsk"]
@expiry_time = json_response["expiryTime"].to_time if json_response["expiryTime"]
@quote_id = json_response["quoteId"]
end
end
end
service.go!
service
end
def display_rate(service, amount, base_ccy, counter_ccy, response_time, start_time)
bid = service.rate_bid.to_d
offer = service.rate_offer.to_d
spread = offer - bid
duration = service.expiry_time - start_time
puts "Status: #{service.quote_type}"
puts "Bid: #{bid}"
puts "Offer: #{offer}"
puts "Spread: #{spread} (#{((spread / ((bid + offer) / 2)) * 100).round(4)}%)"
puts "Expires: #{service.expiry_time.strftime("%H:%M:%S")} (#{duration.round(0)}s / #{(duration / 60).round(1)}min)"
puts "Quote ID: #{service.quote_id}"
puts "Response: #{response_time}ms"
puts ""
puts "Value: #{amount} #{base_ccy} = #{(amount.to_d * offer).round(2)} #{counter_ccy}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment