Longbridge.QuoteContext (longbridge v0.1.0)

Copy Markdown View Source

Quote connection context for Longbridge market data APIs.

Manages a connection to the quote endpoint and provides a high-level API for market data operations.

Usage

{:ok, ctx} = Longbridge.QuoteContext.start_link(config)

# Get security static info
{:ok, result} = Longbridge.QuoteContext.static_info(ctx, ["AAPL.US"])

# Get real-time quotes
{:ok, result} = Longbridge.QuoteContext.quote(ctx, ["AAPL.US", "TSLA.US"])

# Subscribe to push data
:ok = Longbridge.QuoteContext.subscribe(ctx, ["AAPL.US"], [:QUOTE])

# Receive push messages in your process
receive do
  {:longbridge_push, {:push, 101, body}} ->
    quote = Protox.decode!(body, Longbridge.Quote.V1.PushQuote)
    IO.inspect(quote)
end

Push messages can also be dispatched to typed callbacks via set_on_quote/2, set_on_depth/2, set_on_brokers/2, and set_on_trades/2, or to a single default handler via set_default_push_callback/2. Callbacks fire in addition to mailbox delivery — the underlying {:longbridge_push, msg} message is still sent to the calling process when it has subscribed via Longbridge.WSConnection.subscribe_push/2.

Summary

Functions

Returns the broker queue (top 10 bid/ask brokers) for a symbol.

Returns precomputed calc indexes for one or more symbols.

Returns the capital flow size-bucket distribution (super-large / large / medium / small) for a single symbol.

Returns intraday capital flow lines (large/small/medium order net inflow) for a single symbol.

Returns a specification to start this module under a supervisor.

Returns the order book (market depth) for a single symbol.

Queries historical candlesticks for a symbol within a date range.

Queries historical candlesticks for a symbol, walking forward or backward from a specific date and time.

Queries intraday lines for a security.

Returns the current market trade-period metadata for the session (open/close timestamps, timezone, etc.).

Returns the authenticated member ID.

Alias for set_on_trades/2. Mirrors the upstream OnTrade method in longbridge/openapi-go.

Returns the option chain expiry dates available for an underlying.

Returns option chain strike info (price, OI, volume) for an underlying on a specific expiry date.

Returns option quotes (greeks + theoretical price) for one or more option symbols.

Returns the broker participant ID list for the current session's market.

Sets a callback for an arbitrary push topic.

Returns a real-time snapshot quote for one or more symbols.

Returns the user's quote level (e.g. "Lv1", "Lv2").

Returns the user's subscribed quote packages by market.

Returns the most recent cached broker queue for a symbol from the local push-data store.

Returns the most recent cached depth data for a symbol from the local push-data store.

Returns the most recent cached quote data for each symbol from the local push-data store.

Returns the most recent count cached trades for a symbol from the local push-data store (capped at 500).

Removes the callback for a push topic (:quote, :depth, :brokers, :trade, or a custom topic registered via put_push_callback/3).

Clears the local push-data cache. Useful when reconnecting or wanting to ignore stale data.

Returns the current WS session info.

Sets a fallback callback invoked for any push topic without a registered handler.

Sets a callback invoked on each PushBrokers push event.

Sets a callback invoked on each PushDepth push event.

Sets a callback invoked on each PushQuote push event.

Sets a callback invoked on each PushTrade push event.

Starts a QuoteContext linked to the calling process.

Returns static metadata for one or more symbols.

Subscribes to real-time push data for one or more symbols.

Returns the list of subscriptions currently active on the WS connection.

Returns the most recent count trades (tick data) for a symbol.

Queries the user's quote profile (cmd_code 4).

Returns the list of warrant issuers with their numeric ids.

Filters HK warrants for a given underlying symbol.

Returns warrant quotes for one or more warrant symbols.

Types

sub_type()

@type sub_type() :: :QUOTE | :DEPTH | :BROKERS | :TRADE

trade_session()

@type trade_session() ::
  :NORMAL_TRADE
  | :PRE_TRADE
  | :POST_TRADE
  | :OVERNIGHT_TRADE
  | non_neg_integer()

Functions

brokers(pid, symbol)

@spec brokers(pid(), String.t()) :: {:ok, struct()} | {:error, term()}

Returns the broker queue (top 10 bid/ask brokers) for a symbol.

Endpoint: cmd_code 15 (QueryBrokers). Each broker id can be looked up against participant_broker_ids/1.

calc_index(pid, symbols, calc_indexes)

@spec calc_index(pid(), [String.t()], [non_neg_integer()]) ::
  {:ok, struct()} | {:error, term()}

Returns precomputed calc indexes for one or more symbols.

Endpoint: cmd_code 26 (QuerySecurityCalcIndex). calc_indexes is a list of upstream-defined integers (see the SecurityCalcIndex enum in protos/api.proto); the most common values are listed in the upstream docs at https://open.longbridge.com/docs/quote/pull/calc-index.

candlesticks(pid, symbol, period \\ :DAY, count \\ 100, adjust_type \\ 0, trade_session \\ :NORMAL_TRADE)

@spec candlesticks(
  pid(),
  String.t(),
  atom(),
  non_neg_integer(),
  non_neg_integer(),
  trade_session()
) :: {:ok, struct()} | {:error, term()}

Queries candlestick data.

period is one of: :ONE_MINUTE, :FIVE_MINUTE, :FIFTEEN_MINUTE, :THIRTY_MINUTE, :SIXTY_MINUTE, :DAY, :WEEK, :MONTH, :QUARTER, :YEAR

capital_flow_distribution(pid, symbol)

@spec capital_flow_distribution(pid(), String.t()) ::
  {:ok, struct()} | {:error, term()}

Returns the capital flow size-bucket distribution (super-large / large / medium / small) for a single symbol.

Endpoint: cmd_code 25 (QueryCapitalFlowDistribution). For HK/CN symbols only.

capital_flow_intraday(pid, symbol)

@spec capital_flow_intraday(pid(), String.t()) :: {:ok, struct()} | {:error, term()}

Returns intraday capital flow lines (large/small/medium order net inflow) for a single symbol.

Endpoint: cmd_code 24 (QueryCapitalFlowIntraday). For HK/CN symbols only.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

depth(pid, symbol)

@spec depth(pid(), String.t()) :: {:ok, struct()} | {:error, term()}

Returns the order book (market depth) for a single symbol.

Endpoint: cmd_code 14 (QueryDepth). Returns the current top-of-book snapshot; subscribe to :DEPTH push for a continuously-updating view.

Each ask / bid entry is [price_cents, volume, order_count] where price_cents is a decimal string.

history_candlesticks_by_date(pid, symbol, opts)

@spec history_candlesticks_by_date(pid(), String.t(), keyword()) ::
  {:ok, struct()} | {:error, term()}

Queries historical candlesticks for a symbol within a date range.

Endpoint: cmd_code 27 (QueryHistoryCandlestick) with query_type = QUERY_BY_DATE.

Options

  • :period:MIN_1 | :MIN_5 | :MIN_15 | :MIN_30 | :MIN_60 | :DAY | :WEEK | :MONTH | :YEAR | :QUARTER. Required.

  • :adjust_type0 (no adjust) or 1 (forward adjust). Required.
  • :start_date"YYYY-MM-DD" string. Required.
  • :end_date"YYYY-MM-DD" string. Required.
  • :trade_session0 (regular session) or 1 (all sessions). Optional.

Mirrors HistoryCandlesticksByDate in longbridge/openapi-go.

history_candlesticks_by_offset(pid, symbol, opts)

@spec history_candlesticks_by_offset(pid(), String.t(), keyword()) ::
  {:ok, struct()} | {:error, term()}

Queries historical candlesticks for a symbol, walking forward or backward from a specific date and time.

Endpoint: cmd_code 27 (QueryHistoryCandlestick) with query_type = QUERY_BY_OFFSET.

Options

  • :period:MIN_1 | :MIN_5 | :MIN_15 | :MIN_30 | :MIN_60 | :DAY | :WEEK | :MONTH | :YEAR | :QUARTER. Required.

  • :adjust_type0 (no adjust) or 1 (forward adjust). Required.
  • :direction:forward (from offset toward latest data) or :backward (from offset toward historical data). Required.
  • :date — date string "YYYY-MM-DD" for the offset anchor. Required.
  • :minute — minute string "HH:MM" (intraday periods only). Optional.
  • :count — non_neg_integer count. Required.
  • :trade_session0 (regular session) or 1 (all sessions). Optional.

Mirrors HistoryCandlesticksByOffset in longbridge/openapi-go and QuoteContext::history_candlesticks_by_offset in longbridge/openapi/rust.

intraday(pid, symbol, trade_session \\ :NORMAL_TRADE)

@spec intraday(pid(), String.t(), trade_session()) ::
  {:ok, struct()} | {:error, term()}

Queries intraday lines for a security.

trade_session is one of:

  • :NORMAL_TRADE (default) — regular trading session only.
  • :PRE_TRADE — pre-market quotes only.
  • :POST_TRADE — post-market quotes only.
  • :OVERNIGHT_TRADE — overnight session quotes only.

Or pass an integer (0-3) directly.

market_trade_day(pid, market, beg_day, end_day)

@spec market_trade_day(pid(), String.t(), String.t(), String.t()) ::
  {:ok, struct()} | {:error, term()}

Queries market trade days.

The interval must be less than one month and within the most recent year (an upstream constraint). beg_day / end_day accept either "YYYY-MM-DD" or "YYYYMMDD"; the server receives the latter.

market_trade_period(pid)

@spec market_trade_period(pid()) :: {:ok, struct()} | {:error, term()}

Returns the current market trade-period metadata for the session (open/close timestamps, timezone, etc.).

Endpoint: cmd_code 8 (QueryMarketTradePeriod). One-shot; for a specific day's calendar, use market_trade_day/4.

member_id(pid)

@spec member_id(pid()) :: {:ok, integer()} | {:error, term()}

Returns the authenticated member ID.

Convenience over user_quote_profile/2 that extracts just the member_id field — no need to decode the full profile response.

Mirrors QuoteContext::member_id from longbridge/openapi/rust.

on_trade(pid, callback)

@spec on_trade(pid(), (map() -> any())) :: :ok

Alias for set_on_trades/2. Mirrors the upstream OnTrade method in longbridge/openapi-go.

option_chain_date(pid, symbol)

@spec option_chain_date(pid(), String.t()) :: {:ok, struct()} | {:error, term()}

Returns the option chain expiry dates available for an underlying.

Endpoint: cmd_code 20 (QueryOptionChainDate). Each entry in expiry_date is a date string the server accepts as the expiry_date argument to option_chain_strike_info/3.

option_chain_strike_info(pid, symbol, expiry_date)

@spec option_chain_strike_info(pid(), String.t(), String.t()) ::
  {:ok, struct()} | {:error, term()}

Returns option chain strike info (price, OI, volume) for an underlying on a specific expiry date.

Endpoint: cmd_code 21 (QueryOptionChainDateStrikeInfo). expiry_date must be one of the values returned by option_chain_date/2.

option_quote(pid, symbols)

@spec option_quote(pid(), [String.t()]) :: {:ok, struct()} | {:error, term()}

Returns option quotes (greeks + theoretical price) for one or more option symbols.

Endpoint: cmd_code 12 (QueryOptionQuote). The symbol entries must be option symbols ("AAPL250117C150000.US"), not the underlying equity.

participant_broker_ids(pid)

@spec participant_broker_ids(pid()) :: {:ok, struct()} | {:error, term()}

Returns the broker participant ID list for the current session's market.

Endpoint: cmd_code 16 (QueryParticipantBrokerIds). The returned id list is what brokers/2 indexes into. Mirrors ParticipantBrokerIds from longbridge/openapi-go.

put_push_callback(pid, topic, callback)

@spec put_push_callback(pid(), atom() | String.t(), (map() -> any())) :: :ok

Sets a callback for an arbitrary push topic.

Use the predefined set_on_quote/2, set_on_depth/2, set_on_brokers/2, set_on_trades/2 wrappers for the standard topics. Pass a custom string for niche cases.

quote(pid, symbols)

@spec quote(pid(), [String.t()]) :: {:ok, struct()} | {:error, term()}

Returns a real-time snapshot quote for one or more symbols.

Endpoint: cmd_code 11 (QuerySecurityQuote). One-shot request; for a continuously-updating view, subscribe via subscribe/4 with :QUOTE and read the local cache with realtime_quote/2.

The server gzips the response when the body crosses its internal size threshold — Longbridge.Protocol.unpack/1 transparently decompresses it.

Example

{:ok, %{secu_quote: [%{symbol: "AAPL.US", last_done: "282.50", ...} | _]}} =
  Longbridge.QuoteContext.quote(ctx, ["AAPL.US"])

quote_level(pid)

@spec quote_level(pid()) :: {:ok, String.t()} | {:error, term()}

Returns the user's quote level (e.g. "Lv1", "Lv2").

Convenience over user_quote_profile/2 that extracts just the quote_level field. Mirrors QuoteContext::quote_level from longbridge/openapi/rust.

quote_package_details(pid, opts \\ [])

@spec quote_package_details(
  pid(),
  keyword()
) :: {:ok, Longbridge.Quote.V1.UserQuoteLevelDetail.t()} | {:error, term()}

Returns the user's subscribed quote packages by market.

Each market entry contains the package details (key, name, description, start/end timestamps) and a warning_msg shown when no packages are active for that market.

The language parameter ("en" by default) controls the localized package names. Accepted values: "zh-CN", "zh-HK", "en".

Mirrors QuoteContext::quote_package_details from longbridge/openapi/rust.

Example

{:ok, %UserQuoteLevelDetail{} = details} =
  Longbridge.QuoteContext.quote_package_details(ctx, language: "en")
Enum.each(details.market_package_details, fn entry ->
  IO.inspect(entry.market)
end)

realtime_brokers(pid, symbol)

@spec realtime_brokers(pid(), String.t()) :: {:ok, struct() | nil} | {:error, term()}

Returns the most recent cached broker queue for a symbol from the local push-data store.

realtime_depth(pid, symbol)

@spec realtime_depth(pid(), String.t()) :: {:ok, struct() | nil} | {:error, term()}

Returns the most recent cached depth data for a symbol from the local push-data store.

realtime_quote(pid, symbols)

@spec realtime_quote(pid(), [String.t()]) ::
  {:ok, [struct() | nil]} | {:error, term()}

Returns the most recent cached quote data for each symbol from the local push-data store.

Reads from the in-memory store populated by incoming push events. If the symbol has not been pushed since the QuoteContext started, returns nil for that entry.

Mirrors RealtimeQuote from longbridge/openapi-go and QuoteContext::realtime_quote in longbridge/openapi/rust.

realtime_trades(pid, symbol, count \\ 50)

@spec realtime_trades(pid(), String.t(), non_neg_integer()) ::
  {:ok, [struct()]} | {:error, term()}

Returns the most recent count cached trades for a symbol from the local push-data store (capped at 500).

If fewer than count trades have been pushed, returns all available trades in chronological order.

remove_push_callback(pid, topic)

@spec remove_push_callback(pid(), atom() | String.t()) :: :ok

Removes the callback for a push topic (:quote, :depth, :brokers, :trade, or a custom topic registered via put_push_callback/3).

After removal, no callback fires for topic; the default callback (if set via set_default_push_callback/2) still does.

reset_realtime_cache(pid)

@spec reset_realtime_cache(pid()) :: :ok

Clears the local push-data cache. Useful when reconnecting or wanting to ignore stale data.

session(pid)

@spec session(pid()) :: {:ok, String.t(), integer()} | {:error, term()}

Returns the current WS session info.

Returns {:ok, session_id, heartbeat_interval_ms} once the underlying Longbridge.WSConnection has finished authenticating. Returns {:ok, nil, nil} before auth completes.

session_id is the opaque string assigned by the Longbridge backend (e.g. "15766270:21526413:1eef69007cb60d68d6111f7ea02b7531").

set_default_push_callback(pid, callback)

@spec set_default_push_callback(pid(), (map() -> any())) :: :ok

Sets a fallback callback invoked for any push topic without a registered handler.

Useful when you want one function to handle every push type during bring-up or when you don't know the topic key up front (e.g. for custom server topics). The callback receives the raw decoded struct for the push event.

set_on_brokers(pid, callback)

@spec set_on_brokers(pid(), (map() -> any())) :: :ok

Sets a callback invoked on each PushBrokers push event.

The callback receives a %Longbridge.Quote.V1.PushBrokers{} struct. Mirrors QuoteContext::on_brokers from longbridge/openapi-go.

set_on_depth(pid, callback)

@spec set_on_depth(pid(), (map() -> any())) :: :ok

Sets a callback invoked on each PushDepth push event.

The callback receives a %Longbridge.Quote.V1.PushDepth{} struct. Mirrors QuoteContext::on_depth from longbridge/openapi-go.

set_on_quote(pid, callback)

@spec set_on_quote(pid(), (map() -> any())) :: :ok

Sets a callback invoked on each PushQuote push event.

The callback receives a %Longbridge.Quote.V1.PushQuote{} struct. Set this before subscribe/4 (with is_first_push: true) so you don't miss events. Replaces any callback previously set for the :quote topic. Mirrors QuoteContext::on_quote from longbridge/openapi-go.

set_on_trades(pid, callback)

@spec set_on_trades(pid(), (map() -> any())) :: :ok

Sets a callback invoked on each PushTrade push event.

The callback receives a %Longbridge.Quote.V1.PushTrade{} struct. Mirrors QuoteContext::on_trades from longbridge/openapi-go.

start_link(config, opts \\ [])

@spec start_link(
  Longbridge.Config.t(),
  keyword()
) :: GenServer.on_start()

Starts a QuoteContext linked to the calling process.

The context owns a Longbridge.WSConnection (one Mint WebSocket to config.quote_ws_url) and a per-instance RealtimeStore for cached push data. The caller is automatically subscribed to push frames.

Options

Example

{:ok, ctx} = Longbridge.QuoteContext.start_link(config)

static_info(pid, symbols)

@spec static_info(pid(), [String.t()]) :: {:ok, struct()} | {:error, term()}

Returns static metadata for one or more symbols.

Endpoint: cmd_code 10 (QuerySecurityStaticInfo).

Each entry in response.secu_static_info contains the listing exchange, lot size, board, underlying symbol, etc. Mirrors QuoteContext::static_info from longbridge/openapi/rust.

Example

{:ok, %{secu_static_info: [%{symbol: "AAPL.US", name_en: "Apple Inc."} | _]}} =
  Longbridge.QuoteContext.static_info(ctx, ["AAPL.US"])

subscribe(pid, symbols, sub_types, is_first_push \\ true)

@spec subscribe(pid(), [String.t()], [sub_type()], boolean()) ::
  :ok | {:error, term()}

Subscribes to real-time push data for one or more symbols.

Endpoint: cmd_code 6 (Subscribe). Records the subscription internally so it is re-issued automatically after a WS reconnect; callers do not need to re-subscribe after a network blip.

Arguments

  • symbols — user-facing symbols ("AAPL.US", "00700.HK").
  • sub_types — list of atoms from :QUOTE, :DEPTH, :BROKERS, :TRADE. The same (symbols, sub_types) tuple is idempotent: subscribing twice is a no-op on the server.
  • is_first_push — when true (default), the server immediately pushes the current snapshot for each subscribed type. Pass false if you only want deltas after the subscribe lands.

Push delivery

Push data is delivered three ways:

  1. Mailbox — every subscriber of the underlying Longbridge.WSConnection receives {:longbridge, conn_pid, {:push, cmd_code, body}}. The context forwards this to the caller as {:longbridge_push, msg}.
  2. Local cacherealtime_quote/2, realtime_depth/2, realtime_brokers/2, and realtime_trades/3 read the latest value without blocking on the server.
  3. Typed callbacksset_on_quote/2, set_on_depth/2, set_on_brokers/2, set_on_trades/2 (or set_default_push_callback/2 for any topic).

Push command codes:

CodeMessageDecode with
101PushQuoteLongbridge.Quote.V1.PushQuote
102PushDepthLongbridge.Quote.V1.PushDepth
103PushBrokersLongbridge.Quote.V1.PushBrokers
104PushTradeLongbridge.Quote.V1.PushTrade

Example

:ok = QuoteContext.set_on_quote(ctx, fn push -> IO.inspect(push) end)
:ok = QuoteContext.subscribe(ctx, ["AAPL.US"], [:QUOTE], true)

subscription(pid)

@spec subscription(pid()) :: {:ok, struct()} | {:error, term()}

Returns the list of subscriptions currently active on the WS connection.

Endpoint: cmd_code 5 (Subscription). Useful for verifying that subscribe/4 actually landed at the server, and for re-syncing state after a reconnect if you're not relying on the auto-resubscribe.

trades(pid, symbol, count \\ 100)

@spec trades(pid(), String.t(), non_neg_integer()) ::
  {:ok, struct()} | {:error, term()}

Returns the most recent count trades (tick data) for a symbol.

Endpoint: cmd_code 17 (QueryTrade). Each entry has price_cents, volume, timestamp, trade_type (0 = ?, 1 = ?, see upstream docs), and direction (-1/0/+1).

For a live, capped-at-500 tail, subscribe to :TRADE push and read realtime_trades/3.

unsubscribe(pid, symbols, sub_types, unsub_all \\ false)

@spec unsubscribe(pid(), [String.t()], [sub_type()], boolean()) ::
  :ok | {:error, term()}

Unsubscribes from push data.

unsub_all: true removes every subscription for those symbols across all sub-types (server-side ignores sub_types when set). Mirrors Unsubscribe (cmd_code 7) in longbridge/openapi-go.

user_quote_profile(pid, opts \\ [])

@spec user_quote_profile(
  pid(),
  keyword()
) :: {:ok, Longbridge.Quote.V1.UserQuoteProfileResponse.t()} | {:error, term()}

Queries the user's quote profile (cmd_code 4).

Returns the user's member_id, quote_level, subscribe_limit, history_candlestick_limit, per-command rate_limit, and the quote_level_detail (subscribed quote packages by market).

Options

  • :language — response language for quote_level_detail. Accepts "zh-CN", "zh-HK", or "en". Defaults to "en".

Mirrors longbridge/openapi/rust/src/quote/core.rs::Core::connect(), which calls QueryUserQuoteProfile once after auth. The Rust SDK uses the response to populate rate-limit throttling; we expose the raw response so callers can do the same.

Example

{:ok, profile} = Longbridge.QuoteContext.user_quote_profile(ctx)
profile.member_id
profile.subscribe_limit
profile.rate_limit

warrant_issuer_info(pid)

@spec warrant_issuer_info(pid()) :: {:ok, struct()} | {:error, term()}

Returns the list of warrant issuers with their numeric ids.

Endpoint: cmd_code 22 (QueryWarrantIssuerInfo). Pass these ids in the :issuer list of warrant_list/2 to filter by issuer.

warrant_list(pid, opts)

@spec warrant_list(
  pid(),
  keyword()
) :: {:ok, struct()} | {:error, term()}

Filters HK warrants for a given underlying symbol.

Endpoint: cmd_code 23 (QueryWarrantFilterList).

Required options

  • :symbol — the underlying symbol (e.g. "700.HK").
  • :language0 (Simplified Chinese), 1 (English), 2 (Traditional Chinese).

Optional filters

  • :sort_by:last_done | :change_rate | :change_value | :volume | :turnover | :outstanding_qty | :leverage_ratio | :implied_volatility | :status (default: :last_done).

  • :sort_order:desc | :asc (default: :desc).

  • :sort_offset — non_neg_integer pagination offset (default 0).
  • :sort_count — non_neg_integer page size (default 50).
  • :type:call | :put (or 0 | 1).

  • :expiry_date — `:lt_3:between_3_6:between_6_12:gt_12`
    (or `1234`).
  • :status:suspend | :prepare_list | :normal (or 2 | 3 | 4).

  • :price_type:in_bounds | :out_bounds (or 1 | 2).

  • :issuer — list of issuer ids from warrant_issuer_info/1.

Mirrors WarrantList from longbridge/openapi-go.

warrant_quote(pid, symbols)

@spec warrant_quote(pid(), [String.t()]) :: {:ok, struct()} | {:error, term()}

Returns warrant quotes for one or more warrant symbols.

Endpoint: cmd_code 13 (QueryWarrantQuote). Same caveat as option_quote/2symbols are warrant IDs, not the underlying equity.