Skip to content

feat(quote): add QuoteTransport to serve quote pull APIs over HTTP - #604

Open
hogan-yuan wants to merge 3 commits into
mainfrom
feat/quote-http-transport
Open

hogan-yuan wants to merge 3 commits into
mainfrom
feat/quote-http-transport

Conversation

@hogan-yuan

Copy link
Copy Markdown
Member

What

Adds Config::quote_transport(QuoteTransport::{WebSocket, Http}) (env LONGBRIDGE_QUOTE_TRANSPORT=ws|http, default WebSocket). With Http, the 19 QuoteContext pull APIs that have a REST equivalent (static_info, quote, option_quote, warrant_quote, depth, brokers, participants, trades, intraday, candlesticks, history_candlesticks_by_offset/by_date, option_chain_expiry_date_list, warrant_issuers, warrant_list, trading_session, trading_days, capital_flow, capital_distribution, calc_indexes) go over POST /quote/* instead of the quote WebSocket. A process that only pulls data never opens a WebSocket connection. Public method signatures and return types are unchanged.

The option is exposed in all six layers (Rust, C, C++, Java, Node.js, Python), mirroring PushCandlestickMode.

Why

longbridge/longbridge-mcp#162 re-implemented every quote tool on top of the REST endpoints inside the MCP (per-tool JSON reshaping) to get rid of its per-user WebSocket pool. That logic belongs in the SDK: one switch in QuoteContext::request, and every SDK consumer (MCP, CLI, …) gets it with identical types.

How

  • rust/src/quote/cmd_code.rs::http_path maps WS command codes to REST paths; QuoteContext::request / request_without_body branch on the transport. The request is the same prost message serialised as JSON (nulls stripped); the response is decoded into the same prost message by rust/src/quote/http_json.rs, a lenient serde deserializer (int64-as-string, omitted/null → default, camelCase keys, unknown fields ignored), so all existing TryFrom conversions are reused.
  • rust/src/quote/overnight.rs aligns the one known server-side difference: REST always returns US overnight data and has no opt-out, while the WS only returns it when enable_overnight is set. On the HTTP path (and only there) the SDK strips overnight_quote, filters overnight intraday lines for US equities, drops OvernightTrade candlesticks and tops up count/range-capped candlestick windows with offset queries (≤1000 per request, ≤8 rounds). The WebSocket path is byte-identical to main.
  • examples/rust/quote_http_compare calls every pull API over both transports and diffs the results.

Verification

Report with every call's request/response and WS-vs-HTTP diff (canary + production, overnight on/off): https://v.longbridge-inc.com/p/zhanghong.yuan/quote-http-传输验证

  • Canary: 31/33 cases identical in both modes; the 2 remaining are the gateway error-code gap below.
  • Production: all cases structurally identical; the value-level differences are a backend issue (two consecutive REST calls disagree with each other while the WS is stable — different /quote/* replicas serve different data).
  • cargo test -p longbridge --lib quote:: 14/14; cargo clippy --all --all-features adds no warnings; cargo +nightly fmt --all.
  • Two rounds of independent full-branch review; all blockers/should-fix findings addressed before the final runs.

Known gateway gaps (not fixable in the SDK)

  1. REST reports business errors as 500 internal server error instead of passing the code through (WS: 301600, 301604, 301607). Callers that branch on error codes will not work over HTTP until this is fixed.
  2. Production /quote/* data is not consistent across replicas (see report).
  3. No REST opt-out for US overnight data (handled client-side here).

🤖 Generated with Claude Code

Add `Config::quote_transport(QuoteTransport::{WebSocket, Http})` (env
`LONGBRIDGE_QUOTE_TRANSPORT=ws|http`, default WebSocket). With `Http`, the
19 `QuoteContext` pull APIs that have a REST equivalent are sent as
`POST /quote/*` instead of over the quote WebSocket, so a process that only
pulls data never opens a WebSocket connection. Method signatures and return
types are unchanged: the request is the same prost message serialised as
JSON, and the gateway proto-JSON response is decoded back into the same
prost message by a lenient deserializer (int64-as-string, omitted/null
fields, camelCase keys), so the existing conversions are reused.

Results are aligned with the WebSocket, including US overnight data, which
the gateway always returns over REST but the WebSocket only returns when
`enable_overnight` is set: on the HTTP path the SDK strips
`overnight_quote`, filters overnight intraday lines, drops overnight
candlesticks and tops up count/range-capped candlestick windows with offset
queries (`quote::overnight`, unit-tested).

Expose the option in the C, C++, Java, Node.js and Python layers, mirroring
`PushCandlestickMode`, and add `examples/rust/quote_http_compare`, which
calls every pull API over both transports and diffs the results.
- refill: once a page yields no usable bar the cursor is inside the
  contiguous 20:00-04:00 overnight block; fetch a full page to jump it
  instead of inching through (regression tests for both directions)
- gate overnight dropping on the same US-equity predicate everywhere and
  compute the window target in one place (CandlestickWindow / window_target,
  unit-tested)
- CHANGELOG: split the entry, list the top-up endpoint, error-variant,
  429-retry and overnight-session caveats; 20 methods / 19 commands
- drop the undocumented "websocket" env alias; ignore only .env/.env.local;
  revert unrelated example reformatting
@hogan-yuan
hogan-yuan force-pushed the feat/quote-http-transport branch from ef2a9d6 to 7a24f57 Compare October 10, 2026 10:28
- only drop overnight candlesticks for TradeSessions::All queries, so a
  page is either left untouched or dropped and topped up (matches Go)
- a date-range page shorter than the request cap is never treated as
  capped; avoids a wasted top-up request for weekend/holiday starts
- warn when the top-up returns fewer candlesticks than the WebSocket would
- clear overnight_quote only for US equities, like intraday/candlesticks

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant