feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555
Open
hogan-yuan wants to merge 69 commits into
Open
feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555hogan-yuan wants to merge 69 commits into
hogan-yuan wants to merge 69 commits into
Conversation
Longbridge credentials are prefixed with their data center: `us_…` for the US data center and `ap_…` for Asia-Pacific. This applies to the OAuth access token and, in legacy API-key mode, to the `app_key`, `app_secret`, and `access_token`. The API gateway routes a request to the matching data center via the `x-dc-region` header, defaulting to `ap` when absent. - `longbridge-geo`: add `DcRegion` (`from_credential` / `from_credentials` / `as_str`) and the `DC_REGION_HEADER` constant, re-exported through `longbridge-httpcli` and the crate root. - The HTTP client and the quote/trade WebSocket upgrade now auto-inject `x-dc-region` derived from the auth credentials, so US-region tokens reach the US data center with no caller changes. An explicitly-set header (e.g. via a custom header or `Config::dc_region`) is preserved. - `Config::dc_region()` remains as an explicit override. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `us_`/`ap_` prefix on an access token is region metadata used to derive the `x-dc-region` routing header — it is not part of the verifiable bearer credential. Sending the full `us_…` token in `Authorization: Bearer` makes the gateway reject it (401102 token verification failed). Strip the region prefix before building the `Authorization` header (deriving the region from the prefix first), so the gateway verifies the bare token and routes by `x-dc-region`. WebSocket auth is unaffected: it uses an OTP fetched over this same HTTP path. Add `DcRegion::strip_region_prefix`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… URLs
Based on live testing:
- Tokens with region prefixes (hk_m_, us_m_, ap_m_) are sent as-is to the
gateway. The server accepts the full prefixed token and routes via the
x-dc-region header — no prefix stripping is needed.
- strip_region_prefix now only removes a leading "Bearer " prefix.
- Add http_url_staging, quote_ws_url_staging, trade_ws_url_staging helpers:
US: openapi-global.longbridge.xyz
openapi-global-quote.longbridge.xyz
openapi-global-trade.longbridge.xyz
AP: openapi.longbridge.xyz / openapi-quote.longbridge.xyz / ...
- Update strip_region_prefix test to reflect new behavior.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ing via x-dc-region header
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Introduce a declarative `RequestBuilder::dc_restrict(region)` API so a call
site can restrict a request to a single data center. When the session's
region differs, `do_send` short-circuits with a unified
`HttpClientError::DcRegionRestricted { path, required, current }` instead of
forwarding a request the target data center cannot serve.
- geo: `DcRegion::allows()` + uppercase `Display` (AP/US) for messages, while
`as_str()` keeps the lowercase `x-dc-region` header value (us/ap).
- httpcli: `RequestBuilder::dc_restrict()`, `HttpClient::dc_region()`, and the
`DcRegionRestricted` error variant.
- Declare AP-only endpoints via the API: recurring investment (DCA, whole
module), operating reviews, broker holdings, and the broker-queue WebSocket
command.
Supports future US-only endpoints by declaring `DcRegion::Us` at their call
sites — no path-prefix heuristics.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements 14 US-only endpoints behind dc_restrict(DcRegion::Us):
FundamentalContext (9 methods):
- us_company_overview GET /v1/stock-info/company-overview
- us_valuation_overview GET /v1/stock-info/valuation-overview
- us_financial_overview GET /v1/stock-info/finn-overview
- us_financial_statement_v3 GET /v1/us/quote/financials/statements
- us_key_financial_metrics GET /v1/stock-info/fin-keyfactor
- us_analyst_consensus GET /v1/stock-info/fin-consensus
- us_etf_dividend_info GET /v1/stock-info/etf-dividend-info
- us_company_dividends GET /v1/stock-info/company-dividends
- us_etf_files GET /v1/stock-info/etf-files
QuoteContext (1 method):
- us_crypto_overview GET /v1/gemini/crypto-overview
TradeContext (4 methods):
- us_query_orders POST /v1/orders/query
- us_order_detail GET /v3/orders/{order_id}
- us_asset_overview GET /v1/us/assets/overview
- us_realized_pl GET /v1/us/assets/pl/realized
Layers:
- Rust core + blocking wrappers
- Python (sync + async, serde_json::Value via pythonize)
- Node.js (async, raw JSON string for flexible fields)
- Java JNI (returns JSON strings for complex types)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Python: us_crypto_overview (sync+async QuoteContext), us_query_orders,
us_order_detail, us_asset_overview, us_realized_pl (sync+async TradeContext)
+ all US types (USStockPosition, USOptionPosition, USCryptoPosition,
USBuyPower, USAssetOverview, USRealizedPLItem, USRealizedPL,
USCryptoOverview)
- Node.js: us_crypto_overview (QuoteContext), us_query_orders,
us_order_detail, us_asset_overview, us_realized_pl (TradeContext)
+ typed napi(object) structs for all US response types
- Java: quoteContextUsCryptoOverview, tradeContextUsQueryOrders,
tradeContextUsOrderDetail, tradeContextUsAssetOverview,
tradeContextUsRealizedPl — all return JSON strings
All four language bindings compile without errors.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add type stubs for all 14 US-only endpoints: - QuoteContext/AsyncQuoteContext: us_crypto_overview - TradeContext/AsyncTradeContext: us_query_orders, us_order_detail, us_asset_overview, us_realized_pl - FundamentalContext: us_company_overview, us_valuation_overview, us_financial_overview, us_financial_statement_v3, us_key_financial_metrics, us_analyst_consensus, us_etf_dividend_info, us_company_dividends, us_etf_files Add new type classes: USCryptoOverview, USStockPosition, USOptionPosition, USCryptoPosition, USBuyPower, USAssetOverview, USRealizedPLItem, USRealizedPL, USRankTag, USCompanyOverview, USValuationIndicator, USValuationOverview, USFinancialStatement, USETFDividendInfo, USDividendItem, USCompanyDividends, USETFFile, USETFFilesResponse Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…fmt; add Node.js TypeScript types
- Remove .claude/worktrees/agent-a962fdff6e0c7fa74 from git index
(submodule reference was causing CI checkout failure)
- Add .claude/ to .gitignore to prevent recurrence
- Run cargo +nightly fmt across all crates (rust/python/nodejs/java)
- Add US type definitions and method signatures to nodejs/index.d.ts:
USCompanyOverview, USValuationOverview, USFinancialStatement,
USETFDividendInfo, USCompanyDividends, USETFFilesResponse,
USCryptoOverview, USAssetOverview, USRealizedPL, USBuyPower,
USStockPosition, USOptionPosition, USCryptoPosition, USDividendItem
+ usCompanyOverview/usValuationOverview/usFinancialOverview/
usFinancialStatementV3/usKeyFinancialMetrics/usAnalystConsensus/
usEtfDividendInfo/usCompanyDividends/usEtfFiles on FundamentalContext
+ usCryptoOverview on QuoteContext
+ usQueryOrders/usOrderDetail/usAssetOverview/usRealizedPl on TradeContext
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… APIs All US methods now accept the user-facing symbol format (e.g. "AAPL.US", "SPY.US", "BTC.US") and convert to counter_id internally via symbol_to_counter_id(), matching the convention of all existing HK/CN APIs. Affected: FundamentalContext (9 methods), QuoteContext.us_crypto_overview, Python/Node.js bindings, index.d.ts, openapi.pyi Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ings The sed rename in the previous commit left parameter declarations as counter_id while the call sites expected symbol, causing E0425 'cannot find value symbol' compile errors in Python/Node.js crates. All US binding methods now consistently use symbol: String as the parameter name, matching the Rust core convention. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…SD.HAS) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…_id/counter_id_to_symbol - symbol_to_counter_id: BTCUSD.HAS → VA/HAS/BTCUSD - counter_id_to_symbol: VA/HAS/BTCUSD → BTCUSD.HAS - us_crypto_overview uses symbol_to_counter_id - Remove crypto_symbol_to_counter_id Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…exclusion Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…response
- USAssetOverview: cash_list/crypto_list (was positions/buy_power)
- USRealizedPL: realized_pl_list[]{category,metrics} (was items[])
- Remove USStockPosition/USOptionPosition/USCryptoPosition/USBuyPower/USRealizedPLItem
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…response
- USAssetOverview: account_type, asset_timestamp, cash_buy_power,
cash_list (USCashEntry), crypto_list (USCryptoEntry)
(was: positions/option_positions/buy_power — did not match actual API)
- USRealizedPL: realized_pl_list with USRealizedPLEntry{category,currency,metrics}
(was: items[] with symbol/realized_pl — did not match actual API)
- Update Python binding types.rs, mod.rs, context_async (via types)
- Update Node.js binding types.rs
- Update nodejs/index.d.ts interfaces
- Update python/pysrc/longbridge/openapi.pyi stubs
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…USAssetOverview Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…tion header Server validates only bare JWT (eyJ…); sending 'us_m_eyJ…' causes '\xba' decode error. strip_region_prefix now removes everything before 'eyJ' in addition to Bearer. App keys (no eyJ) are unchanged. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…uthorization header" This reverts commit 189d703.
… Python/Node.js bindings - counter_id → symbol, industry_counter_id → industry_symbol (match Rust core rename) - asset_timestamp: String → i64 (unix seconds, from Option<OffsetDateTime>) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…lways empty) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…etUSHistoryOrders
Rust us_realized_pl now takes GetUSRealizedPLOptions{currency, category}
instead of raw strings, matching Go's *GetUSRealizedPL pattern.
Empty currency defaults to 'USD'; empty category = all assets.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
3 tasks
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…s from raw JSON to structs Based on real API response shape (tested against staging). Blocking wrapper also updated. Python/Node.js/Java bindings work as-is since they use pythonize/serde_json::to_string on Serialize types. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…/USAnalystConsensus to Python/Node.js bindings Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…lMetrics/USAnalystConsensus Update method return types in stubs to use typed interfaces instead of string. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- rename us_financial_statement_v3 → us_financial_statement across all bindings (Rust async/blocking, Python sync/async, Node.js, Java, TypeScript stub, Python stub) — V3 was an internal API version detail - USFiscalYearDividend: new typed struct replacing Vec<serde_json::Value> for USETFDividendInfo.fiscal_year_info (Rust core + Python/Node bindings + stubs + mod.rs registration) - USAnalystConsensus.list/opt_reports: serde_json::Value → Vec<serde_json::Value> (API always returns arrays; propagated to Python Vec<JsonValue> and Node.js Vec<serde_json::Value>, stubs updated to Array<unknown>/List[Any]) - add AsyncFundamentalContext to openapi.pyi with all 9 US methods returning Awaitable[T] (was completely missing; asyncio users had no type hints for any US fundamental method) - fix docstring: us_etf_dividend_info/us_etf_files arg was "counter_id", correct param name is "symbol" Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
API returns {currency, report, list, empty_fields} — not the previously
modelled {revenue, net_income, net_margin, periods, currency}.
Updated Rust core, Python and Node.js bindings, and both stub files.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add USFinancialStatementField and USFinancialStatementPeriod structs based on confirmed production API schema. Updated Rust core, Python and Node.js bindings, mod.rs registration, and both stub files. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
report accepts "q1"/"qf"/"saf"/"3q"/"af", not "annual"/"quarterly". Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Confirmed via live API: rpt_date (string) present in every period. Updated Rust core, Python/Node.js bindings, and both stub files. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add USRecentDividend, USDividendHistoryItem, USDividendPayoutRecord. Updated Rust core, Python/Node.js bindings, mod.rs registration, TypeScript stub and Python stub. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
USRankTag: name/chg/rank_type → key/location/title/text/rank_type/highlight_text USCompanyOverview: add share_list field USValuationIndicator → USValuationMetric (circle/part/metric/desc/industry_median) USValuationOverview: current_indicator → metrics HashMap + add ccy_symbol/aichat_data USFiscalYearDividend: year/total_dividend/records → dividend/dividend_yield/fiscal_year/currency/fiscal_year_range USETFFile: name/file_type/url → file_name/file_path/update_date/code/format All changes applied to Rust core, Python binding, Node.js binding, TypeScript stub, and Python stub. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- USSharelistItem{chg, id, name}: typed struct for company_overview.sharelist
- USConsensusEstimate{actual, estimate} + USConsensusItem{ebit, eps, fiscal_year, report_txt, revenue}: typed list items for AnalystConsensus
- USAnalystConsensus.opt_reports: Vec<Value> → Vec<String> (schema-confirmed)
Updated: Rust core, Python/Node.js bindings, mod.rs, TypeScript stub, Python stub.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replace serde_json::Value order fields with fully typed USOrderDetail (72 fields). Add supporting types: USOrderHistory (expanded 15 fields), USButtonControl, USChargeItem, USChargeDetail, USAttachedOrder. us_order_detail now returns USOrderDetailResponse (typed) instead of a JSON string in Python sync/async and Node.js contexts. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…oss all bindings Rust core: use deserialize_counter_id_as_symbol serde attr to expose symbol/underlying_symbol instead of raw counter_id/underlying_counter_id. Python/Node.js bindings: rename fields to match. Python stub + TypeScript stub: updated field names. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ields Add USStockEntry (23 fields, full_symbol via IDToSymbol) to Rust core, Python binding, Node.js binding. Add USStockEntry to Python mod.rs. Update USAssetOverview with stock_list, option_list, overnight_buy_power, currency, multi_leg in all layers. Update Python stub and TypeScript stub. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…s stubs (q1/qf/saf/3q/af)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds 14 US-market-only API methods across all language bindings, behind
dc_restrict(DcRegion::Us). Syncs with openapi-go#106.Depends on: #554 (
feat/us-dc-region)New US-only APIs
All methods short-circuit with
HttpClientError::DcRegionRestrictedfor non-US tokens.FundamentalContext (9)
us_company_overview(counter_id)GET /v1/stock-info/company-overviewus_valuation_overview(counter_id)GET /v1/stock-info/valuation-overviewus_financial_overview(counter_id, report)GET /v1/stock-info/finn-overviewus_financial_statement_v3(counter_id, kind, report)GET /v1/us/quote/financials/statementsus_key_financial_metrics(counter_id, report)GET /v1/stock-info/fin-keyfactorus_analyst_consensus(counter_id, report)GET /v1/stock-info/fin-consensusus_etf_dividend_info(counter_id)GET /v1/stock-info/etf-dividend-infous_company_dividends(counter_id)GET /v1/stock-info/company-dividendsus_etf_files(counter_id, size)GET /v1/stock-info/etf-filesQuoteContext (1)
us_crypto_overview(counter_id)GET /v1/gemini/crypto-overviewTradeContext (4)
query_us_orders(opts)POST /v1/orders/queryus_order_detail(order_id, is_attached)GET /v3/orders/{order_id}us_asset_overview()GET /v1/us/assets/overviewus_realized_pl(currency, category)GET /v1/us/assets/pl/realizedLanguage coverage
rust/src/)dc_restrict(DcRegion::Us)rust/src/blocking/)python/src/)#[pymethods]nodejs/src/)#[napi]asyncjava/src/)Notes
financial_overview,key_financial_metrics,analyst_consensus, order list) are returned asserde_json::Value/ JSON strings in language bindingscounter_idfor US stocks is passed as-is (ST/US/AAPLformat) — no conversion applied🤖 Generated with Claude Code