Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
fd82543
fix(trade): restrict fund_positions and margin_ratio to AP accounts
hogan-yuan Oct 22, 2026
1da5510
feat(trade): add US cash, holding, transaction and exchange-rate APIs
hogan-yuan Oct 22, 2026
8b4049a
feat(bindings): expose US asset APIs in Python, Node.js and Java
hogan-yuan Oct 22, 2026
1ff34ab
docs(changelog): add US asset APIs and AP-only fund/margin calls
hogan-yuan Oct 22, 2026
f8877d2
fix(trade): parse US transaction history with both symbol and counter_id
hogan-yuan Oct 22, 2026
62c5ac5
Merge origin/main into feat/us-asset-apis
hogan-yuan Oct 22, 2026
cab7903
fix(trade): keep quantity and prices on US crypto holdings
hogan-yuan Oct 22, 2026
e090edd
fix(trade): restrict order_detail to AP accounts
hogan-yuan Oct 22, 2026
b33d159
fix(trade): restrict balance, cash flow, positions and exchange rate …
hogan-yuan Oct 23, 2026
5679629
style: wrap long comments for the latest nightly rustfmt
hogan-yuan Oct 23, 2026
93f3b42
fix(httpclient): name the alternative API in region errors
hogan-yuan Oct 23, 2026
059c009
fix(httpclient): name alternatives by endpoint in region errors
hogan-yuan Oct 23, 2026
a932a17
fix(trade): restrict all_executions to AP and point US fundamentals h…
hogan-yuan Oct 23, 2026
a69be57
fix(http): point the US key-metrics hint at the AP earnings snapshot
hogan-yuan Oct 23, 2026
16356f2
fix(trade): default Execution.side when the response omits it
hogan-yuan Oct 23, 2026
f802980
docs(changelog): keep the Fixed list layout
hogan-yuan Oct 23, 2026
1f1b90d
docs(trade): note Unknown execution side on US accounts
hogan-yuan Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **Rust core (async + blocking), Node.js, Python:** four US-account asset methods on `TradeContext`, all restricted to US data-center tokens (`dc_restrict(DcRegion::Us)`, so a non-US token gets `HttpClientError::DcRegionRestricted` without a request):
- `us_cash_and_buy_power(currency)` — `GET /v1/us/assets/cash-and-buy-power`: buying power (`USBuyLimitInfo`), cash per currency (`USCashDetail`) and margin status (`USMarginStatus`) as `USCashAndBuyPower`.
- `us_available_holding(opts)` — `GET /v1/us/assets/available-holding`: quantity of a stock / option / crypto holding available to trade (`USAvailableHolding`); `equity_type` defaults to `STOCK`, `position_side` to `LONG`.
- `us_transaction_history(opts)` — `POST /v1/us/assets/transaction-history`: one page of account transactions (`USTransactionHistory` / `USTransaction`) between two times, with optional transaction-type and currency filters (`page` defaults to 1, `size` to 20).
- `us_exchange_rates()` — `GET /v1/us/assets/exchange-rates`: the upstream two-level map is flattened into `USExchangeRates.exchanges` (`USExchangeRate`), sorted by the two upstream map keys, which are kept on each entry as `universal_key` / `spec_key`; rates accept a JSON number or string and read as an empty string when absent.
- Node.js takes the transaction-history request as a `GetUSTransactionHistoryOptions` object; Python as `start_at` / `end_at` `datetime` plus keyword arguments; the `openapi.pyi` stub is updated.
- **Java:** JNI entry points for the four methods (`tradeContextUsCashAndBuyPower`, `tradeContextUsAvailableHolding`, `tradeContextUsTransactionHistory`, `tradeContextUsExchangeRates`), returning the response as JSON like the existing US JNI stubs; no Java-side `TradeContext` wrappers yet, matching the other US methods.

### Changed

- **All SDKs:** `fund_positions` and `margin_ratio` are AP-only (`dc_restrict(DcRegion::Ap)`): US data-center accounts have no fund holdings or margin-ratio data, so they now get a region error (`HttpClientError::DcRegionRestricted`) instead of an opaque server error. The method docs in every layer say so.
- **All SDKs:** `all_executions` (`GET /v3/trade/execution/all`) is AP-only (`dc_restrict(DcRegion::Ap)`). For a US data-center account the gateway answered HTTP 500 with code 12; it now gets a region error without sending the request. US accounts should use `history_executions` (`GET /v1/trade/execution/history`), which works in both regions. The method docs in every layer say so.
- **All SDKs:** `order_detail` is AP-only (`dc_restrict(DcRegion::Ap)`). For a US data-center account, `GET /v1/trade/order` returned HTTP 500 because the order gateway panics on US orders. It now gets a region error without sending the request. US accounts should use `us_order_detail` (`GET /v1/us/orders/{order_id}`).
- **All SDKs:** `TradeContext.account_balance` (`GET /v1/asset/account`), `TradeContext.cash_flow` (`GET /v1/asset/cashflow`), `TradeContext.stock_positions` (`GET /v1/asset/stock`) and `PortfolioContext.exchange_rate` (`GET /v1/asset/exchange_rates`) are AP-only (`dc_restrict(DcRegion::Ap)`). For a US data-center account the gateway rejected them with an opaque code 12; they now get a region error (`HttpClientError::DcRegionRestricted`) without sending the request. US accounts should use `us_cash_and_buy_power` / `us_asset_overview` (balance), `us_transaction_history` (cash flow), `us_asset_overview` `stock_list` (positions) and `us_exchange_rates`. The `fund_positions` and `margin_ratio` docs now state there is no US equivalent (for US margin info see `us_cash_and_buy_power` `margin_status`).
- **All SDKs:** the `HttpClientError::DcRegionRestricted` message (its `Display` text) gained a suffix naming the alternative by HTTP endpoint, so a caller (or an LLM agent) can recover without a lookup. The existing text is kept unchanged as a prefix and `; <hint>` is appended; code that matches the message by exact equality must be updated (prefix matching keeps working). The hint names endpoints rather than methods because the text is shared by every binding (Rust/Python snake_case, Node.js camelCase, Java/C/C++ without the US methods) and by MCP servers. US-region accounts calling an AP-only path: `/v1/asset/account` → `GET /v1/us/assets/cash-and-buy-power` or `GET /v1/us/assets/overview`; `/v1/asset/cashflow` → `POST /v1/us/assets/transaction-history`; `/v1/asset/stock` → `GET /v1/us/assets/overview`; `/v1/asset/exchange_rates` → `GET /v1/us/assets/exchange-rates` (TradeContext US methods); `/v1/trade/order` → `GET /v1/us/orders/{order_id}`; `/v3/trade/execution/all` → `GET /v1/trade/execution/history`; `/v1/risk/margin-ratio` → no US equivalent (account-level margin: `GET /v1/us/assets/cash-and-buy-power` `margin_status`); `/v1/asset/fund`, quote `brokers`, `/v1/quote/operatings`, `/v1/quote/broker-holding*` and DCA `/v1/dailycoins/*` → no US equivalent. AP-region accounts calling a US-only path: `/v1/us/orders/{id}` → `GET /v1/trade/order`; `/v1/us/orders/query` → `GET /v1/trade/order/today` or `/v1/trade/order/history`; `/v1/us/assets/overview` → `GET /v1/asset/account` + `GET /v1/asset/stock`; `/v1/us/assets/transaction-history` → `GET /v1/asset/cashflow`; `/v1/us/assets/exchange-rates` → `GET /v1/asset/exchange_rates`; `/v1/us/assets/cash-and-buy-power` → `GET /v1/asset/account`; `/v1/us/assets/available-holding` → `GET /v1/asset/stock` (`available_quantity`); US fundamentals → the AP fundamentals endpoints: `/v1/us/stock-info/company-overview` → `GET /v1/quote/comp-overview`, `/v1/us/stock-info/valuation-overview` → `GET /v1/quote/valuation`, `/v1/us/stock-info/finn-overview` and `/v1/us/quote/financials/statements` → `GET /v1/quote/financial-reports`, `/v1/us/stock-info/fin-keyfactor` → `GET /v1/quote/financials/earnings-snapshot`, `/v1/us/stock-info/fin-consensus` → `GET /v1/quote/financial-consensus-detail`, `/v1/us/stock-info/etf-dividend-info` and `/v1/us/stock-info/company-dividends` → `GET /v1/quote/dividends`; other US paths (realized P&L `/v1/us/assets/pl/realized`, crypto overview, ETF files) → no AP equivalent. The variant's fields are unchanged, and bindings still surface it as error kind `Other`.
- **Rust blocking, Python:** the AP-only methods on `TradeContextSync` / `PortfolioContextSync` now document the region restriction and the US alternative, and the `AsyncPortfolioContext.exchange_rate` docstring in `openapi.pyi` points to `AsyncTradeContext.us_exchange_rates` (not the sync `TradeContext`).

### Fixed

- **All SDKs:** `QuoteContext.option_chain_info_by_date` now calls `POST /v1/quote/options/strikes` with a JSON body. The `GET /v1/gemini/option/option_chain_list` endpoint it used since 5.1.0 was renamed on the gateway and returned `404000 api not found` in every region, so the method failed on every call. The signature and the returned `OptionChainContract` are unchanged
- **All SDKs:** `Execution.side` now defaults to `Unknown` when the response omits it. `/v1/trade/execution/history` returns trades without `side` for Longbridge US accounts, which made `history_executions` fail to deserialize.
- **Rust core, Node.js, Python:** `USAssetOverview.crypto_list` entries (`USCryptoEntry`) now carry the holding `quantity`, `market`, `name`, prices (`last_done`, `market_price`, `prev_close`, ...), `today_pl`, `position_side` and the other fields `GET /v1/us/assets/overview` returns for crypto, which were previously dropped, so a crypto holding could not be sized. `symbol` is the bare pair code (e.g. `BTCUSD`); the user-facing symbol is `<symbol>.<market>` (e.g. `BTCUSD.BKKT`).
- **All SDKs:** `QuoteContext.option_chain_info_by_date` now calls `POST /v1/quote/options/strikes` with a JSON body. The `GET /v1/gemini/option/option_chain_list` endpoint it used since 5.1.0 was renamed on the gateway and returned `404000 api not found` in every region, so the method failed on every call. The signature and the returned `OptionChainContract` are unchanged.

## [5.2.2] - 2026-10-16

Expand Down
24 changes: 23 additions & 1 deletion c/csrc/include/longbridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -5740,7 +5740,8 @@ typedef struct lb_execution_t {
*/
const struct lb_decimal_t *price;
/**
* Order side
* Order side. `Unknown` when the response omits it (Longbridge US
* `/v1/trade/execution/history`)
*/
enum lb_order_side_t side;
} lb_execution_t;
Expand Down Expand Up @@ -15659,6 +15660,8 @@ void lb_portfolio_context_release(const struct lb_portfolio_context_t *ctx);

/**
* Get exchange rates. Returns CExchangeRates.
*
* AP accounts only: US data-center accounts get a region error.
*/
void lb_portfolio_context_exchange_rate(const struct lb_portfolio_context_t *ctx,
lb_async_callback_t callback,
Expand Down Expand Up @@ -16390,6 +16393,8 @@ void lb_trade_context_unsubscribe(const struct lb_trade_context_t *ctx,
/**
* Get history executions
*
* `side` may be `Unknown` on Longbridge US accounts.
*
* @param[in] opts Options for get history executions request (can be null)
*/
void lb_trade_context_history_executions(const struct lb_trade_context_t *ctx,
Expand All @@ -16410,6 +16415,9 @@ void lb_trade_context_today_executions(const struct lb_trade_context_t *ctx,
/**
* Get all executions
*
* AP accounts only: US data-center accounts get a region error; use
* `lb_trade_context_history_executions` instead.
*
* @param[in] opts Options for get all executions request (can be null)
*/
void lb_trade_context_all_executions(const struct lb_trade_context_t *ctx,
Expand Down Expand Up @@ -16487,6 +16495,8 @@ void lb_trade_context_cancel_order_attached(const struct lb_trade_context_t *ctx

/**
* Get account balance
*
* AP accounts only: US data-center accounts get a region error.
*/
void lb_trade_context_account_balance(const struct lb_trade_context_t *ctx,
const char *currency,
Expand All @@ -16496,6 +16506,8 @@ void lb_trade_context_account_balance(const struct lb_trade_context_t *ctx,
/**
* Get cash flow
*
* AP accounts only: US data-center accounts get a region error.
*
* @param[in] opts Options for get cash flow request
*/
void lb_trade_context_cash_flow(const struct lb_trade_context_t *ctx,
Expand All @@ -16506,6 +16518,9 @@ void lb_trade_context_cash_flow(const struct lb_trade_context_t *ctx,
/**
* Get fund positions
*
* AP accounts only: US data-center accounts have no fund holdings and get a
* region error. No US equivalent.
*
* @param[in] opts Options for get fund positions request
*/
void lb_trade_context_fund_positions(const struct lb_trade_context_t *ctx,
Expand All @@ -16516,6 +16531,8 @@ void lb_trade_context_fund_positions(const struct lb_trade_context_t *ctx,
/**
* Get stock positions
*
* AP accounts only: US data-center accounts get a region error.
*
* @param[in] opts Options for get stock positions request
*/
void lb_trade_context_stock_positions(const struct lb_trade_context_t *ctx,
Expand All @@ -16525,6 +16542,9 @@ void lb_trade_context_stock_positions(const struct lb_trade_context_t *ctx,

/**
* Get margin ratio
*
* AP accounts only: US data-center accounts get a region error. No US
* equivalent.
*/
void lb_trade_context_margin_ratio(const struct lb_trade_context_t *ctx,
const char *symbol,
Expand All @@ -16533,6 +16553,8 @@ void lb_trade_context_margin_ratio(const struct lb_trade_context_t *ctx,

/**
* Get order detail
*
* AP accounts only: US data-center accounts get a region error.
*/
void lb_trade_context_order_detail(const struct lb_trade_context_t *ctx,
const char *order_id,
Expand Down
2 changes: 2 additions & 0 deletions c/src/portfolio_context/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub unsafe extern "C" fn lb_portfolio_context_release(ctx: *const CPortfolioCont
}

/// Get exchange rates. Returns CExchangeRates.
///
/// AP accounts only: US data-center accounts get a region error.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_portfolio_context_exchange_rate(
ctx: *const CPortfolioContext,
Expand Down
19 changes: 19 additions & 0 deletions c/src/trade_context/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ pub unsafe extern "C" fn lb_trade_context_unsubscribe(

/// Get history executions
///
/// `side` may be `Unknown` on Longbridge US accounts.
///
/// @param[in] opts Options for get history executions request (can be null)
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_history_executions(
Expand Down Expand Up @@ -311,6 +313,9 @@ pub unsafe extern "C" fn lb_trade_context_today_executions(

/// Get all executions
///
/// AP accounts only: US data-center accounts get a region error; use
/// `lb_trade_context_history_executions` instead.
///
/// @param[in] opts Options for get all executions request (can be null)
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_all_executions(
Expand Down Expand Up @@ -726,6 +731,8 @@ pub unsafe extern "C" fn lb_trade_context_cancel_order_attached(
}

/// Get account balance
///
/// AP accounts only: US data-center accounts get a region error.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_account_balance(
ctx: *const CTradeContext,
Expand All @@ -744,6 +751,8 @@ pub unsafe extern "C" fn lb_trade_context_account_balance(

/// Get cash flow
///
/// AP accounts only: US data-center accounts get a region error.
///
/// @param[in] opts Options for get cash flow request
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_cash_flow(
Expand Down Expand Up @@ -777,6 +786,9 @@ pub unsafe extern "C" fn lb_trade_context_cash_flow(

/// Get fund positions
///
/// AP accounts only: US data-center accounts have no fund holdings and get a
/// region error. No US equivalent.
///
/// @param[in] opts Options for get fund positions request
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_fund_positions(
Expand All @@ -799,6 +811,8 @@ pub unsafe extern "C" fn lb_trade_context_fund_positions(

/// Get stock positions
///
/// AP accounts only: US data-center accounts get a region error.
///
/// @param[in] opts Options for get stock positions request
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_stock_positions(
Expand All @@ -820,6 +834,9 @@ pub unsafe extern "C" fn lb_trade_context_stock_positions(
}

/// Get margin ratio
///
/// AP accounts only: US data-center accounts get a region error. No US
/// equivalent.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_margin_ratio(
ctx: *const CTradeContext,
Expand All @@ -836,6 +853,8 @@ pub unsafe extern "C" fn lb_trade_context_margin_ratio(
}

/// Get order detail
///
/// AP accounts only: US data-center accounts get a region error.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_trade_context_order_detail(
ctx: *const CTradeContext,
Expand Down
3 changes: 2 additions & 1 deletion c/src/trade_context/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,8 @@ pub struct CExecution {
pub quantity: *const CDecimal,
/// Executed price
pub price: *const CDecimal,
/// Order side
/// Order side. `Unknown` when the response omits it (Longbridge US
/// `/v1/trade/execution/history`)
pub side: COrderSide,
}

Expand Down
2 changes: 2 additions & 0 deletions cpp/include/portfolio_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ private: const lb_portfolio_context_t* ctx_;
/// Create a PortfolioContext from a Config.
static PortfolioContext create(const Config& config);
/// Get exchange rates for all supported currencies.
///
/// AP accounts only: US data-center accounts get a region error.
void exchange_rate(AsyncCallback<PortfolioContext, ExchangeRates> callback) const;
/// Get portfolio P&L analysis. start/end: optional "YYYY-MM-DD"; pass empty string for none.
void profit_analysis(const std::string& start, const std::string& end, AsyncCallback<PortfolioContext, ProfitAnalysis> callback) const;
Expand Down
19 changes: 19 additions & 0 deletions cpp/include/trade_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class TradeContext
PushCallback<TradeContext, PushOrderChanged> callback) const;

/// Get history executions
///
/// `side` may be `Unknown` on Longbridge US accounts.
void history_executions(
const std::optional<GetHistoryExecutionsOptions>& opts,
AsyncCallback<TradeContext, std::vector<Execution>> callback) const;
Expand All @@ -54,6 +56,9 @@ class TradeContext
AsyncCallback<TradeContext, std::vector<Execution>> callback) const;

/// Get all executions
///
/// AP accounts only: US data-center accounts get a region error; use
/// `history_executions` instead.
void all_executions(
const std::optional<GetAllExecutionsOptions>& opts,
AsyncCallback<TradeContext, AllExecutionsResponse> callback) const;
Expand Down Expand Up @@ -90,34 +95,48 @@ class TradeContext
bool is_attached = false) const;

/// Get account balance with currency
///
/// AP accounts only: US data-center accounts get a region error.
void account_balance(
const std::string& currency,
AsyncCallback<TradeContext, std::vector<AccountBalance>> callback) const;

/// Get account balance
///
/// AP accounts only: US data-center accounts get a region error.
void account_balance(
AsyncCallback<TradeContext, std::vector<AccountBalance>> callback) const;

/// Get cash flow
///
/// AP accounts only: US data-center accounts get a region error.
void account_balance(
const GetCashFlowOptions& opts,
AsyncCallback<TradeContext, std::vector<CashFlow>> callback) const;

/// Get fund positions
///
/// AP accounts only: US data-center accounts have no fund holdings and get a region error. No US equivalent.
void fund_positions(
const std::optional<GetFundPositionsOptions>& opts,
AsyncCallback<TradeContext, FundPositionsResponse> callback) const;

/// Get stock positions
///
/// AP accounts only: US data-center accounts get a region error.
void stock_positions(
const std::optional<GetStockPositionsOptions>& opts,
AsyncCallback<TradeContext, StockPositionsResponse> callback) const;

/// Get margin ratio
///
/// AP accounts only: US data-center accounts get a region error. No US equivalent.
void margin_ratio(const std::string& symbol,
AsyncCallback<TradeContext, MarginRatio> callback) const;

/// Get order detail
///
/// AP accounts only: US data-center accounts get a region error.
void order_detail(const std::string& order_id,
AsyncCallback<TradeContext, OrderDetail> callback) const;

Expand Down
3 changes: 2 additions & 1 deletion cpp/include/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,8 @@ struct Execution
int64_t trade_done_at;
Decimal quantity;
Decimal price;
/// Order side
/// Order side. `Unknown` when the response omits it (Longbridge US
/// `/v1/trade/execution/history`)
OrderSide side;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public synchronized void close() throws Exception {

/**
* Get exchange rates for supported currencies.
* <p>
* AP accounts only: US data-center accounts get a region error.
*
* @return A Future resolving to the current exchange rates
* @throws OpenApiException If an error occurs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public BigDecimal getPrice() {

/**
* Returns the order side.
* <p>
* {@code Unknown} when the response omits it (Longbridge US
* {@code /v1/trade/execution/history}).
*
* @return order side
*/
Expand Down
Loading
Loading