Skip to content

feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555

Open
hogan-yuan wants to merge 40 commits into
mainfrom
feat/us-market-apis
Open

feat(us): US market APIs — Rust, Python, Node.js, Java, blocking#555
hogan-yuan wants to merge 40 commits into
mainfrom
feat/us-market-apis

Conversation

@hogan-yuan

Copy link
Copy Markdown
Member

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::DcRegionRestricted for non-US tokens.

FundamentalContext (9)

Method Path
us_company_overview(counter_id) GET /v1/stock-info/company-overview
us_valuation_overview(counter_id) GET /v1/stock-info/valuation-overview
us_financial_overview(counter_id, report) GET /v1/stock-info/finn-overview
us_financial_statement_v3(counter_id, kind, report) GET /v1/us/quote/financials/statements
us_key_financial_metrics(counter_id, report) GET /v1/stock-info/fin-keyfactor
us_analyst_consensus(counter_id, report) GET /v1/stock-info/fin-consensus
us_etf_dividend_info(counter_id) GET /v1/stock-info/etf-dividend-info
us_company_dividends(counter_id) GET /v1/stock-info/company-dividends
us_etf_files(counter_id, size) GET /v1/stock-info/etf-files

QuoteContext (1)

Method Path
us_crypto_overview(counter_id) GET /v1/gemini/crypto-overview

TradeContext (4)

Method Path
query_us_orders(opts) POST /v1/orders/query
us_order_detail(order_id, is_attached) GET /v3/orders/{order_id}
us_asset_overview() GET /v1/us/assets/overview
us_realized_pl(currency, category) GET /v1/us/assets/pl/realized

Language coverage

Layer Status
Rust core (rust/src/) ✅ async methods + dc_restrict(DcRegion::Us)
Blocking (rust/src/blocking/) ✅ sync wrappers
Python (python/src/) ✅ sync + async #[pymethods]
Node.js (nodejs/src/) #[napi] async
Java (java/src/) ✅ JNI stubs (JSON string return)

Notes

  • Flexible response shapes (financial_overview, key_financial_metrics, analyst_consensus, order list) are returned as serde_json::Value / JSON strings in language bindings
  • counter_id for US stocks is passed as-is (ST/US/AAPL format) — no conversion applied
  • All 4 crates compile without errors

🤖 Generated with Claude Code

huacnlee and others added 24 commits June 30, 2026 12:07
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>
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>
Base automatically changed from feat/us-dc-region to main July 3, 2026 02:14
hogan-yuan and others added 5 commits July 3, 2026 10:58
…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>
… 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>
hogan-yuan and others added 11 commits July 3, 2026 18:50
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>
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.

2 participants