diff --git a/CHANGELOG.md b/CHANGELOG.md index be75bbb7d6..8a8eabc9e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 `; ` 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 `.` (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 diff --git a/c/csrc/include/longbridge.h b/c/csrc/include/longbridge.h index 4cb10fcec2..d81cba568f 100644 --- a/c/csrc/include/longbridge.h +++ b/c/csrc/include/longbridge.h @@ -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; @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, diff --git a/c/src/portfolio_context/context.rs b/c/src/portfolio_context/context.rs index 42b8ec1b84..b29261e323 100644 --- a/c/src/portfolio_context/context.rs +++ b/c/src/portfolio_context/context.rs @@ -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, diff --git a/c/src/trade_context/context.rs b/c/src/trade_context/context.rs index 897eff6e19..8ce00cb5d1 100644 --- a/c/src/trade_context/context.rs +++ b/c/src/trade_context/context.rs @@ -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( @@ -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( @@ -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, @@ -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( @@ -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( @@ -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( @@ -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, @@ -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, diff --git a/c/src/trade_context/types.rs b/c/src/trade_context/types.rs index 081b2ac772..e414e3f6e6 100644 --- a/c/src/trade_context/types.rs +++ b/c/src/trade_context/types.rs @@ -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, } diff --git a/cpp/include/portfolio_context.hpp b/cpp/include/portfolio_context.hpp index f099549cfc..96ad905413 100644 --- a/cpp/include/portfolio_context.hpp +++ b/cpp/include/portfolio_context.hpp @@ -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 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 callback) const; diff --git a/cpp/include/trade_context.hpp b/cpp/include/trade_context.hpp index 32e85f08c2..f395bce1ae 100644 --- a/cpp/include/trade_context.hpp +++ b/cpp/include/trade_context.hpp @@ -44,6 +44,8 @@ class TradeContext PushCallback callback) const; /// Get history executions + /// + /// `side` may be `Unknown` on Longbridge US accounts. void history_executions( const std::optional& opts, AsyncCallback> callback) const; @@ -54,6 +56,9 @@ class TradeContext AsyncCallback> 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& opts, AsyncCallback callback) const; @@ -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> callback) const; /// Get account balance + /// + /// AP accounts only: US data-center accounts get a region error. void account_balance( AsyncCallback> callback) const; /// Get cash flow + /// + /// AP accounts only: US data-center accounts get a region error. void account_balance( const GetCashFlowOptions& opts, AsyncCallback> 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& opts, AsyncCallback callback) const; /// Get stock positions + /// + /// AP accounts only: US data-center accounts get a region error. void stock_positions( const std::optional& opts, AsyncCallback 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 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 callback) const; diff --git a/cpp/include/types.hpp b/cpp/include/types.hpp index 069660d3c5..523a4f69d7 100644 --- a/cpp/include/types.hpp +++ b/cpp/include/types.hpp @@ -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; }; diff --git a/java/javasrc/src/main/java/com/longbridge/portfolio/PortfolioContext.java b/java/javasrc/src/main/java/com/longbridge/portfolio/PortfolioContext.java index 19328b81b8..42c526c6a0 100644 --- a/java/javasrc/src/main/java/com/longbridge/portfolio/PortfolioContext.java +++ b/java/javasrc/src/main/java/com/longbridge/portfolio/PortfolioContext.java @@ -31,6 +31,8 @@ public synchronized void close() throws Exception { /** * Get exchange rates for supported currencies. + *

+ * 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 diff --git a/java/javasrc/src/main/java/com/longbridge/trade/Execution.java b/java/javasrc/src/main/java/com/longbridge/trade/Execution.java index 6bae9831ec..c3ed68a762 100644 --- a/java/javasrc/src/main/java/com/longbridge/trade/Execution.java +++ b/java/javasrc/src/main/java/com/longbridge/trade/Execution.java @@ -71,6 +71,9 @@ public BigDecimal getPrice() { /** * Returns the order side. + *

+ * {@code Unknown} when the response omits it (Longbridge US + * {@code /v1/trade/execution/history}). * * @return order side */ diff --git a/java/javasrc/src/main/java/com/longbridge/trade/TradeContext.java b/java/javasrc/src/main/java/com/longbridge/trade/TradeContext.java index 71b46c4c84..2cbf9b13d5 100644 --- a/java/javasrc/src/main/java/com/longbridge/trade/TradeContext.java +++ b/java/javasrc/src/main/java/com/longbridge/trade/TradeContext.java @@ -108,6 +108,8 @@ public synchronized CompletableFuture unsubscribe(TopicType[] topics) thro /** * Get history executions + *

+ * {@code side} may be {@code Unknown} on Longbridge US accounts. * *

      * {@code
@@ -181,6 +183,9 @@ public synchronized CompletableFuture getTodayExecutions(GetTodayEx
 
     /**
      * Get all executions
+     * 

+ * AP accounts only: US data-center accounts get a region error; use + * {@link #getHistoryExecutions} instead. * * @param opts Options for this request * @return A Future representing the result of the operation @@ -435,6 +440,8 @@ public synchronized CompletableFuture cancelOrder(String orderId, boolean /** * Get account balance with currency + *

+ * AP accounts only: US data-center accounts get a region error. * *

      * {@code
@@ -468,6 +475,8 @@ public synchronized CompletableFuture getAccountBalance(String
 
     /**
      * Get account balance
+     * 

+ * AP accounts only: US data-center accounts get a region error. * *

      * {@code
@@ -500,6 +509,8 @@ public synchronized CompletableFuture getAccountBalance() thro
 
     /**
      * Get cash flow
+     * 

+ * AP accounts only: US data-center accounts get a region error. * *

      * {@code
@@ -537,6 +548,8 @@ public synchronized CompletableFuture getCashFlow(GetCashFlowOptions
 
     /**
      * Get fund positions
+     * 

+ * AP accounts only: US data-center accounts have no fund holdings and get a region error. No US equivalent. * *

      * {@code
@@ -569,6 +582,8 @@ public synchronized CompletableFuture getFundPositions(Ge
 
     /**
      * Get stock positions
+     * 

+ * AP accounts only: US data-center accounts get a region error. * *

      * {@code
@@ -601,6 +616,8 @@ public synchronized CompletableFuture getStockPositions(
 
     /**
      * Get margin ratio
+     * 

+ * AP accounts only: US data-center accounts get a region error. No US equivalent. * *

      * {@code
@@ -633,6 +650,8 @@ public synchronized CompletableFuture getMarginRatio(String symbol)
 
     /**
      * Get order detail
+     * 

+ * AP accounts only: US data-center accounts get a region error. * *

      * {@code
diff --git a/java/src/init.rs b/java/src/init.rs
index 154b7caa35..fa1e80222a 100644
--- a/java/src/init.rs
+++ b/java/src/init.rs
@@ -288,7 +288,8 @@ pub extern "system" fn Java_com_longbridge_SdkNative_init<'a>(
         longbridge::dca::DcaSupportInfo,
         longbridge::dca::DcaSupportList,
         longbridge::dca::DcaCalcDateResult,
-        // AlertContext - list returns JSON via AlertList IntoJValue (serde_json)
+        // AlertContext - list returns JSON via AlertList IntoJValue
+        // (serde_json)
         longbridge::dca::DcaPlan,
         longbridge::dca::DcaList,
         longbridge::dca::DcaStats,
@@ -360,7 +361,8 @@ pub extern "system" fn Java_com_longbridge_SdkNative_init<'a>(
         longbridge::dca::DcaSupportInfo,
         longbridge::dca::DcaSupportList,
         longbridge::dca::DcaCalcDateResult,
-        // AlertContext - list returns JSON via AlertList IntoJValue (serde_json)
+        // AlertContext - list returns JSON via AlertList IntoJValue
+        // (serde_json)
         longbridge::dca::DcaPlan,
         longbridge::dca::DcaList,
         longbridge::dca::DcaStats,
diff --git a/java/src/trade_context.rs b/java/src/trade_context.rs
index 2ab577fbad..75c233a2fb 100644
--- a/java/src/trade_context.rs
+++ b/java/src/trade_context.rs
@@ -23,7 +23,7 @@ use time::{Date, OffsetDateTime};
 
 use crate::{
     async_util,
-    error::jni_result,
+    error::{JniError, jni_result},
     types::{FromJValue, IntoJValue, JavaInteger, JavaLong, ObjectArray, get_field},
 };
 
@@ -1091,6 +1091,111 @@ pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextUsRealiz
     })
 }
 
+#[unsafe(no_mangle)]
+pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextUsCashAndBuyPower(
+    mut env: JNIEnv,
+    _class: JClass,
+    context: i64,
+    currency: JObject,
+    callback: JObject,
+) {
+    jni_result(&mut env, (), |env| {
+        let context = &*(context as *const ContextObj);
+        let __owned_ctx = context.ctx.clone();
+        let currency: Option = FromJValue::from_jvalue(env, currency.into())?;
+        async_util::execute(env, callback, async move {
+            let resp = __owned_ctx
+                .us_cash_and_buy_power(currency.as_deref())
+                .await?;
+            Ok(serde_json::to_string(&resp).unwrap_or_default())
+        })?;
+        Ok(())
+    })
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextUsAvailableHolding(
+    mut env: JNIEnv,
+    _class: JClass,
+    context: i64,
+    symbol: JObject,
+    equity_type: JObject,
+    position_side: JObject,
+    callback: JObject,
+) {
+    jni_result(&mut env, (), |env| {
+        let context = &*(context as *const ContextObj);
+        let __owned_ctx = context.ctx.clone();
+        let symbol: String = FromJValue::from_jvalue(env, symbol.into())?;
+        let equity_type: Option = FromJValue::from_jvalue(env, equity_type.into())?;
+        let position_side: Option = FromJValue::from_jvalue(env, position_side.into())?;
+        async_util::execute(env, callback, async move {
+            let resp = __owned_ctx
+                .us_available_holding(longbridge::trade::GetUSAvailableHoldingOptions {
+                    symbol,
+                    equity_type: equity_type.unwrap_or_default(),
+                    position_side: position_side.unwrap_or_default(),
+                })
+                .await?;
+            Ok(serde_json::to_string(&resp).unwrap_or_default())
+        })?;
+        Ok(())
+    })
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextUsTransactionHistory(
+    mut env: JNIEnv,
+    _class: JClass,
+    context: i64,
+    start_at: i64,
+    end_at: i64,
+    page: i64,
+    size: i64,
+    types: JObject,
+    currency: JObject,
+    callback: JObject,
+) {
+    jni_result(&mut env, (), |env| {
+        let context = &*(context as *const ContextObj);
+        let __owned_ctx = context.ctx.clone();
+        let types: ObjectArray = FromJValue::from_jvalue(env, types.into())?;
+        let currency: Option = FromJValue::from_jvalue(env, currency.into())?;
+        let start_at = OffsetDateTime::from_unix_timestamp(start_at)
+            .map_err(|err| JniError::Other(format!("invalid start_at: {err}")))?;
+        let end_at = OffsetDateTime::from_unix_timestamp(end_at)
+            .map_err(|err| JniError::Other(format!("invalid end_at: {err}")))?;
+        let mut opts = longbridge::trade::GetUSTransactionHistoryOptions::new(start_at, end_at);
+        opts.page = page as i32;
+        opts.size = size as i32;
+        opts.types = types.0;
+        opts.currency = currency.unwrap_or_default();
+        async_util::execute(env, callback, async move {
+            let resp = __owned_ctx.us_transaction_history(opts).await?;
+            Ok(serde_json::to_string(&resp).unwrap_or_default())
+        })?;
+        Ok(())
+    })
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextUsExchangeRates(
+    mut env: JNIEnv,
+    _class: JClass,
+    context: i64,
+    callback: JObject,
+) {
+    jni_result(&mut env, (), |env| {
+        let context = &*(context as *const ContextObj);
+        let __owned_ctx = context.ctx.clone();
+        async_util::execute(env, callback, async move {
+            let resp = __owned_ctx.us_exchange_rates().await?;
+            Ok(serde_json::to_string(&resp).unwrap_or_default())
+        })?;
+        Ok(())
+    })
+}
+
 #[unsafe(no_mangle)]
 pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextOrderDetailAttached(
     mut env: JNIEnv,
diff --git a/nodejs/index.d.ts b/nodejs/index.d.ts
index 9a4213f07c..ad1a992a39 100644
--- a/nodejs/index.d.ts
+++ b/nodejs/index.d.ts
@@ -716,7 +716,10 @@ export declare class Execution {
   get quantity(): Decimal
   /** Executed price */
   get price(): Decimal
-  /** Order side */
+  /**
+   * Order side. `Unknown` when the response omits it (Longbridge US
+   * `/v1/trade/execution/history`)
+   */
   get side(): OrderSide
 }
 
@@ -2953,7 +2956,12 @@ export declare class ParticipantInfo {
 export declare class PortfolioContext {
   /** Create a new PortfolioContext. */
   static new(config: Config): PortfolioContext
-  /** Get exchange rates for supported currencies. */
+  /**
+   * Get exchange rates for supported currencies.
+   *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `TradeContext.usExchangeRates` instead.
+   */
   exchangeRate(): Promise
   /**
    * Get portfolio P&L analysis (summary + per-security breakdown).
@@ -4314,6 +4322,8 @@ export declare class TradeContext {
   /**
    * Get history executions
    *
+   * `side` may be `Unknown` on Longbridge US accounts.
+   *
    * #### Example
    *
    * ```javascript
@@ -4349,7 +4359,12 @@ export declare class TradeContext {
    * ```
    */
   todayExecutions(opts?: GetTodayExecutionsOptions | undefined | null): Promise>
-  /** Get all executions */
+  /**
+   * Get all executions
+   *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `historyExecutions` instead.
+   */
   allExecutions(opts?: GetAllExecutionsOptions | undefined | null): Promise
   /**
    * Get history orders
@@ -4507,6 +4522,9 @@ export declare class TradeContext {
   /**
    * Get account balance
    *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `usCashAndBuyPower` (or `usAssetOverview`) instead.
+   *
    * #### Example
    *
    * ```javascript
@@ -4524,6 +4542,9 @@ export declare class TradeContext {
   /**
    * Get cash flow
    *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `usTransactionHistory` instead.
+   *
    * #### Example
    *
    * ```javascript
@@ -4544,6 +4565,9 @@ export declare class TradeContext {
   /**
    * Get fund positions
    *
+   * AP accounts only: US data-center accounts have no fund holdings and
+   * get a region error. No US equivalent.
+   *
    * #### Example
    *
    * ```javascript
@@ -4559,6 +4583,9 @@ export declare class TradeContext {
   /**
    * Get stock positions
    *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `usAssetOverview` (`stockList`) instead.
+   *
    * #### Example
    *
    * ```javascript
@@ -4574,6 +4601,10 @@ export declare class TradeContext {
   /**
    * Get margin ratio
    *
+   * AP accounts only: US data-center accounts get a region error. No US
+   * equivalent; for US margin info see `usCashAndBuyPower`
+   * (`marginStatus`).
+   *
    * #### Example
    *
    * ```javascript
@@ -4589,6 +4620,9 @@ export declare class TradeContext {
   /**
    * Get order detail
    *
+   * AP accounts only: US data-center accounts get a region error; use
+   * `usOrderDetail` instead.
+   *
    * #### Example
    *
    * ```javascript
@@ -4612,6 +4646,28 @@ export declare class TradeContext {
   usAssetOverview(): Promise
   /** Get US realized P&L. US token required. */
   usRealizedPl(currency: string, category?: string | undefined | null): Promise
+  /**
+   * Get cash, buying power and margin status for the US account. US token
+   * required.
+   *
+   * `currency`: optional, e.g. `"USD"`.
+   */
+  usCashAndBuyPower(currency?: string | undefined | null): Promise
+  /**
+   * Get the quantity of a US holding that is available to trade. US token
+   * required.
+   *
+   * `equityType`: `"STOCK"` (default), `"OPTION"` or `"CRYPTO"`;
+   * `positionSide`: `"LONG"` (default) or `"SHORT"`.
+   */
+  usAvailableHolding(symbol: string, equityType?: string | undefined | null, positionSide?: string | undefined | null): Promise
+  /**
+   * Get the US account transaction history, one page at a time. US token
+   * required.
+   */
+  usTransactionHistory(opts: GetUSTransactionHistoryOptions): Promise
+  /** Get the exchange rates used by the US account. US token required. */
+  usExchangeRates(): Promise
   orderDetailAttached(orderId: string): Promise
   /**
    * Estimating the maximum purchase quantity for Hong Kong and US stocks,
@@ -6718,6 +6774,28 @@ export interface GetTodayOrdersOptions {
   isAttached?: boolean
 }
 
+/** Options for the US transaction history request */
+export interface GetUSTransactionHistoryOptions {
+  /** Start time (inclusive) */
+  startAt: Date
+  /** End time (inclusive) */
+  endAt: Date
+  /** Page number, starting at 1 (default 1) */
+  page?: number
+  /** Page size (default 20) */
+  size?: number
+  /**
+   * Transaction types to include; empty means all. Values:
+   * `TT_DEPOSIT_AND_WITHDRAWAL`, `TT_STOCKS_AND_ETFS_TRADING`,
+   * `TT_OPTIONS_TRADING`, `TT_CRYPTO_TRADING`, `TT_CORPORATE_ACTION`,
+   * `TT_TRANSFER_IN_AND_OUT`, `TT_CRYPTO_TRANSFER`, `TT_MARGIN_FINANCING`,
+   * `TT_OTHER`
+   */
+  types?: Array
+  /** Currency filter, e.g. `USD`; empty means all */
+  currency?: string
+}
+
 /** Data granularity */
 export declare const enum Granularity {
   /** Unknown */
@@ -9065,6 +9143,11 @@ export interface USAttachedOrder {
   withdrawn: boolean
 }
 
+/** Quantity of a US holding that is available to trade */
+export interface USAvailableHolding {
+  availableQty: string
+}
+
 /** Action-button state for an order. */
 export interface USButtonControl {
   withdraw: number
@@ -9072,6 +9155,38 @@ export interface USButtonControl {
   exceptionable: Array
 }
 
+/** Buying power in USCashAndBuyPower */
+export interface USBuyLimitInfo {
+  currency: string
+  cashBuyPower: string
+  overnightBuyPower: string
+  dayTradeBuyPower: string
+  instantBuyPower: string
+  intradayMarginBuyPower: string
+  optionBuyPower: string
+  cryptoBuyPower: string
+  mme: string
+}
+
+/** Cash, buying power and margin status of a US account */
+export interface USCashAndBuyPower {
+  buyLimitInfo: USBuyLimitInfo
+  cashList: Array
+  marginStatus: USMarginStatus
+}
+
+/** One cash currency entry in USCashAndBuyPower */
+export interface USCashDetail {
+  currency: string
+  totalAmount: string
+  availableCash: string
+  withdrawCash: string
+  frozenCash: string
+  settledCash: string
+  outstanding: string
+  externalAmount: string
+}
+
 /** One cash currency entry in USAssetOverview */
 export interface USCashEntry {
   currency: string
@@ -9132,9 +9247,26 @@ export interface USConsensusItem {
 /** One cryptocurrency holding in USAssetOverview */
 export interface USCryptoEntry {
   assetType: string
-  averageCost: string
   symbol: string
+  quantity: string
   currency: string
+  averageCost: string
+  market: string
+  tradeStatus: string
+  prevClose: string
+  lastDone: string
+  marketPrice: string
+  pretradeClose: string
+  stockInvestOfToday: string
+  todayPl: string
+  pretradeStockInvestOfToday: string
+  pretradeTodayPl: string
+  nightLastDone: string
+  nightPrevClose: string
+  positionSide: string
+  openPositionTime: string
+  name: string
+  industryCounterId: string
   industryName: string
 }
 
@@ -9222,6 +9354,22 @@ export interface USETFFilesResponse {
   files: Array
 }
 
+/** One exchange rate in USExchangeRates */
+export interface USExchangeRate {
+  universalKey: string
+  specKey: string
+  baseCurrency: string
+  otherCurrency: string
+  bidRate: string
+  offerRate: string
+  averageRate: string
+}
+
+/** Exchange rates of a US account */
+export interface USExchangeRates {
+  exchanges: Array
+}
+
 /** One balance-sheet entry in USFinancialOverview. */
 export interface USFinancialBSItem {
   debtAssetsRatio: string
@@ -9312,6 +9460,17 @@ export interface USKeyMetricItem {
   fields: Array
 }
 
+/** Margin account status in USCashAndBuyPower */
+export interface USMarginStatus {
+  currency: string
+  nlv: string
+  marginEquity: string
+  marginMaintenanceExcess: string
+  mmr: string
+  regTExcess: string
+  sma: string
+}
+
 /** Full typed order object within USOrderDetailResponse. */
 export interface USOrderDetail {
   id: string
@@ -9498,6 +9657,31 @@ export interface USStockEntry {
   industryName: string
 }
 
+/** One record in USTransactionHistory */
+export interface USTransaction {
+  title: string
+  bizCode: string
+  bizCodeName: string
+  amount: string
+  currency: string
+  symbol: string
+  market: string
+  equityType: string
+  positionSide: string
+  quantity: string
+  quantityDescription: string
+  refNo: string
+  remark: string
+  createAt?: Date
+  doneAt?: Date
+}
+
+/** One page of US account transaction history */
+export interface USTransactionHistory {
+  currentPage: number
+  items: Array
+}
+
 /** One valuation metric entry in USValuationOverview.metrics */
 export interface USValuationMetric {
   circle: string
diff --git a/nodejs/src/portfolio/context.rs b/nodejs/src/portfolio/context.rs
index 004ff58812..a9a4712d5e 100644
--- a/nodejs/src/portfolio/context.rs
+++ b/nodejs/src/portfolio/context.rs
@@ -22,6 +22,9 @@ impl PortfolioContext {
     }
 
     /// Get exchange rates for supported currencies.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `TradeContext.usExchangeRates` instead.
     #[napi]
     pub async fn exchange_rate(&self) -> Result {
         Ok(self.ctx.exchange_rate().await.map_err(ErrorNewType)?.into())
diff --git a/nodejs/src/trade/context.rs b/nodejs/src/trade/context.rs
index 2b3bb169c5..2684d1db31 100644
--- a/nodejs/src/trade/context.rs
+++ b/nodejs/src/trade/context.rs
@@ -11,8 +11,8 @@ use crate::{
         requests::{
             EstimateMaxPurchaseQuantityOptions, GetAllExecutionsOptions, GetCashFlowOptions,
             GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetTodayExecutionsOptions,
-            GetTodayOrdersOptions, ReplaceOrderOptions, SubmitMultiLegOrderOptions,
-            SubmitOrderOptions,
+            GetTodayOrdersOptions, GetUSTransactionHistoryOptions, ReplaceOrderOptions,
+            SubmitMultiLegOrderOptions, SubmitOrderOptions,
         },
         types::{
             AccountBalance, AllExecutionsResponse, CashFlow, EstimateMaxPurchaseQuantityResponse,
@@ -172,6 +172,8 @@ impl TradeContext {
 
     /// Get history executions
     ///
+    /// `side` may be `Unknown` on Longbridge US accounts.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -231,6 +233,9 @@ impl TradeContext {
     }
 
     /// Get all executions
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `historyExecutions` instead.
     #[napi]
     pub async fn all_executions(
         &self,
@@ -457,6 +462,9 @@ impl TradeContext {
 
     /// Get account balance
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `usCashAndBuyPower` (or `usAssetOverview`) instead.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -482,6 +490,9 @@ impl TradeContext {
 
     /// Get cash flow
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `usTransactionHistory` instead.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -510,6 +521,9 @@ impl TradeContext {
 
     /// Get fund positions
     ///
+    /// AP accounts only: US data-center accounts have no fund holdings and
+    /// get a region error. No US equivalent.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -534,6 +548,9 @@ impl TradeContext {
 
     /// Get stock positions
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `usAssetOverview` (`stockList`) instead.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -558,6 +575,10 @@ impl TradeContext {
 
     /// Get margin ratio
     ///
+    /// AP accounts only: US data-center accounts get a region error. No US
+    /// equivalent; for US margin info see `usCashAndBuyPower`
+    /// (`marginStatus`).
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -579,6 +600,9 @@ impl TradeContext {
 
     /// Get order detail
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `usOrderDetail` instead.
+    ///
     /// #### Example
     ///
     /// ```javascript
@@ -684,6 +708,84 @@ impl TradeContext {
         })
     }
 
+    /// Get cash, buying power and margin status for the US account. US token
+    /// required.
+    ///
+    /// `currency`: optional, e.g. `"USD"`.
+    #[napi]
+    pub fn us_cash_and_buy_power<'env>(
+        &self,
+        env: &'env Env,
+        currency: Option,
+    ) -> Result> {
+        let ctx = self.ctx.clone();
+        env.spawn_future(async move {
+            Ok(ctx
+                .us_cash_and_buy_power(currency.as_deref())
+                .await
+                .map_err(ErrorNewType)?
+                .into())
+        })
+    }
+
+    /// Get the quantity of a US holding that is available to trade. US token
+    /// required.
+    ///
+    /// `equityType`: `"STOCK"` (default), `"OPTION"` or `"CRYPTO"`;
+    /// `positionSide`: `"LONG"` (default) or `"SHORT"`.
+    #[napi]
+    pub fn us_available_holding<'env>(
+        &self,
+        env: &'env Env,
+        symbol: String,
+        equity_type: Option,
+        position_side: Option,
+    ) -> Result> {
+        let ctx = self.ctx.clone();
+        env.spawn_future(async move {
+            Ok(ctx
+                .us_available_holding(longbridge::trade::GetUSAvailableHoldingOptions {
+                    symbol,
+                    equity_type: equity_type.unwrap_or_default(),
+                    position_side: position_side.unwrap_or_default(),
+                })
+                .await
+                .map_err(ErrorNewType)?
+                .into())
+        })
+    }
+
+    /// Get the US account transaction history, one page at a time. US token
+    /// required.
+    #[napi]
+    pub fn us_transaction_history<'env>(
+        &self,
+        env: &'env Env,
+        opts: GetUSTransactionHistoryOptions,
+    ) -> Result> {
+        let ctx = self.ctx.clone();
+        let opts = opts.into();
+        env.spawn_future(async move {
+            Ok(ctx
+                .us_transaction_history(opts)
+                .await
+                .map_err(ErrorNewType)?
+                .into())
+        })
+    }
+
+    /// Get the exchange rates used by the US account. US token required.
+    #[napi]
+    pub fn us_exchange_rates<'env>(
+        &self,
+        env: &'env Env,
+    ) -> Result> {
+        let ctx = self.ctx.clone();
+        env.spawn_future(
+            async move { Ok(ctx.us_exchange_rates().await.map_err(ErrorNewType)?.into()) },
+        )
+    }
+
     #[napi]
     pub async fn order_detail_attached(&self, order_id: String) -> Result {
         self.ctx
diff --git a/nodejs/src/trade/requests/get_us_transaction_history.rs b/nodejs/src/trade/requests/get_us_transaction_history.rs
new file mode 100644
index 0000000000..c77c09bf16
--- /dev/null
+++ b/nodejs/src/trade/requests/get_us_transaction_history.rs
@@ -0,0 +1,43 @@
+use chrono::{DateTime, Utc};
+
+use crate::utils::from_datetime;
+
+/// Options for the US transaction history request
+#[napi_derive::napi(object, js_name = "GetUSTransactionHistoryOptions")]
+pub struct GetUSTransactionHistoryOptions {
+    /// Start time (inclusive)
+    pub start_at: DateTime,
+    /// End time (inclusive)
+    pub end_at: DateTime,
+    /// Page number, starting at 1 (default 1)
+    pub page: Option,
+    /// Page size (default 20)
+    pub size: Option,
+    /// Transaction types to include; empty means all. Values:
+    /// `TT_DEPOSIT_AND_WITHDRAWAL`, `TT_STOCKS_AND_ETFS_TRADING`,
+    /// `TT_OPTIONS_TRADING`, `TT_CRYPTO_TRADING`, `TT_CORPORATE_ACTION`,
+    /// `TT_TRANSFER_IN_AND_OUT`, `TT_CRYPTO_TRANSFER`, `TT_MARGIN_FINANCING`,
+    /// `TT_OTHER`
+    pub types: Option>,
+    /// Currency filter, e.g. `USD`; empty means all
+    pub currency: Option,
+}
+
+impl From for longbridge::trade::GetUSTransactionHistoryOptions {
+    #[inline]
+    fn from(opts: GetUSTransactionHistoryOptions) -> Self {
+        let mut opts2 = longbridge::trade::GetUSTransactionHistoryOptions::new(
+            from_datetime(opts.start_at),
+            from_datetime(opts.end_at),
+        );
+        if let Some(page) = opts.page {
+            opts2.page = page;
+        }
+        if let Some(size) = opts.size {
+            opts2.size = size;
+        }
+        opts2.types = opts.types.unwrap_or_default();
+        opts2.currency = opts.currency.unwrap_or_default();
+        opts2
+    }
+}
diff --git a/nodejs/src/trade/requests/mod.rs b/nodejs/src/trade/requests/mod.rs
index e31531851d..649ec90f6b 100644
--- a/nodejs/src/trade/requests/mod.rs
+++ b/nodejs/src/trade/requests/mod.rs
@@ -5,6 +5,7 @@ mod get_history_executions;
 mod get_history_orders;
 mod get_today_executions;
 mod get_today_orders;
+mod get_us_transaction_history;
 mod replace_order;
 mod submit_multileg;
 mod submit_order;
@@ -16,6 +17,7 @@ pub use get_history_executions::GetHistoryExecutionsOptions;
 pub use get_history_orders::GetHistoryOrdersOptions;
 pub use get_today_executions::GetTodayExecutionsOptions;
 pub use get_today_orders::GetTodayOrdersOptions;
+pub use get_us_transaction_history::GetUSTransactionHistoryOptions;
 pub use replace_order::ReplaceOrderOptions;
 pub use submit_multileg::SubmitMultiLegOrderOptions;
 pub use submit_order::SubmitOrderOptions;
diff --git a/nodejs/src/trade/types.rs b/nodejs/src/trade/types.rs
index 0766f4c070..c75382642c 100644
--- a/nodejs/src/trade/types.rs
+++ b/nodejs/src/trade/types.rs
@@ -1,7 +1,7 @@
 use chrono::{DateTime, Utc};
 use longbridge_nodejs_macros::{JsEnum, JsObject};
 
-use crate::{decimal::Decimal, time::NaiveDate, types::Market};
+use crate::{decimal::Decimal, time::NaiveDate, types::Market, utils::to_datetime};
 
 /// Topic type
 #[napi_derive::napi]
@@ -30,7 +30,8 @@ pub struct Execution {
     quantity: Decimal,
     /// Executed price
     price: Decimal,
-    /// Order side
+    /// Order side. `Unknown` when the response omits it (Longbridge US
+    /// `/v1/trade/execution/history`)
     side: OrderSide,
 }
 
@@ -1031,9 +1032,26 @@ impl From for USCashEntry {
 #[derive(Debug, Clone, Default)]
 pub struct USCryptoEntry {
     pub asset_type: String,
-    pub average_cost: String,
     pub symbol: String,
+    pub quantity: String,
     pub currency: String,
+    pub average_cost: String,
+    pub market: String,
+    pub trade_status: String,
+    pub prev_close: String,
+    pub last_done: String,
+    pub market_price: String,
+    pub pretrade_close: String,
+    pub stock_invest_of_today: String,
+    pub today_pl: String,
+    pub pretrade_stock_invest_of_today: String,
+    pub pretrade_today_pl: String,
+    pub night_last_done: String,
+    pub night_prev_close: String,
+    pub position_side: String,
+    pub open_position_time: String,
+    pub name: String,
+    pub industry_counter_id: String,
     pub industry_name: String,
 }
 
@@ -1041,9 +1059,26 @@ impl From for USCryptoEntry {
     fn from(v: longbridge::trade::USCryptoEntry) -> Self {
         Self {
             asset_type: v.asset_type,
-            average_cost: v.average_cost,
             symbol: v.symbol,
+            quantity: v.quantity,
             currency: v.currency,
+            average_cost: v.average_cost,
+            market: v.market,
+            trade_status: v.trade_status,
+            prev_close: v.prev_close,
+            last_done: v.last_done,
+            market_price: v.market_price,
+            pretrade_close: v.pretrade_close,
+            stock_invest_of_today: v.stock_invest_of_today,
+            today_pl: v.today_pl,
+            pretrade_stock_invest_of_today: v.pretrade_stock_invest_of_today,
+            pretrade_today_pl: v.pretrade_today_pl,
+            night_last_done: v.night_last_done,
+            night_prev_close: v.night_prev_close,
+            position_side: v.position_side,
+            open_position_time: v.open_position_time,
+            name: v.name,
+            industry_counter_id: v.industry_counter_id,
             industry_name: v.industry_name,
         }
     }
@@ -1197,6 +1232,229 @@ impl From for USRealizedPL {
     }
 }
 
+/// Quantity of a US holding that is available to trade
+#[napi_derive::napi(object, js_name = "USAvailableHolding")]
+#[derive(Debug, Clone, Default)]
+pub struct USAvailableHolding {
+    pub available_qty: String,
+}
+
+impl From for USAvailableHolding {
+    fn from(v: longbridge::trade::USAvailableHolding) -> Self {
+        Self {
+            available_qty: v.available_qty,
+        }
+    }
+}
+
+/// Buying power in USCashAndBuyPower
+#[napi_derive::napi(object, js_name = "USBuyLimitInfo")]
+#[derive(Debug, Clone, Default)]
+pub struct USBuyLimitInfo {
+    pub currency: String,
+    pub cash_buy_power: String,
+    pub overnight_buy_power: String,
+    pub day_trade_buy_power: String,
+    pub instant_buy_power: String,
+    pub intraday_margin_buy_power: String,
+    pub option_buy_power: String,
+    pub crypto_buy_power: String,
+    pub mme: String,
+}
+
+impl From for USBuyLimitInfo {
+    fn from(v: longbridge::trade::USBuyLimitInfo) -> Self {
+        Self {
+            currency: v.currency,
+            cash_buy_power: v.cash_buy_power,
+            overnight_buy_power: v.overnight_buy_power,
+            day_trade_buy_power: v.day_trade_buy_power,
+            instant_buy_power: v.instant_buy_power,
+            intraday_margin_buy_power: v.intraday_margin_buy_power,
+            option_buy_power: v.option_buy_power,
+            crypto_buy_power: v.crypto_buy_power,
+            mme: v.mme,
+        }
+    }
+}
+
+/// One cash currency entry in USCashAndBuyPower
+#[napi_derive::napi(object, js_name = "USCashDetail")]
+#[derive(Debug, Clone, Default)]
+pub struct USCashDetail {
+    pub currency: String,
+    pub total_amount: String,
+    pub available_cash: String,
+    pub withdraw_cash: String,
+    pub frozen_cash: String,
+    pub settled_cash: String,
+    pub outstanding: String,
+    pub external_amount: String,
+}
+
+impl From for USCashDetail {
+    fn from(v: longbridge::trade::USCashDetail) -> Self {
+        Self {
+            currency: v.currency,
+            total_amount: v.total_amount,
+            available_cash: v.available_cash,
+            withdraw_cash: v.withdraw_cash,
+            frozen_cash: v.frozen_cash,
+            settled_cash: v.settled_cash,
+            outstanding: v.outstanding,
+            external_amount: v.external_amount,
+        }
+    }
+}
+
+/// Margin account status in USCashAndBuyPower
+#[napi_derive::napi(object, js_name = "USMarginStatus")]
+#[derive(Debug, Clone, Default)]
+pub struct USMarginStatus {
+    pub currency: String,
+    pub nlv: String,
+    pub margin_equity: String,
+    pub margin_maintenance_excess: String,
+    pub mmr: String,
+    pub reg_t_excess: String,
+    pub sma: String,
+}
+
+impl From for USMarginStatus {
+    fn from(v: longbridge::trade::USMarginStatus) -> Self {
+        Self {
+            currency: v.currency,
+            nlv: v.nlv,
+            margin_equity: v.margin_equity,
+            margin_maintenance_excess: v.margin_maintenance_excess,
+            mmr: v.mmr,
+            reg_t_excess: v.reg_t_excess,
+            sma: v.sma,
+        }
+    }
+}
+
+/// Cash, buying power and margin status of a US account
+#[napi_derive::napi(object, js_name = "USCashAndBuyPower")]
+#[derive(Debug, Clone, Default)]
+pub struct USCashAndBuyPower {
+    pub buy_limit_info: USBuyLimitInfo,
+    pub cash_list: Vec,
+    pub margin_status: USMarginStatus,
+}
+
+impl From for USCashAndBuyPower {
+    fn from(v: longbridge::trade::USCashAndBuyPower) -> Self {
+        Self {
+            buy_limit_info: v.buy_limit_info.into(),
+            cash_list: v.cash_list.into_iter().map(Into::into).collect(),
+            margin_status: v.margin_status.into(),
+        }
+    }
+}
+
+/// One record in USTransactionHistory
+#[napi_derive::napi(object, js_name = "USTransaction")]
+#[derive(Debug, Clone, Default)]
+pub struct USTransaction {
+    pub title: String,
+    pub biz_code: String,
+    pub biz_code_name: String,
+    pub amount: String,
+    pub currency: String,
+    pub symbol: String,
+    pub market: String,
+    pub equity_type: String,
+    pub position_side: String,
+    pub quantity: String,
+    pub quantity_description: String,
+    pub ref_no: String,
+    pub remark: String,
+    pub create_at: Option>,
+    pub done_at: Option>,
+}
+
+impl From for USTransaction {
+    fn from(v: longbridge::trade::USTransaction) -> Self {
+        Self {
+            title: v.title,
+            biz_code: v.biz_code,
+            biz_code_name: v.biz_code_name,
+            amount: v.amount,
+            currency: v.currency,
+            symbol: v.symbol,
+            market: v.market,
+            equity_type: v.equity_type,
+            position_side: v.position_side,
+            quantity: v.quantity,
+            quantity_description: v.quantity_description,
+            ref_no: v.ref_no,
+            remark: v.remark,
+            create_at: v.create_at.map(to_datetime),
+            done_at: v.done_at.map(to_datetime),
+        }
+    }
+}
+
+/// One page of US account transaction history
+#[napi_derive::napi(object, js_name = "USTransactionHistory")]
+#[derive(Debug, Clone, Default)]
+pub struct USTransactionHistory {
+    pub current_page: i64,
+    pub items: Vec,
+}
+
+impl From for USTransactionHistory {
+    fn from(v: longbridge::trade::USTransactionHistory) -> Self {
+        Self {
+            current_page: v.current_page,
+            items: v.items.into_iter().map(Into::into).collect(),
+        }
+    }
+}
+
+/// One exchange rate in USExchangeRates
+#[napi_derive::napi(object, js_name = "USExchangeRate")]
+#[derive(Debug, Clone, Default)]
+pub struct USExchangeRate {
+    pub universal_key: String,
+    pub spec_key: String,
+    pub base_currency: String,
+    pub other_currency: String,
+    pub bid_rate: String,
+    pub offer_rate: String,
+    pub average_rate: String,
+}
+
+impl From for USExchangeRate {
+    fn from(v: longbridge::trade::USExchangeRate) -> Self {
+        Self {
+            universal_key: v.universal_key,
+            spec_key: v.spec_key,
+            base_currency: v.base_currency,
+            other_currency: v.other_currency,
+            bid_rate: v.bid_rate,
+            offer_rate: v.offer_rate,
+            average_rate: v.average_rate,
+        }
+    }
+}
+
+/// Exchange rates of a US account
+#[napi_derive::napi(object, js_name = "USExchangeRates")]
+#[derive(Debug, Clone, Default)]
+pub struct USExchangeRates {
+    pub exchanges: Vec,
+}
+
+impl From for USExchangeRates {
+    fn from(v: longbridge::trade::USExchangeRates) -> Self {
+        Self {
+            exchanges: v.exchanges.into_iter().map(Into::into).collect(),
+        }
+    }
+}
+
 /// One order state-transition entry within USOrderDetail.
 #[napi_derive::napi(object, js_name = "USOrderHistory")]
 #[derive(Debug, Clone, Default)]
diff --git a/python/pysrc/longbridge/openapi.pyi b/python/pysrc/longbridge/openapi.pyi
index c643ec6a6d..0c898bbba0 100644
--- a/python/pysrc/longbridge/openapi.pyi
+++ b/python/pysrc/longbridge/openapi.pyi
@@ -5906,7 +5906,7 @@ class Execution:
 
     side: OrderSide
     """
-    Order side
+    Order side. `Unknown` when the response omits it (Longbridge US `/v1/trade/execution/history`)
     """
 
 class AllExecutionsResponse:
@@ -7526,6 +7526,8 @@ class TradeContext:
         """
         Get history executions
 
+        ``side`` may be ``OrderSide.Unknown`` on Longbridge US accounts.
+
         Args:
             symbol: Filter by security code, example: `700.HK`, `AAPL.US`
             start_at: Start time
@@ -7593,6 +7595,8 @@ class TradeContext:
         """
         Get all executions
 
+        AP accounts only: US data-center accounts get a region error; use ``history_executions`` instead.
+
         Args:
             symbol: Filter by security code
             order_id: Filter by order ID
@@ -7904,6 +7908,8 @@ class TradeContext:
         """
         Get account balance
 
+        AP accounts only: US data-center accounts get a region error; use ``us_cash_and_buy_power`` (or ``us_asset_overview``) instead.
+
         Args:
             currency: Currency
 
@@ -7937,6 +7943,8 @@ class TradeContext:
         """
         Get cash flow
 
+        AP accounts only: US data-center accounts get a region error; use ``us_transaction_history`` instead.
+
         Args:
             start_at: Start time
             end_at: End time
@@ -7973,6 +7981,8 @@ class TradeContext:
         """
         Get fund positions
 
+        AP accounts only: US data-center accounts have no fund holdings and get a region error. No US equivalent.
+
         Args:
             symbols: Filter by fund codes
 
@@ -8000,6 +8010,8 @@ class TradeContext:
         """
         Get stock positions
 
+        AP accounts only: US data-center accounts get a region error; use ``us_asset_overview`` (``stock_list``) instead.
+
         Args:
             symbols: Filter by stock codes
 
@@ -8025,6 +8037,8 @@ class TradeContext:
         """
         Get margin ratio
 
+        AP accounts only: US data-center accounts get a region error. No US equivalent; for US margin info see ``us_cash_and_buy_power`` (``margin_status``).
+
         Args:
             symbol: Security symbol
 
@@ -8050,6 +8064,8 @@ class TradeContext:
         """
         Get order detail
 
+        AP accounts only: US data-center accounts get a region error; use ``us_order_detail`` instead.
+
         Args:
             order_id: Order id
             is_attached: When set together with order_id, indicates that order_id is an attached sub-order ID. The server will look up using the attached order ID instead of treating it as a regular order ID. Has no effect without order_id
@@ -8175,6 +8191,72 @@ class TradeContext:
         """
         ...
 
+    def us_cash_and_buy_power(self, currency: Optional[str] = None) -> "USCashAndBuyPower":
+        """Get cash, buying power and margin status for the US account. US token required.
+
+        Args:
+            currency: Currency (e.g. ``"USD"``); ``None`` for the server default
+
+        Returns:
+            :class:`USCashAndBuyPower`
+        """
+        ...
+
+    def us_available_holding(
+        self,
+        symbol: str,
+        equity_type: Optional[str] = None,
+        position_side: Optional[str] = None,
+    ) -> "USAvailableHolding":
+        """Get the quantity of a US holding that is available to trade. US token required.
+
+        Args:
+            symbol: Security symbol, e.g. ``"AAPL.US"``, an option symbol such as
+                ``"AAPL261120C345000.US"``, or a crypto pair such as ``"BTCUSD.BKKT"``
+            equity_type: ``"STOCK"`` (default), ``"OPTION"`` or ``"CRYPTO"``
+            position_side: ``"LONG"`` (default) or ``"SHORT"``
+
+        Returns:
+            :class:`USAvailableHolding`
+        """
+        ...
+
+    def us_transaction_history(
+        self,
+        start_at: datetime,
+        end_at: datetime,
+        page: int = 1,
+        size: int = 20,
+        types: Optional[List[str]] = None,
+        currency: Optional[str] = None,
+    ) -> "USTransactionHistory":
+        """Get the US account transaction history, one page at a time. US token required.
+
+        Args:
+            start_at: Start time (inclusive)
+            end_at: End time (inclusive)
+            page: Page number, starting at 1
+            size: Page size
+            types: Transaction types to include; ``None`` for all. Values:
+                ``"TT_DEPOSIT_AND_WITHDRAWAL"``, ``"TT_STOCKS_AND_ETFS_TRADING"``,
+                ``"TT_OPTIONS_TRADING"``, ``"TT_CRYPTO_TRADING"``,
+                ``"TT_CORPORATE_ACTION"``, ``"TT_TRANSFER_IN_AND_OUT"``,
+                ``"TT_CRYPTO_TRANSFER"``, ``"TT_MARGIN_FINANCING"``, ``"TT_OTHER"``
+            currency: Currency filter (e.g. ``"USD"``); ``None`` for all
+
+        Returns:
+            :class:`USTransactionHistory`
+        """
+        ...
+
+    def us_exchange_rates(self) -> "USExchangeRates":
+        """Get the exchange rates used by the US account. US token required.
+
+        Returns:
+            :class:`USExchangeRates`
+        """
+        ...
+
     def set_on_grid_order_changed(self, callback: Callable[["PushGridOrderChanged"], None]) -> None:
         """Set the grid-order-changed push callback."""
         ...
@@ -11413,6 +11495,8 @@ class AsyncTradeContext:
         """
         Get history executions. Optional filters: symbol, start_at, end_at. Returns an awaitable that resolves to execution list.
 
+        ``side`` may be ``OrderSide.Unknown`` on Longbridge US accounts.
+
         Args:
             symbol: Filter by security code.
             start_at: Start time.
@@ -11482,6 +11566,8 @@ class AsyncTradeContext:
         """
         Get all executions. Returns an awaitable that resolves to AllExecutionsResponse.
 
+        AP accounts only: US data-center accounts get a region error; use ``history_executions`` instead.
+
         Args:
             symbol: Filter by security code.
             order_id: Filter by order ID.
@@ -11833,6 +11919,8 @@ class AsyncTradeContext:
         """
         Get account balance. Optional currency filter. Returns an awaitable that resolves to account balance list.
 
+        AP accounts only: US data-center accounts get a region error; use ``us_cash_and_buy_power`` (or ``us_asset_overview``) instead.
+
         Args:
             currency: Currency filter.
 
@@ -11867,6 +11955,8 @@ class AsyncTradeContext:
         """
         Get cash flow. Required: start_at, end_at. Optional: business_type, symbol, page, size. Returns an awaitable that resolves to cash flow list.
 
+        AP accounts only: US data-center accounts get a region error; use ``us_transaction_history`` instead.
+
         Args:
             start_at: Start time.
             end_at: End time.
@@ -11904,6 +11994,8 @@ class AsyncTradeContext:
         """
         Get fund positions. Optional filter: symbols. Returns an awaitable that resolves to fund positions response.
 
+        AP accounts only: US data-center accounts have no fund holdings and get a region error. No US equivalent.
+
         Args:
             symbols: Filter by fund codes.
 
@@ -11932,6 +12024,8 @@ class AsyncTradeContext:
         """
         Get stock positions. Optional filter: symbols. Returns an awaitable that resolves to stock positions response.
 
+        AP accounts only: US data-center accounts get a region error; use ``us_asset_overview`` (``stock_list``) instead.
+
         Args:
             symbols: Filter by stock codes.
 
@@ -11958,6 +12052,8 @@ class AsyncTradeContext:
         """
         Get margin ratio for symbol. Returns an awaitable that resolves to margin ratio.
 
+        AP accounts only: US data-center accounts get a region error. No US equivalent; for US margin info see ``us_cash_and_buy_power`` (``margin_status``).
+
         Args:
             symbol: Security symbol.
 
@@ -11984,6 +12080,8 @@ class AsyncTradeContext:
         """
         Get order detail by order_id. Returns an awaitable that resolves to order detail.
 
+        AP accounts only: US data-center accounts get a region error; use ``us_order_detail`` instead.
+
         Args:
             order_id: Order ID.
             is_attached: When set together with order_id, indicates that order_id is an attached sub-order ID. The server will look up using the attached order ID instead of treating it as a regular order ID. Has no effect without order_id.
@@ -12110,6 +12208,72 @@ class AsyncTradeContext:
         """
         ...
 
+    def us_cash_and_buy_power(self, currency: Optional[str] = None) -> "Awaitable[USCashAndBuyPower]":
+        """Get cash, buying power and margin status for the US account. US token required. Returns awaitable.
+
+        Args:
+            currency: Currency (e.g. ``"USD"``); ``None`` for the server default
+
+        Returns:
+            Awaitable resolving to :class:`USCashAndBuyPower`
+        """
+        ...
+
+    def us_available_holding(
+        self,
+        symbol: str,
+        equity_type: Optional[str] = None,
+        position_side: Optional[str] = None,
+    ) -> "Awaitable[USAvailableHolding]":
+        """Get the quantity of a US holding that is available to trade. US token required. Returns awaitable.
+
+        Args:
+            symbol: Security symbol, e.g. ``"AAPL.US"``, an option symbol such as
+                ``"AAPL261120C345000.US"``, or a crypto pair such as ``"BTCUSD.BKKT"``
+            equity_type: ``"STOCK"`` (default), ``"OPTION"`` or ``"CRYPTO"``
+            position_side: ``"LONG"`` (default) or ``"SHORT"``
+
+        Returns:
+            Awaitable resolving to :class:`USAvailableHolding`
+        """
+        ...
+
+    def us_transaction_history(
+        self,
+        start_at: datetime,
+        end_at: datetime,
+        page: int = 1,
+        size: int = 20,
+        types: Optional[List[str]] = None,
+        currency: Optional[str] = None,
+    ) -> "Awaitable[USTransactionHistory]":
+        """Get the US account transaction history, one page at a time. US token required. Returns awaitable.
+
+        Args:
+            start_at: Start time (inclusive)
+            end_at: End time (inclusive)
+            page: Page number, starting at 1
+            size: Page size
+            types: Transaction types to include; ``None`` for all. Values:
+                ``"TT_DEPOSIT_AND_WITHDRAWAL"``, ``"TT_STOCKS_AND_ETFS_TRADING"``,
+                ``"TT_OPTIONS_TRADING"``, ``"TT_CRYPTO_TRADING"``,
+                ``"TT_CORPORATE_ACTION"``, ``"TT_TRANSFER_IN_AND_OUT"``,
+                ``"TT_CRYPTO_TRANSFER"``, ``"TT_MARGIN_FINANCING"``, ``"TT_OTHER"``
+            currency: Currency filter (e.g. ``"USD"``); ``None`` for all
+
+        Returns:
+            Awaitable resolving to :class:`USTransactionHistory`
+        """
+        ...
+
+    def us_exchange_rates(self) -> "Awaitable[USExchangeRates]":
+        """Get the exchange rates used by the US account. US token required. Returns awaitable.
+
+        Returns:
+            Awaitable resolving to :class:`USExchangeRates`
+        """
+        ...
+
     async def set_on_grid_order_changed(self, callback: Callable[["PushGridOrderChanged"], None]) -> None:
         """Set the grid-order-changed push callback."""
         ...
@@ -16314,7 +16478,11 @@ class PortfolioContext:
         ...
 
     def exchange_rate(self) -> "ExchangeRates":
-        """Get exchange rates for supported currencies."""
+        """
+        Get exchange rates for supported currencies.
+
+        AP accounts only: US data-center accounts get a region error; use ``TradeContext.us_exchange_rates`` instead.
+        """
         ...
 
     def profit_analysis(
@@ -16401,7 +16569,11 @@ class AsyncPortfolioContext:
     def create(cls, config: Config) -> AsyncPortfolioContext: ...
 
     async def exchange_rate(self) -> "ExchangeRates":
-        """Get exchange rates for supported currencies."""
+        """
+        Get exchange rates for supported currencies.
+
+        AP accounts only: US data-center accounts get a region error; use ``AsyncTradeContext.us_exchange_rates`` instead.
+        """
         ...
 
     async def profit_analysis(
@@ -17409,12 +17581,32 @@ class USCryptoEntry:
 
     asset_type: str
     """Asset type, e.g. ``"CRYPTO"``"""
-    average_cost: str
-    """Average cost price"""
     symbol: str
-    """Symbol"""
+    """Trading-pair code, e.g. ``"BTCUSD"``; the user-facing symbol is ``"."``, e.g. ``"BTCUSD.BKKT"``"""
+    quantity: str
+    """Holding quantity"""
     currency: str
     """Settlement currency"""
+    average_cost: str
+    """Average cost price; empty when the server has none"""
+    market: str
+    """Market code, e.g. ``"BKKT"``"""
+    trade_status: str
+    prev_close: str
+    last_done: str
+    market_price: str
+    pretrade_close: str
+    stock_invest_of_today: str
+    today_pl: str
+    pretrade_stock_invest_of_today: str
+    pretrade_today_pl: str
+    night_last_done: str
+    night_prev_close: str
+    position_side: str
+    open_position_time: str
+    """Position open time (Unix-second string; ``"0"`` when unknown)"""
+    name: str
+    """Asset name, e.g. ``"Bitcoin"``"""
     industry_counter_id: str
     """Industry counter_id"""
     industry_name: str
@@ -17503,6 +17695,161 @@ class USRealizedPL:
     """Per-category realized P&L entries"""
 
 
+class USAvailableHolding:
+    """Quantity of a US holding that is available to trade. Returned by TradeContext.us_available_holding."""
+
+    available_qty: str
+    """Quantity available to sell (long) or buy to cover (short); negative for a short position"""
+
+
+class USBuyLimitInfo:
+    """Buying power in USCashAndBuyPower."""
+
+    currency: str
+    """Currency"""
+    cash_buy_power: str
+    """Cash buying power"""
+    overnight_buy_power: str
+    """Overnight buying power"""
+    day_trade_buy_power: str
+    """Day-trade buying power"""
+    instant_buy_power: str
+    """Instant buying power"""
+    intraday_margin_buy_power: str
+    """Intraday margin buying power"""
+    option_buy_power: str
+    """Option buying power"""
+    crypto_buy_power: str
+    """Crypto buying power"""
+    mme: str
+    """Margin maintenance excess used for buying power"""
+
+
+class USCashDetail:
+    """One cash currency entry in USCashAndBuyPower."""
+
+    currency: str
+    """Currency"""
+    total_amount: str
+    """Total cash"""
+    available_cash: str
+    """Available cash"""
+    withdraw_cash: str
+    """Withdrawable cash"""
+    frozen_cash: str
+    """Cash frozen for pending orders"""
+    settled_cash: str
+    """Settled cash"""
+    outstanding: str
+    """Outstanding (unsettled) amount"""
+    external_amount: str
+    """Amount held for external use (e.g. IPO or fund subscriptions)"""
+
+
+class USMarginStatus:
+    """Margin account status in USCashAndBuyPower."""
+
+    currency: str
+    """Currency"""
+    nlv: str
+    """Net liquidation value"""
+    margin_equity: str
+    """Margin equity"""
+    margin_maintenance_excess: str
+    """Margin maintenance excess"""
+    mmr: str
+    """Maintenance margin requirement"""
+    reg_t_excess: str
+    """Regulation T excess"""
+    sma: str
+    """Special memorandum account"""
+
+
+class USCashAndBuyPower:
+    """Cash, buying power and margin status of a US account. Returned by TradeContext.us_cash_and_buy_power."""
+
+    buy_limit_info: USBuyLimitInfo
+    """Buying power"""
+    cash_list: List[USCashDetail]
+    """Cash per currency"""
+    margin_status: USMarginStatus
+    """Margin account status"""
+
+
+class USTransaction:
+    """One record in USTransactionHistory."""
+
+    title: str
+    """Display title"""
+    biz_code: str
+    """Business code"""
+    biz_code_name: str
+    """Business code name"""
+    amount: str
+    """Amount; negative for outflows"""
+    currency: str
+    """Currency"""
+    symbol: str
+    """Security symbol, if the record relates to one (e.g. ``"AAPL.US"``)"""
+    market: str
+    """Market code"""
+    equity_type: str
+    """Holding type"""
+    position_side: str
+    """Position side"""
+    quantity: str
+    """Quantity"""
+    quantity_description: str
+    """Quantity description"""
+    ref_no: str
+    """Reference number"""
+    remark: str
+    """Remark"""
+    create_at: Optional[datetime]
+    """Creation time"""
+    done_at: Optional[datetime]
+    """Completion time"""
+
+
+class USTransactionHistory:
+    """One page of US account transaction history. Returned by TradeContext.us_transaction_history."""
+
+    current_page: int
+    """Current page number"""
+    items: List[USTransaction]
+    """Records on this page. There is no total count: a page shorter than the requested size is the last one."""
+
+
+class USExchangeRate:
+    """One exchange rate in USExchangeRates."""
+
+    universal_key: str
+    """Account channel the rates apply to, e.g. ``us_lb_apex`` (outer ``universal_exchanges`` key)"""
+    spec_key: str
+    """Rate type, e.g. ``am`` or ``reference`` (inner ``spec_exchanges`` key)"""
+    base_currency: str
+    """Base currency"""
+    other_currency: str
+    """Other (quote) currency"""
+    bid_rate: str
+    """Bid rate; empty if not provided"""
+    offer_rate: str
+    """Offer rate; empty if not provided"""
+    average_rate: str
+    """Average rate; empty if not provided"""
+
+
+class USExchangeRates:
+    """Exchange rates of a US account. Returned by TradeContext.us_exchange_rates.
+
+    The upstream two-level map is flattened into ``exchanges``, sorted by the two
+    upstream map keys, which are kept on each entry as ``universal_key`` and ``spec_key``.
+    """
+
+    exchanges: List[USExchangeRate]
+    """Exchange rates"""
+
+
 class USOrderHistory:
     """One order state-transition entry within USOrderDetail."""
     exec_type: int
diff --git a/python/src/fundamental/context_async.rs b/python/src/fundamental/context_async.rs
index da05570809..8e95ae414f 100644
--- a/python/src/fundamental/context_async.rs
+++ b/python/src/fundamental/context_async.rs
@@ -2,7 +2,8 @@ use std::sync::Arc;
 
 use longbridge::FundamentalContext;
 use pyo3::{prelude::*, types::PyType};
-// needed for us_financial_overview / us_key_financial_metrics / us_analyst_consensus
+// needed for us_financial_overview / us_key_financial_metrics /
+// us_analyst_consensus
 #[allow(unused_imports)]
 use pythonize;
 
diff --git a/python/src/portfolio/context.rs b/python/src/portfolio/context.rs
index 72eb47a563..419f4e2ca0 100644
--- a/python/src/portfolio/context.rs
+++ b/python/src/portfolio/context.rs
@@ -21,6 +21,9 @@ impl PortfolioContext {
     }
 
     /// Get exchange rates.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `TradeContext.us_exchange_rates` instead.
     fn exchange_rate(&self) -> PyResult {
         Ok(self.ctx.exchange_rate().map_err(ErrorNewType)?.into())
     }
diff --git a/python/src/portfolio/context_async.rs b/python/src/portfolio/context_async.rs
index 35f94a64bf..e3ea20bdd8 100644
--- a/python/src/portfolio/context_async.rs
+++ b/python/src/portfolio/context_async.rs
@@ -19,6 +19,11 @@ impl AsyncPortfolioContext {
             ctx: Arc::new(PortfolioContext::new(Arc::new(config.0.clone()))),
         }
     }
+
+    /// Get exchange rates. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `TradeContext.us_exchange_rates` instead.
     fn exchange_rate(&self, py: Python<'_>) -> PyResult> {
         let ctx = self.ctx.clone();
         pyo3_async_runtimes::tokio::future_into_py(py, async move {
diff --git a/python/src/trade/context.rs b/python/src/trade/context.rs
index 9a93f2b4d9..bb117cd84e 100644
--- a/python/src/trade/context.rs
+++ b/python/src/trade/context.rs
@@ -147,6 +147,9 @@ impl TradeContext {
     }
 
     /// Get all executions
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `history_executions` instead.
     #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = None, page = None))]
     fn all_executions(
         &self,
@@ -466,6 +469,9 @@ impl TradeContext {
     }
 
     /// Get account balance
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_cash_and_buy_power` (or `us_asset_overview`) instead.
     #[pyo3(signature = (currency = None))]
     fn account_balance(&self, currency: Option) -> PyResult> {
         self.ctx
@@ -477,6 +483,9 @@ impl TradeContext {
     }
 
     /// Get cash flow
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_transaction_history` instead.
     #[pyo3(signature = (start_at, end_at, business_type = None, symbol = None, page = None, size = None))]
     fn cash_flow(
         &self,
@@ -511,6 +520,9 @@ impl TradeContext {
     }
 
     /// Get fund positions
+    ///
+    /// AP accounts only: US data-center accounts have no fund holdings and
+    /// get a region error. No US equivalent.
     #[pyo3(signature = (symbols = None))]
     fn fund_positions(&self, symbols: Option>) -> PyResult {
         self.ctx
@@ -520,6 +532,9 @@ impl TradeContext {
     }
 
     /// Get stock positions
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_asset_overview` (`stock_list`) instead.
     #[pyo3(signature = (symbols = None))]
     fn stock_positions(&self, symbols: Option>) -> PyResult {
         self.ctx
@@ -529,6 +544,10 @@ impl TradeContext {
     }
 
     /// Get margin ratio
+    ///
+    /// AP accounts only: US data-center accounts get a region error. No US
+    /// equivalent; for US margin info see `us_cash_and_buy_power`
+    /// (`margin_status`).
     fn margin_ratio(&self, symbol: String) -> PyResult {
         self.ctx
             .margin_ratio(symbol)
@@ -537,6 +556,9 @@ impl TradeContext {
     }
 
     /// Get order detail
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_order_detail` instead.
     #[pyo3(signature = (order_id, is_attached = false))]
     fn order_detail(&self, order_id: String, is_attached: bool) -> PyResult {
         let mut opts = GetOrderDetailOptions::new(order_id);
@@ -614,6 +636,68 @@ impl TradeContext {
             .into())
     }
 
+    /// Get cash, buying power and margin status for the US account. US token
+    /// required.
+    #[pyo3(signature = (currency = None))]
+    fn us_cash_and_buy_power(
+        &self,
+        currency: Option,
+    ) -> PyResult {
+        Ok(self
+            .ctx
+            .us_cash_and_buy_power(currency.as_deref())
+            .map_err(ErrorNewType)?
+            .into())
+    }
+
+    /// Get the quantity of a US holding that is available to trade. US token
+    /// required.
+    #[pyo3(signature = (symbol, equity_type = None, position_side = None))]
+    fn us_available_holding(
+        &self,
+        symbol: String,
+        equity_type: Option,
+        position_side: Option,
+    ) -> PyResult {
+        Ok(self
+            .ctx
+            .us_available_holding(longbridge::trade::GetUSAvailableHoldingOptions {
+                symbol,
+                equity_type: equity_type.unwrap_or_default(),
+                position_side: position_side.unwrap_or_default(),
+            })
+            .map_err(ErrorNewType)?
+            .into())
+    }
+
+    /// Get the US account transaction history. US token required.
+    #[pyo3(signature = (start_at, end_at, page = 1, size = 20, types = None, currency = None))]
+    fn us_transaction_history(
+        &self,
+        start_at: PyOffsetDateTimeWrapper,
+        end_at: PyOffsetDateTimeWrapper,
+        page: i32,
+        size: i32,
+        types: Option>,
+        currency: Option,
+    ) -> PyResult {
+        let mut opts = longbridge::trade::GetUSTransactionHistoryOptions::new(start_at.0, end_at.0);
+        opts.page = page;
+        opts.size = size;
+        opts.types = types.unwrap_or_default();
+        opts.currency = currency.unwrap_or_default();
+        Ok(self
+            .ctx
+            .us_transaction_history(opts)
+            .map_err(ErrorNewType)?
+            .into())
+    }
+
+    /// Get the exchange rates used by the US account. US token required.
+    fn us_exchange_rates(&self) -> PyResult {
+        Ok(self.ctx.us_exchange_rates().map_err(ErrorNewType)?.into())
+    }
+
     /// Estimating the maximum purchase quantity for Hong Kong and US stocks,
     /// warrants, and options
     #[allow(clippy::too_many_arguments)]
diff --git a/python/src/trade/context_async.rs b/python/src/trade/context_async.rs
index 50504b465a..f9fd652450 100644
--- a/python/src/trade/context_async.rs
+++ b/python/src/trade/context_async.rs
@@ -174,6 +174,9 @@ impl AsyncTradeContext {
     }
 
     /// Get all executions. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `history_executions` instead.
     #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = None, page = None))]
     fn all_executions(
         &self,
@@ -524,6 +527,9 @@ impl AsyncTradeContext {
     }
 
     /// Get account balance. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_cash_and_buy_power` (or `us_asset_overview`) instead.
     #[pyo3(signature = (currency = None))]
     fn account_balance(&self, py: Python<'_>, currency: Option) -> PyResult> {
         let ctx = self.ctx.clone();
@@ -540,6 +546,9 @@ impl AsyncTradeContext {
     }
 
     /// Get cash flow. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_transaction_history` instead.
     #[allow(clippy::too_many_arguments)]
     #[pyo3(signature = (start_at, end_at, business_type = None, symbol = None, page = None, size = None))]
     fn cash_flow(
@@ -576,6 +585,9 @@ impl AsyncTradeContext {
     }
 
     /// Get fund positions. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts have no fund holdings and
+    /// get a region error. No US equivalent.
     #[pyo3(signature = (symbols = None))]
     fn fund_positions(&self, py: Python<'_>, symbols: Option>) -> PyResult> {
         let ctx = self.ctx.clone();
@@ -592,6 +604,9 @@ impl AsyncTradeContext {
     }
 
     /// Get stock positions. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_asset_overview` (`stock_list`) instead.
     #[pyo3(signature = (symbols = None))]
     fn stock_positions(&self, py: Python<'_>, symbols: Option>) -> PyResult> {
         let ctx = self.ctx.clone();
@@ -608,6 +623,10 @@ impl AsyncTradeContext {
     }
 
     /// Get margin ratio. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error. No US
+    /// equivalent; for US margin info see `us_cash_and_buy_power`
+    /// (`margin_status`).
     fn margin_ratio(&self, py: Python<'_>, symbol: String) -> PyResult> {
         let ctx = self.ctx.clone();
         pyo3_async_runtimes::tokio::future_into_py(py, async move {
@@ -622,6 +641,9 @@ impl AsyncTradeContext {
     }
 
     /// Get order detail. Returns awaitable.
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_order_detail` instead.
     #[pyo3(signature = (order_id, is_attached = false))]
     fn order_detail(
         &self,
@@ -731,6 +753,95 @@ impl AsyncTradeContext {
         .map(|b| b.unbind())
     }
 
+    /// Get cash, buying power and margin status for the US account. US token
+    /// required. Returns awaitable.
+    #[pyo3(signature = (currency = None))]
+    fn us_cash_and_buy_power(
+        &self,
+        py: Python<'_>,
+        currency: Option,
+    ) -> PyResult> {
+        let ctx = self.ctx.clone();
+        pyo3_async_runtimes::tokio::future_into_py(py, async move {
+            let r: crate::trade::types::USCashAndBuyPower = ctx
+                .us_cash_and_buy_power(currency.as_deref())
+                .await
+                .map_err(ErrorNewType)?
+                .into();
+            Ok(r)
+        })
+        .map(|b| b.unbind())
+    }
+
+    /// Get the quantity of a US holding that is available to trade. US token
+    /// required. Returns awaitable.
+    #[pyo3(signature = (symbol, equity_type = None, position_side = None))]
+    fn us_available_holding(
+        &self,
+        py: Python<'_>,
+        symbol: String,
+        equity_type: Option,
+        position_side: Option,
+    ) -> PyResult> {
+        let ctx = self.ctx.clone();
+        pyo3_async_runtimes::tokio::future_into_py(py, async move {
+            let r: crate::trade::types::USAvailableHolding = ctx
+                .us_available_holding(longbridge::trade::GetUSAvailableHoldingOptions {
+                    symbol,
+                    equity_type: equity_type.unwrap_or_default(),
+                    position_side: position_side.unwrap_or_default(),
+                })
+                .await
+                .map_err(ErrorNewType)?
+                .into();
+            Ok(r)
+        })
+        .map(|b| b.unbind())
+    }
+
+    /// Get the US account transaction history. US token required. Returns
+    /// awaitable.
+    #[allow(clippy::too_many_arguments)]
+    #[pyo3(signature = (start_at, end_at, page = 1, size = 20, types = None, currency = None))]
+    fn us_transaction_history(
+        &self,
+        py: Python<'_>,
+        start_at: PyOffsetDateTimeWrapper,
+        end_at: PyOffsetDateTimeWrapper,
+        page: i32,
+        size: i32,
+        types: Option>,
+        currency: Option,
+    ) -> PyResult> {
+        let ctx = self.ctx.clone();
+        let mut opts = longbridge::trade::GetUSTransactionHistoryOptions::new(start_at.0, end_at.0);
+        opts.page = page;
+        opts.size = size;
+        opts.types = types.unwrap_or_default();
+        opts.currency = currency.unwrap_or_default();
+        pyo3_async_runtimes::tokio::future_into_py(py, async move {
+            let r: crate::trade::types::USTransactionHistory = ctx
+                .us_transaction_history(opts)
+                .await
+                .map_err(ErrorNewType)?
+                .into();
+            Ok(r)
+        })
+        .map(|b| b.unbind())
+    }
+
+    /// Get the exchange rates used by the US account. US token required.
+    /// Returns awaitable.
+    fn us_exchange_rates(&self, py: Python<'_>) -> PyResult> {
+        let ctx = self.ctx.clone();
+        pyo3_async_runtimes::tokio::future_into_py(py, async move {
+            let r: crate::trade::types::USExchangeRates =
+                ctx.us_exchange_rates().await.map_err(ErrorNewType)?.into();
+            Ok(r)
+        })
+        .map(|b| b.unbind())
+    }
+
     /// Estimate max purchase quantity. Returns awaitable.
     #[allow(clippy::too_many_arguments)]
     #[pyo3(signature = (symbol, order_type, side, price = None, currency = None, order_id = None, fractional_shares = false))]
diff --git a/python/src/trade/mod.rs b/python/src/trade/mod.rs
index 6cbe3570c4..8afe619226 100644
--- a/python/src/trade/mod.rs
+++ b/python/src/trade/mod.rs
@@ -58,6 +58,15 @@ pub(crate) fn register_types(parent: &Bound) -> PyResult<()> {
     parent.add_class::()?;
     parent.add_class::()?;
     parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
+    parent.add_class::()?;
     parent.add_class::()?;
     parent.add_class::()?;
     parent.add_class::()?;
diff --git a/python/src/trade/types.rs b/python/src/trade/types.rs
index ab00587a16..b30ab715a9 100644
--- a/python/src/trade/types.rs
+++ b/python/src/trade/types.rs
@@ -34,7 +34,8 @@ pub(crate) struct Execution {
     quantity: PyDecimal,
     /// Executed price
     price: PyDecimal,
-    /// Order side
+    /// Order side. `Unknown` when the response omits it (Longbridge US
+    /// `/v1/trade/execution/history`)
     side: OrderSide,
 }
 
@@ -1166,9 +1167,26 @@ impl From for USCashEntry {
 #[derive(Debug, Clone, Default)]
 pub(crate) struct USCryptoEntry {
     pub asset_type: String,
-    pub average_cost: String,
     pub symbol: String,
+    pub quantity: String,
     pub currency: String,
+    pub average_cost: String,
+    pub market: String,
+    pub trade_status: String,
+    pub prev_close: String,
+    pub last_done: String,
+    pub market_price: String,
+    pub pretrade_close: String,
+    pub stock_invest_of_today: String,
+    pub today_pl: String,
+    pub pretrade_stock_invest_of_today: String,
+    pub pretrade_today_pl: String,
+    pub night_last_done: String,
+    pub night_prev_close: String,
+    pub position_side: String,
+    pub open_position_time: String,
+    pub name: String,
+    pub industry_counter_id: String,
     pub industry_name: String,
 }
 
@@ -1176,9 +1194,26 @@ impl From for USCryptoEntry {
     fn from(v: longbridge::trade::USCryptoEntry) -> Self {
         Self {
             asset_type: v.asset_type,
-            average_cost: v.average_cost,
             symbol: v.symbol,
+            quantity: v.quantity,
             currency: v.currency,
+            average_cost: v.average_cost,
+            market: v.market,
+            trade_status: v.trade_status,
+            prev_close: v.prev_close,
+            last_done: v.last_done,
+            market_price: v.market_price,
+            pretrade_close: v.pretrade_close,
+            stock_invest_of_today: v.stock_invest_of_today,
+            today_pl: v.today_pl,
+            pretrade_stock_invest_of_today: v.pretrade_stock_invest_of_today,
+            pretrade_today_pl: v.pretrade_today_pl,
+            night_last_done: v.night_last_done,
+            night_prev_close: v.night_prev_close,
+            position_side: v.position_side,
+            open_position_time: v.open_position_time,
+            name: v.name,
+            industry_counter_id: v.industry_counter_id,
             industry_name: v.industry_name,
         }
     }
@@ -1330,6 +1365,229 @@ impl From for USRealizedPL {
     }
 }
 
+/// Quantity of a US holding that is available to trade
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USAvailableHolding {
+    pub available_qty: String,
+}
+
+impl From for USAvailableHolding {
+    fn from(v: longbridge::trade::USAvailableHolding) -> Self {
+        Self {
+            available_qty: v.available_qty,
+        }
+    }
+}
+
+/// Buying power in USCashAndBuyPower
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USBuyLimitInfo {
+    pub currency: String,
+    pub cash_buy_power: String,
+    pub overnight_buy_power: String,
+    pub day_trade_buy_power: String,
+    pub instant_buy_power: String,
+    pub intraday_margin_buy_power: String,
+    pub option_buy_power: String,
+    pub crypto_buy_power: String,
+    pub mme: String,
+}
+
+impl From for USBuyLimitInfo {
+    fn from(v: longbridge::trade::USBuyLimitInfo) -> Self {
+        Self {
+            currency: v.currency,
+            cash_buy_power: v.cash_buy_power,
+            overnight_buy_power: v.overnight_buy_power,
+            day_trade_buy_power: v.day_trade_buy_power,
+            instant_buy_power: v.instant_buy_power,
+            intraday_margin_buy_power: v.intraday_margin_buy_power,
+            option_buy_power: v.option_buy_power,
+            crypto_buy_power: v.crypto_buy_power,
+            mme: v.mme,
+        }
+    }
+}
+
+/// One cash currency entry in USCashAndBuyPower
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USCashDetail {
+    pub currency: String,
+    pub total_amount: String,
+    pub available_cash: String,
+    pub withdraw_cash: String,
+    pub frozen_cash: String,
+    pub settled_cash: String,
+    pub outstanding: String,
+    pub external_amount: String,
+}
+
+impl From for USCashDetail {
+    fn from(v: longbridge::trade::USCashDetail) -> Self {
+        Self {
+            currency: v.currency,
+            total_amount: v.total_amount,
+            available_cash: v.available_cash,
+            withdraw_cash: v.withdraw_cash,
+            frozen_cash: v.frozen_cash,
+            settled_cash: v.settled_cash,
+            outstanding: v.outstanding,
+            external_amount: v.external_amount,
+        }
+    }
+}
+
+/// Margin account status in USCashAndBuyPower
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USMarginStatus {
+    pub currency: String,
+    pub nlv: String,
+    pub margin_equity: String,
+    pub margin_maintenance_excess: String,
+    pub mmr: String,
+    pub reg_t_excess: String,
+    pub sma: String,
+}
+
+impl From for USMarginStatus {
+    fn from(v: longbridge::trade::USMarginStatus) -> Self {
+        Self {
+            currency: v.currency,
+            nlv: v.nlv,
+            margin_equity: v.margin_equity,
+            margin_maintenance_excess: v.margin_maintenance_excess,
+            mmr: v.mmr,
+            reg_t_excess: v.reg_t_excess,
+            sma: v.sma,
+        }
+    }
+}
+
+/// Cash, buying power and margin status of a US account
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USCashAndBuyPower {
+    pub buy_limit_info: USBuyLimitInfo,
+    pub cash_list: Vec,
+    pub margin_status: USMarginStatus,
+}
+
+impl From for USCashAndBuyPower {
+    fn from(v: longbridge::trade::USCashAndBuyPower) -> Self {
+        Self {
+            buy_limit_info: v.buy_limit_info.into(),
+            cash_list: v.cash_list.into_iter().map(Into::into).collect(),
+            margin_status: v.margin_status.into(),
+        }
+    }
+}
+
+/// One record in USTransactionHistory
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USTransaction {
+    pub title: String,
+    pub biz_code: String,
+    pub biz_code_name: String,
+    pub amount: String,
+    pub currency: String,
+    pub symbol: String,
+    pub market: String,
+    pub equity_type: String,
+    pub position_side: String,
+    pub quantity: String,
+    pub quantity_description: String,
+    pub ref_no: String,
+    pub remark: String,
+    pub create_at: Option,
+    pub done_at: Option,
+}
+
+impl From for USTransaction {
+    fn from(v: longbridge::trade::USTransaction) -> Self {
+        Self {
+            title: v.title,
+            biz_code: v.biz_code,
+            biz_code_name: v.biz_code_name,
+            amount: v.amount,
+            currency: v.currency,
+            symbol: v.symbol,
+            market: v.market,
+            equity_type: v.equity_type,
+            position_side: v.position_side,
+            quantity: v.quantity,
+            quantity_description: v.quantity_description,
+            ref_no: v.ref_no,
+            remark: v.remark,
+            create_at: v.create_at.map(Into::into),
+            done_at: v.done_at.map(Into::into),
+        }
+    }
+}
+
+/// One page of US account transaction history
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USTransactionHistory {
+    pub current_page: i64,
+    pub items: Vec,
+}
+
+impl From for USTransactionHistory {
+    fn from(v: longbridge::trade::USTransactionHistory) -> Self {
+        Self {
+            current_page: v.current_page,
+            items: v.items.into_iter().map(Into::into).collect(),
+        }
+    }
+}
+
+/// One exchange rate in USExchangeRates
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USExchangeRate {
+    pub universal_key: String,
+    pub spec_key: String,
+    pub base_currency: String,
+    pub other_currency: String,
+    pub bid_rate: String,
+    pub offer_rate: String,
+    pub average_rate: String,
+}
+
+impl From for USExchangeRate {
+    fn from(v: longbridge::trade::USExchangeRate) -> Self {
+        Self {
+            universal_key: v.universal_key,
+            spec_key: v.spec_key,
+            base_currency: v.base_currency,
+            other_currency: v.other_currency,
+            bid_rate: v.bid_rate,
+            offer_rate: v.offer_rate,
+            average_rate: v.average_rate,
+        }
+    }
+}
+
+/// Exchange rates of a US account
+#[pyclass(get_all, skip_from_py_object)]
+#[derive(Debug, Clone, Default)]
+pub(crate) struct USExchangeRates {
+    pub exchanges: Vec,
+}
+
+impl From for USExchangeRates {
+    fn from(v: longbridge::trade::USExchangeRates) -> Self {
+        Self {
+            exchanges: v.exchanges.into_iter().map(Into::into).collect(),
+        }
+    }
+}
+
 /// One order state-transition entry within USOrderDetail.
 #[pyclass(get_all, skip_from_py_object)]
 #[derive(Debug, Clone, Default)]
diff --git a/rust/crates/httpclient/src/error.rs b/rust/crates/httpclient/src/error.rs
index 7636be944e..e19a27ec15 100644
--- a/rust/crates/httpclient/src/error.rs
+++ b/rust/crates/httpclient/src/error.rs
@@ -37,8 +37,12 @@ pub enum HttpClientError {
 
     /// The requested API is restricted to one data center and cannot be reached
     /// from a session in a different region.
+    ///
+    /// The message names the API to call instead when one exists, so callers
+    /// (including LLM agents) can recover without parsing the path.
     #[error(
-        "this API ({path}) is only available in the {required} data center and is not supported for your {current}-region account"
+        "this API ({path}) is only available in the {required} data center and is not supported for your {current}-region account{}",
+        DcRegionHint::new(.path, *.required)
     )]
     DcRegionRestricted {
         /// The restricted API path (or WebSocket command) that was requested.
@@ -111,6 +115,114 @@ pub enum HttpClientError {
     Sse(String),
 }
 
+/// Suffix appended to [`HttpClientError::DcRegionRestricted`] messages that
+/// tells the caller which API to use instead.
+struct DcRegionHint(Option<&'static str>);
+
+impl DcRegionHint {
+    fn new(path: &str, required: DcRegion) -> Self {
+        Self(region_alternative(path, required))
+    }
+}
+
+impl std::fmt::Display for DcRegionHint {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self.0 {
+            Some(hint) => write!(f, "; {hint}"),
+            None => Ok(()),
+        }
+    }
+}
+
+/// Hint for an AP-only path with no US counterpart.
+const NO_US_EQUIVALENT: &str = "there is no US equivalent";
+
+/// Hint for a US-only path with no AP counterpart.
+const NO_AP_EQUIVALENT: &str = "there is no AP equivalent";
+
+/// Returns the recovery hint for a region-restricted API path.
+///
+/// The hint is shared by every binding (Rust, Python, Node.js, Java, C, C++)
+/// and by MCP servers built on the SDK, whose method and tool names differ,
+/// so it names the alternative by HTTP endpoint rather than by method.
+fn region_alternative(path: &str, required: DcRegion) -> Option<&'static str> {
+    match required {
+        DcRegion::Ap => ap_only_alternative(path),
+        DcRegion::Us => us_only_alternative(path),
+    }
+}
+
+/// Hint for a US-region account calling an AP-only path.
+fn ap_only_alternative(path: &str) -> Option<&'static str> {
+    let hint = match path {
+        "/v1/asset/account" => {
+            "use the US endpoint GET /v1/us/assets/cash-and-buy-power or GET \
+             /v1/us/assets/overview (TradeContext US methods)"
+        }
+        "/v1/asset/cashflow" => {
+            "use the US endpoint POST /v1/us/assets/transaction-history (TradeContext US methods)"
+        }
+        "/v1/asset/stock" => {
+            "use the US endpoint GET /v1/us/assets/overview (TradeContext US methods)"
+        }
+        "/v1/asset/exchange_rates" => {
+            "use the US endpoint GET /v1/us/assets/exchange-rates (TradeContext US methods)"
+        }
+        "/v1/trade/order" => {
+            "use the US endpoint GET /v1/us/orders/{order_id} (TradeContext US methods)"
+        }
+        "/v3/trade/execution/all" => "use GET /v1/trade/execution/history",
+        "/v1/risk/margin-ratio" => {
+            "there is no US equivalent; account-level margin is at GET \
+             /v1/us/assets/cash-and-buy-power (margin_status)"
+        }
+        "/v1/asset/fund" | "quote/brokers" | "/v1/quote/operatings" => NO_US_EQUIVALENT,
+        _ if path.starts_with("/v1/quote/broker-holding")
+            || path.starts_with("/v1/dailycoins/") =>
+        {
+            NO_US_EQUIVALENT
+        }
+        _ => return None,
+    };
+    Some(hint)
+}
+
+/// Hint for an AP-region account calling a US-only path.
+fn us_only_alternative(path: &str) -> Option<&'static str> {
+    let hint = match path {
+        "/v1/us/orders/query" => {
+            "use the AP endpoint GET /v1/trade/order/today or GET /v1/trade/order/history"
+        }
+        "/v1/us/assets/overview" => {
+            "use the AP endpoints GET /v1/asset/account and GET /v1/asset/stock"
+        }
+        "/v1/us/assets/transaction-history" => "use the AP endpoint GET /v1/asset/cashflow",
+        "/v1/us/assets/exchange-rates" => "use the AP endpoint GET /v1/asset/exchange_rates",
+        "/v1/us/assets/cash-and-buy-power" => "use the AP endpoint GET /v1/asset/account",
+        "/v1/us/assets/available-holding" => {
+            "use the AP endpoint GET /v1/asset/stock (available_quantity)"
+        }
+        "/v1/us/stock-info/company-overview" => "use the AP endpoint GET /v1/quote/comp-overview",
+        "/v1/us/stock-info/valuation-overview" => "use the AP endpoint GET /v1/quote/valuation",
+        "/v1/us/stock-info/finn-overview" | "/v1/us/quote/financials/statements" => {
+            "use the AP endpoint GET /v1/quote/financial-reports"
+        }
+        "/v1/us/stock-info/fin-keyfactor" => {
+            "use the AP endpoint GET /v1/quote/financials/earnings-snapshot"
+        }
+        "/v1/us/stock-info/fin-consensus" => {
+            "use the AP endpoint GET /v1/quote/financial-consensus-detail"
+        }
+        "/v1/us/stock-info/etf-dividend-info" | "/v1/us/stock-info/company-dividends" => {
+            "use the AP endpoint GET /v1/quote/dividends"
+        }
+        _ if path.starts_with("/v1/us/orders/") => "use the AP endpoint GET /v1/trade/order",
+        _ if path.starts_with("/v1/us/") => NO_AP_EQUIVALENT,
+        _ => return None,
+    };
+    Some(hint)
+}
+
 /// Represents an HTTP error
 #[derive(Debug)]
 pub struct HttpError(pub reqwest::Error);
@@ -136,3 +248,169 @@ impl std::error::Error for HttpError {}
 
 /// Http client result type
 pub type HttpClientResult = std::result::Result;
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn restricted(path: &str, required: DcRegion) -> String {
+        let current = match required {
+            DcRegion::Ap => DcRegion::Us,
+            DcRegion::Us => DcRegion::Ap,
+        };
+        HttpClientError::DcRegionRestricted {
+            path: path.to_string(),
+            required,
+            current,
+        }
+        .to_string()
+    }
+
+    const AP_PREFIX: &str =
+        "is only available in the AP data center and is not supported for your US-region account";
+    const US_PREFIX: &str =
+        "is only available in the US data center and is not supported for your AP-region account";
+
+    #[test]
+    fn dc_region_restricted_names_us_alternative() {
+        let cases = [
+            (
+                "/v1/asset/account",
+                "use the US endpoint GET /v1/us/assets/cash-and-buy-power or GET /v1/us/assets/overview (TradeContext US methods)",
+            ),
+            (
+                "/v1/asset/cashflow",
+                "use the US endpoint POST /v1/us/assets/transaction-history (TradeContext US methods)",
+            ),
+            (
+                "/v1/asset/stock",
+                "use the US endpoint GET /v1/us/assets/overview (TradeContext US methods)",
+            ),
+            (
+                "/v1/asset/exchange_rates",
+                "use the US endpoint GET /v1/us/assets/exchange-rates (TradeContext US methods)",
+            ),
+            (
+                "/v1/trade/order",
+                "use the US endpoint GET /v1/us/orders/{order_id} (TradeContext US methods)",
+            ),
+            (
+                "/v1/risk/margin-ratio",
+                "there is no US equivalent; account-level margin is at GET /v1/us/assets/cash-and-buy-power (margin_status)",
+            ),
+            (
+                "/v3/trade/execution/all",
+                "use GET /v1/trade/execution/history",
+            ),
+            ("/v1/asset/fund", "there is no US equivalent"),
+            ("quote/brokers", "there is no US equivalent"),
+            ("/v1/quote/operatings", "there is no US equivalent"),
+            ("/v1/quote/broker-holding", "there is no US equivalent"),
+            (
+                "/v1/quote/broker-holding/detail",
+                "there is no US equivalent",
+            ),
+            (
+                "/v1/quote/broker-holding/daily",
+                "there is no US equivalent",
+            ),
+            ("/v1/dailycoins/query", "there is no US equivalent"),
+            ("/v1/dailycoins/create", "there is no US equivalent"),
+        ];
+        for (path, hint) in cases {
+            assert_eq!(
+                restricted(path, DcRegion::Ap),
+                format!("this API ({path}) {AP_PREFIX}; {hint}"),
+                "unexpected message for {path}"
+            );
+        }
+    }
+
+    #[test]
+    fn dc_region_restricted_names_ap_alternative() {
+        let cases = [
+            (
+                "/v1/us/orders/123",
+                "use the AP endpoint GET /v1/trade/order",
+            ),
+            (
+                "/v1/us/orders/query",
+                "use the AP endpoint GET /v1/trade/order/today or GET /v1/trade/order/history",
+            ),
+            (
+                "/v1/us/assets/overview",
+                "use the AP endpoints GET /v1/asset/account and GET /v1/asset/stock",
+            ),
+            (
+                "/v1/us/assets/transaction-history",
+                "use the AP endpoint GET /v1/asset/cashflow",
+            ),
+            (
+                "/v1/us/assets/exchange-rates",
+                "use the AP endpoint GET /v1/asset/exchange_rates",
+            ),
+            (
+                "/v1/us/assets/cash-and-buy-power",
+                "use the AP endpoint GET /v1/asset/account",
+            ),
+            (
+                "/v1/us/assets/available-holding",
+                "use the AP endpoint GET /v1/asset/stock (available_quantity)",
+            ),
+            ("/v1/us/assets/pl/realized", "there is no AP equivalent"),
+            ("/v1/us/gemini/crypto-overview", "there is no AP equivalent"),
+            ("/v1/us/stock-info/etf-files", "there is no AP equivalent"),
+            (
+                "/v1/us/stock-info/company-overview",
+                "use the AP endpoint GET /v1/quote/comp-overview",
+            ),
+            (
+                "/v1/us/stock-info/valuation-overview",
+                "use the AP endpoint GET /v1/quote/valuation",
+            ),
+            (
+                "/v1/us/stock-info/finn-overview",
+                "use the AP endpoint GET /v1/quote/financial-reports",
+            ),
+            (
+                "/v1/us/quote/financials/statements",
+                "use the AP endpoint GET /v1/quote/financial-reports",
+            ),
+            (
+                "/v1/us/stock-info/fin-keyfactor",
+                "use the AP endpoint GET /v1/quote/financials/earnings-snapshot",
+            ),
+            (
+                "/v1/us/stock-info/fin-consensus",
+                "use the AP endpoint GET /v1/quote/financial-consensus-detail",
+            ),
+            (
+                "/v1/us/stock-info/etf-dividend-info",
+                "use the AP endpoint GET /v1/quote/dividends",
+            ),
+            (
+                "/v1/us/stock-info/company-dividends",
+                "use the AP endpoint GET /v1/quote/dividends",
+            ),
+        ];
+        for (path, hint) in cases {
+            assert_eq!(
+                restricted(path, DcRegion::Us),
+                format!("this API ({path}) {US_PREFIX}; {hint}"),
+                "unexpected message for {path}"
+            );
+        }
+    }
+
+    #[test]
+    fn dc_region_restricted_without_hint_keeps_message() {
+        assert_eq!(
+            restricted("/v1/unknown", DcRegion::Ap),
+            format!("this API (/v1/unknown) {AP_PREFIX}")
+        );
+        assert_eq!(
+            restricted("/v1/unknown", DcRegion::Us),
+            format!("this API (/v1/unknown) {US_PREFIX}")
+        );
+    }
+}
diff --git a/rust/src/blocking/portfolio.rs b/rust/src/blocking/portfolio.rs
index cb9b376c6d..1d7e1864d8 100644
--- a/rust/src/blocking/portfolio.rs
+++ b/rust/src/blocking/portfolio.rs
@@ -29,6 +29,9 @@ impl PortfolioContextSync {
     }
 
     /// Get exchange rates
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `TradeContextSync::us_exchange_rates` instead.
     pub fn exchange_rate(&self) -> Result {
         self.rt.call(|ctx| async move { ctx.exchange_rate().await })
     }
diff --git a/rust/src/blocking/trade.rs b/rust/src/blocking/trade.rs
index e19498d6eb..4bb8208f1f 100644
--- a/rust/src/blocking/trade.rs
+++ b/rust/src/blocking/trade.rs
@@ -9,10 +9,12 @@ use crate::{
         FundPositionsResponse, GetAllExecutionsOptions, GetCashFlowOptions,
         GetFundPositionsOptions, GetHistoryExecutionsOptions, GetHistoryOrdersOptions,
         GetOrderDetailOptions, GetStockPositionsOptions, GetTodayExecutionsOptions,
-        GetTodayOrdersOptions, GetUSHistoryOrders, GetUSRealizedPLOptions, MarginRatio, Order,
-        OrderDetail, PushEvent, QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse,
+        GetTodayOrdersOptions, GetUSAvailableHoldingOptions, GetUSHistoryOrders,
+        GetUSRealizedPLOptions, GetUSTransactionHistoryOptions, MarginRatio, Order, OrderDetail,
+        PushEvent, QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse,
         SubmitMultiLegOrderOptions, SubmitOrderOptions, SubmitOrderResponse, TopicType,
-        TradeContext, USAssetOverview, USOrderDetailResponse, USRealizedPL,
+        TradeContext, USAssetOverview, USAvailableHolding, USCashAndBuyPower, USExchangeRates,
+        USOrderDetailResponse, USRealizedPL, USTransactionHistory,
     },
 };
 
@@ -52,6 +54,8 @@ impl TradeContextSync {
 
     /// Get history executions
     ///
+    /// `side` may be `Unknown` on Longbridge US accounts.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -115,6 +119,9 @@ impl TradeContextSync {
     }
 
     /// Get all executions
+    ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `history_executions` instead.
     pub fn all_executions(
         &self,
         options: impl Into> + Send + 'static,
@@ -311,6 +318,9 @@ impl TradeContextSync {
 
     /// Get account balance
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_cash_and_buy_power` (or `us_asset_overview`) instead.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -337,6 +347,9 @@ impl TradeContextSync {
 
     /// Get cash flow
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_transaction_history` instead.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -364,6 +377,9 @@ impl TradeContextSync {
 
     /// Get fund positions
     ///
+    /// AP accounts only: US data-center accounts have no fund holdings and
+    /// get a region error. No US equivalent.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -392,6 +408,9 @@ impl TradeContextSync {
 
     /// Get stock positions
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_asset_overview` (`stock_list`) instead.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -420,6 +439,10 @@ impl TradeContextSync {
 
     /// Get margin ratio
     ///
+    /// AP accounts only: US data-center accounts get a region error. No US
+    /// equivalent; for US margin info see `us_cash_and_buy_power`
+    /// (`margin_status`).
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -445,6 +468,9 @@ impl TradeContextSync {
 
     /// Get order detail
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_order_detail` instead.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -487,12 +513,16 @@ impl TradeContextSync {
     // ───────────────────────────────────────────
 
     /// Query the paginated US order list (blocking)
+    ///
+    /// US token required.
     pub fn us_query_orders(&self, opts: GetUSHistoryOrders) -> Result {
         self.rt
             .call(move |ctx| async move { ctx.us_query_orders(opts).await })
     }
 
     /// Get US order detail (blocking)
+    ///
+    /// US token required.
     pub fn us_order_detail(
         &self,
         order_id: impl Into + Send + 'static,
@@ -502,14 +532,57 @@ impl TradeContextSync {
     }
 
     /// Get the full US account asset overview (blocking)
+    ///
+    /// US token required.
     pub fn us_asset_overview(&self) -> Result {
         self.rt
             .call(move |ctx| async move { ctx.us_asset_overview().await })
     }
 
     /// Get realized P&L for the US account (blocking)
+    ///
+    /// US token required.
     pub fn us_realized_pl(&self, opts: GetUSRealizedPLOptions) -> Result {
         self.rt
             .call(move |ctx| async move { ctx.us_realized_pl(opts).await })
     }
+
+    /// Get cash, buying power and margin status for the US account (blocking)
+    ///
+    /// US token required.
+    pub fn us_cash_and_buy_power(&self, currency: Option<&str>) -> Result {
+        let currency = currency.map(ToString::to_string);
+        self.rt
+            .call(move |ctx| async move { ctx.us_cash_and_buy_power(currency.as_deref()).await })
+    }
+
+    /// Get the quantity of a US holding that is available to trade (blocking)
+    ///
+    /// US token required.
+    pub fn us_available_holding(
+        &self,
+        opts: GetUSAvailableHoldingOptions,
+    ) -> Result {
+        self.rt
+            .call(move |ctx| async move { ctx.us_available_holding(opts).await })
+    }
+
+    /// Get the US account transaction history (blocking)
+    ///
+    /// US token required.
+    pub fn us_transaction_history(
+        &self,
+        opts: GetUSTransactionHistoryOptions,
+    ) -> Result {
+        self.rt
+            .call(move |ctx| async move { ctx.us_transaction_history(opts).await })
+    }
+
+    /// Get the exchange rates used by the US account (blocking)
+    ///
+    /// US token required.
+    pub fn us_exchange_rates(&self) -> Result {
+        self.rt
+            .call(move |ctx| async move { ctx.us_exchange_rates().await })
+    }
 }
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index e8f47ad6cd..3bc6e0813e 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -47,7 +47,7 @@ pub use dca::DCAContext;
 pub use error::{Error, Result, SimpleError, SimpleErrorKind};
 pub use fund::FundContext;
 pub use fundamental::FundamentalContext;
-// ── US-market type re-exports ─────────────────────────────────────────────────
+// US-market type re-exports
 pub use fundamental::types::{
     FinancialStatementKind, IndustryRankIndicator, IndustryRankSortType, USCompanyDividends,
     USCompanyOverview, USDividendItem, USETFDividendInfo, USETFFile, USETFFilesResponse,
@@ -65,8 +65,11 @@ pub use screener::ScreenerContext;
 pub use sharelist::SharelistContext;
 pub use signal::SignalContext;
 pub use trade::{
-    GetUSHistoryOrders, GetUSRealizedPLOptions, QueryUSOrdersOptions, QueryUSOrdersResponse,
-    TradeContext, USAssetOverview, USCashEntry, USCryptoEntry, USOrderDetailResponse,
-    USOrderHistory, USRealizedPL, USRealizedPLEntry, USRealizedPLMetric,
+    GetUSAvailableHoldingOptions, GetUSHistoryOrders, GetUSRealizedPLOptions,
+    GetUSTransactionHistoryOptions, QueryUSOrdersOptions, QueryUSOrdersResponse, TradeContext,
+    USAssetOverview, USAvailableHolding, USBuyLimitInfo, USCashAndBuyPower, USCashDetail,
+    USCashEntry, USCryptoEntry, USExchangeRate, USExchangeRates, USMarginStatus,
+    USOrderDetailResponse, USOrderHistory, USRealizedPL, USRealizedPLEntry, USRealizedPLMetric,
+    USTransaction, USTransactionHistory,
 };
 pub use types::Market;
diff --git a/rust/src/portfolio/context.rs b/rust/src/portfolio/context.rs
index b40921f2c0..6e29325a5d 100644
--- a/rust/src/portfolio/context.rs
+++ b/rust/src/portfolio/context.rs
@@ -1,6 +1,6 @@
 use std::sync::Arc;
 
-use longbridge_httpcli::{HttpClient, Json, Method};
+use longbridge_httpcli::{DcRegion, HttpClient, Json, Method};
 use serde::{Serialize, de::DeserializeOwned};
 use tracing::{Subscriber, dispatcher, instrument::WithSubscriber};
 
@@ -67,11 +67,21 @@ impl PortfolioContext {
 
     /// Get exchange rates for supported currencies.
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `TradeContext::us_exchange_rates` instead.
+    ///
     /// Path: `GET /v1/asset/exchange_rates`
     pub async fn exchange_rate(&self) -> Result {
-        #[derive(Serialize)]
-        struct Empty {}
-        self.get("/v1/asset/exchange_rates", Empty {}).await
+        Ok(self
+            .0
+            .http_cli
+            .request(Method::GET, "/v1/asset/exchange_rates")
+            .dc_restrict(DcRegion::Ap)
+            .response::>()
+            .send()
+            .with_subscriber(self.0.log_subscriber.clone())
+            .await?
+            .0)
     }
 
     // ── profit_analysis ───────────────────────────────────────────
@@ -258,3 +268,30 @@ fn date_to_unix_opt(date: Option<&str>) -> Option {
 fn date_to_unix_end_opt(date: Option<&str>) -> Option {
     date_to_unix_opt(date).map(|ts| ts + 86399)
 }
+
+#[cfg(test)]
+mod dc_restrict_tests {
+    use longbridge_httpcli::HttpClientError;
+
+    use super::*;
+    use crate::Error;
+
+    /// `exchange_rate` fails fast for a US (`us_`) token.
+    #[tokio::test(flavor = "multi_thread")]
+    async fn exchange_rate_rejects_us_token() {
+        let config = Arc::new(Config::from_apikey("us_app_key", "app_secret", "us_token"));
+        let ctx = PortfolioContext::new(config);
+        match ctx.exchange_rate().await {
+            Err(Error::HttpClient(HttpClientError::DcRegionRestricted {
+                path,
+                required,
+                current,
+            })) => {
+                assert_eq!(path, "/v1/asset/exchange_rates", "restricted path mismatch");
+                assert_eq!(required, DcRegion::Ap, "expected AP-only restriction");
+                assert_eq!(current, DcRegion::Us, "expected US session region");
+            }
+            other => panic!("expected DcRegionRestricted, got {other:?}"),
+        }
+    }
+}
diff --git a/rust/src/trade/context.rs b/rust/src/trade/context.rs
index aa4402bfd4..2bbb67c559 100644
--- a/rust/src/trade/context.rs
+++ b/rust/src/trade/context.rs
@@ -15,10 +15,12 @@ use crate::{
         GetAllExecutionsOptions, GetCashFlowOptions, GetFundPositionsOptions,
         GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions,
         GetStockPositionsOptions, GetTodayExecutionsOptions, GetTodayOrdersOptions,
-        GetUSHistoryOrders, GetUSRealizedPLOptions, MarginRatio, Order, OrderDetail, OrderSide,
-        PushEvent, QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse,
+        GetUSAvailableHoldingOptions, GetUSHistoryOrders, GetUSRealizedPLOptions,
+        GetUSTransactionHistoryOptions, MarginRatio, Order, OrderDetail, OrderSide, PushEvent,
+        QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse,
         SubmitMultiLegOrderOptions, SubmitOrderOptions, TopicType, USAssetOverview,
-        USOrderDetailResponse, USRealizedPL,
+        USAvailableHolding, USCashAndBuyPower, USExchangeRates, USOrderDetailResponse,
+        USRealizedPL, USTransactionHistory,
         core::{Command, Core},
     },
 };
@@ -180,6 +182,8 @@ impl TradeContext {
 
     /// Get history executions
     ///
+    /// `side` may be `Unknown` on Longbridge US accounts.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -312,6 +316,9 @@ impl TradeContext {
 
     /// Get all executions
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `history_executions` instead.
+    ///
     /// Reference: 
     pub async fn all_executions(
         &self,
@@ -321,6 +328,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v3/trade/execution/all")
+            .dc_restrict(DcRegion::Ap)
             .query_params(options.into().unwrap_or_default())
             .response::>()
             .send()
@@ -632,6 +640,9 @@ impl TradeContext {
 
     /// Get account balance
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_cash_and_buy_power` (or `us_asset_overview`) instead.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -668,6 +679,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/asset/account")
+            .dc_restrict(DcRegion::Ap)
             .query_params(Request { currency })
             .response::>()
             .send()
@@ -679,6 +691,9 @@ impl TradeContext {
 
     /// Get cash flow
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_transaction_history` instead.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -716,6 +731,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/asset/cashflow")
+            .dc_restrict(DcRegion::Ap)
             .query_params(options)
             .response::>()
             .send()
@@ -729,6 +745,9 @@ impl TradeContext {
     ///
     /// Reference: 
     ///
+    /// AP accounts only: US data-center accounts have no fund holdings and
+    /// get a region error. No US equivalent.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -756,6 +775,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/asset/fund")
+            .dc_restrict(DcRegion::Ap)
             .query_params(opts.into().unwrap_or_default())
             .response::>()
             .send()
@@ -766,6 +786,9 @@ impl TradeContext {
 
     /// Get stock positions
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_asset_overview` (`stock_list`) instead.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -795,6 +818,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/asset/stock")
+            .dc_restrict(DcRegion::Ap)
             .query_params(opts.into().unwrap_or_default())
             .response::>()
             .send()
@@ -807,6 +831,10 @@ impl TradeContext {
     ///
     /// Reference: 
     ///
+    /// AP accounts only: US data-center accounts get a region error. No US
+    /// equivalent; for US margin info see `us_cash_and_buy_power`
+    /// (`margin_status`).
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -836,6 +864,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/risk/margin-ratio")
+            .dc_restrict(DcRegion::Ap)
             .query_params(Request {
                 symbol: symbol.into(),
             })
@@ -848,6 +877,9 @@ impl TradeContext {
 
     /// Get order detail
     ///
+    /// AP accounts only: US data-center accounts get a region error; use
+    /// `us_order_detail` instead.
+    ///
     /// Reference: 
     ///
     /// # Examples
@@ -882,6 +914,7 @@ impl TradeContext {
             .0
             .http_cli
             .request(Method::GET, "/v1/trade/order")
+            .dc_restrict(DcRegion::Ap)
             .response::>()
             .query_params(options.into())
             .send()
@@ -1093,4 +1126,194 @@ impl TradeContext {
             .await?
             .0)
     }
+
+    /// Get cash, buying power and margin status for the US account.
+    ///
+    /// `currency`: optional, e.g. `"USD"`.
+    ///
+    /// Path: `GET /v1/us/assets/cash-and-buy-power`
+    ///
+    /// US token required.
+    pub async fn us_cash_and_buy_power(&self, currency: Option<&str>) -> Result {
+        #[derive(Serialize)]
+        struct Query<'a> {
+            #[serde(skip_serializing_if = "Option::is_none")]
+            currency: Option<&'a str>,
+        }
+
+        Ok(self
+            .0
+            .http_cli
+            .request(Method::GET, "/v1/us/assets/cash-and-buy-power")
+            .dc_restrict(DcRegion::Us)
+            .query_params(Query { currency })
+            .response::>()
+            .send()
+            .with_subscriber(self.0.log_subscriber.clone())
+            .await?
+            .0)
+    }
+
+    /// Get the quantity of a US holding that is available to trade.
+    ///
+    /// Path: `GET /v1/us/assets/available-holding`
+    ///
+    /// US token required.
+    pub async fn us_available_holding(
+        &self,
+        opts: GetUSAvailableHoldingOptions,
+    ) -> Result {
+        #[derive(Serialize)]
+        struct Query {
+            symbol: String,
+            equity_type: String,
+            position_side: String,
+        }
+
+        let equity_type = if opts.equity_type.is_empty() {
+            "STOCK".to_string()
+        } else {
+            opts.equity_type
+        };
+        let position_side = if opts.position_side.is_empty() {
+            "LONG".to_string()
+        } else {
+            opts.position_side
+        };
+
+        Ok(self
+            .0
+            .http_cli
+            .request(Method::GET, "/v1/us/assets/available-holding")
+            .dc_restrict(DcRegion::Us)
+            .query_params(Query {
+                symbol: opts.symbol,
+                equity_type,
+                position_side,
+            })
+            .response::>()
+            .send()
+            .with_subscriber(self.0.log_subscriber.clone())
+            .await?
+            .0)
+    }
+
+    /// Get the US account transaction history (deposits, withdrawals, trades,
+    /// corporate actions, transfers and so on), one page at a time.
+    ///
+    /// Path: `POST /v1/us/assets/transaction-history`
+    ///
+    /// US token required.
+    pub async fn us_transaction_history(
+        &self,
+        opts: GetUSTransactionHistoryOptions,
+    ) -> Result {
+        #[derive(Debug, Serialize)]
+        struct Body {
+            start: i64,
+            end: i64,
+            page: i32,
+            size: i32,
+            #[serde(skip_serializing_if = "Vec::is_empty")]
+            types: Vec,
+            #[serde(skip_serializing_if = "String::is_empty")]
+            currency: String,
+        }
+
+        Ok(self
+            .0
+            .http_cli
+            .request(Method::POST, "/v1/us/assets/transaction-history")
+            .dc_restrict(DcRegion::Us)
+            .body(Json(Body {
+                start: opts.start_at.unix_timestamp(),
+                end: opts.end_at.unix_timestamp(),
+                page: if opts.page > 0 { opts.page } else { 1 },
+                size: if opts.size > 0 { opts.size } else { 20 },
+                types: opts.types,
+                currency: opts.currency,
+            }))
+            .response::>()
+            .send()
+            .with_subscriber(self.0.log_subscriber.clone())
+            .await?
+            .0)
+    }
+
+    /// Get the exchange rates used by the US account.
+    ///
+    /// The upstream two-level map is flattened into
+    /// [`USExchangeRates::exchanges`]; each entry keeps the two upstream map
+    /// keys as `universal_key` and `spec_key`.
+    ///
+    /// Path: `GET /v1/us/assets/exchange-rates`
+    ///
+    /// US token required.
+    pub async fn us_exchange_rates(&self) -> Result {
+        Ok(self
+            .0
+            .http_cli
+            .request(Method::GET, "/v1/us/assets/exchange-rates")
+            .dc_restrict(DcRegion::Us)
+            .response::>()
+            .send()
+            .with_subscriber(self.0.log_subscriber.clone())
+            .await?
+            .0)
+    }
+}
+
+#[cfg(test)]
+mod dc_restrict_tests {
+    use longbridge_httpcli::HttpClientError;
+    use time::macros::datetime;
+
+    use super::*;
+    use crate::Error;
+
+    fn us_trade_context() -> TradeContext {
+        let config = Arc::new(Config::from_apikey("us_app_key", "app_secret", "us_token"));
+        TradeContext::new(config).0
+    }
+
+    #[track_caller]
+    fn assert_ap_restricted(res: Result, path: &str)
+    where
+        T: std::fmt::Debug,
+    {
+        match res {
+            Err(Error::HttpClient(HttpClientError::DcRegionRestricted {
+                path: p,
+                required,
+                current,
+            })) => {
+                assert_eq!(p, path, "restricted path mismatch");
+                assert_eq!(required, DcRegion::Ap, "expected AP-only restriction");
+                assert_eq!(current, DcRegion::Us, "expected US session region");
+            }
+            other => panic!("expected DcRegionRestricted for {path}, got {other:?}"),
+        }
+    }
+
+    /// AP-only asset/risk/order endpoints fail fast for a US (`us_`) token
+    /// instead of sending a request the US data center rejects.
+    #[tokio::test(flavor = "multi_thread")]
+    async fn ap_only_endpoints_reject_us_token() {
+        let ctx = us_trade_context();
+
+        assert_ap_restricted(ctx.account_balance(None).await, "/v1/asset/account");
+        assert_ap_restricted(
+            ctx.cash_flow(GetCashFlowOptions::new(
+                datetime!(2026-01-01 0:00 UTC),
+                datetime!(2026-01-02 0:00 UTC),
+            ))
+            .await,
+            "/v1/asset/cashflow",
+        );
+        assert_ap_restricted(ctx.fund_positions(None).await, "/v1/asset/fund");
+        assert_ap_restricted(ctx.stock_positions(None).await, "/v1/asset/stock");
+        assert_ap_restricted(ctx.margin_ratio("700.HK").await, "/v1/risk/margin-ratio");
+        assert_ap_restricted(ctx.order_detail("1").await, "/v1/trade/order");
+        assert_ap_restricted(ctx.all_executions(None).await, "/v3/trade/execution/all");
+    }
 }
diff --git a/rust/src/trade/mod.rs b/rust/src/trade/mod.rs
index 31ecdedcd8..e35c7979e2 100644
--- a/rust/src/trade/mod.rs
+++ b/rust/src/trade/mod.rs
@@ -35,8 +35,10 @@ pub use types::{
     FundPositionChannel,
     FundPositionsResponse,
     // US-market types
+    GetUSAvailableHoldingOptions,
     GetUSHistoryOrders,
     GetUSRealizedPLOptions,
+    GetUSTransactionHistoryOptions,
     MarginRatio,
     MultiLegInfo,
     MultiLegOrderLeg,
@@ -63,11 +65,18 @@ pub use types::{
     TriggerStatus,
     USAssetOverview,
     USAttachedOrder,
+    USAvailableHolding,
     USButtonControl,
+    USBuyLimitInfo,
+    USCashAndBuyPower,
+    USCashDetail,
     USCashEntry,
     USChargeDetail,
     USChargeItem,
     USCryptoEntry,
+    USExchangeRate,
+    USExchangeRates,
+    USMarginStatus,
     USOrderDetail,
     USOrderDetailResponse,
     USOrderHistory,
@@ -75,4 +84,6 @@ pub use types::{
     USRealizedPLEntry,
     USRealizedPLMetric,
     USStockEntry,
+    USTransaction,
+    USTransactionHistory,
 };
diff --git a/rust/src/trade/types.rs b/rust/src/trade/types.rs
index 7a73024189..3b0a5a2c66 100644
--- a/rust/src/trade/types.rs
+++ b/rust/src/trade/types.rs
@@ -1,3 +1,5 @@
+use std::collections::BTreeMap;
+
 use num_enum::{FromPrimitive, IntoPrimitive};
 use rust_decimal::Decimal;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -133,7 +135,9 @@ pub struct Execution {
     pub quantity: Decimal,
     /// Executed price
     pub price: Decimal,
-    /// Order side
+    /// Order side. `Unknown` when the response omits it, as
+    /// `/v1/trade/execution/history` does for Longbridge US accounts.
+    #[serde(default)]
     pub side: OrderSide,
 }
 
@@ -1517,15 +1521,67 @@ pub struct USCryptoEntry {
     /// Asset type (e.g. `"CRYPTO"`)
     #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
     pub asset_type: String,
-    /// Average cost price
-    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
-    pub average_cost: String,
-    /// User-facing trading-pair symbol (e.g. `"BTCUSD.BKKT"`)
+    /// Trading-pair code (e.g. `"BTCUSD"`); the user-facing symbol is
+    /// `"."` (e.g. `"BTCUSD.BKKT"`)
     #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
     pub symbol: String,
+    /// Holding quantity
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub quantity: String,
     /// Settlement currency
     #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
     pub currency: String,
+    /// Average cost price; empty when the server has none
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub average_cost: String,
+    /// Market code (e.g. `"BKKT"`)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub market: String,
+    /// Trade status
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub trade_status: String,
+    /// Previous close price
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub prev_close: String,
+    /// Latest price
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub last_done: String,
+    /// Market price
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub market_price: String,
+    /// Pre-market close price
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub pretrade_close: String,
+    /// Today's investment value
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub stock_invest_of_today: String,
+    /// Today's profit/loss
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub today_pl: String,
+    /// Today's investment value (pre-market)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub pretrade_stock_invest_of_today: String,
+    /// Today's profit/loss (pre-market)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub pretrade_today_pl: String,
+    /// Overnight-session latest price
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub night_last_done: String,
+    /// Overnight-session previous close
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub night_prev_close: String,
+    /// Position side (long/short)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub position_side: String,
+    /// Position open time (Unix-second string; `"0"` when unknown)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub open_position_time: String,
+    /// Asset name (e.g. `"Bitcoin"`)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub name: String,
+    /// Industry classification ID
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub industry_counter_id: String,
     /// Industry name
     #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
     pub industry_name: String,
@@ -1691,12 +1747,474 @@ pub struct USRealizedPL {
     pub realized_pl_list: Vec,
 }
 
+/// Request for [`crate::TradeContext::us_available_holding`].
+#[derive(Debug, Clone, Default)]
+pub struct GetUSAvailableHoldingOptions {
+    /// Security symbol, e.g. `"AAPL.US"`, an option symbol such as
+    /// `"AAPL261120C345000.US"`, or a crypto pair such as `"BTCUSD.BKKT"`.
+    pub symbol: String,
+    /// Holding type: `"STOCK"`, `"OPTION"` or `"CRYPTO"`. Defaults to
+    /// `"STOCK"` if empty.
+    pub equity_type: String,
+    /// Position side: `"LONG"` or `"SHORT"`. Defaults to `"LONG"` if empty.
+    pub position_side: String,
+}
+
+/// Response for [`crate::TradeContext::us_available_holding`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USAvailableHolding {
+    /// Quantity available to sell (long) or buy to cover (short); negative for
+    /// a short position
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub available_qty: String,
+}
+
+/// Buying power in [`USCashAndBuyPower`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USBuyLimitInfo {
+    /// Currency
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub currency: String,
+    /// Cash buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub cash_buy_power: String,
+    /// Overnight buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub overnight_buy_power: String,
+    /// Day-trade buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub day_trade_buy_power: String,
+    /// Instant buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub instant_buy_power: String,
+    /// Intraday margin buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub intraday_margin_buy_power: String,
+    /// Option buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub option_buy_power: String,
+    /// Crypto buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub crypto_buy_power: String,
+    /// Margin maintenance excess used for buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub mme: String,
+}
+
+/// One cash currency entry in [`USCashAndBuyPower`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USCashDetail {
+    /// Currency
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub currency: String,
+    /// Total cash
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub total_amount: String,
+    /// Available cash
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub available_cash: String,
+    /// Withdrawable cash
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub withdraw_cash: String,
+    /// Cash frozen for pending orders
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub frozen_cash: String,
+    /// Settled cash
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub settled_cash: String,
+    /// Outstanding (unsettled) amount
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub outstanding: String,
+    /// Amount held for external use (e.g. IPO or fund subscriptions)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub external_amount: String,
+}
+
+/// Margin account status in [`USCashAndBuyPower`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USMarginStatus {
+    /// Currency
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub currency: String,
+    /// Net liquidation value
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub nlv: String,
+    /// Margin equity
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub margin_equity: String,
+    /// Margin maintenance excess
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub margin_maintenance_excess: String,
+    /// Maintenance margin requirement
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub mmr: String,
+    /// Regulation T excess
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub reg_t_excess: String,
+    /// Special memorandum account
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub sma: String,
+}
+
+/// Response for [`crate::TradeContext::us_cash_and_buy_power`].
+/// Field names match `GET /v1/us/assets/cash-and-buy-power`.
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USCashAndBuyPower {
+    /// Buying power
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub buy_limit_info: USBuyLimitInfo,
+    /// Cash per currency
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub cash_list: Vec,
+    /// Margin account status
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub margin_status: USMarginStatus,
+}
+
+/// Request for [`crate::TradeContext::us_transaction_history`].
+#[derive(Debug, Clone)]
+pub struct GetUSTransactionHistoryOptions {
+    /// Start time (inclusive)
+    pub start_at: OffsetDateTime,
+    /// End time (inclusive)
+    pub end_at: OffsetDateTime,
+    /// Page number, starting at 1. Defaults to 1 if 0.
+    pub page: i32,
+    /// Page size. Defaults to 20 if 0.
+    pub size: i32,
+    /// Transaction types to include; empty means all. Values:
+    /// `"TT_DEPOSIT_AND_WITHDRAWAL"`, `"TT_STOCKS_AND_ETFS_TRADING"`,
+    /// `"TT_OPTIONS_TRADING"`, `"TT_CRYPTO_TRADING"`, `"TT_CORPORATE_ACTION"`,
+    /// `"TT_TRANSFER_IN_AND_OUT"`, `"TT_CRYPTO_TRANSFER"`,
+    /// `"TT_MARGIN_FINANCING"`, `"TT_OTHER"`.
+    pub types: Vec,
+    /// Currency filter, e.g. `"USD"`; empty means all.
+    pub currency: String,
+}
+
+impl GetUSTransactionHistoryOptions {
+    /// Create a request for transactions between `start_at` and `end_at`.
+    pub fn new(start_at: OffsetDateTime, end_at: OffsetDateTime) -> Self {
+        Self {
+            start_at,
+            end_at,
+            page: 1,
+            size: 20,
+            types: Vec::new(),
+            currency: String::new(),
+        }
+    }
+}
+
+/// One record in [`USTransactionHistory`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USTransaction {
+    /// Display title
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub title: String,
+    /// Business code
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub biz_code: String,
+    /// Business code name
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub biz_code_name: String,
+    /// Amount; negative for outflows
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub amount: String,
+    /// Currency
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub currency: String,
+    /// Security symbol, if the record relates to one (e.g. `"AAPL.US"`)
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub symbol: String,
+    /// Market code
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub market: String,
+    /// Holding type
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub equity_type: String,
+    /// Position side
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub position_side: String,
+    /// Quantity
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub quantity: String,
+    /// Quantity description
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub quantity_description: String,
+    /// Reference number
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub ref_no: String,
+    /// Remark
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub remark: String,
+    /// Creation time
+    #[serde(
+        default,
+        deserialize_with = "crate::serde_utils::timestamp_opt_lenient::deserialize",
+        serialize_with = "crate::serde_utils::rfc3339_opt::serialize"
+    )]
+    pub create_at: Option,
+    /// Completion time
+    #[serde(
+        default,
+        deserialize_with = "crate::serde_utils::timestamp_opt_lenient::deserialize",
+        serialize_with = "crate::serde_utils::rfc3339_opt::serialize"
+    )]
+    pub done_at: Option,
+}
+
+/// Response for [`crate::TradeContext::us_transaction_history`].
+/// Field names match `POST /v1/us/assets/transaction-history`.
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USTransactionHistory {
+    /// Current page number
+    #[serde(default, with = "crate::serde_utils::int64_str")]
+    pub current_page: i64,
+    /// Records on this page. The API returns no total count: a page shorter
+    /// than the requested size is the last one.
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    pub items: Vec,
+}
+
+/// One exchange rate in [`USExchangeRates`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct USExchangeRate {
+    /// Account channel the rates apply to, e.g. `"us_lb_apex"` (outer
+    /// `universal_exchanges` key)
+    pub universal_key: String,
+    /// Rate type, e.g. `"am"` or `"reference"` (inner `spec_exchanges` key)
+    pub spec_key: String,
+    /// Base currency
+    pub base_currency: String,
+    /// Other (quote) currency
+    pub other_currency: String,
+    /// Bid rate
+    pub bid_rate: String,
+    /// Offer rate
+    pub offer_rate: String,
+    /// Average rate
+    pub average_rate: String,
+}
+
+/// Response for [`crate::TradeContext::us_exchange_rates`].
+///
+/// The upstream response is a two-level map
+/// (`universal_exchanges..spec_exchanges..exchanges[]`); it is
+/// flattened into a single list, sorted by the two upstream map keys, with
+/// the keys kept on each entry as [`USExchangeRate::universal_key`] and
+/// [`USExchangeRate::spec_key`].
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+#[serde(from = "RawUSExchangeRates")]
+pub struct USExchangeRates {
+    /// Exchange rates
+    pub exchanges: Vec,
+}
+
+#[derive(Deserialize, Default)]
+struct RawUSExchangeRate {
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    base_currency: String,
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    other_currency: String,
+    #[serde(default, with = "crate::serde_utils::value_as_opt_string")]
+    bid_rate: Option,
+    #[serde(default, with = "crate::serde_utils::value_as_opt_string")]
+    offer_rate: Option,
+    #[serde(default, with = "crate::serde_utils::value_as_opt_string")]
+    average_rate: Option,
+}
+
+#[derive(Deserialize, Default)]
+struct RawUSSpecExchanges {
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    exchanges: Vec,
+}
+
+#[derive(Deserialize, Default)]
+struct RawUSUniversalExchanges {
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    spec_exchanges: BTreeMap,
+}
+
+#[derive(Deserialize, Default)]
+struct RawUSExchangeRates {
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    universal_exchanges: BTreeMap,
+    /// Already-flattened form, so that the serialized [`USExchangeRates`]
+    /// deserializes back.
+    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
+    exchanges: Vec,
+}
+
+impl From for USExchangeRates {
+    fn from(raw: RawUSExchangeRates) -> Self {
+        let mut exchanges = raw.exchanges;
+        for (universal_key, universal) in raw.universal_exchanges {
+            for (spec_key, spec) in universal.spec_exchanges {
+                exchanges.extend(spec.exchanges.into_iter().map(|rate| USExchangeRate {
+                    universal_key: universal_key.clone(),
+                    spec_key: spec_key.clone(),
+                    base_currency: rate.base_currency,
+                    other_currency: rate.other_currency,
+                    bid_rate: rate.bid_rate.unwrap_or_default(),
+                    offer_rate: rate.offer_rate.unwrap_or_default(),
+                    average_rate: rate.average_rate.unwrap_or_default(),
+                }));
+            }
+        }
+        Self { exchanges }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use time::macros::datetime;
 
     use super::*;
 
+    #[test]
+    fn execution_without_side_defaults_to_unknown() {
+        // `/v1/trade/execution/history` on a Longbridge US account returns
+        // trades with no `side`; they must still deserialize.
+        let data = r#"{
+            "order_id": "1000000000000000001",
+            "trade_id": "1000000000000000001-1",
+            "symbol": "ETHUSD.BKKT",
+            "trade_done_at": "1790203596",
+            "quantity": "0.168",
+            "price": "2690.34165646"
+        }"#;
+        let execution: Execution = serde_json::from_str(data).expect("execution without side");
+        assert_eq!(
+            execution.side,
+            OrderSide::Unknown,
+            "missing side defaults to Unknown"
+        );
+        assert_eq!(execution.symbol, "ETHUSD.BKKT", "symbol is kept");
+    }
+
+    #[test]
+    fn us_exchange_rates_response() {
+        let data = r#"{
+            "universal_exchanges": {
+                "2": {"spec_exchanges": {"USD": {"exchanges": [
+                    {"base_currency": "USD", "other_currency": "HKD", "bid_rate": 7.8, "offer_rate": "7.85", "average_rate": null}
+                ]}}},
+                "1": {"spec_exchanges": {
+                    "b": {"exchanges": [{"base_currency": "USD", "other_currency": "CNH", "bid_rate": "7.1"}]},
+                    "a": {"exchanges": null}
+                }}
+            }
+        }"#;
+        let resp: USExchangeRates = serde_json::from_str(data).unwrap();
+        assert_eq!(resp.exchanges.len(), 2);
+        assert_eq!(resp.exchanges[0].universal_key, "1");
+        assert_eq!(resp.exchanges[0].spec_key, "b");
+        assert_eq!(resp.exchanges[0].other_currency, "CNH");
+        assert_eq!(resp.exchanges[0].offer_rate, "");
+        assert_eq!(resp.exchanges[1].universal_key, "2");
+        assert_eq!(resp.exchanges[1].spec_key, "USD");
+        assert_eq!(resp.exchanges[1].bid_rate, "7.8");
+        assert_eq!(resp.exchanges[1].offer_rate, "7.85");
+        assert_eq!(resp.exchanges[1].average_rate, "");
+
+        let json = serde_json::to_string(&resp).unwrap();
+        let back: USExchangeRates = serde_json::from_str(&json).unwrap();
+        assert_eq!(back.exchanges.len(), 2);
+        assert_eq!(back.exchanges[1].bid_rate, "7.8");
+    }
+
+    #[test]
+    fn us_cash_and_buy_power_response() {
+        let data = r#"{
+            "buy_limit_info": {"currency": "USD", "cash_buy_power": "100.5", "overnight_buy_power": "90"},
+            "cash_list": [{"currency": "USD", "total_amount": "120", "available_cash": "100.5", "withdraw_cash": "80", "frozen_cash": null}],
+            "margin_status": {"currency": "USD", "nlv": "1200"}
+        }"#;
+        let resp: USCashAndBuyPower = serde_json::from_str(data).unwrap();
+        assert_eq!(resp.buy_limit_info.cash_buy_power, "100.5");
+        assert_eq!(resp.cash_list[0].withdraw_cash, "80");
+        assert_eq!(resp.cash_list[0].frozen_cash, "");
+        assert_eq!(resp.margin_status.nlv, "1200");
+    }
+
+    #[test]
+    fn us_transaction_history_response() {
+        let data = r#"{
+            "current_page": "2",
+            "items": [
+                {"title": "Buy", "amount": "-100", "currency": "USD", "symbol": "AAPL.US", "create_at": "1792600000", "done_at": 1792600060},
+                {"title": "Buy", "amount": "-10", "currency": "USD", "symbol": "BTCUSD.BKKT", "counter_id": "VA/BKKT/BTCUSD", "done_at": "0"}
+            ]
+        }"#;
+        let resp: USTransactionHistory = serde_json::from_str(data).unwrap();
+        assert_eq!(resp.current_page, 2);
+        assert_eq!(resp.items[0].symbol, "AAPL.US");
+        assert_eq!(
+            resp.items[0].create_at.unwrap().unix_timestamp(),
+            1792600000
+        );
+        assert_eq!(resp.items[0].done_at.unwrap().unix_timestamp(), 1792600060);
+        assert_eq!(resp.items[1].symbol, "BTCUSD.BKKT");
+        assert!(resp.items[1].done_at.is_none());
+    }
+
+    /// Shapes (field names, JSON types, map keys) as returned by US prod.
+    #[test]
+    fn us_asset_responses_as_returned_by_prod() {
+        let data = r#"{
+            "current_page": 1,
+            "items": [{
+                "amount": "0.5", "biz_code": "LVAVNSCR", "biz_code_name": "Cryptocurrency Deposit",
+                "counter_id": "VA/BKKT/BTCUSD", "create_at": "1791478565", "currency": "",
+                "done_at": "1791478565", "equity_type": "CRYPTO", "market": "BKKT",
+                "position_side": "LONG", "quantity": "0.5", "quantity_description": "0.5",
+                "ref_no": "R1", "remark": "", "symbol": "BTCUSD.BKKT",
+                "title": "Cryptocurrency Deposit: BTCUSD"
+            }]
+        }"#;
+        let resp: USTransactionHistory = serde_json::from_str(data).unwrap();
+        assert_eq!(resp.current_page, 1);
+        assert_eq!(resp.items[0].symbol, "BTCUSD.BKKT");
+        assert_eq!(resp.items[0].equity_type, "CRYPTO");
+        assert_eq!(resp.items[0].done_at.unwrap().unix_timestamp(), 1791478565);
+
+        let data = r#"{"universal_exchanges": {"us_lb_apex": {"spec_exchanges": {
+            "reference": {"exchanges": [{"average_rate": 1, "base_currency": "USD", "bid_rate": 1, "offer_rate": 1, "other_currency": "USD"}]},
+            "am": {"exchanges": [{"average_rate": 1, "base_currency": "USD", "bid_rate": 1, "offer_rate": 1, "other_currency": "USD"}]}
+        }}}}"#;
+        let resp: USExchangeRates = serde_json::from_str(data).unwrap();
+        let keys: Vec<_> = resp
+            .exchanges
+            .iter()
+            .map(|e| (e.universal_key.as_str(), e.spec_key.as_str()))
+            .collect();
+        assert_eq!(keys, [("us_lb_apex", "am"), ("us_lb_apex", "reference")]);
+        assert_eq!(resp.exchanges[0].average_rate, "1");
+
+        let data = r#"{
+            "account_type": "1", "asset_timestamp": "1792661597", "currency": "USD",
+            "stock_list": [{"symbol": "MULL", "full_symbol": "MULL.US", "counter_id": "ETF/US/MULL", "quantity": "10", "market": "US"}],
+            "crypto_list": [{
+                "asset_type": "CRYPTO", "average_cost": "", "counter_id": "VA/BKKT/ETHUSD",
+                "currency": "USD", "last_done": "2500", "market": "BKKT", "market_price": "2500",
+                "name": "Ethereum", "open_position_time": "0", "position_side": "LONG",
+                "quantity": "0.1", "symbol": "ETHUSD", "today_pl": "", "trade_status": "105"
+            }],
+            "option_list": [], "multi_leg": {"holdings": []}
+        }"#;
+        let resp: USAssetOverview = serde_json::from_str(data).unwrap();
+        assert_eq!(resp.asset_timestamp.unwrap().unix_timestamp(), 1792661597);
+        assert_eq!(resp.stock_list[0].full_symbol, "MULL.US");
+        let crypto = &resp.crypto_list[0];
+        assert_eq!(crypto.symbol, "ETHUSD");
+        assert_eq!(crypto.market, "BKKT");
+        assert_eq!(crypto.quantity, "0.1");
+        assert_eq!(crypto.name, "Ethereum");
+        assert_eq!(crypto.market_price, "2500");
+    }
+
     #[test]
     fn fund_position_response() {
         let data = r#"