Trade context for Longbridge trading APIs.
Manages a WebSocket connection to the trade endpoint for push subscriptions (order-changed events) and provides HTTP-based APIs for order submission, order queries, account balance, positions, executions, cash flow, and risk checks.
Usage
{:ok, ctx} = Longbridge.TradeContext.start_link(config)
# Submit a limit order
{:ok, %{"order_id" => order_id}} =
Longbridge.TradeContext.submit_order(ctx,
symbol: "00700.HK",
side: :buy,
order_type: :lo,
submitted_quantity: "100",
time_in_force: :day,
submitted_price: "375.00"
)
# Cancel it
{:ok, _} = Longbridge.TradeContext.cancel_order(ctx, order_id)
# Today's orders
{:ok, %{"orders" => orders}} =
Longbridge.TradeContext.today_orders(ctx)
# Account balance (USD)
{:ok, %{"list" => balances}} =
Longbridge.TradeContext.account_balance(ctx, "USD")Push events
Subscribe after starting:
:ok = Longbridge.TradeContext.subscribe(ctx, [:private])
:ok = Longbridge.TradeContext.set_on_order_changed(ctx, fn event ->
IO.inspect(event, label: "order changed")
end)Subscriptions are recorded on the context state and re-issued
automatically after a WS reconnect. Order-changed events arrive
as {:longbridge_push, ...} messages in the caller's mailbox and
fire the registered :order_changed callback.
Two transports
start_link/2 splits the config into:
state.ws_config—Longbridge.Config.with_socket_token/1applied, used to authenticate the Mint WebSocket. Auth uses the OTP, not the long-lived access token.state.http_config— the original config, used to sign REST requests with HMAC-SHA256. HTTP401 Unauthorizedresponses are automatically retried once after a token refresh.
For OAuth users, inject token_refresher: to start_link/2 so
the context can refresh the long-lived token after a 401.
Summary
Functions
Returns account balance across all currencies.
Optionally filter by currency (e.g. "HKD", "USD").
Cancels an order by order_id.
Returns cash flow history.
Returns a specification to start this module under a supervisor.
Estimates the maximum purchase quantity for a symbol.
Returns fund positions. Optionally filter by symbols (list of strings).
Returns historical executions. Requires
Returns historical orders. Requires
Returns the initial/maintain margin ratios for a symbol.
Alias for set_on_order_changed/2. Mirrors the upstream
OnOrderChanged method name.
Returns the full state for a single order.
Sets a callback for a specific push topic.
Removes the callback for a specific push topic.
Replaces (amends) an existing order.
Returns the current WS session info.
Sets a fallback callback invoked when push data arrives for a topic with no registered callback.
Sets a callback for order-changed push events.
Starts a TradeContext linked to the calling process.
Returns stock positions. Optionally filter by symbols (list of strings).
Submits a new order.
Subscribes to trade push data. Accepts a list of topics
Returns today's executions. Accepts optional filters
Returns today's orders. Accepts optional filters
Unsubscribes from trade push topics.
Types
@type market() :: :us | :hk | :cn | :sg
@type order_side() :: :buy | :sell
@type order_status() ::
:not_reported
| :replaced
| :cancelled
| :rejected
| :new
| :partially_filled
| :filled
@type order_type() ::
:lo | :elo | :alo | :odd | :lit | :mit | :tslpamt | :tslppct | :market
@type outside_rth() :: :rth_only | :any_time | :overnight
@type time_in_force() :: :day | :gtc | :gtd
Functions
Returns account balance across all currencies.
Optionally filter by currency (e.g. "HKD", "USD").
Cancels an order by order_id.
Returns {:ok, %{}} (the API responds with a 200 + empty body on
success). If the order is already in a terminal state
(:filled, :cancelled), the API returns an error that surfaces
as {:error, reason} — check it before reporting success to the
caller.
Endpoint: DELETE /v1/trade/order
Returns cash flow history.
Options
:start_at— Start time as Unix timestamp (seconds).:end_at— End time as Unix timestamp (seconds).:business_type—:cash,:stock, or:fund.:symbol— Stock symbol filter.:page— Page number (default 1).:size— Page size (default 50).
Returns a specification to start this module under a supervisor.
See Supervisor.
Estimates the maximum purchase quantity for a symbol.
Options
:symbol— Stock symbol (required).:order_type— Order type (required).:side—:buyor:sell(required).:price— Price as a string (optional).:currency— Currency (optional).:fractional_shares— Boolean (optional, default false).
Returns fund positions. Optionally filter by symbols (list of strings).
Returns historical executions. Requires:
:start_at— Start time as a Unix timestamp (seconds).:end_at— End time as a Unix timestamp (seconds).
Returns historical orders. Requires:
:start_at— Start time as a Unix timestamp (seconds).:end_at— End time as a Unix timestamp (seconds).
Returns the initial/maintain margin ratios for a symbol.
Endpoint: GET /v1/risk/margin-ratio?symbol=<s>. Useful for
margin checks before submitting levered orders. The response has
im_factor (initial margin factor), mm_factor (maintain margin
factor), fm_factor, mcm_factor, short_im_factor, and
short_fm_factor — all decimal strings.
Alias for set_on_order_changed/2. Mirrors the upstream
OnOrderChanged method name.
Returns the full state for a single order.
Endpoint: GET /v1/trade/order?order_id=<id>. Includes current
status, filled quantity, average fill price, fees, and timestamps.
Use today_orders/2 (or history_orders/2) to find the order_id
if you don't have it.
Sets a callback for a specific push topic.
The callback receives the decoded JSON event map
for the given topic (e.g., @order_changed_topic).
See set_on_order_changed/2 for a convenience wrapper.
Removes the callback for a specific push topic.
Replaces (amends) an existing order.
Options
:order_id— The order to replace (required).:quantity— New quantity as a string (required).:price— New price as a string (required).
Returns the current WS session info.
Returns {:ok, session_id, heartbeat_interval_ms} once the
underlying Longbridge.WSConnection has finished authenticating,
or {:ok, nil, nil} before auth completes.
session_id is the opaque string assigned by the Longbridge
backend (e.g. "15766270:21526413:...").
Sets a fallback callback invoked when push data arrives for a topic with no registered callback.
Sets a callback for order-changed push events.
The callback receives a map with fields like
order_id, status, filled_qty, executed_price, etc.
Set this before calling subscribe/2 so you don't miss events.
@spec start_link( Longbridge.Config.t(), keyword() ) :: GenServer.on_start()
Starts a TradeContext linked to the calling process.
The context owns both:
- a
Longbridge.WSConnectiontoconfig.trade_ws_urlfor push subscriptions (order-changed events, etc.). Auth uses the OTP fromLongbridge.Config.with_socket_token/1. - a per-instance HTTP config for signed REST requests (orders,
account, executions, positions, cash flow). The original
config.tokenis kept onstate.http_configso HTTP requests sign with the long-lived access token, while WS auth uses the OTP fromws_config.
Options
:name— registered process name, passed through toGenServer.start_link/3.:token_refresher—nil(default) or a 1-arity function that refreshes the HTTP access token. The default usesLongbridge.Config.refresh_access_token/1, which only works for legacy app-key auth. OAuth users must inject a custom refresher that performs therefresh_tokengrant.:skip_connection— whentrue, skip WS startup (HTTP-only context). Used by tests; not part of the stable API.- Any other
GenServeroption (:timeout,:spawn_opt, ...).
Example
{:ok, ctx} =
Longbridge.TradeContext.start_link(config,
token_refresher: fn cfg ->
with {:ok, %OAuth.Token{access_token: t, expires_at: exp}} <-
MyApp.OAuth.refresh(cfg.client_id) do
{:ok, %{cfg | token: t, expired_at: exp}}
end
end
)
Returns stock positions. Optionally filter by symbols (list of strings).
Submits a new order.
See the Longbridge Submit Order docs.
Options
:symbol— Stock symbol inticker.regionformat (required).:side—:buyor:sell(required).:order_type— Order type (required). Seeorder_type/0.:submitted_quantity— Quantity as a string (required).:time_in_force—:day,:gtc, or:gtd(required).:submitted_price— Price as a string. Required for LO/ELO/ALO/ODD/LIT.:trigger_price— Trigger price. Required for LIT/MIT.:limit_offset— Limit offset. Required for TSLPAMT/TSLPPCT when limit_depth_level is 0.:trailing_amount— Trailing amount for TSLPAMT.:trailing_percent— Trailing percent for TSLPPCT.:expire_date— Expiry date as"YYYY-MM-DD". Required for GTD.:outside_rth— Outside RTH mode. For US stocks only.:remark— Remark (max 255 chars).:limit_depth_level— Bid/ask depth level (-5 to 5).:monitor_price— Monitoring price for TSLPAMT/TSLPPCT.:trigger_count— Trigger count (0-3).
Subscribes to trade push data. Accepts a list of topics:
:private— Order status updates.
Set a callback with set_on_order_changed/2 first to receive
structured push events. Raw events arrive at the caller's mailbox
as {:longbridge_push, {:push, cmd_code, body}} messages.
Returns today's executions. Accepts optional filters:
:symbol— Stock symbol.:order_id— A specific order ID.
Returns today's orders. Accepts optional filters:
:symbol— Stock symbol.:status— List of order statuses (atoms).:side—:buyor:sell.:market—:us,:hk,:cn,:sg.:order_id— A specific order ID.
Unsubscribes from trade push topics.
topics is a list of atoms; currently :private is the only
supported value (it controls order-changed events). Passing an
empty list is a no-op. Mirrors Unsubscribe (cmd_code 17).