Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

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

## [Unreleased]

### Added

- **Rust core (async + blocking):** new `FundContext` / `FundContextSync` for the mutual-fund channel, covering 28 endpoints across fund catalog & market data (hot funds, fund list, filters, detail, analysis/trend, annual/quarterly returns, performance & comparison, latest/historical NAV, top-10 holdings, reverse stock holdings), the user's fund positions (overview, single position, performance, profits, NAV history, dividends), and fund orders/trading (order list & detail, transactions/cash-flow, order validate/submit/cancel). The fund identifier is exposed as `counter_id` (e.g. `UT/FD/HK0000384492`); because it contains `/` it cannot sit in the URL path, so single-fund endpoints take it as a `counter_id` query parameter (fixed sub-paths like `/v1/fund/funds/detail`, `/v1/fund/funds/nav`) rather than a path segment. Three batch-backed endpoints — latest NAV (`nav`), daily performance (`performance`) and held-fund performance (`position_performance`) — instead send the identifier as a one-element JSON array in a `counter_ids` query parameter, matching their backend contract. Nested response objects the backend may return as `null` — `FundDetail.asset_allocation`, `FundTrend.contrast_performances`, `FundPositionDetail.detail_values` and `FundOrderDetail.order` — are modeled as optional/nullable (`Option` / `std::optional` / nullable pointer / `T | null` / `Optional[T]`) so those responses deserialize instead of erroring on `null`. Numeric `int64` fields tolerate the backend sending them as either a JSON number or a quoted string, so a numeric value never fails the whole response. Mirrored across the C, C++, Java, Node.js and Python layers; the separate Go SDK is pending.
- **C:** `lb_fund_context_*` FFI (all 28 methods via `c/src/fund_context`) with the request-option structs (`lb_get_funds_options_t`, `lb_submit_fund_order_options_t`, …) and all 39 fund response structs (`lb_fund_detail_t`, `lb_hot_fund_t`, `lb_fund_order_t`, …) emitted into `c/csrc/include/longbridge.h`. The fund context and its option structs are added to the cbindgen `[export.rename]` map so they follow the `lb_*_t` naming convention like every other channel (rather than emitting raw `C…` names).
- **Node.js:** `FundContext` (napi) binding mirroring the Rust `FundContext` (all 28 methods) plus the fund response/option types, regenerated into `nodejs/index.d.ts`. The fund-channel position entry is exposed to JS as `FundHoldingPosition` to avoid colliding with the existing trade `FundPosition`. Server-defined "any" JSON fields are surfaced as raw JSON `string` (or `Array<string>`), unix-second timestamps as `number`, and numeric-string fields as `string`.
- **Java:** `com.longbridge.fund.FundContext` JNI binding mirroring the Rust `FundContext` (all 28 methods), plus the fund response and option types under `com.longbridge.fund`. Server-defined "any" JSON fields are surfaced as raw JSON `String` (or `String[]`), unix-second timestamps as `long`, and numeric-string fields as `String`.
- **Python:** `longbridge.openapi.FundContext` (PyO3) binding mirroring the Rust `FundContext` (all 28 methods), plus all fund response types (`HotFund`, `FundBrief`, `FundFilters`, `FundDetail`, `FundAnalysis`/`FundAnalysisDetail`, `FundTrend`, `FundPerformanceComparison`, `FundHoldings`, `FundPositions`, `FundPositionDetail`, `FundOrderDetail`, `FundDividends`, `FundOrderValidation`, `FundOrderSubmitResponse`, and their nested types). The fund-channel position entry is exposed as `FundHoldingPosition` to avoid colliding with the existing trade `FundPosition`. Server-defined "any" JSON fields are surfaced as raw JSON `str` (or `list[str]`), unix-second timestamps as `int`, and numeric-string fields as `str`. The `openapi.pyi` type stub is updated to match.
- **C++:** `longbridge::fund::FundContext` binding wrapping the C FFI layer (all 28 methods), plus the fund request-option and response types under `longbridge::fund` in `types.hpp`. Server-defined "any" JSON fields are surfaced as raw JSON `std::string` (or `std::vector<std::string>`), unix-second timestamps as `int64_t`, and numeric-string fields as `std::string`.

### Fixed

- **C / C++:** resolved a cbindgen name collision introduced with the fund C FFI layer: the fund module's `CFundPosition` and `CGetFundPositionsOptions` shared their names with the existing portfolio types, so the regenerated `longbridge.h` overwrote `lb_fund_position_t` and `lb_get_fund_positions_options_t` with the fund field layouts, breaking the C++ trade/portfolio converters. The fund structs were renamed to `CFundPositionItem` (emitted as `lb_fund_position_item_t`, reachable via `lb_fund_positions_t.list`) and `CFundPositionsOptions` (`lb_fund_positions_options_t`, a `lb_fund_context_positions` parameter) so both modules coexist with distinct names.

### Changed

- **All SDKs (breaking):** `TradeContext.fund_positions` — the `FundPosition` identifier field is renamed from `symbol` (which carried the fund's ISIN) to `counter_id`, aligning it with the rest of the fund tooling. The value is now the full fund `counter_id` (e.g. `UT/FD/HK0000384492`); the ISIN remains recoverable as the last `/`-separated segment. Renamed across every layer: Rust core (`counter_id`, deserializes the legacy `symbol` key via a serde alias for transition), C (`lb_fund_position_t.counter_id`), C++ (`FundPosition::counter_id`), Java (`FundPosition.getCounterId()`), Node.js (`FundPosition.counterId`), Python (`FundPosition.counter_id`). Note the request-side filter (`GetFundPositionsOptions.symbols`) is unchanged — you still filter holdings by user symbol, but the response now returns the fund `counter_id`.
- **All SDKs:** `CalendarContext.finance_calendar` now exposes the endpoint's pagination controls so callers can page through results themselves. Previously the method issued a single request with no page-size control, so the server's default page cap (historically ~10 events) made even a one-day query look truncated at 10 results. Three optional parameters were added — `count` (max events per page), `offset` (events to skip), and `next` (a new `CalendarPageDirection` enum: `Later` / `Earlier`) — and the response's `next_date` cursor is returned as-is. To retrieve a full window, request a larger `count`, or re-call with the returned `next_date` as `start` until it comes back empty. This is a signature change across every layer (Rust core + blocking, C, C++, Java, Node.js, Python); the new arguments are optional in the languages that support defaults. Reported as longbridge/developers#1265

## [5.1.0] - 2026-09-20
Expand Down
67 changes: 67 additions & 0 deletions c/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,65 @@ cpp_compat = true
"CChargeCategoryCode" = "lb_charge_category_code_t"
"CGetCashFlowOptions" = "lb_get_cash_flow_options_t"
"CGetFundPositionsOptions" = "lb_get_fund_positions_options_t"
"CFundPositionsOptions" = "lb_fund_positions_options_t"
"CFundPositionsResponse" = "lb_fund_position_response_t"
"CFundPositionChannel" = "lb_fund_position_channel_t"
"CFundPosition" = "lb_fund_position_t"
# --- fund module response views ---
"CFundAnalysis" = "lb_fund_analysis_t"
"CFundAnalysisDetail" = "lb_fund_analysis_detail_t"
"CFundAnnualReturn" = "lb_fund_annual_return_t"
"CFundAssetAllocation" = "lb_fund_asset_allocation_t"
"CFundAssetAllocationItem" = "lb_fund_asset_allocation_item_t"
"CFundBrief" = "lb_fund_brief_t"
"CFundDatedValue" = "lb_fund_dated_value_t"
"CFundDetail" = "lb_fund_detail_t"
"CFundDividend" = "lb_fund_dividend_t"
"CFundDividends" = "lb_fund_dividends_t"
"CFundFilters" = "lb_fund_filters_t"
"CFundHolding" = "lb_fund_holding_t"
"CFundHoldings" = "lb_fund_holdings_t"
"CFundNamedContrast" = "lb_fund_named_contrast_t"
"CFundNavValue" = "lb_fund_nav_value_t"
"CFundOrder" = "lb_fund_order_t"
"CFundOrderDetail" = "lb_fund_order_detail_t"
"CFundOrderInfo" = "lb_fund_order_info_t"
"CFundOrderKeyword" = "lb_fund_order_keyword_t"
"CFundOrderStage" = "lb_fund_order_stage_t"
"CFundOrderSubmitResponse" = "lb_fund_order_submit_response_t"
"CFundOrderValidation" = "lb_fund_order_validation_t"
"CFundPerformance" = "lb_fund_performance_t"
"CFundPerformanceComparison" = "lb_fund_performance_comparison_t"
"CFundPerformancePoint" = "lb_fund_performance_point_t"
"CFundPositionDetail" = "lb_fund_position_detail_t"
"CFundPositionDetailValues" = "lb_fund_position_detail_values_t"
"CFundPositionItem" = "lb_fund_position_item_t"
"CFundPositionNav" = "lb_fund_position_nav_t"
"CFundPositionPerformance" = "lb_fund_position_performance_t"
"CFundPositionProfits" = "lb_fund_position_profits_t"
"CFundPositions" = "lb_fund_positions_t"
"CFundQuarterlyReturn" = "lb_fund_quarterly_return_t"
"CFundStockHolding" = "lb_fund_stock_holding_t"
"CFundTransaction" = "lb_fund_transaction_t"
"CFundTrend" = "lb_fund_trend_t"
"CFundTrendContrast" = "lb_fund_trend_contrast_t"
"CFundUnitValue" = "lb_fund_unit_value_t"
"CHotFund" = "lb_hot_fund_t"
# --- fund module: context + option structs ---
"CFundContext" = "lb_fund_context_t"
"CGetFundsOptions" = "lb_get_funds_options_t"
"CGetFundAnalysisOptions" = "lb_get_fund_analysis_options_t"
"CFundPageOptions" = "lb_fund_page_options_t"
"CFundNavRangeOptions" = "lb_fund_nav_range_options_t"
"CGetFundHoldingsOptions" = "lb_get_fund_holdings_options_t"
"CGetFundStockHoldingsOptions" = "lb_get_fund_stock_holdings_options_t"
"CGetFundPositionOptions" = "lb_get_fund_position_options_t"
"CGetFundPositionProfitsOptions" = "lb_get_fund_position_profits_options_t"
"CGetFundPositionDividendsOptions" = "lb_get_fund_position_dividends_options_t"
"CGetFundOrdersOptions" = "lb_get_fund_orders_options_t"
"CGetFundTransactionsOptions" = "lb_get_fund_transactions_options_t"
"CValidateFundOrderOptions" = "lb_validate_fund_order_options_t"
"CSubmitFundOrderOptions" = "lb_submit_fund_order_options_t"
"CGetStockPositionsOptions" = "lb_get_stock_positions_options_t"
"CStockPositionsResponse" = "lb_stock_position_response_t"
"CStockPositionChannel" = "lb_stock_position_channel_t"
Expand Down Expand Up @@ -444,6 +500,17 @@ include = [
"CGridOrder", "CGridOrderSubOrder", "CGridOrderHistory", "CGridOrderDetail",
"CTriggerOrder", "CGridBidSize", "CGridChannelInfo", "CGridSymbolInfo",
"CGridOrdersResponse", "CGridTriggerHistoryResponse",
# FundContext: mutual-fund response views (via void* async data pointer)
"CFundAnalysis", "CFundAnalysisDetail", "CFundAnnualReturn", "CFundAssetAllocation",
"CFundAssetAllocationItem", "CFundBrief", "CFundDatedValue", "CFundDetail",
"CFundDividend", "CFundDividends", "CFundFilters", "CFundHolding",
"CFundHoldings", "CFundNamedContrast", "CFundNavValue", "CFundOrder",
"CFundOrderDetail", "CFundOrderInfo", "CFundOrderKeyword", "CFundOrderStage",
"CFundOrderSubmitResponse", "CFundOrderValidation", "CFundPerformance", "CFundPerformanceComparison",
"CFundPerformancePoint", "CFundPositionDetail", "CFundPositionDetailValues", "CFundPositionItem",
"CFundPositionNav", "CFundPositionPerformance", "CFundPositionProfits", "CFundPositions",
"CFundQuarterlyReturn", "CFundStockHolding", "CFundTransaction", "CFundTrend",
"CFundTrendContrast", "CFundUnitValue", "CHotFund",
# TradeContext: grid trading push (stays on trade side)
"CPushGridOrderChanged",
"CEstimateMaxPurchaseQuantityResponse",
Expand Down
Loading
Loading