Skip to content

Releases: underloam/xbbg

xbbg 1.5.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 01:59

Added

  • Python LangChain/LangGraph adapter. The separate xbbg-langgraph package in py-xbbg-langgraph/ exposes 23 Bloomberg request/recipe/snapshot tools and 11 native helper/chart tools. It supports sync/async invocation, bounded content-and-artifact results, application-owned engines, and cancellation-safe subscription cleanup without adding LangChain dependencies to ordinary xbbg installs. Includes Python matrix and dependency-floor CI coverage; installation is from the checkout pending its first package publication.
  • Exchange auction and imbalance data. Bloomberg publishes imbalance, indicative-price, auction-state, and auction-result fields only on the listing where the auction runs. resolve_venues() routes each ticker or ISIN there — equities and ETFs to their primary-exchange ticker (SPY US Equity → SPY UP Equity), preferreds to their venue pricing source (/isin/<ISIN>@SNY2) — and validates Bloomberg's returned EXCH_CODE/PRICING_SOURCE on every call, so an ignored routing suffix is reported as mismatch instead of returning composite data; routing lookups are cached for 12 hours. auction_snapshot() fetches the auction fields with typed columns (times and dates included) in one validated reference-data request. subscribe_auction() / stream_auction() resolve every input before subscribing and label rows with the identifiers you passed. AUCTION field groups use streaming names (THEO_PRICE, not PX_THEO), and imbalance_side() maps venue codes such as MBUY/RBUY to buy/sell. Available in Python (xbbg.ext), JavaScript (Engine.resolveVenues, auctionSnapshot, subscribeAuction, streamAuction, AuctionFields, imbalanceSide), LangGraph (xbbg_resolve_venues, xbbg_auction_snapshot), and MCP (resolve_venues, auction_snapshot).
  • Shared real-time subscriptions. Within one engine, //blp/mktdata subscriptions to the same security and options share one Bloomberg subscription that requests the union of their fields, instead of each opening its own. A subscription joining an existing feed immediately gets one SUMMARY/INITPAINT row from the feed's current values. Adding fields the feed lacks re-subscribes it once: the requesting subscription gets Bloomberg's full repaint, and subscriptions that already had the image get one row only for values the repaint changed. isolated=True keeps a subscription on its own feeds and session; subscription_feeds() lists feeds, field unions, and consumer counts. Other services are not shared.
  • Current values, field growth, and labels on live subscriptions. sub.latest() returns one row per security with each field's current value plus last_update, live, and delayed, typed from Bloomberg's field metadata at subscribe time, and raises once the subscription has ended. rows=False (Node rows: false) keeps only current values for polling: nothing is queued, so it cannot overflow, and after a Bloomberg DATALOSS xbbg re-subscribes the feed for a fresh image (DataLoss and FeedRecovered events) instead of ending the subscription. zero_as_null shows 0 as missing in latest() for chosen fields; auction subscriptions apply it to the price fields in AUCTION.ZERO_PRICE_FIELDS by default. sub.add_fields() extends a running subscription, and aliases label rows, status, and remove() with your own identifiers.
  • Delayed-data and rejected-field warnings. Subscriptions read Bloomberg's IS_DELAYED_STREAM flag and warn once per security when data is delayed (on_delayed="warn" | "raise" | "ignore"; Python BlpDelayedDataWarning, Node process.emitWarning). Fields Bloomberg rejects at subscribe time, such as static-only PX_BID, are reported in field_errors with a BlpFieldWarning instead of silently staying empty; on_field_error="raise" fails the affected securities instead, and "ignore" records the error without warning. Node subscriptions also gain status, events, failures, failedTickers, topicStates, and fieldErrors.

Changed

  • GitHub repository links and generated MCP metadata now use the underloam organization. The MCP Registry identity is io.github.underloam/xbbg-mcp; package names and xbbg.org are unchanged.
  • Lower per-event subscription processing cost. Wide, sparse requested-field updates use a bounded present-field scan; narrow and dense updates retain name lookups. Schema discovery and type changes build the final immutable layout once per message without changing version increments. Requested-field order, null/absence semantics, terminal errors, and individual-event delivery are unchanged; no batching or API changes.
  • BREAKING: filtered market-data subscriptions skip rows that contain none of their fields. Rows carrying only MKTDATA_EVENT_TYPE/MKTDATA_EVENT_SUBTYPE are no longer emitted, so a subscription's output does not depend on other subscriptions sharing its feed. all_fields=True subscriptions still see every scalar field the feed receives, including fields other subscriptions requested.
  • BREAKING (Rust): Engine::subscribe(SubscribeRequest) replaces subscribe(...) and subscribe_with_options(...) in xbbg-async. Streams split into a receiver and a cloneable SubscriptionHandle that owns consumer memberships rather than a session claim. xbbg_core sessions add resubscribe(). Python and JavaScript signatures only gain optional arguments.
  • Subscription sessions host shared feeds. A subscription that only joins existing feeds uses no session; max_subscription_sessions still caps concurrent sessions, and a session returns to the pool once it hosts no feeds. Python sync stream() no longer keeps its own producer counter: a stream that only joins existing feeds never waits, and one that needs a new session waits up to 5 seconds for capacity, then raises the same RuntimeError("sync stream producer limit reached (N)") as before instead of blocking. When a session terminates, only the securities on it fail; a stream ends with the session error once none of its securities remain.
  • BREAKING (typed outputs): date and time fields keep their types. Bloomberg's field metadata reports every date and time field as Datetime, which xbbg resolved to text. Types now follow the field's kind: LONG_TYPED adds a value_time column (Time64, µs) after value_ts for time-only values, and value_ts holds full datetimes only; SEMI_LONG date/time columns become Date32, Time64, or UTC timestamps; LONG_WITH_METADATA reports the matching dtype. Default LONG output still returns text. Field-type caches written by older versions are discarded and refreshed on first use.
  • BREAKING (Python): recipe failures raise typed xbbg exceptions. Engine errors from xbbg.ext recipes (for example resolve_isins(), cdx_ticker(), etf_nav_snapshot(), and the new auction helpers) now raise the same BlpTimeoutError, BlpRequestError, BlpValidationError, and other BlpError subclasses as the request APIs instead of RuntimeError; except RuntimeError no longer catches them. Invalid arguments still raise ValueError.
  • BREAKING (Rust): xbbg_core::MessageIterator is a cursor, not an Iterator. Loop with let mut messages = event.messages(); while let Some(msg) = messages.next() { ... }. Each message borrows the cursor, so iterator adapters such as count() and collect() no longer apply to messages. Event::iter() is removed; use Event::messages().

Fixed

  • Every Python sync API works in notebooks (#353). In Jupyter, VS Code Interactive, and marimo, blp.bql() and the other sync wrappers outside the former bdp/bdh/bds/bdib/bdtick/request allowlist (for example bsrch(), beqs(), bflds(), bta(), bschema(), and the subscribe()/vwap()/mktbar()/depth()/chains() subscription handles) now use the notebook bridge instead of raising cannot be used inside an async context. The xbbg.schema sync helpers, resolve_field_types(), xbbg.markets fetch_exchange_info(), and generate_ta_stubs() use the same boundary instead of calling asyncio.run() directly. Other running event loops, such as FastAPI or ASGI apps, still raise and name the async API.
  • Synchronized native release versions. Cargo workspace and internal dependency versions now match 1.4.12, and future release workflows stamp and commit them before tagging. The binding version uses the stamped crate identity even without Git metadata; Git descriptions remain in build provenance. Release builds reject unstamped source trees and wheels whose Python, binding, or core versions disagree.
  • Patched JavaScript test tooling. Both JavaScript packages now require Vitest ^4.1.11 and lock its coordinated @vitest/* dependencies, including @vitest/mocker, to 4.1.11, addressing the redirect-mock path traversal and arbitrary file read in GHSA-82fw-gwwq-j7x9.
  • Patched MCPB archive tooling. The private build tools now pin fflate to 0.8.3, fixing the malformed ZIP64 infinite loop in GHSA-px8p-9vwx-vf98.
  • Patched JavaScript dev tooling. Both JavaScript packages now lock brace-expansion 5.0.12 (#355), fixing the denial-of-service advisories GHSA-6j4f-fj2g-mc7p, GHSA-qhr7-859c-m2p7, and GHSA-q2hr-2g5m-vwhr. It is a development dependency and is not part of the published packages.
  • Python docs no longer claim a 60-second request timeout. The PyEngineConfig.request_timeout_ms docstring and type stub still said Default: 60_000, but the default has been 0 (no timeout) since 1.1.1. Requests wait for Bloomberg until they finish unless you opt in with configure(request_timeout_ms=...).
  • **resolve_isins() no longer reports preferre...
Read more

xbbg 1.4.12

Choose a tag to compare

@github-actions github-actions released this 11 Sep 10:37

Added

  • Explicit resource limits and ownership controls. Engines expose runtime_worker_threads / runtimeWorkerThreads (default 2) and max_subscription_sessions / maxSubscriptionSessions (default 32). Native Arrow carriers expose compact() to detach retained slices from larger backing allocations when the caller prefers a copy over retaining the parent.
  • Independent application and model result budgets. LangGraph tools bound application artifacts and model content separately, including aggregate node and streaming-materialization limits. MCP adds cell, UTF-8 string, metadata, and final-result byte budgets alongside its row limit; bounded envelopes retain primary diagnostics and report omissions rather than silently presenting partial data as complete.

Changed

  • BREAKING — subscriptions preserve sparse deltas and fail closed on continuity gaps. Missing fields are no longer fabricated as null clears. Arrow output adds non-null binary __xbbg_present with schema-mapped presence bits; JavaScript accessors return undefined for absent fields and null for explicit clears. Bloomberg DATALOSS and local overflow/forwarding timeout now end the affected stream with BlpSubscriptionDataLossError; resubscribe for a fresh image.
  • Streaming resources are bounded across the Python bridge, SDK sessions, and consumer queues. Synchronous Python streams share a managed event loop with bounded per-stream buffering and producer admission. Subscription sessions use explicit leases and a hard cap; full consumer queues no longer make the SDK callback wait. Status changes are published in batches instead of cloning snapshots for each topic transition.
  • Arrow conversion does less unnecessary allocation and materialization. Small subscription batches use right-sized builders; logical slices and validity buffers are normalized before handoff. Node Arrow construction avoids IPC encoding/decoding while exposing exclusively JS-owned mutable buffer snapshots, rather than writable aliases of immutable Rust storage. BQL scalar deserialization no longer requires an intermediate JSON value tree.
  • Optional dataframe backends preserve ownership and deferred work. DuckDB relations share one process-local database while retaining independent connections and source lifetimes; an initialized database is explicitly rejected after fork. Polars conversion preserves Arrow chunk boundaries, and narwhals_lazy now uses a real Polars lazy plan for local dataframe operations. The supported Polars floor is 0.20.4, with its timezone extra supplying Windows timezone data.
  • Recipes avoid repeated work without changing financial results. Futures metadata lookups are combined, independent ETF request legs can overlap, and dividend windows advance over active events while preserving boundary rules and floating-point results.
  • Large MCP serialization uses bounded blocking work. The MCP runtime uses two async workers and admits at most two offloaded serializations, keeping large result conversion off the async workers without creating an unbounded work queue.
  • Benchmark results now describe the work actually measured. Cold/setup, warm timing, consumption, and memory observation are separated; percentile output requires enough samples (20 for p95, 100 for p99). Replay loss accounting and comparison inputs are checked. Native build provenance comes from Cargo's actual artifact and compiler settings, includes the SDK link input and artifact hashes, and rejects mismatched or host-tuned artifacts during portable release staging.
  • README badges are grouped by ecosystem. The header now shows one labeled row each for Python, JavaScript, and Rust with version, runtime, and download badges, adds PyPI downloads per month, and adds crates.io (xbbg_core) alongside PyPI and npm. The conda-forge badge moved to shields.io for a consistent style, and the project links list now includes npm and crates.io.

Fixed

  • Subscription extraction preserves valid timestamps and schema transitions. The LAST_UPDATE_ALL_SESSIONS_RT null guard is removed; valid time-only values use the SDK getter. All-fields caches revalidate datatype and shape, requested arrays/complex fields fail instead of truncating, non-null decode failures are errors, and JavaScript promoted string layouts retain concrete scalar values.
  • Terminal delivery and draining are reliable across Rust, Python, and JavaScript. Full queues cannot displace the first terminal error; committed data is followed by that error and EOF, including shutdown after remove-all. Draining preserves the selected dict/raw/backend or scalar/Arrow representation and raises unread failures after cleanup. Explicit Python output overrides legacy mode flags; partial-topic failures remain nonterminal.
  • Subscription shutdown preserves cancellation and errors across bindings. Pending reads, iterator return() / early for await exit, abort signals, drain barriers, and shared scalar/Arrow views coordinate one native close. Failed closes—including an undefined JavaScript rejection reason—remain failures and release completed session claims. Ordinary engine shutdown is distinct from interpreter finalization, which suppresses unsafe Python completion callbacks.
  • Configuration and caches no longer race their owners. Scoped Python engines use context-local tokens; configuration replacement and field-cache generations are coordinated. Schema caches and readers are bounded, publications are ordered and atomic, service filenames are collision-free, and targeted invalidation reports failed persistence. Windows publication uses shared-handle POSIX rename semantics so concurrent readers retain complete snapshots; unsupported filesystems fail without an unsafe replacement fallback.
  • Native Arrow edge cases preserve data. Zero-column tables retain their row counts through construction, renaming, and Narwhals row access. Mixed numeric inference does not round inexact large integers through float64, and native temporal schemas retain their precision and timezone through Narwhals and legacy Polars conversion.

Full Changelog: v1.4.11...v1.4.12

xbbg 1.4.11

Choose a tag to compare

@github-actions github-actions released this 02 Sep 00:34

Fixed

  • xbbg-mcp no longer mistakes a failed stdin worker or abnormal service stop for clean EOF. Stderr diagnostics are now best-effort instead of using eprintln!, whose panic on a closed host log pipe could kill the detached reader and recreate the silent exit from #348. The reader reports its terminal state out of band before closing the transport; read failures, worker panics, unexpected transport closure, task failures, cancellation, and reader-thread spawn failures now reach main as errors and return a nonzero process status.
  • The Windows MCPB launcher now guarantees that the Bloomberg DLL it validates is the one the loader can select. The chosen runtime directory becomes the child's working directory and first PATH entry, while a higher-priority blpapi3_64.dll beside the executable or in a Windows system directory is rejected rather than silently shadowing the checked file. Candidates with unreadable version metadata are skipped; packaging fails closed when the binary exposes no versioned Bloomberg imports; --min-blpapi-version accepts only a canonical three- or four-part numeric version; and loader-status messages no longer blame a specific module without evidence.
  • MCPB release artifacts are now reproducible and built with integrity-locked tooling. A locked fflate 0.8.2 compressor writes sorted members with fixed timestamps and explicit Unix modes, so rerunning the same tag with identical binaries preserves both the executable launchers and the MCPB SHA-256 recorded in the official registry. The workflow also installs exactly @anthropic-ai/mcpb 2.1.2 from the committed npm lockfile, overrides its vulnerable transitive tmp dependency with patched 0.2.7, disables lifecycle scripts, runs the packer regression tests, and uses the pinned CLI to validate and inspect the deterministic archive instead of executing mutable latest code.

Full Changelog: v1.4.10...v1.4.11

xbbg 1.4.10

Choose a tag to compare

@github-actions github-actions released this 01 Sep 23:30

Fixed

  • The 1.4.9 Windows MCPB launcher refused every Bloomberg runtime older than 3.26.7.1, including current Python blpapi packages. The runtime gate introduced in 1.4.9 was seeded with the SDK version the release was built against rather than the oldest runtime that exports the entry points the binary imports, so the bundle rejected runtimes such as blpapi 3.26.4.2 that work. scripts/package_xbbg_mcpb.py now derives the minimum from the binaries themselves -- the newest BLPAPI_x.y.z symbol version referenced by the Linux build, currently 3.20.0, which is the same function set the Windows binary imports by name -- and accepts --min-blpapi-version only as an explicit override. Every blpapi package on Bloomberg's index from 3.21.0 onward passes; a Terminal DLL older than 3.20.0 is still skipped with a message naming its version, because the loader would kill the process without one.

Full Changelog: v1.4.9...v1.4.10

xbbg 1.4.9

Choose a tag to compare

@github-actions github-actions released this 01 Sep 22:54

Fixed

  • xbbg-mcp no longer stops silently when stdin misbehaves, and the Windows MCPB launcher stays out of the byte stream (#348). On one Windows host the v1.4.6 server answered initialize and exited a moment later with status 0 and nothing on stderr: tokio::io::stdin() reports any zero-byte read as end-of-input and turns read errors into a bare "connection closed", and no log subscriber was installed, so nothing recorded why. The server now reads stdin on its own thread -- a zero-byte read on a pipe whose writer is still connected (PeekNamedPipe) is retried instead of ending the session, a failed read is reported on stderr, and the process states why it stops (xbbg-mcp: stdin closed; shutting down, or the abnormal quit reason). It also installs the workspace stderr logger, so RUST_LOG works and rmcp/engine warnings reach the host's server log. The Windows launcher (xbbg-mcp.ps1) ran xbbg-mcp.exe as a PowerShell native command, which lets Windows PowerShell 5.1 sit between the MCP host and the server -- re-encoding stdout through the console code page and, under the script's $ErrorActionPreference = "Stop", terminating the child on its first stderr line. It now starts the binary with inherited standard handles and propagates its exit status, the Windows equivalent of the POSIX launcher's exec. The reported machine state did not reproduce on Windows 11 through Claude Desktop's own client library, a Node parent, a console, or a bare pipe, with either the shipped v1.4.6 binary or this build; the fix therefore closes every path by which stdin could end the process without a message rather than a single guessed cause.
  • The Windows MCPB launcher checks the Bloomberg runtime it picks (#348). It accepted any directory holding blpapi3_64.dll or blpapi3_32.dll, so pointing XBBG_MCP_LIB_DIR at a Terminal's C:\blp\DAPI passed and the 64-bit binary then died in the loader with STATUS_ENTRYPOINT_NOT_FOUND and no output. It now requires blpapi3_64.dll, compares its file version with the Bloomberg API version the release was built against (scripts/package_xbbg_mcpb.py --blpapi-sdk-version, supplied by the release workflow), skips older runtimes with a message naming the version found, searches PATH as well (the Windows convention; a Terminal install puts C:\blp\DAPI there) before falling back to the Python blpapi package, and translates the loader statuses STATUS_DLL_NOT_FOUND, STATUS_ENTRYPOINT_NOT_FOUND, and STATUS_INVALID_IMAGE_FORMAT into one-line explanations.
  • The MCPB manifest.json lists all nine tools (#348). check_entitlements was missing from the manifest's tools array and from scripts/xbbg_mcp_smoke.py's expected set even though the server advertised it.
  • v1.4.7 and v1.4.8 shipped no PyPI, npm, or MCP assets. Both tags were cut, and their Rust crates published, without the PyPI and npm publish workflows being dispatched, so v1.4.6 stayed the newest installable release everywhere but crates.io. This release publishes every surface.

Full Changelog: v1.4.8...v1.4.9

xbbg 1.4.8

Choose a tag to compare

@github-actions github-actions released this 01 Sep 21:54

Added

  • Closed value sets now declared in defs/bloomberg.toml: Overflow policies, validation modes, and SDK log levels are now centralized in the configuration file as the single source of truth. defs/codegen/generate.py generates a TypeScript vocabulary (_defs_gen.ts) for both JavaScript packages and Rust contract tests that fail if a hand-written parser stops accepting a declared spelling.

Changed

  • Documentation and error messages now name complete legal value sets and defaults: Surface layers across Python (pyo3-xbbg), JavaScript (N-API), the MCP server, API docstrings, and READMEs now document every accepted value for closed enums (overflow policy, validation mode, SDK log level, subscription output, request format, auth method, ZFP remote) alongside the default and any accepted aliases.

Fixed

  • @xbbg/core exported a format wire value the engine rejects: Format.LONG_WITH_METADATA was 'long_with_metadata', but the engine only accepts 'long_metadata' (defs/bloomberg.toml and the generated Python enum already used the correct value, so only the hand-written JavaScript constant was wrong). js-xbbg/test/smoke.test.ts asserted the broken value, which is why it went unnoticed. Format and FormatKind are now generated from defs/bloomberg.toml.
  • LangGraph snapshot tools advertised a rejected overflow policy: overflowPolicy on xbbg_stream_snapshot, xbbg_mktbar_snapshot, and xbbg_depth_snapshot was a free-form string whose description named no legal values and whose example was the drop_oldest policy removed in 1.2.0, so models emitted it and the engine failed the call with unknown overflow policy 'drop_oldest'. It is now a closed enum generated from defs/bloomberg.toml, and its description carries the accepted values, their semantics, and the default.

Full Changelog: v1.4.7...v1.4.8

xbbg 1.4.7

Choose a tag to compare

@github-actions github-actions released this 28 Aug 01:10

Added

  • Rust crates now publish automatically on release. .github/workflows/crates-publish.yml publishes the six public crates to crates.io in dependency order, authenticating tokenlessly through rust-lang/crates-io-auth-action (GitHub OIDC), so no CARGO_REGISTRY_TOKEN secret exists. semantic_version.yml invokes it as a workflow_call job rather than relying on a tag trigger, because a tag pushed with GITHUB_TOKEN does not start tag-triggered workflows -- the documented reason the PyPI and npm workflows still need a manual dispatch. The job skips any version already in the index, so a retry after a partial failure is safe, and it stamps workspace.package.version plus every internal [workspace.dependencies] entry from the release version so all crates ship in lockstep.

Changed

  • BREAKING -- optional-backend and narwhals floors now reflect versions that actually work. The previous lower bounds were never resolved or exercised by CI, and three of them named combinations that cannot function. narwhals moves from >=2.0 to >=2.10.0 -- it is the only mandatory runtime dependency, and only 2.10.0 onward honours the narwhals.plugins entry point xbbg registers, so on 2.0-2.9 the plugin never loads and any conversion raises TypeError: Expected pandas-like dataframe, Polars dataframe, or Polars lazyframe, got: <class 'xbbg._core.ArrowTable'>. The pandas extra moves from >=2.0 to >=2.2.2,<4, because pandas 2.0.x declares no numpy<2 bound, so a fresh resolve pairs it with numpy 2.x and pandas then fails to import with numpy.dtype size changed, may indicate binary incompatibility; 2.2.2 is the first release supporting numpy 2. The duckdb extra moves from >=1.0 to >=1.5.0, because below 1.5.0 the connection backing a returned relation is lost (Connection has already been closed), and 1.0.0 additionally cannot register an Arrow PyCapsule object at all. pytest-cov in the test extra gains a >=5.0 bound; unpinned, a lowest-direct resolve selected pytest-cov 2.0.0 from 2018. polars>=0.20 and pyarrow>=22.0.0 were verified as genuinely working and are unchanged. Environments already on current releases are unaffected; anyone pinned below these bounds must upgrade.
  • Declared floors are now verified by CI. A new floors job resolves the project with uv pip install --resolution lowest-direct on Python 3.10 -- the lowest supported interpreter, and the only one where the oldest wheels are still selectable -- and runs the full non-live suite against the result. Each floor in pyproject.toml carries a comment recording the measured reason it cannot go lower.
  • Rust MSRV is declared. [workspace.package] now sets rust-version = "1.88", matching the highest rust-version in the resolved dependency graph, and pixi.toml raises its rust floor from >=1.75 to >=1.88 to agree. The published sdist compiles the Rust extension on the user's machine, so the toolchain requirement is part of the package contract rather than a local development detail; >=1.75 had been unsatisfiable for several majors.
  • Third-party Rust versions are centralized in [workspace.dependencies]. The arrow family alone was restated across eight manifests and tokio across five, and the disabled xbbg-cli / dotnet-xbbg manifests had already drifted to arrow 57.1.0 and a csbindgen 2 that has never been published. Members now inherit with { workspace = true } and layer only their own features. default-features is set in the workspace table because Cargo silently ignores a member's default-features = false when the workspace entry omits it. The migration is feature-neutral: resolved feature sets were diffed per package before and after.
  • rmcp upgraded from 2.1.0 to 3.1.2 in xbbg-mcp, with no source changes required. Both versions default ProtocolVersion::LATEST to MCP 2025-11-25, so the advertised revision is unchanged; 3.x additionally negotiates the 2026-07-28 draft.
  • Internal crate versions are centralized too, and now carry a version. Every intra-workspace dependency was a bare { path = ... }. cargo publish rejects a path dependency with no version, so no crate with an internal dependency could be published at all -- the actual reason the Rust crates sat at 1.1.2 while the project tagged v1.4.6. The internal crates now sit in [workspace.dependencies] as { path, version } and members inherit with { workspace = true }, matching the convention already used for third-party crates. Because those entries set default-features = false, xbbg-mcp and xbbg-bench now name features = ["live"] explicitly where they previously inherited it via default features.
  • crates.io package metadata is complete and points at the project, not a personal account. All five published crates had repository and homepage pointing at a legacy personal GitHub account and its github.io pages site; both now resolve to the xbbg-org repository and https://xbbg.org/. main had also dropped the homepage, readme, and keywords that 1.1.2 actually shipped. Every published crate now declares homepage, readme, keywords, categories, and rust-version (crates.io reported the MSRV as unset for all of them), plus an explicit include allowlist so only source, Cargo.toml, and README.md are ever packaged.
  • blpapi-sys is renamed to xbbg-blpapi-sys to match the name it is published under. The bare blpapi-sys name is taken on crates.io, so the local package name never matched the registry name and cargo publish -p xbbg-blpapi-sys could not resolve. [lib] name = "blpapi_sys" is retained, so Rust code still says blpapi_sys:: and the change is source-compatible with the published 1.1.2.
  • exchanges.toml moved from defs/ into crates/xbbg-ext/data/. xbbg-ext embeds it with include_str!, and the path reached outside the crate root, so the published sdist would not have contained the file and the crate would have been unbuildable from crates.io. xbbg-ext was its only consumer.

Removed

  • xbbg-sys is deleted. It was 16 lines that re-exported blpapi_sys::* behind a mandatory live feature, with a compile_error! on every other configuration -- a leftover seam from the removed mock backend. xbbg_core now depends on xbbg-blpapi-sys directly, and the compile_error! guard moves to xbbg_core/src/lib.rs so a non-live build still fails with one clear message instead of dozens of unresolved imports. The crate should also be deleted on crates.io, which is possible only after a release where xbbg_core no longer depends on it.
  • apps/xbbg-cli and bindings/dotnet-xbbg are deleted. Both were stubs of 16 and 10 lines, commented out of the workspace members, and had already drifted to dependency versions that do not resolve.

Fixed

  • Engine teardown no longer panics when the engine is dropped inside an async context. Engine owns its tokio runtime, and tokio refuses to release a runtime's last handle from inside another runtime because teardown must block to join worker threads. Any async owner therefore aborted with Cannot drop a runtime in a context where blocking is not allowed -- including xbbg-mcp, which holds the engine across #[tokio::main] and so panicked on every clean shutdown once an engine had started. Engine::drop now takes the runtime out of its field and hands it to Runtime::shutdown_background() when a runtime is current, which is race-free because the field is left empty and no second release path can reach a zero refcount. Outside an async context the previous blocking drop is retained. The live integration test that used std::mem::forget to dodge this panic -- and leaked the runtime doing so -- now drops the engine normally.
  • Engine startup failures report the real error instead of a runtime-teardown panic. Engine::start built its tokio runtime before constructing the worker pools, so any early return dropped the runtime on an async caller's thread and replaced the underlying failure with tokio's unrelated panic message. With a Bloomberg terminal unavailable, Engine::start now surfaces failed to spawn worker 0: session start failed rather than Cannot drop a runtime in a context where blocking is not allowed. The runtime is constructed after every fallible step.
  • Three high-severity advisories cleared from the JavaScript dev dependency trees (postcss GHSA-fxqj-rqcc-2cmp / GHSA-r28c-9q8g-f849, nanoid GHSA-28wg-ghj8-5hjv / GHSA-2v37-7h3g-55p8, brace-expansion GHSA-mh99-v99m-4gvg / GHSA-rgw5-rvv9-x895), plus cryptography GHSA-g6cj-pr64-35w5 and c-ares CVE-2026-33630 in the pixi environment. These are build- and test-time dependencies only and are not redistributed in any published artifact.
  • Stale pyo3 advisory ignores removed from .cargo/audit.toml and deny.toml. They suppressed RUSTSEC-2026-0176 and RUSTSEC-2026-0177 on the premise that the fix required a pyo3 0.29 chain that dependencies did not yet support; the workspace has since resolved to pyo3 0.29.2 exclusively, so the entries were unreachable and would have masked a future regression onto a vulnerable pyo3.
  • blpapi-sys no longer advertises a documentation build it cannot perform. Its docs.rs metadata requested all-features = true while build.rs panics when the mutually exclusive static and dynamic linkage features are both enabled, which also broke cargo clippy --all-features for the whole workspace. The metadata now names the default dynamic linkage.
  • xbbg_core keeps its underscore, permanently. crates.io normalizes - and _ to the same package identity, so xbbg-core is not an available name while xbbg_core exists, and claiming it would require deleting the crate and waiting out the name-reuse block. The manifest documents this so the inconsistency is not "corrected" later.

Full Changelog: https://github.com/x...

Read more

xbbg 1.4.6

Choose a tag to compare

@github-actions github-actions released this 06 Aug 22:57

Changed

  • Linux artifacts now support glibc 2.28 and newer: wheels, the @xbbg/core-linux-x64 native addon, and the xbbg-mcp linux-amd64 binary build inside the manylinux_2_28 (AlmaLinux 8) container instead of on bare ubuntu-latest, so they run on RHEL/Alma/Rocky 8, Debian 10+, Ubuntu 20.04+, and Amazon Linux 2023. Linux wheels are tagged manylinux_2_28_x86_64 (enforced via auditwheel repair --plat), and the new scripts/check-glibc-max.sh guard fails CI and release builds if any Linux binary references newer GLIBC symbol versions.
  • lookback_days on active_cdx is now a minimum, not the whole window: the activity window always reaches back to the resolved series' first accrual date, so "this series has traded" can only flip false to true as the date advances.

Removed

  • BREAKING -- **kwargs on xbbg.ext.acdx_ticker / aactive_cdx: these forwarded Bloomberg request keywords to internal metadata lookups and never affected the returned ticker; passing them is now a TypeError.

Fixed

  • CDX series resolution is now as-of the requested date, and monotone: cdx_ticker / active_cdx, Engine.cdxTicker() / Engine.activeCdx(), and the underlying xbbg-recipes entry points resolve the series whose Bloomberg CDS_FIRST_ACCRUAL_START_DATE is the latest one on or before the reference date, walking the accrual ladder in batched reference-data requests. Previously they read ROLLING_SERIES off the generic ticker -- a point-in-time field that reports today's series whatever date was asked for -- and stepped back at most one series, so every historical date collapsed onto the current series or its predecessor (cdx_ticker('CDX IG CDSI GEN 5Y Corp', '2020-06-01') returned S45; it now returns S34). active_cdx additionally chose between the two candidates by whichever had the later PX_LAST print, which flipped the answer back to the older series on any day the newer one had not yet printed. Series, and version within a series, are now non-decreasing as the date advances.
  • CDX roll dates are read, not assumed: the semi-annual cadence only sizes the candidate window; the series is decided by comparing against the accrual dates Bloomberg returns. Business-day-adjusted rolls therefore resolve exactly -- CDX.NA.IG.45 first accrues 2025-09-22, so 2025-09-21 resolves to S44.
  • CDX version is resolved per series: the Vn token is the version Bloomberg reports for the resolved series (CDX.NA.HY.32 resolves to V14, HY.40 to V4), instead of the current series' version stamped onto every answer. Version is scoped to a series and resets at each roll, so it is non-decreasing within a series but not across one.
  • BREAKING -- failed CDX resolution raises: xbbg.ext.cdx_ticker / active_cdx no longer swallow Bloomberg errors, missing metadata, or unparseable series numbers into an empty-string ticker. They now delegate to the same xbbg-recipes resolver as @xbbg/core, so the Python and JavaScript surfaces cannot drift apart, and raise ValueError (non-generic ticker, date before the index's first series) or RuntimeError (missing or inconsistent Bloomberg metadata) instead. Callers that tested for "" must catch instead.
  • Clean session shutdown no longer logs SessionConnectionDown / SessionTerminated as WARN/ERROR (#346): tearing an engine down -- including the implicit teardown at interpreter exit after a one-shot call such as blp.bdh() -- makes the Bloomberg SDK emit both events for every pooled session. The request path already recognized a requested shutdown and logged at INFO, but the subscription path did not, so any script that simply ran a request printed a spurious SessionTerminated -- SDK gave up reconnecting; closing subscriptions at ERROR on exit, with active_subs=0 and an empty reason. Subscription workers now publish the shutdown flag before asking the SDK to stop and classify each lifecycle event (shutdown_in_progress at INFO versus connection_down_without_shutdown / termination_without_shutdown at the original WARN/ERROR), so genuine mid-session failures keep their severity.
  • import xbbg no longer leaks SyntaxWarnings from Bloomberg's blpapi wheel (#346): importing xbbg runs SDK discovery, which imports the blpapi Python package because the pip wheel ships the shared library and is probed ahead of a Terminal DAPI install. Bloomberg's resolutionlist.py and topiclist.py contain invalid escape sequences in their docstrings, so Python 3.12+ printed SyntaxWarning: invalid escape sequence '\s' on first import for anyone with the wheel installed -- from an import the caller never asked for. Discovery now performs that import with SyntaxWarning filtered, leaving the user's own warning filters untouched.

Full Changelog: v1.4.5...v1.4.6

xbbg 1.4.5

Choose a tag to compare

@github-actions github-actions released this 18 Jul 01:06

Added

  • Shared ETF NAV / iNAV toolkit with Python and JavaScript parity: A new xbbg-recipes module resolves Bloomberg's authoritative ETF_NAV_TICKER / ETF_INAV_TICKER relationships (normalized to one Index suffix and validated as genuine Index securities, so non-conventional targets such as QQQ US Equity -> QXV Index and null/AT1IN Index legs survive intact), serves current NAV/iNAV snapshots and daily history with a FUND_NET_ASSET_VAL fallback for ETFs without a daily NAV Index, and powers Python xbbg.ext (etf_nav_relationships, etf_nav_snapshot, etf_nav_history, subscribe_etf_inav plus async variants) and @xbbg/core (etfNavRelationships, etfNavSnapshot, etfNavHistory, subscribeEtfInav) with identical schemas and atomic iNAV subscription preflight.

Changed

  • Canonical CDX series identities across Rust, Python, and JavaScript: xbbg-recipes, cdx_ticker / active_cdx, and Engine.cdxTicker() / Engine.activeCdx() now require Bloomberg VERSION metadata and return explicit Vn identifiers (including V1) by default, resolve prior-series versions independently, and round-trip explicit-version tickers correctly. Pass versionless=True or { versionless: true } only when a legacy Bloomberg alias is required.

Full Changelog: v1.4.4...v1.4.5

xbbg 1.4.4

Choose a tag to compare

@github-actions github-actions released this 12 Jul 22:00

Added

  • Complete Bloomberg entitlement-ID routes across bindings: Python and @xbbg/core now request EIDs for intraday bars and ticks as well as BDP/BDS/BDH; LangGraph exposes returnEids on BDP/BDS/BDH/BDIB/BDTICK plus xbbg_check_entitlements, and MCP exposes return_eids on its dedicated BDP/BDS/BDH/BDIB tools and generic IntradayTick route plus check_entitlements, with bounded results preserving entitlement metadata.
  • Official MCP Registry publish workflow: Added a manual GitHub Actions workflow that publishes release server.json metadata through mcp-publisher with GitHub Actions OIDC, so the xbbg-org namespace can publish without relying on a maintainer's local public organization membership.
  • Batched subscription delivery in @xbbg/core: one native crossing now drains many ticks (nextUpdates) and Arrow subscriptions return multi-row zero-copy batches (nextArrowBatch); tick field layouts cross the boundary once per layout version and Tick caches decoded BigInt/Date values.
  • SubscriptionArrowBatcher in the Rust engine: cached schema + reusable Arrow builders convert streaming updates into multi-row RecordBatches instead of one-row batches per tick.
  • Offline benchmark coverage: registered the previously orphaned Arrow/subscription bench targets, added a serde_json vs simd-json BQL parser bench, and added offline Rust→Python / Rust→JS binding-handoff benches that run without a Bloomberg connection.
  • Host-tuned build modes: pixi run build-native and npm run build:native:host produce target-cpu=native artifacts for internal deployments; published artifacts stay portable.

Changed

  • Subscription sessions moved to Bloomberg SDK asynchronous callback mode: the 1 ms nextEvent busy-poll loop, its command channel, and per-loop topic-status scans are gone; events are dispatched by SDK callbacks and deactivation warnings run on a 1 s timer. Idle subscription workers no longer consume CPU.
  • Faster response decoding: typed long-format reference/historical output uses fixed-schema builders (no per-cell string-keyed map lookups), BDS bulk decoding walks each row once via interned name keys instead of O(rows × subfields) lookups, intraday bars use fixed builders, streaming chunks pre-reserve capacity, and BQL infers column types in a single pass.
  • Cheaper ticks: DATALOSS detection is folded into the normal extraction pass, message types are read via borrowed strings instead of refcounted Name duplicates, small updates avoid heap allocation (SmallVec), and repeated string values (exchange/condition codes) are interned per field.
  • Python pandas conversion is Arrow-native: backend='pandas' now converts through the Arrow C stream (pyarrow.table(...).to_pandas()) instead of materializing every cell as a Python object; the row-based path remains only as a documented no-pyarrow fallback. Python subscriptions with backend=None now yield native Arrow wrappers and resolve their converter once at construction.
  • @xbbg/core request responses are zero-copy: reference/historical/recipe results cross N-API as Arrow buffer descriptors instead of Arrow IPC bytes that were immediately reparsed; schema APIs cache their JSON payloads.
  • Request workers decode responses outside the shared slot table lock, so large partial responses no longer block unrelated in-flight requests on the same worker.
  • OverflowPolicy::Block is now bounded on the SDK callback thread: instead of parking Bloomberg's dispatcher indefinitely when a consumer stalls, the producer retries briefly, then records a slow-consumer event and drops the update.
  • npm run build:native builds release by default (use build:native:debug for local iteration), and packaging refuses to stage a native addon whose build profile isn't release.
  • blpapi-sys caches generated bindings next to the vendored SDK keyed by target and build-script hash, and tracks headers/env precisely, removing bindgen from warm clean builds and spurious CONDA_PREFIX rebuilds on non-Windows hosts.
  • Metadata caches (exchange info, field types) publish snapshots per batch with bounded capacity instead of cloning the whole map per inserted key.

Fixed

  • Marimo notebook compatibility: Synchronous one-shot Python APIs such as blp.bdp() now use the notebook bridge inside marimo's async execution context instead of raising the generic async-context error.

Full Changelog: v1.4.3...v1.4.4