Streaming FX quotes and Market Order execution over Banking Circle's FX
WebSocket — the "sophisticated FX workflows" path Banking Circle's docs
explicitly say to reach for only after you've outgrown the REST APIs
(BankingCircle.FX).
This is a genuinely different integration shape from the rest of this
library: a long-lived, stateful connection instead of request/response,
built on WebSockex rather than Req. Start one per session you want
open (typically one per customer_id/desk, not one per request).
Usage
{:ok, pid} =
BankingCircle.FX.Stream.start_link(
client: :default,
customer_id: "000012345",
handler: self()
)
BankingCircle.FX.Stream.subscribe(pid, "EUR/USD", :spot)
receive do
{:banking_circle_fx, %{"type" => "IncrementalRefresh"} = quote} ->
IO.inspect(quote)
end
BankingCircle.FX.Stream.market_order(pid, %{
client_order_id: "my-unique-id",
buy_currency: "EUR",
sell_currency: "USD",
amount_currency: "EUR",
amount: 3_000_000,
tenor: :spot
})handler receives every parsed server message as
{:banking_circle_fx, decoded_map} — decoded_map["type"] is one of
"IncrementalRefresh", "ExecutionReport", "MarketDataRequestReject",
or "ErrorMessage". handler can be a pid (messages sent via send/2)
or a 1-arity function called with the decoded map.
Token refresh
The connection is authenticated once at handshake via the
Authorization header; Banking Circle disconnects you if your token
expires without a TokenRefresh message. This module handles that
automatically — it fetches a fresh token from
BankingCircle.Auth.TokenServer (the same cache the REST calls share)
and sends TokenRefresh on a timer, well before the ~5-minute expiry.
Implementation note
This module is built on the WebSockex library and has been written
and reviewed carefully but — like the rest of this package — not
compiled or run against Banking Circle's actual WebSocket endpoint in
this environment. Verify the connection lifecycle (especially
reconnect-on-drop behavior, which WebSockex does not do automatically)
against your own sandbox before depending on this for production FX
execution.
Summary
Functions
Closes the WebSocket connection.
Executes a Market Order over the WebSocket. attrs requires
:client_order_id, :buy_currency, :sell_currency, :amount_currency,
:amount, :tenor; optionally :target_price, :max_slippage,
:buy_account, :sell_account, :note.
Connects to the FX WebSocket for the given :client (config name,
default :default) and :customer_id, forwarding all parsed server
messages to :handler (a pid or 1-arity function).
Subscribes to a live quote stream for currency_pair (e.g. "EUR/USD") at the given tenor.
Unsubscribes from a previously-subscribed currency pair/tenor.
Functions
@spec disconnect(pid()) :: :ok
Closes the WebSocket connection.
Executes a Market Order over the WebSocket. attrs requires
:client_order_id, :buy_currency, :sell_currency, :amount_currency,
:amount, :tenor; optionally :target_price, :max_slippage,
:buy_account, :sell_account, :note.
Banking Circle replies asynchronously (to handler) with two
ExecutionReport messages: an initial "New"/"Pending" ack, then a
"Filled" or "Rejected" final report.
Connects to the FX WebSocket for the given :client (config name,
default :default) and :customer_id, forwarding all parsed server
messages to :handler (a pid or 1-arity function).
Subscribes to a live quote stream for currency_pair (e.g. "EUR/USD") at the given tenor.
Unsubscribes from a previously-subscribed currency pair/tenor.