Releases: underloam/xbbg
Releases · underloam/xbbg
Release list
xbbg 1.5.0
Added
- Python LangChain/LangGraph adapter. The separate
xbbg-langgraphpackage inpy-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 returnedEXCH_CODE/PRICING_SOURCEon every call, so an ignored routing suffix is reported asmismatchinstead 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.AUCTIONfield groups use streaming names (THEO_PRICE, notPX_THEO), andimbalance_side()maps venue codes such asMBUY/RBUYto 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/mktdatasubscriptions 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 oneSUMMARY/INITPAINTrow 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=Truekeeps 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 pluslast_update,live, anddelayed, typed from Bloomberg's field metadata at subscribe time, and raises once the subscription has ended.rows=False(Noderows: false) keeps only current values for polling: nothing is queued, so it cannot overflow, and after a BloombergDATALOSSxbbg re-subscribes the feed for a fresh image (DataLossandFeedRecoveredevents) instead of ending the subscription.zero_as_nullshows 0 as missing inlatest()for chosen fields; auction subscriptions apply it to the price fields inAUCTION.ZERO_PRICE_FIELDSby default.sub.add_fields()extends a running subscription, andaliaseslabel rows, status, andremove()with your own identifiers. - Delayed-data and rejected-field warnings. Subscriptions read Bloomberg's
IS_DELAYED_STREAMflag and warn once per security when data is delayed (on_delayed="warn" | "raise" | "ignore"; PythonBlpDelayedDataWarning, Nodeprocess.emitWarning). Fields Bloomberg rejects at subscribe time, such as static-onlyPX_BID, are reported infield_errorswith aBlpFieldWarninginstead of silently staying empty;on_field_error="raise"fails the affected securities instead, and"ignore"records the error without warning. Node subscriptions also gainstatus,events,failures,failedTickers,topicStates, andfieldErrors.
Changed
- GitHub repository links and generated MCP metadata now use the
underloamorganization. The MCP Registry identity isio.github.underloam/xbbg-mcp; package names andxbbg.orgare 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_SUBTYPEare no longer emitted, so a subscription's output does not depend on other subscriptions sharing its feed.all_fields=Truesubscriptions still see every scalar field the feed receives, including fields other subscriptions requested. - BREAKING (Rust):
Engine::subscribe(SubscribeRequest)replacessubscribe(...)andsubscribe_with_options(...)inxbbg-async. Streams split into a receiver and a cloneableSubscriptionHandlethat owns consumer memberships rather than a session claim.xbbg_coresessions addresubscribe(). 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_sessionsstill caps concurrent sessions, and a session returns to the pool once it hosts no feeds. Python syncstream()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 sameRuntimeError("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_TYPEDadds avalue_timecolumn (Time64, µs) aftervalue_tsfor time-only values, andvalue_tsholds full datetimes only;SEMI_LONGdate/time columns become Date32, Time64, or UTC timestamps;LONG_WITH_METADATAreports the matchingdtype. DefaultLONGoutput 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.extrecipes (for exampleresolve_isins(),cdx_ticker(),etf_nav_snapshot(), and the new auction helpers) now raise the sameBlpTimeoutError,BlpRequestError,BlpValidationError, and otherBlpErrorsubclasses as the request APIs instead ofRuntimeError;except RuntimeErrorno longer catches them. Invalid arguments still raiseValueError. - BREAKING (Rust):
xbbg_core::MessageIteratoris a cursor, not anIterator. Loop withlet mut messages = event.messages(); while let Some(msg) = messages.next() { ... }. Each message borrows the cursor, so iterator adapters such ascount()andcollect()no longer apply to messages.Event::iter()is removed; useEvent::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 formerbdp/bdh/bds/bdib/bdtick/requestallowlist (for examplebsrch(),beqs(),bflds(),bta(),bschema(), and thesubscribe()/vwap()/mktbar()/depth()/chains()subscription handles) now use the notebook bridge instead of raisingcannot be used inside an async context. Thexbbg.schemasync helpers,resolve_field_types(),xbbg.marketsfetch_exchange_info(), andgenerate_ta_stubs()use the same boundary instead of callingasyncio.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.11and lock its coordinated@vitest/*dependencies, including@vitest/mocker, to4.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
fflateto0.8.3, fixing the malformed ZIP64 infinite loop in GHSA-px8p-9vwx-vf98. - Patched JavaScript dev tooling. Both JavaScript packages now lock
brace-expansion5.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_msdocstring and type stub still saidDefault: 60_000, but the default has been0(no timeout) since 1.1.1. Requests wait for Bloomberg until they finish unless you opt in withconfigure(request_timeout_ms=...). - **
resolve_isins()no longer reports preferre...
xbbg 1.4.12
Added
- Explicit resource limits and ownership controls. Engines expose
runtime_worker_threads/runtimeWorkerThreads(default 2) andmax_subscription_sessions/maxSubscriptionSessions(default 32). Native Arrow carriers exposecompact()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_presentwith schema-mapped presence bits; JavaScript accessors returnundefinedfor absent fields andnullfor explicit clears. BloombergDATALOSSand local overflow/forwarding timeout now end the affected stream withBlpSubscriptionDataLossError; 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, andnarwhals_lazynow uses a real Polars lazy plan for local dataframe operations. The supported Polars floor is0.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_RTnull 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
outputoverrides legacy mode flags; partial-topic failures remain nonterminal. - Subscription shutdown preserves cancellation and errors across bindings. Pending reads, iterator
return()/ earlyfor awaitexit, 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
Fixed
xbbg-mcpno longer mistakes a failed stdin worker or abnormal service stop for clean EOF. Stderr diagnostics are now best-effort instead of usingeprintln!, 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 reachmainas 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
PATHentry, while a higher-priorityblpapi3_64.dllbeside 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-versionaccepts 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
fflate0.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/mcpb2.1.2 from the committed npm lockfile, overrides its vulnerable transitivetmpdependency 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 mutablelatestcode.
Full Changelog: v1.4.10...v1.4.11
xbbg 1.4.10
Fixed
- The 1.4.9 Windows MCPB launcher refused every Bloomberg runtime older than 3.26.7.1, including current Python
blpapipackages. 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 asblpapi3.26.4.2 that work.scripts/package_xbbg_mcpb.pynow derives the minimum from the binaries themselves -- the newestBLPAPI_x.y.zsymbol 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-versiononly as an explicit override. Everyblpapipackage 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
Fixed
xbbg-mcpno 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 answeredinitializeand 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, soRUST_LOGworks andrmcp/engine warnings reach the host's server log. The Windows launcher (xbbg-mcp.ps1) ranxbbg-mcp.exeas 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'sexec. 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.dllorblpapi3_32.dll, so pointingXBBG_MCP_LIB_DIRat a Terminal'sC:\blp\DAPIpassed and the 64-bit binary then died in the loader withSTATUS_ENTRYPOINT_NOT_FOUNDand no output. It now requiresblpapi3_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, searchesPATHas well (the Windows convention; a Terminal install putsC:\blp\DAPIthere) before falling back to the Pythonblpapipackage, and translates the loader statusesSTATUS_DLL_NOT_FOUND,STATUS_ENTRYPOINT_NOT_FOUND, andSTATUS_INVALID_IMAGE_FORMATinto one-line explanations. - The MCPB
manifest.jsonlists all nine tools (#348).check_entitlementswas missing from the manifest'stoolsarray and fromscripts/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
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.pygenerates 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/coreexported a format wire value the engine rejects:Format.LONG_WITH_METADATAwas'long_with_metadata', but the engine only accepts'long_metadata'(defs/bloomberg.tomland the generated Python enum already used the correct value, so only the hand-written JavaScript constant was wrong).js-xbbg/test/smoke.test.tsasserted the broken value, which is why it went unnoticed.FormatandFormatKindare now generated fromdefs/bloomberg.toml.- LangGraph snapshot tools advertised a rejected overflow policy:
overflowPolicyonxbbg_stream_snapshot,xbbg_mktbar_snapshot, andxbbg_depth_snapshotwas a free-form string whose description named no legal values and whose example was thedrop_oldestpolicy removed in 1.2.0, so models emitted it and the engine failed the call withunknown overflow policy 'drop_oldest'. It is now a closed enum generated fromdefs/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
Added
- Rust crates now publish automatically on release.
.github/workflows/crates-publish.ymlpublishes the six public crates to crates.io in dependency order, authenticating tokenlessly throughrust-lang/crates-io-auth-action(GitHub OIDC), so noCARGO_REGISTRY_TOKENsecret exists.semantic_version.ymlinvokes it as aworkflow_calljob rather than relying on a tag trigger, because a tag pushed withGITHUB_TOKENdoes 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 stampsworkspace.package.versionplus every internal[workspace.dependencies]entry from the release version so all crates ship in lockstep.
Changed
- BREAKING -- optional-backend and
narwhalsfloors 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.narwhalsmoves from>=2.0to>=2.10.0-- it is the only mandatory runtime dependency, and only 2.10.0 onward honours thenarwhals.pluginsentry point xbbg registers, so on 2.0-2.9 the plugin never loads and any conversion raisesTypeError: Expected pandas-like dataframe, Polars dataframe, or Polars lazyframe, got: <class 'xbbg._core.ArrowTable'>. Thepandasextra moves from>=2.0to>=2.2.2,<4, because pandas 2.0.x declares nonumpy<2bound, so a fresh resolve pairs it with numpy 2.x and pandas then fails to import withnumpy.dtype size changed, may indicate binary incompatibility; 2.2.2 is the first release supporting numpy 2. Theduckdbextra moves from>=1.0to>=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-covin thetestextra gains a>=5.0bound; unpinned, a lowest-direct resolve selected pytest-cov 2.0.0 from 2018.polars>=0.20andpyarrow>=22.0.0were 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
floorsjob resolves the project withuv pip install --resolution lowest-directon 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 inpyproject.tomlcarries a comment recording the measured reason it cannot go lower. - Rust MSRV is declared.
[workspace.package]now setsrust-version = "1.88", matching the highestrust-versionin the resolved dependency graph, andpixi.tomlraises itsrustfloor from>=1.75to>=1.88to 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.75had been unsatisfiable for several majors. - Third-party Rust versions are centralized in
[workspace.dependencies]. The arrow family alone was restated across eight manifests andtokioacross five, and the disabledxbbg-cli/dotnet-xbbgmanifests had already drifted toarrow 57.1.0and acsbindgen 2that has never been published. Members now inherit with{ workspace = true }and layer only their ownfeatures.default-featuresis set in the workspace table because Cargo silently ignores a member'sdefault-features = falsewhen the workspace entry omits it. The migration is feature-neutral: resolved feature sets were diffed per package before and after. rmcpupgraded from 2.1.0 to 3.1.2 inxbbg-mcp, with no source changes required. Both versions defaultProtocolVersion::LATESTto MCP2025-11-25, so the advertised revision is unchanged; 3.x additionally negotiates the2026-07-28draft.- Internal crate versions are centralized too, and now carry a
version. Every intra-workspace dependency was a bare{ path = ... }.cargo publishrejects 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 setdefault-features = false,xbbg-mcpandxbbg-benchnow namefeatures = ["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
repositoryandhomepagepointing at a legacy personal GitHub account and itsgithub.iopages site; both now resolve to thexbbg-orgrepository andhttps://xbbg.org/.mainhad also dropped thehomepage,readme, andkeywordsthat 1.1.2 actually shipped. Every published crate now declareshomepage,readme,keywords,categories, andrust-version(crates.io reported the MSRV as unset for all of them), plus an explicitincludeallowlist so only source,Cargo.toml, andREADME.mdare ever packaged. blpapi-sysis renamed toxbbg-blpapi-systo match the name it is published under. The bareblpapi-sysname is taken on crates.io, so the local package name never matched the registry name andcargo publish -p xbbg-blpapi-syscould not resolve.[lib] name = "blpapi_sys"is retained, so Rust code still saysblpapi_sys::and the change is source-compatible with the published 1.1.2.exchanges.tomlmoved fromdefs/intocrates/xbbg-ext/data/.xbbg-extembeds it withinclude_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-extwas its only consumer.
Removed
xbbg-sysis deleted. It was 16 lines that re-exportedblpapi_sys::*behind a mandatorylivefeature, with acompile_error!on every other configuration -- a leftover seam from the removed mock backend.xbbg_corenow depends onxbbg-blpapi-sysdirectly, and thecompile_error!guard moves toxbbg_core/src/lib.rsso a non-livebuild 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 wherexbbg_coreno longer depends on it.apps/xbbg-cliandbindings/dotnet-xbbgare 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.
Engineowns 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 withCannot drop a runtime in a context where blocking is not allowed-- includingxbbg-mcp, which holds the engine across#[tokio::main]and so panicked on every clean shutdown once an engine had started.Engine::dropnow takes the runtime out of its field and hands it toRuntime::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 usedstd::mem::forgetto 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::startbuilt 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::startnow surfacesfailed to spawn worker 0: session start failedrather thanCannot 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 (
postcssGHSA-fxqj-rqcc-2cmp / GHSA-r28c-9q8g-f849,nanoidGHSA-28wg-ghj8-5hjv / GHSA-2v37-7h3g-55p8,brace-expansionGHSA-mh99-v99m-4gvg / GHSA-rgw5-rvv9-x895), pluscryptographyGHSA-g6cj-pr64-35w5 andc-aresCVE-2026-33630 in the pixi environment. These are build- and test-time dependencies only and are not redistributed in any published artifact. - Stale
pyo3advisory ignores removed from.cargo/audit.tomlanddeny.toml. They suppressedRUSTSEC-2026-0176andRUSTSEC-2026-0177on 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-sysno longer advertises a documentation build it cannot perform. Itsdocs.rsmetadata requestedall-features = truewhilebuild.rspanics when the mutually exclusivestaticanddynamiclinkage features are both enabled, which also brokecargo clippy --all-featuresfor the whole workspace. The metadata now names the defaultdynamiclinkage.xbbg_corekeeps its underscore, permanently. crates.io normalizes-and_to the same package identity, soxbbg-coreis not an available name whilexbbg_coreexists, 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...
xbbg 1.4.6
Changed
- Linux artifacts now support glibc 2.28 and newer: wheels, the
@xbbg/core-linux-x64native addon, and thexbbg-mcplinux-amd64 binary build inside the manylinux_2_28 (AlmaLinux 8) container instead of on bareubuntu-latest, so they run on RHEL/Alma/Rocky 8, Debian 10+, Ubuntu 20.04+, and Amazon Linux 2023. Linux wheels are taggedmanylinux_2_28_x86_64(enforced viaauditwheel repair --plat), and the newscripts/check-glibc-max.shguard fails CI and release builds if any Linux binary references newer GLIBC symbol versions. lookback_daysonactive_cdxis 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 --
**kwargsonxbbg.ext.acdx_ticker/aactive_cdx: these forwarded Bloomberg request keywords to internal metadata lookups and never affected the returned ticker; passing them is now aTypeError.
Fixed
- CDX series resolution is now as-of the requested date, and monotone:
cdx_ticker/active_cdx,Engine.cdxTicker()/Engine.activeCdx(), and the underlyingxbbg-recipesentry points resolve the series whose BloombergCDS_FIRST_ACCRUAL_START_DATEis the latest one on or before the reference date, walking the accrual ladder in batched reference-data requests. Previously they readROLLING_SERIESoff 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_cdxadditionally chose between the two candidates by whichever had the laterPX_LASTprint, 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
Vntoken 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_cdxno longer swallow Bloomberg errors, missing metadata, or unparseable series numbers into an empty-string ticker. They now delegate to the samexbbg-recipesresolver as@xbbg/core, so the Python and JavaScript surfaces cannot drift apart, and raiseValueError(non-generic ticker, date before the index's first series) orRuntimeError(missing or inconsistent Bloomberg metadata) instead. Callers that tested for""must catch instead. - Clean session shutdown no longer logs
SessionConnectionDown/SessionTerminatedas WARN/ERROR (#346): tearing an engine down -- including the implicit teardown at interpreter exit after a one-shot call such asblp.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 spuriousSessionTerminated -- SDK gave up reconnecting; closing subscriptionsat ERROR on exit, withactive_subs=0and an empty reason. Subscription workers now publish the shutdown flag before asking the SDK to stop and classify each lifecycle event (shutdown_in_progressat INFO versusconnection_down_without_shutdown/termination_without_shutdownat the original WARN/ERROR), so genuine mid-session failures keep their severity. import xbbgno longer leaksSyntaxWarnings from Bloomberg'sblpapiwheel (#346): importing xbbg runs SDK discovery, which imports theblpapiPython package because the pip wheel ships the shared library and is probed ahead of a Terminal DAPI install. Bloomberg'sresolutionlist.pyandtopiclist.pycontain invalid escape sequences in their docstrings, so Python 3.12+ printedSyntaxWarning: 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 withSyntaxWarningfiltered, leaving the user's own warning filters untouched.
Full Changelog: v1.4.5...v1.4.6
xbbg 1.4.5
Added
- Shared ETF NAV / iNAV toolkit with Python and JavaScript parity: A new
xbbg-recipesmodule resolves Bloomberg's authoritativeETF_NAV_TICKER/ETF_INAV_TICKERrelationships (normalized to oneIndexsuffix and validated as genuine Index securities, so non-conventional targets such asQQQ US Equity -> QXV Indexand null/AT1IN Indexlegs survive intact), serves current NAV/iNAV snapshots and daily history with aFUND_NET_ASSET_VALfallback for ETFs without a daily NAV Index, and powers Pythonxbbg.ext(etf_nav_relationships,etf_nav_snapshot,etf_nav_history,subscribe_etf_inavplus 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, andEngine.cdxTicker()/Engine.activeCdx()now require BloombergVERSIONmetadata and return explicitVnidentifiers (includingV1) by default, resolve prior-series versions independently, and round-trip explicit-version tickers correctly. Passversionless=Trueor{ versionless: true }only when a legacy Bloomberg alias is required.
Full Changelog: v1.4.4...v1.4.5
xbbg 1.4.4
Added
- Complete Bloomberg entitlement-ID routes across bindings: Python and
@xbbg/corenow request EIDs for intraday bars and ticks as well as BDP/BDS/BDH; LangGraph exposesreturnEidson BDP/BDS/BDH/BDIB/BDTICK plusxbbg_check_entitlements, and MCP exposesreturn_eidson its dedicated BDP/BDS/BDH/BDIB tools and generic IntradayTick route pluscheck_entitlements, with bounded results preserving entitlement metadata. - Official MCP Registry publish workflow: Added a manual GitHub Actions workflow that publishes release
server.jsonmetadata throughmcp-publisherwith 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 andTickcaches decodedBigInt/Datevalues. SubscriptionArrowBatcherin 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_jsonvssimd-jsonBQL 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-nativeandnpm run build:native:hostproducetarget-cpu=nativeartifacts for internal deployments; published artifacts stay portable.
Changed
- Subscription sessions moved to Bloomberg SDK asynchronous callback mode: the 1 ms
nextEventbusy-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
Nameduplicates, 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 withbackend=Nonenow yield native Arrow wrappers and resolve their converter once at construction. @xbbg/corerequest 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::Blockis 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:nativebuilds release by default (usebuild:native:debugfor local iteration), and packaging refuses to stage a native addon whose build profile isn'trelease.blpapi-syscaches 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 spuriousCONDA_PREFIXrebuilds 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