From 05b4765f97af5c3310b4f904c5188312cfd7be49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=AB=A0=E6=B4=AA?= Date: Sun, 20 Sep 2026 16:08:39 +0800 Subject: [PATCH] chore: release v5.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the workspace version 5.0.0 → 5.1.0 and open the [5.1.0] - 2026-09-20 CHANGELOG section. Minor release. Contents new since v5.0.0: - (Breaking) QuoteContext.option_chain_info_by_date moves off quote socket command 21 onto the HTTP endpoint GET /v1/gemini/option/option_chain_list; return type reshaped to a flat OptionChainContract (StrikePriceInfo removed), plus OptionExpiryCycleType / OptionStandardAttr enums and a standard_only parameter (#588). - (Added) MultiLegStrategy gains CalendarCallSpread (7) and CalendarPutSpread (8) — calendar spreads for submit_multileg (#590). - (Changed) Refreshed the option Greek field descriptions on SecurityCalcIndex; theta is now documented as a per-day value (#586). Changelog housekeeping: the post-5.0.0 PRs had each re-inserted the whole [5.0.0] block plus their own entry, leaving [5.0.0] with duplicated Added/Changed/Fixed subsections (public_agents / parent_message_id / submit_multileg / grid-trading / Execution.side / SignalContext all listed twice). Restored [5.0.0] to its tagged content and moved the three genuinely-new entries into [5.1.0]. public_agents and parent_message_id were already shipped in 4.5.0, so they are not repeated here. --- CHANGELOG.md | 30 ++++++++++++------------------ Cargo.toml | 16 ++++++++-------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index babd1b5c2..b584f9c2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [5.0.0] - 2026-09-14 +## [5.1.0] - 2026-09-20 + +### Breaking changes + +- **All SDKs:** `QuoteContext.option_chain_info_by_date` moves off quote socket business command `21` onto the plain HTTP endpoint `GET /v1/gemini/option/option_chain_list` (longbridge/developers#1244), and its return type changes shape. The paired `StrikePriceInfo` (`price` + `call_symbol` + `put_symbol` + `standard`) is **removed** in favour of a flat, one-entry-per-contract `OptionChainContract` (`symbol`, `expiry_date`, `strike_price`, `direction`, `option_type`, `standard_attr`, `days_to_expiry`). Calls and puts are no longer paired by strike, so a strike listed on one side only now yields a single entry instead of an entry with an empty `call_symbol`/`put_symbol`, and callers must filter on `direction` where they used to read the two symbol fields. Two new enums come with it: `OptionExpiryCycleType` (`Unknown` / `Monthly` / `Weekly` / `Quarterly`) for the special expiration cycle — the server's empty `option_type` means a standard monthly option — and `OptionStandardAttr` (`Unknown` / `Normal` / `Old`) marking the legacy contracts left over from a corporate action (e.g. `BABA2261218C10000.US`); both fall back to `Unknown` for an unrecognized server value. The method also gains a `standard_only` parameter that filters those legacy contracts out server-side (positional `bool` in Rust incl. blocking, C, C++ and Java; optional `standardOnly?: boolean` in Node.js; `standard_only: bool = False` in Python) — it is omitted from the query string when false, which the endpoint treats as "return everything". The 30-minute client-side cache of the chain is gone, matching the other HTTP quote endpoints. New types per layer: C `lb_option_chain_contract_t` / `lb_option_expiry_cycle_type_t` / `lb_option_standard_attr_t` (`lb_strike_price_info_t` removed, and `lb_quote_context_option_chain_info_by_date` gains a `bool standard_only` argument before the callback), C++ `quote::OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr`, Java `com.longbridge.quote.OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr` (`StrikePriceInfo` deleted, and `getOptionChainInfoByDate` becomes `getOptionChainInfoByDate(String, LocalDate, boolean)`), Node.js `OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr`, and Python the same three (incl. the `openapi.pyi` stub). `QuoteContext.option_chain_expiry_date_list` is **unchanged** and still uses socket command `20`: the new endpoint requires `expiry_date`, so it cannot enumerate expiry dates, and the gateway path for the replacement expiry-date-list endpoint is not settled upstream yet + +### Added + +- **All languages:** `MultiLegStrategy` gains `CalendarCallSpread` (`7`) and `CalendarPutSpread` (`8`) — calendar (horizontal) spreads, accepted by `TradeContext.submit_multileg` and reported back on the `multi_leg` field of order queries and the order-changed push. Both are appended after `Strangle`, so the discriminants of the existing variants are unchanged. Added across Rust, C, C++, Java, Node.js, and Python. Documented in longbridge/developers#1251 ### Changed - **All SDKs:** refreshed the option Greek field descriptions on `SecurityCalcIndex` (`calc_indexes`) — `delta` / `gamma` / `theta` / `vega` / `rho` — to match the Calc Index interface documentation. Notably, `theta` is now documented as a per-day value: the server divides the raw annualized value by 365, so the returned `theta` is already daily (previously the doc said the raw value was annualized by 252 and had to be divided by 252). Doc comments only — no field or behaviour changes +## [5.0.0] - 2026-09-14 + ### Breaking changes -- **All SDKs:** `QuoteContext.option_chain_info_by_date` moves off quote socket business command `21` onto the plain HTTP endpoint `GET /v1/gemini/option/option_chain_list` (longbridge/developers#1244), and its return type changes shape. The paired `StrikePriceInfo` (`price` + `call_symbol` + `put_symbol` + `standard`) is **removed** in favour of a flat, one-entry-per-contract `OptionChainContract` (`symbol`, `expiry_date`, `strike_price`, `direction`, `option_type`, `standard_attr`, `days_to_expiry`). Calls and puts are no longer paired by strike, so a strike listed on one side only now yields a single entry instead of an entry with an empty `call_symbol`/`put_symbol`, and callers must filter on `direction` where they used to read the two symbol fields. Two new enums come with it: `OptionExpiryCycleType` (`Unknown` / `Monthly` / `Weekly` / `Quarterly`) for the special expiration cycle — the server's empty `option_type` means a standard monthly option — and `OptionStandardAttr` (`Unknown` / `Normal` / `Old`) marking the legacy contracts left over from a corporate action (e.g. `BABA2261218C10000.US`); both fall back to `Unknown` for an unrecognized server value. The method also gains a `standard_only` parameter that filters those legacy contracts out server-side (positional `bool` in Rust incl. blocking, C, C++ and Java; optional `standardOnly?: boolean` in Node.js; `standard_only: bool = False` in Python) — it is omitted from the query string when false, which the endpoint treats as "return everything". The 30-minute client-side cache of the chain is gone, matching the other HTTP quote endpoints. New types per layer: C `lb_option_chain_contract_t` / `lb_option_expiry_cycle_type_t` / `lb_option_standard_attr_t` (`lb_strike_price_info_t` removed, and `lb_quote_context_option_chain_info_by_date` gains a `bool standard_only` argument before the callback), C++ `quote::OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr`, Java `com.longbridge.quote.OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr` (`StrikePriceInfo` deleted, and `getOptionChainInfoByDate` becomes `getOptionChainInfoByDate(String, LocalDate, boolean)`), Node.js `OptionChainContract` / `OptionExpiryCycleType` / `OptionStandardAttr`, and Python the same three (incl. the `openapi.pyi` stub). `QuoteContext.option_chain_expiry_date_list` is **unchanged** and still uses socket command `20`: the new endpoint requires `expiry_date`, so it cannot enumerate expiry dates, and the gateway path for the replacement expiry-date-list endpoint is not settled upstream yet - **All SDKs:** removed `GridContext.submit_strategy_questionnaire` (`POST /v1/record/questionnaire`) and its `SubmitStrategyQuestionnaireOptions` type. The endpoint has been retired; the strategy risk-disclosure record is no longer submitted through the OpenAPI SDK. Removed across Rust (incl. blocking), C, C++, Java, Node.js, and Python bindings - **All SDKs:** `WarrantStatus` gains an `Unknown` variant (first variant, matching `WarrantType`), and `QuoteContext.warrant_list` now maps an unrecognized status discriminant to it instead of failing. The same placeholder rows that carry an empty `expiry_date` also carry `status: 0`, which no `WarrantStatus` variant matched (`Suspend = 2` / `PrepareList = 3` / `Normal = 4`), so they failed the whole list with `parse field: state: No discriminant in enum WarrantStatus matches the value 0`. Adding a variant shifts the ordinal of the existing ones in the C/C++/Java/Node.js/Python bindings - **All SDKs:** `WarrantInfo.expiry_date` (`QuoteContext.warrant_list`) is now optional. The server returns an empty `expiry_date` for some warrants, and the strict `[year][month][day]` parse turned that single bad row into a `parse field: expiry_date: the 'year' component could not be parsed` error that failed the **entire** list — observed live on `700.HK`, where one warrant out of 126 (`68463.HK`) discarded the other 125. An unparseable date now yields an absent value instead (Rust `Option`, Python `Optional[date]`, Node.js `NaiveDate | null`, Java nullable `LocalDate`, C `const lb_date_t*` NULL-when-absent, C++ `std::optional`) @@ -23,8 +32,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- **All languages:** add `AgentContext.public_agents` (`GET /v1/ai/agents`) — list all publicly available Agents on the platform (the Explore catalog). Unlike `agents`, it is not scoped to a Workspace and returns every published, publicly-shared Agent. Takes the same optional `page` / `limit` / `name` parameters and returns the existing `AgentsResponse` -- **All languages:** add optional `parent_message_id` parameter to the AI Agent `conversation` and `conversation_streamed` methods — pass the `message_id` from a previous response to attach a follow-up message after the specified one, keeping the message stream in order. Only valid together with `chat_uid`; must not be set for a new conversation - **Rust:** `Signal.status` is now a `SignalStatus` enum (pending / active / deleted / ai-failed / filtered-by-manual / ai-submit-failed), `SignalsResponse.total` is `i32` to match the wire contract, and the `risk_level` / `display_control` fields were dropped — neither is part of the API contract nor served in production - **Rust:** `SignalContext.security_facts` now returns a typed `SecurityFact` instead of raw JSON — fact id / type / direction, the securities it is about, the factors behind it (with their anomaly test and groups), the data sources, and the natural-language `nl_info`. Adds the `FactType` and `FactDirection` enums, and `FactNlInfo::summary_tags()` / `invest_anal_tags()` / `eli_explain_tags()` for the `{tag, value}` entries the API carries as JSON inside a string - **Rust:** add `SignalContext` — strategy signals and the catalyst facts behind them. `signals` (`GET /v1/signals`) queries signals with symbol / strategy / catalyst / time-range filters and paging; `signal` (`GET /v1/signals/{signal_id}`) returns one signal including the full strategy analysis in `json_data`; `security_facts` (`GET /v1/facts/security_facts`) lists a security's fact (catalyst) events. Bindings for the other languages are not wired up yet @@ -61,20 +68,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **All SDKs:** document that `SubmitMultiLegOrderLeg.ratio_quantity` must be a positive number. A leg's direction comes from the `strategy` plus the order `side`, not from the sign of the ratio; the server rejects a negative or zero ratio with `602001` (`value does not match regex pattern "^([1-9]\\d*(\\.\\d+)?)$"`). Doc comments only — no behaviour or type changes - **All SDKs:** `FundamentalContext.executive` (`GET /v1/quote/company-professionals`) sent its security in a `symbol` query parameter, but the endpoint expects the plural `symbols` (it takes a comma-separated list). The server silently ignored the unknown parameter and answered with an empty group (`total: 0`, no `symbol`, a `forward_url` missing the security id), so the call appeared to succeed while returning nothing. Verified live against `700.HK` and `AAPL.US` - **All SDKs:** every optional response field now tolerates an explicit JSON `null`. `#[serde(default)]` alone only covers a *missing* key, so a server that sent `null` for any of ~700 optional fields aborted the whole response with `deserialize response body error: invalid type: null`. All `#[serde(default)]` response fields across every module (quote, trade, fundamental, market, dca, alert, sharelist, portfolio, calendar, content, screener, agent) now map `null` to the field's default value. First observed live as `institution_rating_detail` `"target"/"evaluate": null` (symbols without analyst coverage) and `us_company_dividends` `"recent_dividends": null` (no trailing dividends). No field types changed, so the language bindings are unaffected - -### Added - -- **All languages:** `MultiLegStrategy` gains `CalendarCallSpread` (`7`) and `CalendarPutSpread` (`8`) — calendar (horizontal) spreads, accepted by `TradeContext.submit_multileg` and reported back on the `multi_leg` field of order queries and the order-changed push. Both are appended after `Strangle`, so the discriminants of the existing variants are unchanged. Added across Rust, C, C++, Java, Node.js, and Python. Documented in longbridge/developers#1251 -- **Rust:** `Signal.status` is now a `SignalStatus` enum (pending / active / deleted / ai-failed / filtered-by-manual / ai-submit-failed), `SignalsResponse.total` is `i32` to match the wire contract, and the `risk_level` / `display_control` fields were dropped — neither is part of the API contract nor served in production -- **Rust:** `SignalContext.security_facts` now returns a typed `SecurityFact` instead of raw JSON — fact id / type / direction, the securities it is about, the factors behind it (with their anomaly test and groups), the data sources, and the natural-language `nl_info`. Adds the `FactType` and `FactDirection` enums, and `FactNlInfo::summary_tags()` / `invest_anal_tags()` / `eli_explain_tags()` for the `{tag, value}` entries the API carries as JSON inside a string -- **Rust:** add `SignalContext` — strategy signals and the catalyst facts behind them. `signals` (`GET /v1/signals`) queries signals with symbol / strategy / catalyst / time-range filters and paging; `signal` (`GET /v1/signals/{signal_id}`) returns one signal including the full strategy analysis in `json_data`; `security_facts` (`GET /v1/facts/security_facts`) lists a security's fact (catalyst) events. Bindings for the other languages are not wired up yet -- **All languages:** add `TradeContext.submit_multileg` (`POST /v1/trade/order/multileg`) — submit a multi-leg option combination order (vertical spreads, straddles, strangles, collars, etc.) whose legs are placed together as a single strategy order. Takes `side`, `order_type`, `submitted_quantity`, `strategy` (`MultiLegStrategy`), a list of legs (`symbol` + `ratio_quantity`), and optional `submitted_price` / `remark` / `client_request_id`; returns the existing `SubmitOrderResponse` -- **All languages:** order queries and the order push now expose multi-leg strategy information. `Order` (from `today_orders` / `history_orders`), `OrderDetail` (from `order_detail`), and the `PushOrderChanged` order-changed event gain an optional `multi_leg` field (`MultiLegInfo`) — present only for multi-leg option combination orders — carrying the `strategy`, `strategy_name`, `multileg_id`, `code`, and the combination `legs` (each with `symbol`, `side`, `position`, `ratio_quantity`, `strike_price`, `expire_date`, and `contract_direction`). Adds the `MultiLegStrategy`, `MultiLegPosition`, and `ContractDirection` enums -- **All languages:** add grid-trading support via a standalone `GridContext` — submit / replace / cancel / suspend / restart grid orders, list orders (paged and by IDs), fetch order detail and trigger history, submit the strategy risk-disclosure questionnaire, and query the security (symbol) info (`symbol_info` → `GridSymbolInfo`: name, last price, lot sizes, price-step rules, channel/authorization) needed to build a grid order. Available in the Rust, Python, Node.js, Java, and C/C++ bindings -- **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 - -### Fixed - - **All languages:** the AI Agent streamed conversation no longer errors mid-run when the server sends an explicit `"outputs": null`. `WorkflowFinishedPayload.outputs`, `NodeToolUseFinishedPayload.outputs`, and `SubagentFinishedPayload.outputs` were annotated `#[serde(default)]`, which only covers a *missing* key, not an explicit `null` — so a `workflow_finished` / `node_tool_use_finished` / `subagent_finished` event carrying `null` outputs failed to deserialize and aborted the whole event stream (`invalid type: null, expected struct WorkflowOutputs`). These fields now map `null` to the type's default - **All languages:** likewise, list-typed fields on the streamed AI Agent event payloads no longer error on an explicit `null` (`invalid type: null, expected a sequence`). `tip_chips` (on the node / subagent / agent-tool `*_started` payloads), `WorkflowFinishedPayload.process_data`, and `SubagentStartedPayload.tools` were `#[serde(default)]`, which does not accept an explicit `null`; they now deserialize `null` to an empty list - **All languages:** clarified that `CompanyOverview.employees` is typed as a **string** (not an integer) across all SDK languages — the Longbridge API returns this field as a JSON string (e.g. `"10000"`). Doc comments have been updated to make this explicit and prevent downstream tools from incorrectly treating the value as an integer @@ -507,3 +500,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # [1.0.32] 2024-08-28 - make Depth.price to optional type + diff --git a/Cargo.toml b/Cargo.toml index 191bd8c01..c082ec85f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,20 +3,20 @@ resolver = "3" members = ["rust", "python", "nodejs", "java", "c"] [workspace.package] -version = "5.0.0" +version = "5.1.0" edition = "2024" [profile.release] lto = true [workspace.dependencies] -longbridge-geo = { path = "rust/crates/geo", version = "5.0.0" } -longbridge-wscli = { path = "rust/crates/wsclient", version = "5.0.0" } -longbridge-httpcli = { path = "rust/crates/httpclient", version = "5.0.0" } -longbridge-proto = { path = "rust/crates/proto", version = "5.0.0" } -longbridge-candlesticks = { path = "rust/crates/candlesticks", version = "5.0.0" } -longbridge-oauth = { path = "rust/crates/oauth", version = "5.0.0" } -longbridge = { path = "rust", version = "5.0.0" } +longbridge-geo = { path = "rust/crates/geo", version = "5.1.0" } +longbridge-wscli = { path = "rust/crates/wsclient", version = "5.1.0" } +longbridge-httpcli = { path = "rust/crates/httpclient", version = "5.1.0" } +longbridge-proto = { path = "rust/crates/proto", version = "5.1.0" } +longbridge-candlesticks = { path = "rust/crates/candlesticks", version = "5.1.0" } +longbridge-oauth = { path = "rust/crates/oauth", version = "5.1.0" } +longbridge = { path = "rust", version = "5.1.0" } tokio = "1.47.1" tokio-tungstenite = "0.27.0"