From e8e62853f15e2ed096263ea661bd131117b86987 Mon Sep 17 00:00:00 2001 From: Sunli Date: Thu, 30 Jul 2026 11:46:00 +0800 Subject: [PATCH 1/5] chore: release v4.4.2 --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9a4fbbb5..881443b28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.4.2] - 2026-07-30 + ### Added - **All languages:** corrected `OptionVolumeStats` and `OptionVolumeDailyStat` to match the actual API response — fields now are `symbol`, `call_volume`, `put_volume`, `call_open_interest`, `put_open_interest`, `pc_vol` (f32/float), `pc_oi` (f32/float); `OptionVolumeDaily` gains a top-level `symbol` field; `OptionVolumeDailyStat` date field renamed from `timestamp` to `date` (YYYY-MM-DD string) diff --git a/Cargo.toml b/Cargo.toml index 570b445f2..b56a0ae90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = ["rust", "python", "nodejs", "java", "c"] [workspace.package] -version = "4.4.1" +version = "4.4.2" edition = "2024" [profile.release] From c4f26a1d0ce120dad668b70fc418bdeb931ca317 Mon Sep 17 00:00:00 2001 From: Sunli Date: Wed, 22 Jul 2026 17:29:51 +0800 Subject: [PATCH 2/5] feat(trade): re-enable all_executions across all SDKs The API is now available. Uncomment the previously disabled all_executions implementations in Rust, blocking, Python (sync/async), Java, Node.js, C, and C++ SDKs, and restore the Python type stub. --- c/csrc/include/longbridge.h | 36 +++++++++++ c/src/trade_context/context.rs | 95 ++++++++++++++--------------- cpp/include/trade_context.hpp | 3 - cpp/src/trade_context.cpp | 3 - java/src/trade_context.rs | 91 ++++++++++++++------------- nodejs/src/trade/context.rs | 35 ++++++----- python/pysrc/longbridge/openapi.pyi | 58 ++++++++++++------ python/src/trade/context.rs | 70 +++++++++++---------- python/src/trade/context_async.rs | 81 ++++++++++++------------ rust/src/blocking/trade.rs | 23 ++++--- rust/src/trade/context.rs | 42 ++++++------- 11 files changed, 290 insertions(+), 247 deletions(-) diff --git a/c/csrc/include/longbridge.h b/c/csrc/include/longbridge.h index 9fb1509d4..76ee4c608 100644 --- a/c/csrc/include/longbridge.h +++ b/c/csrc/include/longbridge.h @@ -3466,6 +3466,32 @@ typedef struct lb_get_today_executions_options_t { const char *order_id; } lb_get_today_executions_options_t; +/** + * Options for get all executions request + */ +typedef struct lb_get_all_executions_options_t { + /** + * Security code (can be null) + */ + const char *symbol; + /** + * Order id (can be null) + */ + const char *order_id; + /** + * Start time (can be null) + */ + const int64_t *start_at; + /** + * End time (can be null) + */ + const int64_t *end_at; + /** + * Page number (can be null) + */ + const uint64_t *page; +} lb_get_all_executions_options_t; + /** * Options for get history orders request */ @@ -12232,6 +12258,16 @@ void lb_trade_context_today_executions(const struct lb_trade_context_t *ctx, lb_async_callback_t callback, void *userdata); +/** + * Get all executions + * + * @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, + const struct lb_get_all_executions_options_t *opts, + lb_async_callback_t callback, + void *userdata); + /** * Get history orders * diff --git a/c/src/trade_context/context.rs b/c/src/trade_context/context.rs index 73a7c6ddd..e29bce27c 100644 --- a/c/src/trade_context/context.rs +++ b/c/src/trade_context/context.rs @@ -20,14 +20,14 @@ use crate::{ trade_context::{ enum_types::CTopicType, types::{ - CAccountBalanceOwned, CCashFlowOwned, CEstimateMaxPurchaseQuantityOptions, - CEstimateMaxPurchaseQuantityResponseOwned, CExecutionOwned, - CFundPositionsResponseOwned, CGetCashFlowOptions, CGetFundPositionsOptions, - CGetHistoryExecutionsOptions, CGetHistoryOrdersOptions, CGetStockPositionsOptions, - CGetTodayExecutionsOptions, CGetTodayOrdersOptions, CMarginRatioOwned, - COrderDetailOwned, COrderOwned, CPushOrderChanged, CPushOrderChangedOwned, - CReplaceOrderOptions, CStockPositionsResponseOwned, CSubmitOrderOptions, - CSubmitOrderResponseOwned, + CAccountBalanceOwned, CAllExecutionsResponseOwned, CCashFlowOwned, + CEstimateMaxPurchaseQuantityOptions, CEstimateMaxPurchaseQuantityResponseOwned, + CExecutionOwned, CFundPositionsResponseOwned, CGetAllExecutionsOptions, + CGetCashFlowOptions, CGetFundPositionsOptions, CGetHistoryExecutionsOptions, + CGetHistoryOrdersOptions, CGetStockPositionsOptions, CGetTodayExecutionsOptions, + CGetTodayOrdersOptions, CMarginRatioOwned, COrderDetailOwned, COrderOwned, + CPushOrderChanged, CPushOrderChangedOwned, CReplaceOrderOptions, + CStockPositionsResponseOwned, CSubmitOrderOptions, CSubmitOrderResponseOwned, }, }, types::{CCow, CVec, ToFFI, cstr_array_to_rust, cstr_to_rust}, @@ -265,46 +265,45 @@ pub unsafe extern "C" fn lb_trade_context_today_executions( }); } -// TODO: temporarily disabled — restore when API is available -// Get all executions -// -// @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( -// ctx: *const CTradeContext, -// opts: *const CGetAllExecutionsOptions, -// callback: CAsyncCallback, -// userdata: *mut c_void, -// ) { -// let ctx_inner = (*ctx).ctx.clone(); -// let mut opts2 = GetAllExecutionsOptions::new(); -// if !opts.is_null() { -// if !(*opts).symbol.is_null() { -// opts2 = opts2.symbol(cstr_to_rust((*opts).symbol)); -// } -// if !(*opts).order_id.is_null() { -// opts2 = opts2.order_id(cstr_to_rust((*opts).order_id)); -// } -// if !(*opts).start_at.is_null() { -// opts2 = opts2.start_at( -// OffsetDateTime::from_unix_timestamp(*(*opts).start_at).expect("invalid start -// at"), ); -// } -// if !(*opts).end_at.is_null() { -// opts2 = opts2.end_at( -// OffsetDateTime::from_unix_timestamp(*(*opts).end_at).expect("invalid end -// at"), ); -// } -// if !(*opts).page.is_null() { -// opts2 = opts2.page(*(*opts).page); -// } -// } -// execute_async(callback, ctx, userdata, async move { -// let resp: CCow = -// CCow::new(ctx_inner.all_executions(opts2).await?); -// Ok(resp) -// }); -// } +/// Get all executions +/// +/// @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( + ctx: *const CTradeContext, + opts: *const CGetAllExecutionsOptions, + callback: CAsyncCallback, + userdata: *mut c_void, +) { + let ctx_inner = (*ctx).ctx.clone(); + let mut opts2 = GetAllExecutionsOptions::new(); + if !opts.is_null() { + if !(*opts).symbol.is_null() { + opts2 = opts2.symbol(cstr_to_rust((*opts).symbol)); + } + if !(*opts).order_id.is_null() { + opts2 = opts2.order_id(cstr_to_rust((*opts).order_id)); + } + if !(*opts).start_at.is_null() { + opts2 = opts2.start_at( + OffsetDateTime::from_unix_timestamp(*(*opts).start_at).expect("invalid start at"), + ); + } + if !(*opts).end_at.is_null() { + opts2 = opts2.end_at( + OffsetDateTime::from_unix_timestamp(*(*opts).end_at).expect("invalid end at"), + ); + } + if !(*opts).page.is_null() { + opts2 = opts2.page(*(*opts).page); + } + } + execute_async(callback, ctx, userdata, async move { + let resp: CCow = + CCow::new(ctx_inner.all_executions(opts2).await?); + Ok(resp) + }); +} /// Get history orders /// diff --git a/cpp/include/trade_context.hpp b/cpp/include/trade_context.hpp index e61fd6fa8..90dd9fe8b 100644 --- a/cpp/include/trade_context.hpp +++ b/cpp/include/trade_context.hpp @@ -53,13 +53,10 @@ class TradeContext const std::optional& opts, AsyncCallback> callback) const; - // TODO: temporarily disabled — restore when API is available - /* /// Get all executions void all_executions( const std::optional& opts, AsyncCallback callback) const; - */ /// Get history orders void history_orders( diff --git a/cpp/src/trade_context.cpp b/cpp/src/trade_context.cpp index 271bd70bd..34065766e 100644 --- a/cpp/src/trade_context.cpp +++ b/cpp/src/trade_context.cpp @@ -221,8 +221,6 @@ TradeContext::today_executions( new AsyncCallback>(callback)); } -// TODO: temporarily disabled — restore when API is available -/* /// Get all executions void TradeContext::all_executions( @@ -261,7 +259,6 @@ TradeContext::all_executions( }, new AsyncCallback(callback)); } -*/ /// Get history orders void diff --git a/java/src/trade_context.rs b/java/src/trade_context.rs index 1b4d50abe..7a7c3ca9d 100644 --- a/java/src/trade_context.rs +++ b/java/src/trade_context.rs @@ -4,7 +4,7 @@ use jni::{ JNIEnv, JavaVM, errors::Result, objects::{GlobalRef, JClass, JObject, JString}, - sys::{jboolean, jobjectArray}, + sys::jobjectArray, }; use longbridge::{ Config, Decimal, Market, TradeContext, @@ -13,8 +13,8 @@ use longbridge::{ GetAllExecutionsOptions, GetCashFlowOptions, GetFundPositionsOptions, GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions, GetStockPositionsOptions, GetTodayExecutionsOptions, GetTodayOrdersOptions, OrderSide, - OrderStatus, OrderType, OutsideRTH, PushEvent, QueryUSOrdersOptions, ReplaceAttachedParams, - ReplaceOrderOptions, SubmitAttachedParams, SubmitOrderOptions, TimeInForceType, TopicType, + OrderStatus, OrderType, OutsideRTH, PushEvent, ReplaceAttachedParams, ReplaceOrderOptions, + SubmitAttachedParams, SubmitOrderOptions, TimeInForceType, TopicType, }, }; use parking_lot::Mutex; @@ -214,49 +214,48 @@ pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextTodayExe }) } -// TODO: temporarily disabled — restore when API is available -// #[unsafe(no_mangle)] -// pub unsafe extern "system" fn -// Java_com_longbridge_SdkNative_tradeContextAllExecutions( mut env: JNIEnv, -// _class: JClass, -// context: i64, -// opts: JObject, -// callback: JObject, -// ) { -// jni_result(&mut env, (), |env| { -// let context = &*(context as *const ContextObj); -// let opts = if !opts.is_null() { -// let mut new_opts = GetAllExecutionsOptions::new(); -// let symbol: Option = get_field(env, &opts, "symbol")?; -// if let Some(symbol) = symbol { -// new_opts = new_opts.symbol(symbol); -// } -// let order_id: Option = get_field(env, &opts, "orderId")?; -// if let Some(order_id) = order_id { -// new_opts = new_opts.order_id(order_id); -// } -// let start_at: Option = get_field(env, &opts, "startAt")?; -// if let Some(start_at) = start_at { -// new_opts = new_opts.start_at(start_at); -// } -// let end_at: Option = get_field(env, &opts, "endAt")?; -// if let Some(end_at) = end_at { -// new_opts = new_opts.end_at(end_at); -// } -// let page: Option = get_field(env, &opts, "page")?; -// if let Some(page) = page { -// new_opts = new_opts.page(i32::from(page) as u64); -// } -// Some(new_opts) -// } else { -// None -// }; -// async_util::execute(env, callback, async move { -// Ok(context.ctx.all_executions(opts).await?) -// })?; -// Ok(()) -// }) -// } +#[unsafe(no_mangle)] +pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextAllExecutions( + mut env: JNIEnv, + _class: JClass, + context: i64, + opts: JObject, + callback: JObject, +) { + jni_result(&mut env, (), |env| { + let context = &*(context as *const ContextObj); + let opts = if !opts.is_null() { + let mut new_opts = GetAllExecutionsOptions::new(); + let symbol: Option = get_field(env, &opts, "symbol")?; + if let Some(symbol) = symbol { + new_opts = new_opts.symbol(symbol); + } + let order_id: Option = get_field(env, &opts, "orderId")?; + if let Some(order_id) = order_id { + new_opts = new_opts.order_id(order_id); + } + let start_at: Option = get_field(env, &opts, "startAt")?; + if let Some(start_at) = start_at { + new_opts = new_opts.start_at(start_at); + } + let end_at: Option = get_field(env, &opts, "endAt")?; + if let Some(end_at) = end_at { + new_opts = new_opts.end_at(end_at); + } + let page: Option = get_field(env, &opts, "page")?; + if let Some(page) = page { + new_opts = new_opts.page(i32::from(page) as u64); + } + Some(new_opts) + } else { + None + }; + async_util::execute(env, callback, async move { + Ok(context.ctx.all_executions(opts).await?) + })?; + Ok(()) + }) +} #[unsafe(no_mangle)] pub unsafe extern "system" fn Java_com_longbridge_SdkNative_tradeContextHistoryOrders( diff --git a/nodejs/src/trade/context.rs b/nodejs/src/trade/context.rs index 706575e7e..fa886b97b 100644 --- a/nodejs/src/trade/context.rs +++ b/nodejs/src/trade/context.rs @@ -9,13 +9,13 @@ use crate::{ error::ErrorNewType, trade::{ requests::{ - EstimateMaxPurchaseQuantityOptions, GetCashFlowOptions, GetHistoryExecutionsOptions, - GetHistoryOrdersOptions, GetTodayExecutionsOptions, GetTodayOrdersOptions, - ReplaceOrderOptions, SubmitOrderOptions, + EstimateMaxPurchaseQuantityOptions, GetAllExecutionsOptions, GetCashFlowOptions, + GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetTodayExecutionsOptions, + GetTodayOrdersOptions, ReplaceOrderOptions, SubmitOrderOptions, }, types::{ - AccountBalance, CashFlow, EstimateMaxPurchaseQuantityResponse, Execution, - FundPositionsResponse, MarginRatio, Order, OrderDetail, PushOrderChanged, + AccountBalance, AllExecutionsResponse, CashFlow, EstimateMaxPurchaseQuantityResponse, + Execution, FundPositionsResponse, MarginRatio, Order, OrderDetail, PushOrderChanged, StockPositionsResponse, SubmitOrderResponse, TopicType, }, }, @@ -193,19 +193,18 @@ impl TradeContext { .collect() } - // TODO: temporarily disabled — restore when API is available - // Get all executions - // #[napi] - // pub async fn all_executions( - // &self, - // opts: Option, - // ) -> Result { - // self.ctx - // .all_executions(opts.map(Into::into)) - // .await - // .map_err(ErrorNewType)? - // .try_into() - // } + /// Get all executions + #[napi] + pub async fn all_executions( + &self, + opts: Option, + ) -> Result { + self.ctx + .all_executions(opts.map(Into::into)) + .await + .map_err(ErrorNewType)? + .try_into() + } /// Get history orders /// diff --git a/python/pysrc/longbridge/openapi.pyi b/python/pysrc/longbridge/openapi.pyi index 13376c640..4bbd92bc2 100644 --- a/python/pysrc/longbridge/openapi.pyi +++ b/python/pysrc/longbridge/openapi.pyi @@ -7156,15 +7156,27 @@ class TradeContext: print(resp) """ - # TODO: temporarily disabled — restore when API is available - # def all_executions( - # self, - # symbol: Optional[str] = None, - # order_id: Optional[str] = None, - # start_at: Optional[datetime] = None, - # end_at: Optional[datetime] = None, - # page: Optional[int] = None, - # ) -> AllExecutionsResponse: ... + def all_executions( + self, + symbol: Optional[str] = None, + order_id: Optional[str] = None, + start_at: Optional[datetime] = None, + end_at: Optional[datetime] = None, + page: Optional[int] = None, + ) -> AllExecutionsResponse: + """ + Get all executions + + Args: + symbol: Filter by security code + order_id: Filter by order ID + start_at: Start time filter + end_at: End time filter + page: Page number + + Returns: + All executions response + """ def history_orders( self, @@ -7861,15 +7873,25 @@ class AsyncTradeContext: """ ... - # TODO: temporarily disabled — restore when API is available - # def all_executions( - # self, - # symbol: Optional[str] = None, - # order_id: Optional[str] = None, - # start_at: Optional[datetime] = None, - # end_at: Optional[datetime] = None, - # page: Optional[int] = None, - # ) -> Awaitable[AllExecutionsResponse]: ... + def all_executions( + self, + symbol: Optional[str] = None, + order_id: Optional[str] = None, + start_at: Optional[datetime] = None, + end_at: Optional[datetime] = None, + page: Optional[int] = None, + ) -> Awaitable[AllExecutionsResponse]: + """ + Get all executions. Returns an awaitable that resolves to AllExecutionsResponse. + + Args: + symbol: Filter by security code. + order_id: Filter by order ID. + start_at: Start time filter. + end_at: End time filter. + page: Page number. + """ + ... def history_orders( self, diff --git a/python/src/trade/context.rs b/python/src/trade/context.rs index 8ddfd6d26..5c35ccee1 100644 --- a/python/src/trade/context.rs +++ b/python/src/trade/context.rs @@ -6,8 +6,7 @@ use longbridge::{ CancelOrderOptions, EstimateMaxPurchaseQuantityOptions, GetAllExecutionsOptions, GetCashFlowOptions, GetFundPositionsOptions, GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions, GetStockPositionsOptions, - GetTodayExecutionsOptions, GetTodayOrdersOptions, QueryUSOrdersOptions, - ReplaceOrderOptions, SubmitOrderOptions, + GetTodayExecutionsOptions, GetTodayOrdersOptions, ReplaceOrderOptions, SubmitOrderOptions, }, }; use parking_lot::Mutex; @@ -134,40 +133,39 @@ impl TradeContext { .collect() } - // TODO: temporarily disabled — restore when API is available - // Get all executions - // #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = - // None, page = None))] fn all_executions( - // &self, - // symbol: Option, - // order_id: Option, - // start_at: Option, - // end_at: Option, - // page: Option, - // ) -> PyResult { - // let mut opts = GetAllExecutionsOptions::new(); - // - // if let Some(symbol) = symbol { - // opts = opts.symbol(symbol); - // } - // if let Some(order_id) = order_id { - // opts = opts.order_id(order_id); - // } - // if let Some(start_at) = start_at { - // opts = opts.start_at(start_at.0); - // } - // if let Some(end_at) = end_at { - // opts = opts.end_at(end_at.0); - // } - // if let Some(page) = page { - // opts = opts.page(page); - // } - // - // self.ctx - // .all_executions(Some(opts)) - // .map_err(ErrorNewType)? - // .try_into() - // } + /// Get all executions + #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = None, page = None))] + fn all_executions( + &self, + symbol: Option, + order_id: Option, + start_at: Option, + end_at: Option, + page: Option, + ) -> PyResult { + let mut opts = GetAllExecutionsOptions::new(); + + if let Some(symbol) = symbol { + opts = opts.symbol(symbol); + } + if let Some(order_id) = order_id { + opts = opts.order_id(order_id); + } + if let Some(start_at) = start_at { + opts = opts.start_at(start_at.0); + } + if let Some(end_at) = end_at { + opts = opts.end_at(end_at.0); + } + if let Some(page) = page { + opts = opts.page(page); + } + + self.ctx + .all_executions(Some(opts)) + .map_err(ErrorNewType)? + .try_into() + } /// Get history orders #[pyo3(signature = (symbol = None, status = None, side = None, market = None, start_at = None, end_at = None))] diff --git a/python/src/trade/context_async.rs b/python/src/trade/context_async.rs index cc0075ec8..21e03764b 100644 --- a/python/src/trade/context_async.rs +++ b/python/src/trade/context_async.rs @@ -6,8 +6,8 @@ use longbridge::trade::{ CancelOrderOptions, EstimateMaxPurchaseQuantityOptions, GetAllExecutionsOptions, GetCashFlowOptions, GetFundPositionsOptions, GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions, GetStockPositionsOptions, - GetTodayExecutionsOptions, GetTodayOrdersOptions, QueryUSOrdersOptions, ReplaceOrderOptions, - SubmitOrderOptions, TradeContext, + GetTodayExecutionsOptions, GetTodayOrdersOptions, ReplaceOrderOptions, SubmitOrderOptions, + TradeContext, }; use parking_lot::Mutex; use pyo3::{prelude::*, types::PyType}; @@ -163,45 +163,44 @@ impl AsyncTradeContext { .map(|b| b.unbind()) } - // TODO: temporarily disabled — restore when API is available - // Get all executions. Returns awaitable. - // #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = - // None, page = None))] fn all_executions( - // &self, - // py: Python<'_>, - // symbol: Option, - // order_id: Option, - // start_at: Option, - // end_at: Option, - // page: Option, - // ) -> PyResult> { - // let ctx = self.ctx.clone(); - // let mut opts = GetAllExecutionsOptions::new(); - // if let Some(s) = symbol { - // opts = opts.symbol(s); - // } - // if let Some(o) = order_id { - // opts = opts.order_id(o); - // } - // if let Some(s) = start_at { - // opts = opts.start_at(s.0); - // } - // if let Some(e) = end_at { - // opts = opts.end_at(e.0); - // } - // if let Some(p) = page { - // opts = opts.page(p); - // } - // pyo3_async_runtimes::tokio::future_into_py(py, async move { - // let r: AllExecutionsResponse = ctx - // .all_executions(Some(opts)) - // .await - // .map_err(ErrorNewType)? - // .try_into()?; - // Ok(r) - // }) - // .map(|b| b.unbind()) - // } + /// Get all executions. Returns awaitable. + #[pyo3(signature = (symbol = None, order_id = None, start_at = None, end_at = None, page = None))] + fn all_executions( + &self, + py: Python<'_>, + symbol: Option, + order_id: Option, + start_at: Option, + end_at: Option, + page: Option, + ) -> PyResult> { + let ctx = self.ctx.clone(); + let mut opts = GetAllExecutionsOptions::new(); + if let Some(s) = symbol { + opts = opts.symbol(s); + } + if let Some(o) = order_id { + opts = opts.order_id(o); + } + if let Some(s) = start_at { + opts = opts.start_at(s.0); + } + if let Some(e) = end_at { + opts = opts.end_at(e.0); + } + if let Some(p) = page { + opts = opts.page(p); + } + pyo3_async_runtimes::tokio::future_into_py(py, async move { + let r: AllExecutionsResponse = ctx + .all_executions(Some(opts)) + .await + .map_err(ErrorNewType)? + .try_into()?; + Ok(r) + }) + .map(|b| b.unbind()) + } /// Get history orders. Returns awaitable. #[allow(clippy::too_many_arguments)] diff --git a/rust/src/blocking/trade.rs b/rust/src/blocking/trade.rs index c5e17c297..f750e4c15 100644 --- a/rust/src/blocking/trade.rs +++ b/rust/src/blocking/trade.rs @@ -10,9 +10,9 @@ use crate::{ GetFundPositionsOptions, GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions, GetStockPositionsOptions, GetTodayExecutionsOptions, GetTodayOrdersOptions, GetUSHistoryOrders, GetUSRealizedPLOptions, MarginRatio, Order, - OrderDetail, PushEvent, QueryUSOrdersOptions, QueryUSOrdersResponse, ReplaceOrderOptions, - StockPositionsResponse, SubmitOrderOptions, SubmitOrderResponse, TopicType, TradeContext, - USAssetOverview, USOrderDetailResponse, USRealizedPL, + OrderDetail, PushEvent, QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse, + SubmitOrderOptions, SubmitOrderResponse, TopicType, TradeContext, USAssetOverview, + USOrderDetailResponse, USRealizedPL, }, }; @@ -114,15 +114,14 @@ impl TradeContextSync { .call(move |ctx| async move { ctx.today_executions(options).await }) } - // TODO: temporarily disabled — restore when API is available - // Get all executions - // pub fn all_executions( - // &self, - // options: impl Into> + Send + 'static, - // ) -> Result { - // self.rt - // .call(move |ctx| async move { ctx.all_executions(options).await }) - // } + /// Get all executions + pub fn all_executions( + &self, + options: impl Into> + Send + 'static, + ) -> Result { + self.rt + .call(move |ctx| async move { ctx.all_executions(options).await }) + } /// Get history orders /// diff --git a/rust/src/trade/context.rs b/rust/src/trade/context.rs index b87a43b04..efaa6c283 100644 --- a/rust/src/trade/context.rs +++ b/rust/src/trade/context.rs @@ -16,9 +16,8 @@ use crate::{ GetHistoryExecutionsOptions, GetHistoryOrdersOptions, GetOrderDetailOptions, GetStockPositionsOptions, GetTodayExecutionsOptions, GetTodayOrdersOptions, GetUSHistoryOrders, GetUSRealizedPLOptions, MarginRatio, Order, OrderDetail, OrderSide, - PushEvent, QueryUSOrdersOptions, QueryUSOrdersResponse, ReplaceOrderOptions, - StockPositionsResponse, SubmitOrderOptions, TopicType, USAssetOverview, - USOrderDetailResponse, USRealizedPL, + PushEvent, QueryUSOrdersResponse, ReplaceOrderOptions, StockPositionsResponse, + SubmitOrderOptions, TopicType, USAssetOverview, USOrderDetailResponse, USRealizedPL, core::{Command, Core}, }, }; @@ -276,25 +275,24 @@ impl TradeContext { .trades) } - // TODO: temporarily disabled — restore when API is available - // Get all executions - // - // Reference: - // pub async fn all_executions( - // &self, - // options: impl Into>, - // ) -> Result { - // Ok(self - // .0 - // .http_cli - // .request(Method::GET, "/v3/trade/execution/all") - // .query_params(options.into().unwrap_or_default()) - // .response::>() - // .send() - // .with_subscriber(self.0.log_subscriber.clone()) - // .await? - // .0) - // } + /// Get all executions + /// + /// Reference: + pub async fn all_executions( + &self, + options: impl Into>, + ) -> Result { + Ok(self + .0 + .http_cli + .request(Method::GET, "/v3/trade/execution/all") + .query_params(options.into().unwrap_or_default()) + .response::>() + .send() + .with_subscriber(self.0.log_subscriber.clone()) + .await? + .0) + } /// Get history orders /// From bde610b3815c2eb2ff61d9cc7d01d405549aa13f Mon Sep 17 00:00:00 2001 From: Sunli Date: Tue, 28 Jul 2026 15:17:47 +0800 Subject: [PATCH 3/5] feat(trade): add side field to Execution across all SDKs The today/history/all executions responses now return the buy/sell direction of each fill. Expose it as `Execution.side` (`OrderSide`) in every binding: Rust core, Python, Node.js, C, C++, and Java. Regenerate the C header (cbindgen) and Node.js bindings. --- CHANGELOG.md | 4 ++++ c/csrc/include/longbridge.h | 4 ++++ c/src/trade_context/types.rs | 7 ++++++ cpp/include/types.hpp | 24 ++++++++++--------- cpp/src/convert.hpp | 4 ++++ .../java/com/longbridge/trade/Execution.java | 14 +++++++++-- java/src/types/classes.rs | 10 +++++++- nodejs/index.d.ts | 2 ++ nodejs/src/trade/types.rs | 2 ++ python/pysrc/longbridge/openapi.pyi | 5 ++++ python/src/trade/types.rs | 2 ++ rust/src/trade/types.rs | 2 ++ 12 files changed, 66 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881443b28..a99b643cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- **All languages:** `Execution` gains a `side` field (`OrderSide`) — the buy/sell direction of the fill, now returned by the `today_executions`, `history_executions`, and `all_executions` responses + ## [4.4.2] - 2026-07-30 ### Added diff --git a/c/csrc/include/longbridge.h b/c/csrc/include/longbridge.h index 76ee4c608..189ad1152 100644 --- a/c/csrc/include/longbridge.h +++ b/c/csrc/include/longbridge.h @@ -4600,6 +4600,10 @@ typedef struct lb_execution_t { * Executed price */ const struct lb_decimal_t *price; + /** + * Order side + */ + enum lb_order_side_t side; } lb_execution_t; /** diff --git a/c/src/trade_context/types.rs b/c/src/trade_context/types.rs index 6bcecd4ce..b13c43830 100644 --- a/c/src/trade_context/types.rs +++ b/c/src/trade_context/types.rs @@ -563,6 +563,8 @@ pub struct CExecution { pub quantity: *const CDecimal, /// Executed price pub price: *const CDecimal, + /// Order side + pub side: COrderSide, } #[derive(Debug)] @@ -573,6 +575,7 @@ pub(crate) struct CExecutionOwned { trade_done_at: i64, quantity: CDecimal, price: CDecimal, + side: OrderSide, } impl From for CExecutionOwned { @@ -584,6 +587,7 @@ impl From for CExecutionOwned { trade_done_at, quantity, price, + side, } = execution; CExecutionOwned { order_id: order_id.into(), @@ -592,6 +596,7 @@ impl From for CExecutionOwned { trade_done_at: trade_done_at.unix_timestamp(), quantity: quantity.into(), price: price.into(), + side, } } } @@ -607,6 +612,7 @@ impl ToFFI for CExecutionOwned { trade_done_at, quantity, price, + side, } = self; CExecution { order_id: order_id.to_ffi_type(), @@ -615,6 +621,7 @@ impl ToFFI for CExecutionOwned { trade_done_at: *trade_done_at, quantity: quantity.to_ffi_type(), price: price.to_ffi_type(), + side: (*side).into(), } } } diff --git a/cpp/include/types.hpp b/cpp/include/types.hpp index d7be4c139..9104ef2c1 100644 --- a/cpp/include/types.hpp +++ b/cpp/include/types.hpp @@ -1360,6 +1360,17 @@ enum class TopicType Private, }; +/// Order side +enum class OrderSide +{ + /// Unknown + Unknown, + /// Buy + Buy, + /// Sell + Sell, +}; + /// Exexution struct Execution { @@ -1369,6 +1380,8 @@ struct Execution int64_t trade_done_at; Decimal quantity; Decimal price; + /// Order side + OrderSide side; }; /// Options for get history executions request @@ -1456,17 +1469,6 @@ enum class OrderStatus PartialWithdrawal, }; -/// Order side -enum class OrderSide -{ - /// Unknown - Unknown, - /// Buy - Buy, - /// Sell - Sell, -}; - /// Order type enum class OrderType { diff --git a/cpp/src/convert.hpp b/cpp/src/convert.hpp index 63bb42341..2cde8ee99 100644 --- a/cpp/src/convert.hpp +++ b/cpp/src/convert.hpp @@ -963,12 +963,16 @@ convert(TopicType ty) } } +inline OrderSide +convert(lb_order_side_t side); + inline Execution convert(const lb_execution_t* info) { return Execution{ info->order_id, info->trade_id, info->symbol, info->trade_done_at, info->quantity, Decimal(info->price), + convert(info->side), }; } 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 18f991cae..6bae9831e 100644 --- a/java/javasrc/src/main/java/com/longbridge/trade/Execution.java +++ b/java/javasrc/src/main/java/com/longbridge/trade/Execution.java @@ -13,6 +13,7 @@ public class Execution { private OffsetDateTime tradeDoneAt; private BigDecimal quantity; private BigDecimal price; + private OrderSide side; /** * Returns the order ID. @@ -68,9 +69,18 @@ public BigDecimal getPrice() { return price; } + /** + * Returns the order side. + * + * @return order side + */ + public OrderSide getSide() { + return side; + } + @Override public String toString() { - return "Execution [orderId=" + orderId + ", price=" + price + ", quantity=" + quantity + ", symbol=" + symbol - + ", tradeDoneAt=" + tradeDoneAt + ", tradeId=" + tradeId + "]"; + return "Execution [orderId=" + orderId + ", price=" + price + ", quantity=" + quantity + ", side=" + side + + ", symbol=" + symbol + ", tradeDoneAt=" + tradeDoneAt + ", tradeId=" + tradeId + "]"; } } diff --git a/java/src/types/classes.rs b/java/src/types/classes.rs index 0c271c29c..291da18c6 100644 --- a/java/src/types/classes.rs +++ b/java/src/types/classes.rs @@ -648,7 +648,15 @@ impl_java_class!( impl_java_class!( "com/longbridge/trade/Execution", longbridge::trade::Execution, - [order_id, trade_id, symbol, trade_done_at, quantity, price] + [ + order_id, + trade_id, + symbol, + trade_done_at, + quantity, + price, + side + ] ); impl_java_class!( diff --git a/nodejs/index.d.ts b/nodejs/index.d.ts index 0774ff7ed..6d24468da 100644 --- a/nodejs/index.d.ts +++ b/nodejs/index.d.ts @@ -686,6 +686,8 @@ export declare class Execution { get quantity(): Decimal /** Executed price */ get price(): Decimal + /** Order side */ + get side(): OrderSide } /** Filing item */ diff --git a/nodejs/src/trade/types.rs b/nodejs/src/trade/types.rs index f355b3776..ee5c1c451 100644 --- a/nodejs/src/trade/types.rs +++ b/nodejs/src/trade/types.rs @@ -30,6 +30,8 @@ pub struct Execution { quantity: Decimal, /// Executed price price: Decimal, + /// Order side + side: OrderSide, } #[napi_derive::napi] diff --git a/python/pysrc/longbridge/openapi.pyi b/python/pysrc/longbridge/openapi.pyi index 4bbd92bc2..88a81c44b 100644 --- a/python/pysrc/longbridge/openapi.pyi +++ b/python/pysrc/longbridge/openapi.pyi @@ -5743,6 +5743,11 @@ class Execution: Executed price """ + side: OrderSide + """ + Order side + """ + class AllExecutionsResponse: """ Response for get all executions request diff --git a/python/src/trade/types.rs b/python/src/trade/types.rs index d9ade78f2..ff7293b5a 100644 --- a/python/src/trade/types.rs +++ b/python/src/trade/types.rs @@ -34,6 +34,8 @@ pub(crate) struct Execution { quantity: PyDecimal, /// Executed price price: PyDecimal, + /// Order side + side: OrderSide, } /// Response for get all executions request diff --git a/rust/src/trade/types.rs b/rust/src/trade/types.rs index 79d316699..e42e41f94 100644 --- a/rust/src/trade/types.rs +++ b/rust/src/trade/types.rs @@ -130,6 +130,8 @@ pub struct Execution { pub quantity: Decimal, /// Executed price pub price: Decimal, + /// Order side + pub side: OrderSide, } /// Response for get all executions request From cbd0dacc29b191cb73e66e67281854aafd07db2d Mon Sep 17 00:00:00 2001 From: Sunli Date: Thu, 30 Jul 2026 12:04:35 +0800 Subject: [PATCH 4/5] test(trade): add side field to history_executions test fixture --- rust/src/trade/types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/src/trade/types.rs b/rust/src/trade/types.rs index e42e41f94..bbe71ebb9 100644 --- a/rust/src/trade/types.rs +++ b/rust/src/trade/types.rs @@ -1840,7 +1840,8 @@ mod tests { "quantity": "100", "symbol": "700.HK", "trade_done_at": "1648611351", - "trade_id": "693664675163312128-1648611351433741210" + "trade_id": "693664675163312128-1648611351433741210", + "side": "Buy" } ] } @@ -1861,6 +1862,7 @@ mod tests { assert_eq!(execution.symbol, "700.HK"); assert_eq!(execution.trade_done_at, datetime!(2022-03-30 11:35:51 +8)); assert_eq!(execution.trade_id, "693664675163312128-1648611351433741210"); + assert_eq!(execution.side, OrderSide::Buy); } #[test] From ff430f81c2b9c8565fcf15e302fb1822f4dfc709 Mon Sep 17 00:00:00 2001 From: Sunli Date: Thu, 30 Jul 2026 12:40:38 +0800 Subject: [PATCH 5/5] fix(nodejs): export GetAllExecutionsOptions from requests module --- nodejs/src/trade/requests/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/nodejs/src/trade/requests/mod.rs b/nodejs/src/trade/requests/mod.rs index 6a47881ff..d1f521759 100644 --- a/nodejs/src/trade/requests/mod.rs +++ b/nodejs/src/trade/requests/mod.rs @@ -9,6 +9,7 @@ mod replace_order; mod submit_order; pub use estimate_max_purchase_quantity::EstimateMaxPurchaseQuantityOptions; +pub use get_all_executions::GetAllExecutionsOptions; pub use get_cash_flow::GetCashFlowOptions; pub use get_history_executions::GetHistoryExecutionsOptions; pub use get_history_orders::GetHistoryOrdersOptions;