feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555
Open
hogan-yuan wants to merge 40 commits into
Open
feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555hogan-yuan wants to merge 40 commits into
hogan-yuan wants to merge 40 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>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- QueryUSOrdersResponse: add total_count field - USOrderDetailResponse: replace USAttachedOrder dead code with order/order_histories/current_attached_order matching real API response - Remove USAttachedOrder, export USOrderHistory instead - CryptoOverview USCryptoOverview: add counter_id, base_asset, logo, wiki_url; profile changed to String (API returns JSON string) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…SCryptoEntry, asset_timestamp P0: - Python/Node.js USCryptoOverview: add counter_id, base_asset, logo, wiki_url - index.d.ts USCryptoEntry: counterId→symbol, remove industryCounterId - Python stubs USCryptoEntry: same - asset_timestamp type: str→int (i64 unix seconds) - index.d.ts: add USOrderDetailResponse/USOrderHistory interfaces; usOrderDetail return type Promise<string>→Promise<USOrderDetailResponse> - Python stubs: fix CryptoOverview doc from CY/US/BTC to BTCUSD.BKKT Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…js/stubs Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
P0: - Fix profile double-serialization: v.profile is String; drop serde_json::to_string() - Python stub USCryptoOverview: add symbol, base_asset, logo, wiki_url fields P1: - Blocking us_crypto_overview: rename param counter_id → symbol - Java JNI us_crypto_overview: rename local var counter_id → symbol Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Python stub: us_order_detail docstring describes JSON shape - index.d.ts: usQueryOrders JSDoc describes JSON shape and queryType values Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…tches Go) - GetUSHistoryOrders: Symbol/Side/StartAt/EndAt/QueryType/Page/Limit typed fields; SDK builds POST body with defaults internally - QueryUSOrdersOptions kept as type alias for backward compat - USQueryOrdersBody is the internal serialization struct (pub(crate)) - Blocking wrapper and Python/Node.js bindings updated to use GetUSHistoryOrders (still accept old individual params from user, build GetUSHistoryOrders internally) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…l layers P1-1: Python/Node.js/Java binding us_query_orders now accepts symbol (optional), action (0/1/2), start_at, end_at, query_type, page, limit — same ergonomic style as Go GetUSHistoryOrders. Raw params (account_channel, counter_ids, security_types, query_version) are now internal SDK concerns. P1-2: Java us_query_orders was building QueryUSOrdersOptions (now alias) with old fields — compile error fixed by switching to GetUSHistoryOrders. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Matches the binding: (symbol?, action, start_at, end_at, query_type, page, limit) Removes: account_channel, counter_ids, security_types, query_version Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
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