Skip to content

Changelog

This page is generated from the repository root CHANGELOG.md during docs builds.

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog 1.1.0, and this project adheres to Semantic Versioning 2.0.0.

  • xbbg-browser, xbbg-bridge, and xbbg-server retired: The apps/xbbg-server Rust HTTP server, its @xbbg/bridge npm launcher and 5 platform-specific bridge binaries, and the @xbbg/browser HTTP client are removed. js-xbbg, napi-xbbg, and pyo3-xbbg remain the supported bindings.
  • Native datetime/date acceptance across all surfaces (#317): bdh, bdib, bdtick, bqr, arequest, and the xbbg.ext.bonds / xbbg.ext.options / xbbg.ext.fixed_income / xbbg.ext.historical / xbbg.ext.futures helpers now accept datetime.date, datetime.datetime (naive or tz-aware), and duck-typed pd.Timestamp (no hard pandas dependency) anywhere they previously took only str. ISO 8601, Bloomberg-native (YYYYMMDD), and "today" strings continue to work; ambiguous MM/DD/YYYY-style inputs are now rejected with a clear ValueError. The two divergent _fmt_date helpers were consolidated into a single source of truth in xbbg.ext._utils (extended with native-type support and a new _fmt_datetime). Bloomberg field overrides passed as **kwargs (e.g. USER_LOCAL_TRADE_DATE=date(2023, 1, 17)) are normalized to YYYYMMDD via value-based duck typing. Mirrored on the JS side: @xbbg/core accepts Date, ISO/Bloomberg-native string, epoch-ms number, and duck-typed Luxon DateTime across bdh / bdib / bdtick / bqr / recipe surfaces, with new formatDate / formatDateTime helpers and DateLike / DateTimeLike exported types. New guide at docs/python/guides/dates.
  • @xbbg/core subscription replay benchmark: Added a JS-only npm run bench:subscription-replay harness for one-update-at-a-time synthetic replay, JSONL fixture replay, live XBTUSD Curncy capture, and path-specific timing (legacy, arrow-decode-only, subscription-wrapper). Replay now supports --consume rows|vector|schema|none and --warmup-iterations; row materialization remains the default. Live capture reports existing sub.stats slow-consumer telemetry without changing the production streaming API.
  • xbbg-bench offline Rust replay benchmarks: Added benchmark-controlled, non-Bloomberg, non-datamock harnesses for Arrow/TypedBuilder append/finalize paths and synthetic xbbg-async subscription-shaped replay. These live entirely under crates/xbbg-bench, emit JSON artifacts, and use env knobs for row counts, flush size, and iterations so production crates do not carry benchmark-only hot-path changes.
  • xbbg-bench cached subscription-to-Arrow bridge benchmark: Added a bounded live Bloomberg subscription capture that replays cached real SDK Event/Message objects through xbbg-async SubscriptionState into Arrow batches. This connects core SDK traversal with the subscription Arrow path while keeping Bloomberg usage to a small initial capture and avoiding datamock.
  • Low-data live regression coverage for recent Bloomberg issues: Added live integration coverage for recent BDTICK/ABDTICK, BDS bulk headers, numeric backend typing, optional conversion backend dispatch, BQL economic calendar, exchange-resolution, subscription timestamp, and options-extension regressions. The new fixtures favor bounded requests (maxDataPoints, narrow chains, and current low-volume windows) so the live suite avoids excessive Bloomberg data usage while still exercising real service behavior.
  • Bloomberg Excel/0.x request aliases restored (#301): bdh / abdh, bdib / abdib, and bdtick / abdtick now accept the 0.x/Excel-style request aliases (Per, PerAdj, Curr/FX, Days, Fill, Points, Quote, QuoteType/QtTyp, CshAdj*, CapChg, UseDPDF, Calendar, BarSz/BarSize, BarTp/BarType, and IncludeExchangeCodes) and normalize enum shorthand values before requests reach Bloomberg. bdh() also consumes Excel-only presentation aliases (Dts/Dates, DtFmt/DateFormat, Sort, Orientation/Direction/Dir) locally for date/period display, row ordering, and default orientation. Coverage includes offline routing tests plus a capped live Bloomberg suite.
  • Python backend clean-cutover to native xbbg Arrow objects: The Rust layer now returns native xbbg._core.ArrowTable / ArrowRecordBatch carriers internally, with explicit backend="native" for callers that want those raw objects. The public default remains a Narwhals DataFrame and prefers a real PyArrow table when PyArrow is installed, then falls back through installed dataframe libraries before the minimal xbbg Narwhals plugin. backend="pyarrow" returns a real pyarrow.Table; the misleading Backend.ARROW / backend="arrow" alias was removed. Pandas, Polars, DuckDB, and Narwhals remain explicit optional conversion backends, and PyArrow is no longer a core dependency.
  • @xbbg/core subscriptions now require NAPI Arrow zero-copy transfer: Subscription.next() asks the native binding for Arrow buffer descriptors and builds Apache Arrow JS tables directly from native Arrow buffers for common Bloomberg subscription types (bool, date32, float64, int32, int64, time64[us], timestamp[us], utf8, null). The JS subscription path no longer falls back to standalone IPC; unsupported or sliced schemas fail fast with column-level diagnostics while the public Subscription.next(): Table API remains unchanged.
  • @xbbg/core exposes full Bloomberg subscription payloads: JS streaming APIs now accept allFields: true, forwarding the existing Rust engine all_fields mode so callers can receive every top-level scalar field Bloomberg sends instead of only requested fields plus MKTDATA_EVENT_TYPE / MKTDATA_EVENT_SUBTYPE. The NAPI zero-copy bridge also supports time64[us] columns for dynamic all-fields schemas.
  • Rust Bloomberg SDK handle ownership hardened: xbbg-core now models session-owned SDK views with Rust lifetimes instead of unsupported Send/Sync marker impls. Service, schema operations/definitions, and constants are tied to their owning session/service, pointer correlation IDs are explicit unsafe values, and async request workers reopen short-lived service handles rather than caching session-owned handles across worker state.
  • Reference data fieldExceptions logging aggregated: Per-security fieldExceptions diagnostics now stay at DEBUG with field-level detail, while bulk requests emit a single summary warning with total exception count and affected tickers.
  • @xbbg/core TypeScript request surface completed: JS wrappers now forward validateFields on bdp/bds/bdh, requestTz/outputTz on bdib/bdtick, and typed bdtick include-code options while rejecting unknown backend strings instead of silently returning Arrow.
  • Generic bds() / abds() bulk-header contract documented (#274): xbbg preserves Bloomberg bulk subfield labels exactly in the generic BDS path; only ticker and field are xbbg-added metadata columns. Higher-level helpers that need stable semantic names must rename their own outputs explicitly.
  • Generated sync wrappers now resolve in IDEs (#307): bdp, bdh, bds, bdib, bdtick, bql, bsrch, bqr, bflds, beqs, blkp, bport, bcurves, and bgovts now expose static signatures for parameter hints, hover docs, and go-to-definition. Top-level xbbg exports were also completed for abqr / bqr and the generated endpoint stubs.
  • Retired mock crates removed from the workspace: The old C++ mock stack and Cargo mock feature forwarding were removed so the Rust workspace has a single live Bloomberg SDK FFI path.
  • BQR dealer attribution restored (#312): bqr() / abqr() and xbbg.ext.bqr() now default to BID/ASK quote events with includeBrokerCodes=true, normalize output to the 0.x-compatible event_type / price / broker_buy / broker_sell columns, warn when an attributed request is not shaped like a fixed-income ISIN with @MSG1 Corp, and raise when Bloomberg returns quote rows without broker attribution unless callers explicitly opt out with include_broker_codes=False. Low-data live coverage uses an @MSG1 Corp fixed-income ISIN fixture capped with maxDataPoints=5.

  • Subscription schemas preserve sparse numeric quote fields: Requested subscription fields now observe Bloomberg element datatypes even when a particular update carries a null value, so sparse streams such as XBTUSD Curncy quote updates keep BID / ASK as Float64 instead of degrading the Arrow schema to Utf8 before a non-null quote arrives. Live schema tests now print sample raw batches for easier diagnosis.

  • Exchange/session resolution handles Bloomberg time-valued metadata: Exchange metadata parsing now accepts Arrow time columns for TRADING_DAY_START_TIME_EOD / TRADING_DAY_END_TIME_EOD, avoids futures-only metadata field requests on ordinary equities, preserves futures fallback via FUT_TRADING_HRS, and applies the Japan equity 09:00-15:30 session rule so market_timing(..., "EOD", "UTC") resolves to the expected Tokyo close.

  • Options live tests derive valid contracts dynamically: The options extension live suite no longer relies on stale hardcoded SPY expiry/strike fixtures; it discovers a current low-data SPY call through a narrow option_chain() request and reuses that valid ticker/expiry/strike for info, greeks, pricing, screen, and BQL-chain checks.

  • bdtick include-code options now keep typed tick tables (#309): IntradayTickState dynamically discovers scalar fields inside Bloomberg’s tickData.tickData[] rows, so options such as includeConditionCodes, includeExchangeCodes, and includeBloombergStandardConditionCodes add typed columns after the stable core [ticker, time, type, value, size] instead of forcing callers into generic [path, type, value_str, value_num] output. Dynamic columns are padded with nulls for ticks where Bloomberg omitted that field; response metadata such as tickData.eidData remains excluded from per-tick rows.

  • bds bulk rows discover subfields across the whole response: BulkDataState now scans every scalar child in each Bloomberg bulk row instead of freezing the output schema from the first row. Late-appearing subfields are appended in first-seen order and earlier rows are padded with nulls, preserving row alignment for dynamic bulk datasets.

  • bds manually selected bulk extraction could be overwritten by defaults: RequestParams::with_defaults() now preserves an explicit non-default extractor hint, preventing bulk requests from falling back to reference-data long extraction when callers build request params manually.

  • Pixi/libclang bindgen discovery on Windows: Shared build support now creates an OUT_DIR-local libclang.dll alias for pixi/conda’s versioned libclang-*.dll, so all bindgen build scripts can run without manually installing LLVM or mutating the pixi environment.

  • Live reference-data tests and benchmarks used the wrong Bloomberg array accessor: securityData value arrays now use get_element(0) rather than child-element lookup, matching the SDK response shape.

  • @xbbg/core TypeScript package metadata repaired: Native optional dependencies now use package versions instead of local file: links, release scripts use a checked-in CJS platform map helper, packaged-install smoke checks the published dist entrypoint, and the npm package includes the Apache license.

  • @xbbg/core local Windows runtime loading fixed: The Node binding now adds the vendored Bloomberg SDK runtime DLL directory from vendor/blpapi-sdk/<version> (or XBBG_DEV_SDK_ROOT) to PATH before loading napi_xbbg.node, so local tests do not require a manually exported BLPAPI_ROOT.

  • Python subscription unsubscribe keeps reusable workers clean: PySubscription.unsubscribe() now propagates Bloomberg unsubscribe failures instead of suppressing them and only clears active subscription status after termination succeeds, so clean explicit unsubscribes return the subscription worker to the pool while failed/implicit cleanup keeps the conservative discard path.

  • xbbg-async async boundaries no longer perform cache disk I/O on hot Tokio paths: Request kwarg routing now uses memory-only schema metadata, explicit schema loads/persists are offloaded to blocking workers, field and exchange caches preload during engine startup, and exchange cache persistence snapshots entries before filesystem writes instead of holding cache locks across I/O.

  • Rust subscription cleanup preserves clean worker reuse and avoids blocking drop flushes: SubscriptionStream::unsubscribe() now clears active status after successful termination before the claim drops, matching the Python/NAPI clean-close path, while SubscriptionState::Drop uses best-effort try_send so OverflowPolicy::Block cannot block the subscription worker during cleanup.

  • Dynamic extractor hot paths avoid repeated linear duplicate scans and JSON clones: bds bulk rows and bdtick dynamic columns now track discovered fields with membership sets while preserving output order, and BQL JSON parsing stores borrowed intermediate values where safe before building owned Arrow arrays.

  • bdh / bdp with format='semi_long' dropped Int64-typed fields (#303): Bloomberg sends integer-typed fields (PX_VOLUME, OPEN_INT, etc.) as Float64 on the wire in HistoricalDataResponse even though FieldInfo declares them Int64/Long. crates/xbbg-core/src/value.rs::Value::as_i64 (and its OwnedValue twin) and the inline TypedBuilder::Int32::append_value match in crates/xbbg-async/src/engine/state/typed_builder.rs had no Float64 arm, so the wide-path Int builder null-filled those columns. Consequence: blp.bdh("ESH20 Index", flds=[..., "PX_VOLUME", "OPEN_INT"], format='semi_long') returned NaN for every volume / open-interest row. long / long_typed / long_metadata were unaffected because their builders route via Float64 or stringify. Fixed by accepting Float64 when it’s finite, has fract()==0.0, and fits the target integer range. TestOutputFormats::test_bdh_semi_long_integer_fields_issue_303 locks this in live, plus existing bdp/bdh semi_long tests now assert notna().all() per column instead of just column names.
  • @xbbg/core: recipe helpers exposed on the JS Engine: Eleven recipe methods surfaced through the NAPI bindings — yas, preferreds, corporateBonds, futTicker, activeFutures, cdxTicker, activeCdx, dividend, turnover, etfHoldings, currencyConversion — wrapping the corresponding xbbg_recipes entry points. Returns Arrow Table by default with Backend.JSON / Backend.POLARS opt-in via options.backend; errors route through the standard BlpError hierarchy. Ships with TypeScript definitions (YasOptions, PreferredsOptions, CorporateBondsOptions, FuturesResolveOptions, ActiveCdxOptions, DividendOptions, TurnoverOptions, EtfHoldingsOptions, RecipeBackendOptions), README usage examples, and smoke-test coverage in js-xbbg/test.js.
  • Prebuilt cross-platform offline bundles for @xbbg/core (scripts/build-offline-bundle.js): Packages @xbbg/core plus the prebuilt @xbbg/core-<label> native addon into a hoisted bundle/node_modules tree alongside source tarballs for air-gapped installs. js_github_release.yml gains a pack-offline-bundles job that attaches xbbg-offline-<label>-<version>.zip to the GitHub release (covered by the existing validate-release-payload scanner for Bloomberg SDK leakage); ci-rust.yml mirrors the job per-commit with a 7-day artifact retention for downstream consumers.
  • EngineConfig.request_timeout_ms default changed from 60_000 to 0 (disabled): The previous 60s hard cap was self-inflicting timeouts on legitimately long requests — e.g. a full-day bdtick for a liquid future routinely exceeds 60s on the Bloomberg side, so the worker was cancelling healthy requests and surfacing a BlpTimeoutError to the caller. The enforcement machinery is unchanged; callers who want a hard upper bound must now opt in explicitly by passing request_timeout_ms=<ms> (Python), requestTimeoutMs (NAPI), or PyEngineConfig.request_timeout_ms (pyo3).
  • bdtick / bdib silently dropped overrides= kwargs (#295): _build_abdtick_plan and _build_abdib_plan in py-xbbg/src/xbbg/blp.py were doing elements, _ = await _aroute_kwargs(...) — the _ threw away the overrides list before the request reached the Rust engine. Other endpoints (bdp/bdh/bds/beqs/bport) capture both; only the two intraday builders discarded overrides. Now forwarded. Note that Bloomberg’s IntradayTickRequest / IntradayBarRequest schemas have no overrides sub-element, so forwarded overrides now surface as a Bloomberg element-not-found error instead of being silently no-oped; for response-size limits use the top-level maxDataPoints kwarg instead.

  • bdib + maxDataPoints fell back to the generic flattener, losing the typed schema: crates/xbbg-async/src/engine/worker.rs routed intraday-bar / tick requests through GenericState whenever any user-supplied element was set, on the assumption that extra elements imply extra response columns. That holds for tick include* flags (condition codes, exchange codes, etc. which add per-tick columns), but not for behavior-only elements like maxDataPoints, maxDataPointsOrigin, gapFillInitialBar, or adjustment* — those don’t change the response shape. Consequence: blp.bdib(..., maxDataPoints=1) returned [path, type, value_str, value_num] instead of the typed [ticker, time, open, high, low, close, volume, numEvents], and blp.bdtick(..., maxDataPoints=1) returned 6 rows instead of 1 (the generic extractor exploded one tick into per-field rows). Fallback removed entirely for IntradayBar (no column-adding elements exist on IntradayBarRequest); narrowed to include* keys on IntradayTick.

  • Offline-bundle packing rejected by npm with EBADPLATFORM: npm install in the pack-offline-bundles job runs on a Linux runner but pulls in @xbbg/core-<label> packages that declare os/cpu for their target platform (e.g. win32/x64). scripts/build-offline-bundle.js now passes --force so the cross-platform install succeeds; the bundle is never executed on the install host, so the platform check is safe to skip.

  • bdp / bdh silently returned long-shape output for format='semi_long' (#296, #299): crates/xbbg-async/src/engine/worker.rs had no "semi_long" arm in its format-string match — the RefData branch hardcoded OutputFormat::Long and only varied LongMode; the HistData branch only recognised "wide". So blp.bdp(..., format='semi_long') returned [ticker, field, value] instead of the documented [ticker, <field1>, <field2>, …] pivoted shape, and blp.bdh(..., format='semi_long') returned [ticker, date, field, value] instead of [ticker, date, <field1>, …]. The Format::SemiLong enum in services.rs parsed "semi_long" round-trip correctly; the break was purely in the worker routing. Fixed by mapping "semi_long" | "wide"OutputFormat::Wide in both arms. Regression coverage: new TestOutputFormats class in py-xbbg/tests/live/test_api.py asserts column shape for all four Format variants (long, semi_long, long_typed, long_metadata) on both bdp and bdh, verified live against Bloomberg.

  • BQL secondaryColumns extracted from responses (#288, refs #289 / #290 / #291): parse_bql_json in xbbg-async now pulls DATE, CURRENCY, and other secondary dimensions out of BQL JSON so time-series queries like with(dates=range(-5d, 0d)) return usable row labels instead of ambiguous duplicate-ticker rows. Three latent parser issues fixed in the same pass: column lengths are now clamped to idColumn size via resize() so partial errors with mismatched field lengths stop failing RecordBatch::try_new (#289); column typing now uses Bloomberg’s valuesColumn.type metadata with .all() fallback instead of value-sniffing with .any() (#290); a warning is logged when BQL falls through to the legacy Element-API path where secondaryColumns are unavailable (#291).

  • xbbg-async: per-subscription availability tracking via SubscriptionStreamsActivated/SubscriptionStreamsDeactivated: Bloomberg SDK v3.11.6+ recovers subscriptions internally across transient disconnections; the ChangeLog explicitly instructs applications to use the Streams* events to detect failover. xbbg now consumes both and exposes per-topic streams_active on TopicStatusInfo. A debounced Warning event (SubscriptionStreamsDeactivatedPersisting) fires when a topic stays streams-inactive past streams_deactivated_warn_ms, so callers polling status can tell “SDK is still recovering” from “data is dead”. See .omc/research/reconnect-correctness.md for the full SDK-contract evidence trail.

  • EngineConfig.request_timeout_ms (default 60_000; 0 disables): Hard per-request upper bound. Request workers now cancel the Bloomberg request and fail the oneshot with BlpError::Timeout when the timeout expires, guaranteeing callers cannot hang forever on a stuck response regardless of SDK or server-side misbehavior. Exposed through all three bindings: Python request_timeout_ms, NAPI requestTimeoutMs, pyo3 PyEngineConfig.request_timeout_ms.

  • EngineConfig.streams_deactivated_warn_ms (default 30_000; 0 disables): Threshold for the per-topic streams-inactive warning described above. Exposed as streamsDeactivatedWarnMs in NAPI and streams_deactivated_warn_ms in pyo3/Python.

  • Worker health on SubscriptionWorker: Mirrors the existing RequestWorker health field. Goes to Dead on SessionTerminated; the pool’s claim() and release() paths drop Dead handles and spawn fresh replacements so a wave of SessionTerminated events cannot permanently cripple the engine.

  • reconnect_probe example (crates/xbbg-core/examples/reconnect_probe.rs): Observational tool that subscribes to a live ticker and logs every SessionStatus / SubscriptionStatus event with timestamps and reason.description for validating reconnect behavior against a real Bloomberg session.

  • xbbg-bench: benches/cache_contention.rs: Harness measuring SchemaCache::get and FieldTypeResolver::get latency percentiles under reader/writer pressure at 10/100/1000 reader concurrency, one writer inserting every 5ms, 2-second runs. Produces p50/p99/p99.9/max tables via hdrhistogram and saves them to target/bench_cache/<BENCH_LABEL>.txt for before/after diffing. Run with DYLD_LIBRARY_PATH=vendor/blpapi-sdk/3.26.2.1/Darwin BENCH_LABEL=<name> cargo bench -p xbbg-bench --bench cache_contention.

  • Keep-alive tuning on EngineConfig: keep_alive_enabled (bool, default true), keep_alive_inactivity_ms (Option<i32>, SDK default 20s), keep_alive_response_timeout_ms (Option<i32>, SDK default 10s). Default SDK window of ~30s silence before SessionConnectionDown is aggressive for VPN/WAN BPIPE connections; raising these prevents spurious disconnects without changing local-Terminal behavior. Exposed through pyo3 / NAPI / Python.

  • Slow-consumer water marks on EngineConfig: slow_consumer_hi_water_mark and slow_consumer_lo_water_mark (Option<f32>, fractions of max_event_queue_size). SDK defaults 0.75 / 0.5. Exposed through all three bindings (slowConsumerHiWaterMark / slowConsumerLoWaterMark in NAPI with 0.0..=1.0 / 0.0..1.0 validation).

  • AuthorizationRevoked handling during live session: Previously only checked at startup (crates/xbbg-core/src/session.rs::wait_until_started). If identity was revoked mid-session (token expiry, policy change), requests silently failed with opaque RequestFailure and subscriptions silently stopped. Both RequestWorker and SubscriptionWorker now handle AuthorizationRevoked symmetrically to SessionTerminated: drain in-flight/subscriptions with a dedicated “please re-authenticate” error, mark the worker Dead, and let the pool spawn a fresh worker that re-auths during startup.

  • ServiceDown now emits a subscription-category warning when active subs exist: Previously only recorded on service status. Callers polling sub.events missed the signal that their streams were affected until SubscriptionStreamsDeactivated fired per topic. Now a single ServiceDownAffectsActiveSubscriptions event fires at the moment of ServiceDown so callers see immediately that their data may go quiet.

  • reason.description parsed on SubscriptionStarted: Bloomberg sometimes includes partial-permission details (e.g. “only delayed data authorized”) on the reason element of SubscriptionStarted. These were discarded; now surfaced via the status event detail.

  • EngineConfig transport surface restructured as a Transport enum (internal Rust only; Python/JS kwargs unchanged): The six flat transport fields (server_host, server_port, servers, zfp_remote, socks5_host, socks5_port) and five flat TLS fields (tls_client_credentials, tls_client_credentials_password, tls_trust_material, tls_handshake_timeout_ms, tls_crl_fetch_timeout_ms) on xbbg_async::EngineConfig collapsed into transport: Transport + tls: Option<TlsConfig>. Transport::Direct(Vec<ServerAddr>) carries per-server SOCKS5 (matching blpapi::SessionOptions::setServerAddress(serverHost, serverPort, socks5Config, index) in vendor/blpapi-sdk/3.26.2.1/include/blpapi_sessionoptions.h:501-511); Transport::Zfp(ZfpRemote) takes no server addresses by construction, so the #294 bug class is unrepresentable in the type system. Conflict validation lives at the PyO3 / NAPI boundary — resolve_transport rejects zfp_remote combined with host/port/servers/socks5_* with specific ValueError/InvalidArg messages. start_configured_session is now a three-stage pipeline (transport → optional TLS re-apply → session-behavior config) with no shared mutation, matching Bloomberg’s own canonical demo-app structure (vendor/blpapi-sdk/.../examples/demoapps/util/ConnectionAndAuthOptions.h:213-296). TLS is applied once at the SDK level: through ZfpUtil::getOptionsForLeasedLines for ZFP, via SessionOptions::setTlsOptions for Direct; the previous double-apply (ZfpUtil + inline set_tls_options) is eliminated. The engine tracing span now logs transport = %config.transport via a new Display impl on Transport/ZfpRemote (e.g. localhost:8194, primary.example.com:8194 (+2 failover), zfp:8194). All public Python configure() kwargs and @xbbg/core EngineConfigInput fields are unchanged — the flat surface is preserved and converted at the binding boundary.

  • xbbg-async cache hot paths: RwLock<HashMap>ArcSwap<HashMap> (schema) and DashMap (field): SchemaCache reads are now lock-free atomic pointer loads; writes publish a new snapshot via RCU. FieldTypeResolver uses DashMap’s sharded internal locking (plus OnceLock for the lazy disk-load flag). Public API unchanged; all 100 xbbg-async lib tests pass. Measured via benches/cache_contention.rs (2s run, 1 writer inserting every 5ms, artifacts in target/bench_cache/):

    Scenariop50p99p99.9throughput
    schema, 1000 readers1.96µs → 125ns17.1µs → 667ns22.5ms → 1.2µs (~19 000×)22× more samples
    schema, 100 readers1.71µs → 166ns19.8µs → 667ns6.5ms → 1.2µs (~5 400×)14× more samples
    schema, 10 readers1.75µs → 166ns16.1µs → 500ns56µs → 750ns (75×)14× more samples
    field, 1000 readers2.67µs → 125ns19.2µs → 583ns30.4ms → 1.2µs (~25 000×)20× more samples
    field, 100 readers2.58µs → 125ns20.4µs → 583ns11.1ms → 1.2µs (~9 200×)20× more samples
    field, 10 readers2.50µs → 125ns18.4µs → 583ns52µs → 1.1µs (46×)19× more samples

    Eliminates the writer-thundering-herd pathology where a ~1µs write-lock window would queue hundreds of readers and blow out p99.9 into the millisecond range. Relevant under burst load — e.g. many parallel //blp/refdata requests landing during a //blp/apiflds introspection, where schema/field lookups are on every critical-path hop. p50 and p99 also improve because the RwLock acquire/release was the dominant cost of an uncontended cache hit. max is still OS-scheduler jitter (threads can be preempted for a full quantum) and unrelated to cache design.

  • ensure_service switched from synchronous openService to openServiceAsync + nested event dispatch: The synchronous blpapi_Session_openService internally blocks on the session’s event queue, which stalls delivery of every other in-flight event for the duration of the call. Measured locally against a Bloomberg Terminal: open_service takes 200-300ms per call, post-call delivery rates spike to 1.6-2.3× baseline (consistent with queue-and-release). Worker threads now call open_service_async, tag replies with a dedicated high-bit-set correlation ID (1 << 62), and run a nested dispatch loop that continues to process SubscriptionData / SessionStatus / RequestStatus while waiting for ServiceOpened. Both SubscriptionWorker::ensure_service and RequestWorker::ensure_service are affected. Added Session::open_service_async on xbbg-core with a BlpError::Timeout after SERVICE_OPEN_TIMEOUT_MS (10s default).

  • SessionConnectionDown/Up are now treated as informational on the subscription path (matching Bloomberg’s canonical guidance: vendor/blpapi-sdk/.../examples/unittests/snippets/events/events.t.cpp:42-54 — “Applications can safely ignore… These events are informational only and applications should not react to them”). Only SessionTerminated drains active subscriptions and marks the worker Dead. The SDK’s own auto-restart + internal subscription recovery handle transient network blips.
  • Request-side handling preserves drain-on-Down semantics but marks workers Degraded (not Dead): requests are transactional, so a response mid-transit when TCP drops is lost and must be failed fast. On SessionConnectionUp the worker flips back to Healthy. On SessionTerminated, it drains and goes Dead with pool replacement.
  • BlpError produced on RequestFailure and SessionTerminated now includes Bloomberg’s reason.description instead of opaque "RequestFailure" / "Bloomberg session terminated" strings. Same parser shape as the existing startup_error_from_message helper.
  • SubscriptionSessionPool::claim drops dead handles during the pop loop and spawns a fresh replacement if every available handle is Dead. release() discards Dead handles instead of returning them to the pool.
  • ZFP over leased lines failed with Failed to connect to 127.0.0.1:8194 (#294): blp.configure(zfp_remote="8194", tls_client_credentials=..., tls_trust_material=...) started a session but the SDK tried to connect to localhost:8194 instead of the Bloomberg infrastructure endpoints. Root cause in crates/xbbg-async/src/engine/mod.rs: start_configured_session called configure_zfp_options (which populates the SessionOptions server list via ZfpUtil::getOptionsForLeasedLines), then unconditionally called configure_session_options, whose server-address loop overwrote index 0 with the server_host/server_port fallback of localhost:8194. The SDK contract (vendor/blpapi-sdk/3.26.2.1/include/blpapi_zfputil.h:154-162) explicitly states the SessionOptions returned by ZfpUtil is “only valid for private leased line connectivity” — layering setServerAddress on top is undefined behavior. Two related latent bugs in the same code path are also fixed: passing servers=[…] alongside zfp_remote would clobber ZFP endpoints at indices 0..N, and passing socks5_host alongside zfp_remote wrapped the overwritten localhost address in SOCKS5 semantics. All three combinations now raise ValueError at configure() time with specific messages instead of producing silent connection failures. See the Changed entry below for the underlying refactor.

  • Silent subscription death after a transient blip: With the default SubscriptionRecoveryPolicy::None, a SessionConnectionDownUp cycle would silently produce a live session with zero data flowing — the SDK reconnected TCP, but xbbg never re-established subscriptions, and sub.next() hung forever. The SDK actually recovers subscriptions itself (v3.11.6+); xbbg just needed to stop fighting it and consume the SubscriptionStreams* events. Fixed by the above refactor.

  • Aggressive drain on transient SessionConnectionDown for subscription workers: The previous handler marked subscription workers Dead and drained all in-flight subscriptions on every transient Down event, contradicting Bloomberg’s “informational” contract. Now a no-op on the subscription side.

  • Lifetime leak of recovery_attempt_count: record_recovery_success never reset the counter, so max_recovery_attempts=3 became a process-lifetime cap, permanently disabling recovery after three flaps. Removed along with the rest of the recovery machinery (see Removed).

  • SubscriptionWorker with a terminated session remained claimable from the pool: the worker drained its subs but had no health field, so a subsequent claim() would hand out a handle whose underlying session pointer was dead. Fixed by adding health tracking and the pool-level eviction + replacement path.

  • Live subscription tests hardcoded to expired H6 (March 2026) futures contracts: ESH6 / NQH6 / UXH6 returned Security is not valid for subscription [EX336] from Bloomberg after 2026-03-20. Switched to generic front-month continuation tickers (ES1 / NQ1 / UX1) which Bloomberg auto-rolls; matches the pattern already used in js-xbbg/test-live.js.

  • crates/xbbg-core/tests/live.rs checked for "SessionResumed": Not a real BLPAPI message name — zero matches in the vendored SDK headers. The check never fired because SessionStarted always arrived first; removed to match the canonical event set.

  • Message::topic_name(): Bloomberg deprecated Message::topicName() in BLPAPI SDK 3.14.8 — the method always returns an empty string, and the SDK docs explicitly instruct callers to maintain their own CID→topic map (include/blpapi_message.h:253-274). Subscription workers already do this via the slab. No production code called it.
  • SubscriptionRecoveryPolicy enum + recover_active_subscriptions + recovery_* fields/methods: Removed entirely. The SDK recovers subscriptions internally; xbbg’s parallel implementation fought the SDK (would re-subscribe with in-use correlation IDs → correlationIdError) and its default of None silently dropped subs across blips. Deleted together: SubscriptionRecoveryPolicy, recover_active_subscriptions, recovery_attempt_count, recovery_success_count, last_recovery_attempt_us, last_recovery_success_us, last_recovery_error, record_recovery_attempt, record_recovery_success, record_recovery_error, and SessionStatusInfo.recovery_policy. BREAKING: drops the recovery_policy kwarg from asubscribe / astream / subscribe_with_options in Python, pyo3, and NAPI, plus the corresponding fields from sub.session_status.
  • EngineConfig.max_recovery_attempts, EngineConfig.recovery_timeout_ms, EngineConfig.health_check_interval_ms: All three were defined, documented, and exposed through all three bindings (pyo3 / NAPI / py-xbbg), but zero consumers existed in the engine — dead config surface that misled callers. Removed from all three bindings. BREAKING for any caller that set these; the behavior they advertised wasn’t actually implemented.
  • @xbbg/core: Engine.bdp/bds/bdh/bdib/bdtick ignored options.backend: The five core reference/historical/intraday methods did not forward backend into Engine.request, so callers asking for Backend.JSON or Backend.POLARS silently received Arrow Tables regardless. backend is now threaded through all five methods and the corresponding BdpOptions/BdhOptions/BdibOptions/BdtickOptions types in index.d.ts. Verified live against a Bloomberg session.
  • @xbbg/core: Engine.requestRaw and Subscription.add/remove did not wrap native errors: Engine.request and Subscription.next routed native rejections through wrapError, but the raw request path and subscription mutators did not. Callers discriminating on BlpError/BlpRequestError subclasses missed failures from those paths. All three now wrap consistently.
  • @xbbg/core: session-start failures surfaced as plain Error: connect(...), new Engine(...), and Engine.withConfig(...) no longer bypass wrapError, and wrapError now matches the actual NAPI session-start messages ("failed to spawn worker", "session start failed", "Failed to start session", "connect event failed"). Failed connects now classify as BlpSessionError.
  • @xbbg/core: BlpRequestError.request_id was never populated: The Rust engine appends [request_id=<uuid>] to request-failure messages when a correlation id exists, but wrapError did not parse it. The id is now extracted into err.request_id.
  • @xbbg/core: a transient connect failure permanently poisoned every top-level helper: getConfiguredEngine cached the first connect(...) promise unconditionally, so a rejected bootstrap produced the same rejection on every subsequent call until configure() was invoked again (observed live as 7.2s first attempt followed by 0ms cached rejection). Rejected promises are now cleared so the next call re-attempts.
  • rand bumped to 0.9.3 in Cargo.lock (GHSA-cq8v-f236-94qc / RUSTSEC-2026-0097, low): The advisory is scoped to runtime rand::rng() use from inside a custom log implementation that triggers ThreadRng reseeding — not something xbbg exercises. The remaining rand 0.8.5 in the graph is build-time only (phf_generator for phf macros, unicode_names2_generator for pyo3-stub-gen), outside the advisory’s exposure surface.
  • xbbg-mcp local MCP server: Added a stdio Bloomberg MCP application under apps/xbbg-mcp with tool surfaces for bdp, bdh, bds, bdib, bql, bsrch, bflds, and generic request execution. Responses are bounded structured JSON with Arrow schema metadata for coding agents.
  • GitHub-release MCP distribution path: Added release packaging for xbbg-mcp, a Unix launcher wrapper (scripts/xbbg-mcp), and a convenience installer (scripts/install-xbbg-mcp.sh) so Claude Code and OpenCode users can install a local MCP binary without cloning or compiling the repo first.
  • @xbbg/core Node.js package: New first-class JavaScript/TypeScript client under js-xbbg/ that wraps the Rust engine via NAPI. Exposes the full request surface (bdp, bdh, bds, bdib, bdtick, bql, bqr, bsrch, beqs, blkp, bport, bcurves, bgovts, bflds), a typed error hierarchy, optional backends (Apache Arrow tables by default, nodejs-polars as an optional peer), and a BPIPE/auth-aware configure(). Native addons are prebuilt and distributed as optional platform packages (@xbbg/core-darwin-arm64, @xbbg/core-linux-x64, @xbbg/core-win32-x64) so npm install @xbbg/core Just Works without a Rust toolchain.
  • @xbbg/bridge async browser bridge: New companion package exposing the Rust engine through an async postMessage bridge, shipped alongside @xbbg/core with matching platform-specific native addons.
  • GitHub-only JS package release workflow: Added a manual js_github_release.yml path that builds, versions, validates, and attaches GitHub release tarballs for @xbbg/core and @xbbg/bridge without npm publishing. The workflow intentionally ships the currently supported 8-asset set only: @xbbg/core wrapper plus darwin-arm64/linux-x64/win32-x64, and @xbbg/bridge wrapper plus darwin-arm64/linux-x64/win32-x64. The unreleased @xbbg/bridge-darwin-x64 and @xbbg/bridge-linux-arm64 package stubs remain excluded until Bloomberg SDK archive support exists.
  • Friendlier AttributeError for removed blp legacy APIs: blp.connect, blp.disconnect, and blp.getBlpapiVersion now raise an AttributeError whose message points directly at the 1.0 replacement (xbbg.configure, xbbg.shutdown/xbbg.reset, xbbg.get_sdk_info) with a copy-pasteable B-PIPE example, instead of the bare “module has no attribute” default. Implemented via a module-level __getattr__ hook in py-xbbg/src/xbbg/blp.py.
  • Backend conversion moved to a single boundary with pa.Table as canonical form: _execute_request_terminal now returns the raw pa.Table from the Rust engine without wrapping in narwhals first; arequest does a single _convert_backend call at its return. _convert_backend dispatches directly from pa.Table via zero-copy primitives (pl.from_arrow, table.to_pandas, identity for pa.Table → pa.Table), bypassing the narwhals wrap/unwrap on the hot path. Short-circuiting middlewares that return non-pa.Table values (e.g. caches returning lists) keep full control over their result. Measured on a 1000×10 frame: pa.Table → pa.Table went from 17.78 µs to 0.04 µs (464×), pa.Table → pl.DataFrame from 39.89 µs to 18.67 µs (2.1×). Subscriptions streaming at 10k msgs/sec previously spent ~33% of a core on redundant wrap/unwrap in the dispatch layer; this cuts it roughly in half. Narwhals remains the canonical abstraction for backend-agnostic data manipulation in ext/historical.py, ext/currency.py, ext/futures.py, ext/_utils.py, and _reshape_bqr_generic — this refactor only removes it from the pure routing path where it added overhead without value.
  • Minimum narwhals version bumped to >=2.0: Required for the nw.Implementation enum and .implementation property used by the new _convert_backend dispatch. Downstream users pinned to narwhals 1.x will need to upgrade. No other narwhals 2.x breaking changes affect xbbg — get_native_namespace, new_series(native_namespace=), from_native idempotency, and .to_native() all remain stable across the 1→2 boundary.
  • xbbg.configure() rejects unknown kwargs: configure() now raises TypeError on any keyword it does not recognize. Previously unknown kwargs were silently dropped by the Rust PyEngineConfig constructor, which meant typos (e.g. hots=... instead of host=...) would leave the host at the default without any warning. The Python normalizer now validates the kwarg set against the canonical field list before handing off to Rust.
  • Docs site restructured with Python/JavaScript split: The Starlight site under docs/ now has distinct python/ and javascript/ sections, an auto-generated releases/changelog.mdx page (scripts/generate-changelog-docs.sh), and auto-generated Python API reference (scripts/generate-python-api-docs.sh, renamed from generate-api-docs.sh). The deploy-docs.yml workflow now drives publishing automatically, and the host build no longer depends on sharp so it works on macOS without libvips.
  • Incorrect value types in bdp/bdh long format (issue #280): The default long format (LongMode::String) was converting all Bloomberg values to strings, ignoring resolved field_types. Now the Rust engine computes a common Arrow type from the field type hints at construction time — when all fields are numeric, the value column is Float64 instead of Utf8. Mixed-type queries (e.g., numeric + string fields) gracefully fall back to string. The fix is zero-copy: Value is moved into the Arrow builder instead of being stringified and re-parsed.
  • macOS/Linux: import xbbg._core fails with Library not loaded: @rpath/libblpapi3_64.so (issue #276): The pyo3 cdylib ships with zero LC_RPATH entries on macOS, so dyld had nowhere to look for libblpapi3_64.so at import time. Previously only Windows had pre-import SDK setup in __init__.py. Now _prepare_sdk_for_core_import() dispatches per-platform: Windows keeps the existing add_dll_directory path, while macOS and Linux preload libblpapi3_64.so via ctypes.CDLL(..., RTLD_GLOBAL) so dyld/ld.so resolves the @rpath reference via install-name / already-loaded image matching. This mirrors the idiom Bloomberg’s own blpapi/internals.py uses for its ffiutils extension (which also ships with no rpath). All four SDK sources (xbbg.set_sdk_path(), blpapi package, DAPI, BLPAPI_ROOT) are now honored on every platform. The friendly ImportError wrapper also recognizes macOS dlopen error strings (Library not loaded, image not found).
  • RequestEnvironment.zfp_remote type annotation: Corrected the dataclass field annotation from int | None to str | None to match the Rust Option<String> (ZFP remote values are strings like "8194"/"8196"). The defensive getattr() access in _snapshot_request_environment had been masking this type mismatch from static analyzers.
  • _convert_backend no longer hard-imports polars: A follow-up to the Arrow-canonical refactor accidentally replaced the intentional hasattr(native, "to_arrow") capability check in the pyarrow branch with an unconditional isinstance(native, pl.DataFrame), which forced import polars as pl at module-load time and broke environments where polars (an optional backend) isn’t installed. Restored the capability check, short-circuiting pandas inputs via isinstance first so the hasattr path only fires for genuine polars frames.
  • Polars/pyarrow global backend causes AttributeError in all generated endpoints (issue #287): _execute_generated_endpoint was effectively calling _convert_backend twice on the same frame — once inside the middleware terminal (which resolved backend=None to the global default and returned a native frame) and again in the outer call, which tried nw_df.to_native() on the already-native frame. Pandas users were silently masked by an isinstance(nw_df, pd.DataFrame) short-circuit at the top of _convert_backend; polars and pyarrow users had no equivalent guard and saw AttributeError: 'DataFrame' object has no attribute 'to_native'. Affected all 14 generated endpoints (bdp/abdp, bdh/abdh, bds/abds, bdib/abdib, bdtick/abdtick, bql/abql, bqr/abqr, bsrch/absrch, beqs/abeqs, blkp/ablkp, bport/abport, bcurves/abcurves, bgovts/abgovts, bflds/abflds) — not just bdp as reported. Verified end-to-end against a real Bloomberg Terminal.
  • ext/futures.py date-like duck-typing: Collapsed three hasattr(value, "year"/"month"/"day") calls into a single isinstance(value, date) check now that date is imported unconditionally. More precise and removes false positives from unrelated objects that happen to expose .year.
  • markets/{info,bloomberg}.py imports: Replaced importlib.import_module("xbbg") + getattr(..., "bdp"/"abdp") # noqa: B009 with deferred from xbbg.blp import bdp/abdp inside the consuming functions. Same lazy-loading behavior, removes the lint suppression, and lets static checkers resolve the symbol.
  • Incorrect timestamp in parse_rfc3339_utc test: Fixed hardcoded expected value from 1717242600 to 1717252200 (correct UTC epoch for 2024-06-01T14:30:00+00:00).
  • Legacy configure() kwarg aliases: xbbg.configure() no longer accepts the legacy connection-style aliases carried over from xbbg 0.x: server, server_host, server_port, max_attempt, auto_restart, max_recovery, retry_max, retry_delay, retry_backoff. The NotImplementedError placeholders for sess and tls_options are likewise gone — unknown kwargs now raise a uniform TypeError. Use the canonical EngineConfig field names instead: host, port, num_start_attempts, auto_restart_on_disconnection, max_recovery_attempts, retry_max_retries, retry_initial_delay_ms, retry_backoff_factor.
  • Subscription event timestamps (issue #273): asubscribe(..., tick_mode=True) and raw subscription batches now expose the event timestamp column as UTC-aware Arrow/Python datetimes instead of naive UTC values. This fixes incorrect .timestamp() conversions on non-UTC hosts.
  • PyPI classifiers: Added Development Status :: 5 - Production/Stable, Intended Audience :: Financial and Insurance Industry, Intended Audience :: Science/Research, Topic :: Office/Business :: Financial, Programming Language :: Rust, and Typing :: Typed.
  • README: Fixed all documentation links from defunct ReadTheDocs to Starlight site (alpha-xone.github.io/xbbg), updated the latest-release marker to rc4, removed stale Codecov/Codacy/CodeFactor badges, replaced dead Auto CI build badge with ci-rust.yml, and removed “beta” language in project description.
  • Issue templates: Updated documentation links and environment version examples for v1.
  • CONTRIBUTING.md: Corrected minimum Rust version from 1.70 to 1.75.
  • Bloomberg SDK ABI compatibility check: New scripts/abi-check.sh and CI job that verifies every C symbol xbbg-core depends on exists across SDK versions (oldest supported through latest). Minimum supported SDK version defined in defs/bloomberg.toml (min_sdk_version).
  • SECURITY.md: Restored security policy with vulnerability reporting instructions and hardening notes.
  • GitHub Pages deploy workflow: Added deploy-docs.yml for automated Starlight docs deployment on push to main.
  • Documentation: Wrote complete content for all guide and reference pages (migration, streaming, async, backends, output formats, configuration, type mappings).
  • Shutdown panic (issue #270): Fixed tokio worker thread panic (Python::attach after Py_Finalize) when Python exits with active subscriptions. Root cause: signal_shutdown() didn’t close the data path to __anext__, leaving tokio futures alive during interpreter teardown. Fix adds Engine::shutdown_signal (watch channel) that immediately wakes pending __anext__ futures, and shutdown_safe_future wrapper that prevents future_into_py from delivering results to a dead interpreter. Affects all async methods (requests, subscriptions, recipes).
  • Engine startup race condition (issue #272): configure() no longer raises RuntimeError if the engine was auto-created with defaults before configuration (e.g., by a health check or background thread in FastAPI). It now shuts down the default engine with a RuntimeWarning and stores the new config for the next request. Also added thread safety to _get_engine() (double-checked locking) and clear error messages when sync wrappers (bdp, bdh, etc.) are called inside async contexts.
  • Type checking: Resolved all 178 ty errors to zero. Exception classes properly subclassed in Python instead of monkey-patching __init__ on Rust classes. Added exception stubs to _core/__init__.pyi. Remaining 6 type: ignore comments are all upstream stub gaps (narwhals, stdlib, platform-specific).
  • Unused pandas import: Removed leftover TYPE_CHECKING import of pandas in blp.py after Format.WIDE removal.
  • Exception hierarchy: BlpRequestError, BlpSecurityError, BlpFieldError, and BlpValidationError are now proper Python subclasses of the Rust base classes with typed __init__ signatures, replacing fragile __init__ monkey-patching.
  • Pygments ReDoS (CVE): Upgraded Pygments 2.19.2 to 2.20.0, fixing a regular expression denial of service in GUID matching.
  • OverflowPolicy::DropOldest: Removed unimplemented overflow policy that silently behaved as DropNewest. Will be reintroduced in a future release with correct ring-buffer semantics. Use 'drop_newest' (default) or 'block'.
  • Format.WIDE: Removed the deprecated wide output format. Use Format.SEMI_LONG for field-as-column output, or call .pivot() on Format.LONG results.
  • asset_config(): Removed the deprecated market config helper. Use market_info(ticker) instead.
  • BQL error handling: Parse Bloomberg’s responseExceptions for actionable error messages (e.g. “Undefined item: CUR_YLD”) instead of opaque “missing ‘results’ field” errors. Null results with no exceptions now return an empty DataFrame. Partial exceptions with valid results log warnings instead of failing.
  • corporate_bonds() cross-market support: Switched from bondsuniv + TICKER== filter (US-only) to debt() universe, matching the approach used by preferreds(). Now accepts full equity tickers (e.g. “9984 JT Equity”) and works across all markets.
  • CDX on-the-run indicator: Accept 'true' (returned by Bloomberg for CDX generic tickers) in addition to 'Y' for ON_THE_RUN_CURRENT_BD_INDICATOR, fixing false warnings on CDX instruments.
  • is_connected() checks real session health: Now queries actual Bloomberg worker health via request_pool_health() instead of just checking if the Python engine object exists.
  • fieldExceptions logging: Downgraded from WARN to DEBUG and now includes actual field names and error messages (e.g. “MATURITY: Field not applicable to security”) instead of just a count.
  • Subscription field exposure (#265): all_fields on asubscribe, astream, and stream (and PyEngine.subscribe / subscribe_with_options). When False (default), batches include only requested fields plus MKTDATA_EVENT_TYPE and MKTDATA_EVENT_SUBTYPE. When True, each batch includes every top-level scalar field Bloomberg sends (e.g. full SUMMARY/INITPAINT snapshots), with the schema growing as new fields appear. The same flag is available on avwap, amktbar, adepth, and achains for consistency across streaming services.
  • Intraday timezone controls (request_tz / output_tz): abdib/bdib, abdtick/bdtick, arequest, and Rust RequestParams accept optional request_tz (interpret naive start_datetime/end_datetime before Bloomberg) and output_tz (relabel Arrow time to an IANA zone). Supported labels include UTC, local, exchange, NY/LN/TK/HK, reference tickers, and explicit IANA names. Implemented in xbbg-async (chrono-tz, iana-time-zone) with nested RefData calls routed through request_without_intraday_transform to avoid recursion.
  • Pixi environment management: Added pixi.toml with 11 environments (default, test, lint, benchmark, docs, py310–py314), 21 tasks, and conda-forge deps for Rust, libclang, and pyarrow. Single pixi install && pixi run install replaces manual toolchain setup.
  • mimalloc allocator: PyO3 extension now uses mimalloc by default (feature-gated) for improved Rust-side allocation performance.
  • ty type checking: Lint environment includes Astral’s ty type checker alongside ruff; CI lint job now runs type checking automatically.
  • SOCKS5 proxy support (#180): Route Bloomberg connections through a SOCKS5 proxy via socks5_host and socks5_port kwargs on configure() and Engine(). Uses the Bloomberg SDK’s Socks5Config API (no auth, hostname + port only).
  • Enterprise-friendly request middleware context: RequestContext now carries a read-only RequestEnvironment snapshot so middleware can inspect engine source, host/port, server list, auth method, app/user context, and validation mode without reaching into private globals.
  • Standardised on BLPAPI_ROOT: Removed XBBG_DEV_SDK_ROOT env var across the codebase (build.rs, scripts, docs). SDK discovery now uses BLPAPI_ROOT only (set by pixi activation or .cargo/config.toml). No hardcoded SDK version — build.rs scans versioned subdirs automatically.
  • Removed BLPAPI_LINK_LIB_NAME: Library name is now always auto-detected by detect_link_lib_name() based on target platform.
  • Build profiles cleaned up: Removed redundant [profile.release.package.xbbg_core]; added [profile.dev.package."*"] opt-level = 2 so all deps are optimised in dev builds; pixi run install uses target-cpu=native for local builds.
  • Migrated from uv to pixi for dev tooling: Removed [dependency-groups], [tool.uv.*] from pyproject.toml; deleted uv.lock; pre-commit hooks use bare ruff instead of uvx ruff; README dev instructions updated to pixi commands.
  • Consolidated config files: Merged .coveragerc into pyproject.toml [tool.coverage.*]; deleted .env (pixi activation replaces it); un-gitignored .cargo/config.toml (now contains only project-standard BLPAPI_ROOT).
  • CI lint job uses pixi: lint-python job now uses prefix-dev/setup-pixi with the lightweight lint environment, replacing uvx ruff.
  • Request tracing is more consistent: Python request middleware now sees the generated request_id in both RequestContext.request_id and RequestContext.params_dict, centralized request logs include the request ID, and the Rust request path forwards it as the Bloomberg request label for better audit/debug correlation.
  • Bindgen/libclang toolchain aligned: All Rust FFI crates now use bindgen 0.72.1 with runtime loading, and the pixi environment now requires libclang >=22. This fixes incorrect Bloomberg SDK blpapi_ManagedPtr_t_ generation under newer libclang releases and removes the need for correlation-ID layout workarounds.
  • XBBG_DEV_SDK_ROOT env var: Use BLPAPI_ROOT instead. The .env file fallback in blpapi-sys/build.rs has been removed.
  • BLPAPI_LINK_LIB_NAME env var: Auto-detection covers all platforms.
  • uv.lock: Replaced by pixi.lock.
  • .coveragerc: Configuration moved to pyproject.toml.
  • De-duplicated Rust recipe helpers: Extracted array_value_as_string, date32_to_naive, as_string_col into shared xbbg-recipes/src/utils.rs.
  • De-duplicated Python code: Consolidated _to_pandas_wide (was in both info.py and bloomberg.py); unified _FUTURES_MONTH_CODES to use Rust-sourced ext_get_futures_months(); extracted _apply_settle_override helper replacing 5 repeated blocks in bonds.py.
  • Python type stubs for xbbg._core via pyo3-stub-gen: auto-generated .pyi files provide full IDE autocompletion and type-checker support for EngineConfig, Engine, Subscription, and all Rust-backed functions. Includes py.typed PEP 561 marker.
  • macOS ARM64 wheel builds in CI and release workflows. Wheels are now built and tested for Linux x86_64, Windows x86_64, and macOS ARM64 across Python 3.10–3.14.
  • CI auto-regeneration of type stubs: stubs are regenerated and auto-committed after all CI checks pass, ensuring .pyi files stay in sync with Rust annotations.
  • Engine class for non-global multi-engine routing. Create independent engine instances and scope them via with engine: (sync) or async with engine: (async). The global configure() + blp.bdp() API is unchanged — Engine is fully opt-in.
  • TLS support for encrypted B-PIPE connections: tls_client_credentials, tls_trust_material, tls_handshake_timeout_ms on EngineConfig and configure().
  • Identity lifecycle FFI: Session.generate_token(), Session.send_authorization_request(), Session.subscribe_with_identity() for multi-user entitlement flows.
  • Runtime SDK version: get_sdk_info() now includes runtime_version field reporting the linked Bloomberg C SDK version via blpapi_getVersionInfo() (e.g., "3.26.2.1"). Also available as xbbg._core.sdk_version()(major, minor, patch, build) tuple.
  • Async request cancellation: cancelling the Python task for any async Bloomberg request now propagates to the Bloomberg SDK via Session::cancel(correlationId). The worker drops local request state immediately after a successful cancel and remains usable for subsequent requests.
  • Reconnect resilience (Phases 1–3) for the Rust engine (#245):
    • Fail-fast on session death: request workers now immediately drain all in-flight requests with an error on SessionTerminated/SessionConnectionDown instead of letting callers hang indefinitely. Workers are marked Dead and restored to Healthy on SessionConnectionUp.
    • Service re-open before re-subscribe: recover_active_subscriptions() now re-opens all previously opened services before re-issuing subscriptions after reconnect, fixing a critical gap where recovery could silently fail.
    • Health-aware dispatch: request pool round-robin skips Dead workers; returns AllWorkersDown immediately if the entire pool is dead.
    • Retry with exponential backoff: RetryPolicy on EngineConfig (retry_max_retries, retry_initial_delay_ms, retry_backoff_factor, retry_max_delay_ms) enables automatic retry of transient request failures.
    • Recovery limits: max_recovery_attempts and recovery_timeout_ms cap subscription recovery to prevent infinite loops.
    • Lifecycle events: ConnectionLost, Reconnected, and RecoveryFailed events emitted to subscription status for observability.
    • New error variants: BlpAsyncError::SessionLost and AllWorkersDown mapped to Python BlpSessionError.
    • Python surface: all new config fields exposed in EngineConfig, configure(), and Engine(); engine.worker_health() returns per-worker health status.
  • Multi-server failover via servers kwarg (#250). Pass a list of (host, port) tuples for automatic Bloomberg SDK failover using setServerAddress(host, port, index). Existing host/port kwargs unchanged for single-server use.
  • ZFP over leased lines via zfp_remote kwarg (#255). Set to "8194" or "8196" with TLS credentials to connect via Bloomberg Zero Footprint without a local Terminal. Uses ZfpUtil::getOptionsForLeasedLines from the SDK.
  • Identity entitlement checking (#252): Identity.is_authorized(service), Identity.has_entitlements(service, eids), and Identity.seat_type() for B-PIPE multi-user entitlement verification.
  • Bloomberg SDK logging bridge (#253): enable_sdk_logging(level) and EngineConfig.sdk_log_level route native BLPAPI internal logs into xbbg-log tracing target xbbg.sdk. Default is off; registration happens before session start when enabled.
  • Engine Architecture & EngineConfig documentation: README now includes a full reference for all 20+ EngineConfig fields (worker pools, subscription tuning, buffers, validation, auth), an ASCII architecture diagram, and auth mode examples.
  • API surface updated to v1: README function tables, examples, and Connection Options section now reflect v1 names (blkp, bport, earnings, convert_ccy, configure(), subscribe/stream, etc.) and remove stale v0.x references (lookupSecurity, exchange_tz, set_format, Format enum).
  • Dev setup and contributing guides updated for v1 project structure (py-xbbg/src paths, Astro docs, uv sync dependency-groups).
  • cargo-deny advisory ignores for unmaintained unic-* crates (transitive deps of rustpython-parser via pyo3-stub-gen, build-time only).
  • Internal correlation ID dispatch overhaul: The async engine no longer uses raw Bloomberg integer correlation IDs as direct slab indexes. All request and session dispatch now routes through an explicit dispatch-key layer at the session boundary, preventing ID collisions between auth subscriptions and user requests and aligning lifecycle tracking with Bloomberg SDK semantics.
  • Logging levels better match the quiet-by-default workflow: Request roundtrip telemetry and Python subscription lifecycle messages now emit at DEBUG instead of INFO, while exchange metadata fetch failures that cleanly fall back now emit at WARNING instead of ERROR, keeping normal control-flow noise out of default logs without hiding real request telemetry.
  • SAPI authentication fails with BLPAPI_ERROR_DUPLICATE_CORRELATIONID (#248): CorrelationId::default() returned Int(0), which is a valid explicit correlation ID. When setSessionIdentityOptions registered Int(0) for the auth flow, subsequent sendRequest calls with the same default ID were rejected as duplicates (rc=131077). The default is now CorrelationId::Unset (maps to BLPAPI_CORRELATION_TYPE_UNSET in the FFI struct), matching the official Python blpapi behavior where the SDK auto-generates unique IDs. Affects all SAPI authentication modes (app, user, userapp, dir, token).
  • Rust-backed Bloomberg session authentication for v1: Added structured auth support across the Rust core, async engine, and PyO3 bindings for user, app, userapp, dir, manual, and token auth modes, enabling SAPI/B-PIPE session configuration from the v1 Python API.
  • Request middleware chain for telemetry and wrappers: Added RequestContext plus middleware registration helpers around arequest() so callers can layer centralized request instrumentation, logging, caching, and wrapper behavior without patching individual endpoint functions.
  • configure() is now the canonical engine/session setup surface: Connection/auth setup now flows through configure() with support for legacy aliases such as server_host, server_port, max_attempt, and auto_restart, while the temporary connect() / disconnect() wrappers were removed before release.
  • Auth/session startup failures now propagate with context: Request and subscription workers now wait for Bloomberg startup/auth events before proceeding, so failed authentication and session-start problems surface as actionable errors instead of being swallowed or masked by later service-open failures.
  • Rust/Python CI regressions in the new auth path: Cleaned release-blocking lint and formatting issues in the new auth/middleware code paths so the full Linux/Windows CI matrix passes with the beta 5 changes.
  • Subscription failure isolation for mixed-topic streams: Real-time subscriptions now treat Bloomberg SubscriptionFailure and unexpected SubscriptionTerminated events as per-ticker status instead of fatal stream errors when other topics remain healthy. Mixed subscriptions keep delivering data for valid tickers while exposing failed topics through subscription metadata.
  • Subscription lifecycle observability: Real-time subscriptions now retain bounded status/event history for topic lifecycle transitions, session connectivity, service readiness, slow-consumer/data-loss signals, and reconnect recovery attempts so callers can inspect operational state without scraping logs.
  • Non-fatal disconnect handling with opt-in recovery: SessionConnectionDown no longer tears down healthy subscriptions by default. Callers can opt into recovery_policy="resubscribe" to issue reconnect-time recovery subscribes while tracking attempts, successes, and last recovery errors through subscription status metadata.
  • Subscription failure metadata: Python subscriptions now expose failed_tickers and failures so callers can inspect which topics Bloomberg rejected or terminated, along with the reported reason and failure kind.
  • Subscription health/status surfaces: Python subscriptions now expose status, events, topic_states, session_status, admin_status, service_status, all_failed, and expanded stats fields including data-loss counters, last-message timestamps, and effective overflow policy.
  • Backend enum and availability checks (#234): Ported Backend enum and backend availability infrastructure from release/0.x into py-xbbg/src/xbbg/backend.py. The canonical Backend enum now has all 13 backends (added CUDF, MODIN, DASK, IBIS, PYSPARK, SQLFRAME). New public helpers: is_backend_available(), check_backend(), get_available_backends(), print_backend_status(), validate_backend_format(), is_format_supported(), get_supported_formats(), check_format_compatibility(). Includes MIN_VERSIONS, PACKAGE_NAMES, MODULE_NAMES, and SUPPORTED_FORMATS dicts for version validation and actionable install instructions.
  • Subscription mutation synchronization: Refactored subscription worker ownership to split the single-owner pool lease from a cloneable command handle, allowing subscription add()/remove() paths in both xbbg-async and PyO3 to drop metadata locks before awaiting Bloomberg command dispatch while still serializing mutations safely.
  • Additional GIL release coverage in PyO3 bindings: Released the GIL around synchronous cache-save calls, Arrow pivot/format inspection helpers, and subscription metadata snapshots so Python threads are not blocked during disk I/O, pure Rust Arrow work, or waits on subscription state locks.
  • Reduced avoidable Arrow-path copies: Removed intermediate string allocations for borrowed Bloomberg string/enum values and stopped cloning field-name/subfield-name vectors in refdata, histdata, and bulkdata extraction paths before the existing zero-copy PyArrow export boundary.
  • Removed unused lief dependency: Dropped lief>=0.17 from core [project.dependencies]; the package was never imported anywhere in the codebase.
  • Field-validation toggle for refdata/histdata requests: Added optional validate_fields request parameter in request()/arequest() and typed wrappers (abdp/bdp, abdh/bdh, abds/bds). This supports per-request strict validation override while still honoring engine-level validation_mode defaults.
  • Engine-side field-validation enforcement: xbbg-async now validates requested fields for ReferenceDataRequest and HistoricalDataRequest before dispatch when validation is enabled, returning configuration errors for unknown Bloomberg fields in strict mode.
  • Live validation toggle smoke script: Added py-xbbg/tests/live/field_validation_toggle_smoke.py to verify on/off behavior against a connected Bloomberg session.
  • Request-plumbing coverage for validate_fields: Added py-xbbg/tests/test_validate_fields_toggle.py to verify Python parameter serialization and forwarding through async/sync wrappers.
  • Canonical exception exports: xbbg.exceptions now re-exports Rust _core exception classes (BlpError, BlpRequestError, etc.) as the single source of truth, with Python-only exceptions remaining additive.
  • Validation helper compatibility: Preserved BlpValidationError.from_rust_error(...) by attaching the compatibility classmethod to the canonical Rust-backed validation exception.
  • Generated sync wrapper metadata: blp.py generated sync wrappers now derive __doc__ and __annotations__ from async templates directly; remaining manual generated sync wrapper boilerplate was removed.
  • Integration logging expectations: Updated logging integration assertions to match centralized arequest request logging (bloomberg ... ReferenceDataRequest) instead of deprecated endpoint-specific debug strings.
  • Optional pandas integration paths: Updated pandas-dependent integration tests to use pytest.importorskip("pandas"), avoiding hard failures when pandas is not installed.
  • except BlpError catchability gap: Runtime exceptions raised by Rust (for example BlpRequestError) are now catchable via xbbg.exceptions.BlpError import paths because both now point to the same canonical Rust exception hierarchy.
  • Endpoint-factory regression tests: Added focused coverage for generated abflds/bflds and abqr/bqr routing, validation, and reshape behavior in py-xbbg/tests/test_endpoint_factory_bflds.py and py-xbbg/tests/test_endpoint_factory_bqr.py
  • Template endpoint generation in blp.py: Migrated clean-fit wrappers to generated async/sync endpoints backed by _GeneratedEndpointSpec and _EndpointPlan, including abdp/bdp, abdh/bdh, abds/bds, abdib/bdib, abdtick/bdtick, abql/bql, abqr/bqr, absrch/bsrch, abeqs/beqs, ablkp/blkp, abport/bport, abcurves/bcurves, abgovts/bgovts, and abflds/bflds
  • bqr pandas dependency regression: Removed unconditional to_pandas() conversion in BQR postprocessing; quote requests now use Arrow-native checks/reshape and run without requiring pandas for standard flows
  • bqr()/abqr() Bloomberg Quote Request: Tick-level dealer quotes with date_offset (-2d, -1w, -3h), start_date/end_date date ranges, and optional include_broker_codes, include_spread_price, include_yield, include_condition_codes, include_exchange_codes parameters. Generic extractor fallback reshaped via _reshape_bqr_generic()
  • bflds()/abflds() unified field metadata lookup: Single function for both field info (fields=[...]) and keyword search (search_spec='...'). bfld/abfld provided as backward-compatible aliases. Convenience wrappers fieldInfo()/fieldSearch() preserved
  • include_security_errors option for bdp()/arequest(): Optionally surface per-security failures as rows in the result DataFrame instead of silently dropping them
  • Extension modules (xbbg.ext): bonds (6 functions), options (6 functions + 5 enums), cdx (8 functions) for fixed income, equity options, and credit default swap index analytics
  • Streaming performance enhancements: Per-subscription config (flush_threshold, overflow_policy, stream_capacity), observability metrics via shared atomics, tick_mode support
  • Live integration tests: 69 tests across test_ext_bonds.py (21), test_ext_options.py (20), test_ext_cdx.py (22) covering all ext module functions
  • Streaming tests: Tests for tick_mode, per-subscription config, and observability metrics
  • Rust exchange/session APIs: Added low-level exchange resolution support with ExchangeInfo metadata, runtime exchange overrides, session timezone conversion utilities, and market_timing helpers in the Rust layer (xbbg-ext, xbbg-async, pyo3-xbbg)
  • Live exchange smoke test: Added py-xbbg/tests/live/test_exchange_resolution.py covering override precedence, UTC session conversion, live resolve_exchange, fetch_market_info, and market_timing
  • README: Updated API reference tables with bflds(), expanded BQR section with spread/yield/broker parameters and examples
  • Futures resolver: Aligned with release/0.x chain methodology (FUT_CHAIN_LAST_TRADE_DATES)
  • CDX resolver: Aligned methodology with release/0.x
  • Legacy xbbg/ Python package directory: Fully removed; all code now lives in py-xbbg/src/xbbg/
  • Empty RecordBatch construction: Handle empty ordered RecordBatch in xbbg-async without panic
  • Security failure surfacing: refdata extractor now properly surfaces per-security errors instead of silently dropping them
  • FIELD_SEARCH extractor: Corrected to use ExtractorHint.FIELD_INFO instead of generic extractor
  • Unused logging import in ext/options.py: Removed to pass ruff lint
  • Test imports: BlpInternalError imported from _core (Rust) instead of exceptions (Python)
  • CI fixes: Resolved 4 Python test failures, clippy warnings (too_many_arguments, SubscriptionMetrics re-export), ruff check/format violations, cargo fmt formatting, module path for test_markets.py, Linux test runtime setup
  • Exchange refdata parsing shape support: resolve_exchange now handles both WIDE and LONG refdata responses by mapping (field, value) rows when Bloomberg returns long-shape metadata
  • README: Comprehensive rewrite with full API reference tables, comparison matrix, multi-backend documentation, detailed intraday session guide, fixed income/options/CDX analytics examples, troubleshooting section, and data storage documentation
  • Rust-powered engine: Complete ground-up rewrite delivering up to 10x faster data retrieval with zero-copy Arrow transfer between Rust and Python. The engine spans 11 purpose-built crates: safe FFI bindings with SIMD-accelerated parsing (blpapi-sys, xbbg-core), an async worker pool engine with state machines for every Bloomberg request type (xbbg-async), Rust ports of extension and recipe logic (xbbg-ext, xbbg-recipes — all 12 recipes exposed via PyO3), zero-GIL tracing (xbbg-log), CI/test stubs (xbbg-sys), and PyO3 Python bindings (pyo3-xbbg)
  • New Python package (py-xbbg/): Complete v1 API powered by the Rust backend, replacing the pure-Python xbbg/ package. Lazy-loaded via __getattr__ for near-instant import
  • Streaming APIs: vwap()/avwap() for VWAP streaming (//blp/mktvwap), mktbar()/amktbar() for market bar streaming, depth()/adepth() for market depth (B-PIPE), chains()/achains() for option/futures chain streaming (B-PIPE) — all with async variants
  • New Bloomberg API functions: bcurves()/abcurves() for yield curve lookup, bgovts()/abgovts() for government securities lookup, bflds()/abflds() for field search (replacing fieldInfo/fieldSearch)
  • Generic request API: request()/arequest() — direct access to any Bloomberg service and operation with schema-driven kwargs routing. Power users can hit any Bloomberg endpoint without a dedicated wrapper
  • Schema introspection: bops()/abops() to list service operations, bschema()/abschema() for full service schema, get_schema()/aget_schema(), list_operations()/alist_operations(), get_enum_values()/aget_enum_values(), list_valid_elements()/alist_valid_elements() — all with async variants. generate_stubs() and configure_ide_stubs() for IDE auto-completion generated from live Bloomberg schemas
  • Field type cache: FieldTypeCache, FieldInfo, resolve_field_types()/aresolve_field_types(), cache_field_types(), get_field_info(), clear_field_cache() for caching and resolving Bloomberg field metadata
  • Engine lifecycle management: shutdown(), reset(), is_connected() for explicit Rust engine control
  • EngineConfig: Rust-native engine configuration (PyO3 PyEngineConfig) — subscription pool size, request pool size, flush thresholds, auto-restart on disconnection
  • Auto-restart on disconnection: Subscription sessions automatically reconnect after network interruptions via setAutoRestartOnDisconnection
  • Time64Micros value type: Microsecond-precision time-of-day extraction from Bloomberg Datetime fields, with Arrow Time64Micros type support in generic, histdata, and refdata state handlers
  • BlpBPipeError exception: New exception class for B-PIPE-specific errors, added to the existing exception hierarchy
  • Technical Analysis improvements: ta_study_params() to inspect study parameters, generate_ta_stubs() for IDE auto-completion of TA study names
  • Logging control: set_log_level(), get_log_level() to control Rust-side tracing verbosity without Python overhead
  • Bloomberg SDK message receive time: Message::receive_time() for latency measurement and diagnostics
  • Service definitions: Service, Operation, OutputMode, RequestParams, ExtractorHint enums for type-safe Bloomberg service configuration
  • Extension modules (py-xbbg/src/xbbg/ext/): currency, fixed_income, futures, historical — ported to work with the Rust backend in LONG format
  • Markets module (py-xbbg/src/xbbg/markets/): bloomberg, info, overrides, resolvers, sessions — exchange metadata, market timing, and override normalization
  • Data definition files: defs/bloomberg.toml and defs/exchanges.toml for data-driven Bloomberg and exchange configuration
  • Starlight documentation site: Full rewrite from Sphinx to Astro Starlight — API reference (blp.md, exceptions.md, schema.md, services.md), getting started guides (installation.mdx, introduction.mdx, quickstart.mdx), async/streaming/migration/output-format guides, and configuration reference
  • Benchmark suites: Rust benchmarks via Criterion (xbbg-bench — allocation profiling, datetime/name micro-benchmarks, cached response parsing, live bdp/subscription benchmarks) and Python benchmarks (benchmarks/bdp, bdh, bdib, bdtick, bql, raw blpapi with version-based result tracking)
  • Comprehensive test suites: py-xbbg/tests/ with unit tests for imports, backends, blp API, backend conversion, currency conversion, exceptions, futures validation, integration, markets, and yield types. Live test suite (py-xbbg/tests/live/) for API, engine, subscription lifecycle, and subscription fixes
  • CI infrastructure: ci-rust.yml for multi-platform Rust CI (clippy, rustfmt, unit tests, integration tests, cargo-audit, cargo-deny, semver-checks), ci-docker.yml for reusable container image builds, Docker containers for Rust CI and manylinux wheel builds
  • Codegen tool (codegen/generate.py): Python code generator for service definitions, including SEMI_LONG output format support from release/0.x
  • SDK setup script (scripts/sdktool.ps1): PowerShell script for Bloomberg SDK vendor layout management
  • cargo-deny configuration (deny.toml): License and security policy for all Rust dependencies
  • Future language binding scaffolds: bindings/napi-xbbg/ (Node.js N-API), bindings/dotnet-xbbg/ (.NET), apps/xbbg-cli/ (CLI), apps/xbbg-server/ (server), and js-xbbg/ (npm package)
  • vendor/blpapi-sdk/README.md: Instructions for vendoring the Bloomberg C++ SDK locally
  • Build system: Switched to setuptools-rust (PyO3) with setuptools_scm versioning. pyproject.toml now builds the Rust extension via setuptools.build_meta
  • Python package source location: Moved from xbbg/ (in-tree) to py-xbbg/src/xbbg/ for the Rust-backed package layout. The native extension is compiled as xbbg._core
  • Runtime dependencies: pandas is no longer required — now only narwhals>=1.30, pyarrow>=22.0.0, lief>=0.17. Removed blpapi, tomli, and all other previous hard dependencies
  • Python version support: Added Python 3.14 to classifiers (>=3.10,<3.15)
  • pypi_upload.yml workflow: Completely rewritten for setuptools-rust wheel builds with Bloomberg SDK detection, replacing the pure-Python sdist/wheel workflow
  • pre-commit-config.yaml: Updated hooks for the Rust+Python monorepo — added cargo fmt, cargo clippy, and scoped ruff to py-xbbg/ and xbbg/
  • .gitignore: Expanded for Rust build artifacts (target/), native extension outputs, SDK vendor directory, benchmark results, and IDE files
  • README.md: Rewritten for v1.0 — concise project description, Rust-powered backend highlights, installation and quick start replacing the extensive v0.x documentation
  • CONTRIBUTING.md: Rewritten for the Rust+Python development workflow
  • LICENSE: Updated to Apache-2.0 with revised copyright
  • Maximum-performance release builds: lto = "fat", codegen-units = 1, panic = "abort", strip = "symbols" for production; opt-level = 3 for xbbg-core, opt-level = 2 for dev
  • Subscription pool default: Reduced from 4 to 1 worker, consolidated into EngineConfig
  • Legacy xbbg/ package: Minor cleanups — added from __future__ import annotations across all __init__.py files, normalized docstring quotes from single to double, removed # noqa lint suppression comments, replaced lambda: [] with list in pipeline factory registry default resolvers
  • xbbg/__init__.py: Top-level package init replaced by py-xbbg/src/xbbg/__init__.py with Rust backend
  • xbbg/blp.py: 178-line deprecation compatibility layer — all functions now live in py-xbbg/src/xbbg/blp.py backed by Rust
  • xbbg/const.py: 187-line constants module — constants moved to Rust crates and defs/*.toml
  • xbbg/core/__init__.py: 35-line core package init — core functionality replaced by Rust engine
  • xbbg/core/process.py: 787-line Bloomberg message processing module — replaced by xbbg-async Rust engine state machines
  • xbbg/utils/pipeline.py: 336-line pipeline utilities — replaced by Rust engine pipeline
  • xbbg/io/__init__.py: IO module init removed (module gutted in v0.12.0)
  • xbbg/markets/__init__.py: 76-line markets package init — replaced by py-xbbg/src/xbbg/markets/
  • xbbg/markets/resolvers.py: Futures/CDX resolvers moved to xbbg-ext Rust crate
  • examples/feeds/pub.py and examples/feeds/sub.py: Legacy feed examples
  • Sphinx documentation: docs/conf.py, docs/index.rst (1,293 lines), docs/Makefile, docs/make.bat, docs/docstring_style.rst — replaced by Starlight
  • .readthedocs.yaml: ReadTheDocs configuration (docs now use Starlight)
  • MANIFEST.in: No longer needed with the setuptools-rust build system
  • SECURITY.md: Security policy document
  • _config.yml: Jekyll configuration
  • codecov.yml: Codecov configuration
  • 9 CI workflows: auto_ci.yml, ci_docs.yml, codeql-analysis.yml, publish_docs.yml, publish_testpypi.yml, pypi_build_test.yml, release_assets.yml, update_index_on_release.yml, update_readme_on_release.yml — consolidated into ci-rust.yml, ci-docker.yml, and rewritten pypi_upload.yml
  • Clippy 1.93 lints: Resolved map_or and doc indentation warnings across all Rust crates
  • Windows LLVM/LIBCLANG_PATH setup: Fixed detection and configuration for bindgen on Windows CI
  • Linux LIBCLANG_PATH detection: Fixed libclang-dev path resolution on Linux CI
  • Non-ASCII characters in comments: Replaced em dashes with ASCII equivalents to pass CI source checks
  • Subscription slab key reuse race: Prevented key reuse on subscription removal in xbbg-async that could cause events to route to wrong handlers
  • Subscription error propagation: Subscription errors now propagate as Python exceptions via PyO3 instead of being silently swallowed
  • Subscription pipeline rewrite: Multi-type support, error propagation, and event time tracking in xbbg-async
  • Datetime field zeroed date parts: Added parts bitmask check to correctly handle Bloomberg Datetime fields with zeroed date components
  • DLL search path setup (Windows): Moved SDK DLL search path configuration to module level in py-xbbg to fix from xbbg._core import X failures
  • Request::set_bool: Use setElementString for Bool elements in Bloomberg requests (Bloomberg API quirk)
  • TA study requests: Wired through elements instead of unused json_elements path
  • WIDE format compatibility: Produces 0.7.7-compatible DataFrame structure from the Rust backend
  • Backend double-conversion bug: Fixed duplicate conversion when Rust backend returns data that is then converted again by Python
  • Async-first architecture: All Bloomberg API functions (bdp, bds, bdh, bdib, bdtick, bql, beqs, bsrch, bqr, bta) now have async counterparts (abdp, abds, abdh, etc.) as the source of truth; sync wrappers delegate via _run_sync() (#218)
  • Bond analytics module (xbbg.ext.bonds): 6 new functions for fixed income analytics — bond_info (reference metadata and ratings), bond_risk (duration, convexity, DV01), bond_spreads (OAS, Z-spread, I-spread, ASW), bond_cashflows (cash flow schedule), bond_key_rates (key rate durations and risks), bond_curve (multi-bond relative value comparison)
  • Options analytics module (xbbg.ext.options): 6 new functions and 5 enums for equity option analytics — option_info (contract metadata), option_greeks (Greeks and implied volatility), option_pricing (value decomposition and activity), option_chain (chain via CHAIN_TICKERS with overrides), option_chain_bql (chain via BQL with rich filtering), option_screen (multi-option comparison). Enums: PutCall, ChainPeriodicity, StrikeRef, ExerciseType, ExpiryMatch
  • CDX analytics (xbbg.ext.cdx): 8 new functions for credit default swap index analytics — cdx_info, cdx_defaults, cdx_pricing, cdx_risk, cdx_basis, cdx_default_prob, cdx_cashflows, cdx_curve. cdx_pricing/cdx_risk support CDS_RR recovery rate override
  • YieldType expanded: Added YTW (Yield to Worst), YTP (Yield to Put), CFY (Cash Flow Yield) to YieldType enum
  • workout_dt parameter for yas(): Workout date for yield-to-worst/call calculations, maps to YAS_WORKOUT_DT Bloomberg override. Accepts str (YYYYMMDD) or datetime
  • tz parameter for bdib()/abdib(): Controls output timezone for intraday bar data. Defaults to None (exchange local timezone, matching v0.7.x behavior). Set tz='UTC' to keep UTC timestamps, or pass any IANA timezone string (e.g., 'Europe/London')
  • exchange_tz() helper: Returns the IANA timezone string for any Bloomberg ticker (e.g., blp.exchange_tz('AAPL US Equity') -> 'America/New_York'). Exported via blp.exchange_tz()
  • LONG_TYPED output format: New _to_long_typed() function produces typed value columns (value_f64, value_i64, value_str, value_bool, value_date, value_ts) with exactly one populated per row based on the Arrow type of each field
  • LONG_WITH_METADATA output format: New _to_long_with_metadata() function produces (ticker, date, field, value, dtype) where value is stringified and dtype contains the Arrow type name (e.g. double, int64, string)
  • CI non-ASCII source check: New auto_ci.yml step rejects non-ASCII characters in Python source files (allows CJK for ticker tests)
  • Comprehensive test coverage: 55+ new tests including bond analytics (7), CDX analytics (8), options analytics, timezone conversion (13), ovrds dict normalization (7), _events_to_table() (16), bdtick format variants (5), mixed-type BDP (2), and output format tests (12)
  • Unified I/O layer: All Bloomberg requests now flow through a single arequest() async entry point in conn.py, replacing scattered session/service management across modules (#218)
  • Futures resolution uses FUT_CHAIN_LAST_TRADE_DATES (#223): Replaced manual candidate generation (FUT_GEN_MONTH + batch bdp) with Bloomberg-native FUT_CHAIN_LAST_TRADE_DATES via single bds() call. ~2x faster (0.25-0.30s vs 0.53-0.72s)
  • sync_api decorator: Replaces 13 hand-written sync wrappers across API modules (screening.py, historical.py, intraday.py, etc.) with a single sync_api(async_fn) call
  • Table-driven deprecation wrappers: 23 manual wrapper functions in blp.py replaced by dict + loop pattern; 24 warn_* functions in deprecation.py replaced by _DEPRECATION_REGISTRY + get_warn_func() lookup
  • Market session rules extracted to TOML (markets/config/sessions.toml): All MIC and exchange code rules moved from sessions.py into data-driven TOML config, reducing sessions.py from 364 to 168 lines (54% reduction)
  • Pipeline factory registry (pipeline_factories.py): Centralized factory dispatch replaces scattered conditionals
  • CDX ticker format corrected: Version is now a separate space-delimited token (e.g., CDX HY CDSI S45 V2 5Y Corp instead of S45V2)
  • tomli conditional dependency added: tomli>=2.0.1 for Python < 3.11 (TOML parsing for sessions.toml)
  • Net reduction of ~1,346 lines across 27 files from codegen and table-driven optimizations
  • xbbg/io/db.py: SQLite database helper module (zero imports across codebase) (#218)
  • xbbg/io/param.py: Legacy parameter/configuration module (zero imports across codebase) (#218)
  • xbbg/io/files.py: File path utility module (zero imports after replacing 6 usages in cache.py and const.py with pathlib.Path) (#218)
  • regression_testing/: Standalone v0.7.7 regression test directory; all scenarios covered by test_live_endpoints.py (#218)
  • MONTH_CODE_MAP and futures candidate generation helpers: Superseded by FUT_CHAIN_LAST_TRADE_DATES chain resolution (#223)
  • Stale files: pmc_cache.json, xone.db, empty __init__ files, test_param.py (#218)
  • bdtick format parameter was completely non-functional: All five output formats (LONG, SEMI_LONG, WIDE, LONG_TYPED, LONG_WITH_METADATA) were broken due to MultiIndex column wrapping, killed index name, and mixed-type Arrow conversion errors
  • bdib timezone regression: The Arrow pipeline rewrite (v0.11.0) dropped the UTC-to-exchange local timezone conversion that existed in v0.7.x. Restored with configurable tz parameter
  • ArrowInvalid on multi-field BDP calls: Bloomberg returns different Python types for different fields. New _events_to_table() builds Arrow tables with automatic type coercion fallback (#219)
  • create_request crashed when ovrds passed as dict: Now normalizes dict to list of tuples before iteration (SO#79880156)
  • Case-sensitive backend and format parameters: Added _missing_ classmethod to Backend and Format enums for case-insensitive lookup (#221)
  • Mock session leak in tests: Added autouse _reset_session_manager fixture to prevent MagicMock persistence across test modules (#213)
  • interval parameter leaked as Bloomberg override: Added to PRSV_COLS so it stays local (#145)
  • StrEnum Python 3.10 compatibility: Added polyfill for Python < 3.11
  • Non-ASCII characters in source: Replaced with ASCII equivalents for CI compliance
  • Bump cryptography from 46.0.4 to 46.0.5: Fixes CVE-2026-26007 (#217)
  • Bond analytics module (xbbg.ext.bonds): 6 new functions for fixed income analytics — bond_info (reference metadata and ratings), bond_risk (duration, convexity, DV01), bond_spreads (OAS, Z-spread, I-spread, ASW), bond_cashflows (cash flow schedule), bond_key_rates (key rate durations and risks), bond_curve (multi-bond relative value comparison)
  • Options analytics module (xbbg.ext.options): 6 new functions and 5 enums for equity option analytics — option_info (contract metadata), option_greeks (Greeks and implied volatility), option_pricing (value decomposition and activity), option_chain (chain via CHAIN_TICKERS with overrides), option_chain_bql (chain via BQL with rich filtering), option_screen (multi-option comparison). Enums: PutCall, ChainPeriodicity, StrikeRef, ExerciseType, ExpiryMatch
  • CDX analytics (xbbg.ext.cdx): 8 new functions for credit default swap index analytics — cdx_info, cdx_defaults, cdx_pricing, cdx_risk, cdx_basis, cdx_default_prob, cdx_cashflows, cdx_curve. cdx_pricing/cdx_risk support CDS_RR recovery rate override
  • YieldType expanded: Added YTW (Yield to Worst), YTP (Yield to Put), CFY (Cash Flow Yield) to YieldType enum
  • workout_dt parameter for yas(): Workout date for yield-to-worst/call calculations, maps to YAS_WORKOUT_DT Bloomberg override. Accepts str (YYYYMMDD) or datetime
  • tz parameter for bdib()/abdib(): Controls output timezone for intraday bar data. Defaults to None (exchange local timezone, matching v0.7.x behavior). Set tz='UTC' to keep UTC timestamps, or pass any IANA timezone string (e.g., 'Europe/London')
  • exchange_tz() helper: Returns the IANA timezone string for any Bloomberg ticker (e.g., blp.exchange_tz('AAPL US Equity') -> 'America/New_York'). Exported via blp.exchange_tz()
  • tz field on DataRequest and RequestBuilder: Propagates timezone control through the pipeline. RequestBuilder gains .tz() builder method
  • CI non-ASCII source check: New auto_ci.yml step rejects non-ASCII characters in Python source files (allows CJK for ticker tests)
  • Live endpoint tests: 7 tests for bond analytics, 8 tests for CDX analytics, plus options analytics coverage in test_live_endpoints.py
  • 13 unit tests for timezone conversion (test_intraday_timezone.py): Covers default exchange tz, explicit UTC, explicit timezone, Japanese equities, empty exchange info, empty tables, column renaming, and DataRequest/RequestBuilder propagation
  • 7 regression tests for ovrds dict normalization (test_overrides.py): Covers dict crash, correct element setting, multiple overrides, list-of-tuples backward compat, and None/empty edge cases
  • Futures resolution uses FUT_CHAIN_LAST_TRADE_DATES (#223): Replaced manual candidate generation (FUT_GEN_MONTH + batch bdp) with Bloomberg-native FUT_CHAIN_LAST_TRADE_DATES via single bds() call. ~2x faster (0.25-0.30s vs 0.53-0.72s). Removed MONTH_CODE_MAP, _get_cycle_months, _construct_contract_ticker
  • sync_api decorator: Replaces 13 hand-written sync wrappers across API modules (screening.py, historical.py, intraday.py, etc.) with a single sync_api(async_fn) call
  • Table-driven deprecation wrappers: 23 manual wrapper functions in blp.py replaced by dict + loop pattern; 24 warn_* functions in deprecation.py replaced by _DEPRECATION_REGISTRY + get_warn_func() lookup
  • Market session rules extracted to TOML (markets/config/sessions.toml): All MIC and exchange code rules moved from sessions.py into data-driven TOML config, reducing sessions.py from 364 to 168 lines (54% reduction)
  • Pipeline factory registry (pipeline_factories.py): Centralized factory dispatch replaces scattered conditionals
  • Wildcard imports in __init__.py files: 9 __init__.py files simplified to use wildcard imports with explicit __all__ lists
  • CDX ticker format corrected: Version is now a separate space-delimited token (e.g., CDX HY CDSI S45 V2 5Y Corp instead of S45V2)
  • tomli conditional dependency added: tomli>=2.0.1 for Python < 3.11 (TOML parsing for sessions.toml)
  • Net reduction of ~1,346 lines across 27 files from codegen and table-driven optimizations
  • update_readme_on_release.yml workflow: Inline changelog in README replaced by link to CHANGELOG.md
  • MONTH_CODE_MAP and futures candidate generation helpers: Superseded by FUT_CHAIN_LAST_TRADE_DATES chain resolution (#223)
  • bdib timezone regression: The Arrow pipeline rewrite (v0.11.0) dropped the UTC-to-exchange local timezone conversion that existed in v0.7.x. Intraday bar timestamps were returned in UTC instead of exchange local time. Restored the conversion in IntradayTransformer.transform() with configurable tz parameter
  • create_request crashed when ovrds passed as dict: create_request(ovrds={"PRICING_SOURCE": "BGN"}) raised ValueError: too many values to unpack because iterating a dict yields keys (strings), not (key, value) tuples. Now normalizes dict to list of tuples before iteration. Also updated type annotation to accept dict[str, Any] (SO#79880156)
  • Case-sensitive backend and format parameters: Backend("POLARS") and Format("WIDE") raised ValueError because enum values are lowercase. Added _missing_ classmethod to both Backend and Format enums for case-insensitive lookup (#221)
  • StrEnum Python 3.10 compatibility: Added StrEnum polyfill in options module for Python < 3.11 where enum.StrEnum does not exist
  • Python 3.10 mock patching: Fixed patch.object() usage for Python 3.10 compatible mock patching in tests by exposing submodules and patching at source
  • Non-ASCII characters in source: Replaced checkmarks, em dashes, and arrows with ASCII equivalents across the codebase for CI compliance
  • Ruff lint errors: Fixed import sorting (I001) and docstring formatting issues
  • 16 unit tests for _events_to_table() (test_events_to_table.py): covers basic contract, mixed-type columns (float+str, int+str, float+date, kitchen sink), null handling, non-uniform dict keys, and pipeline integration (#219)
  • 2 live regression tests for mixed-type BDP (test_live_endpoints.py): test_bdp_mixed_type_fields and test_bdp_mixed_type_multiple_tickers exercise the exact bug scenario with ES1 Index / NQ1 Index using FUT_CONT_SIZE + FUT_VAL_PT (#219)
  • ArrowInvalid on multi-field BDP calls: Bloomberg returns different Python types for different fields (e.g., float for FUT_CONT_SIZE, str for FUT_VAL_PT). When both land in the same Arrow value column, pa.array() raised ArrowInvalid. New _events_to_table() builds Arrow tables directly from event dicts with automatic type coercion fallback — stringify on ArrowInvalid/ArrowTypeError, preserving nulls (#219)
  • Post-transform pa.Table.from_pandas() mixed-type failure: Protected the secondary Arrow conversion (after narwhals transform) with the same stringify fallback for object columns (#219)
  • Async-first architecture: All Bloomberg API functions (bdp, bds, bdh, bdib, bdtick, bql, beqs, bsrch, bqr, bta) now have async counterparts (abdp, abds, abdh, etc.) as the source of truth; sync wrappers delegate via _run_sync() (#218)
  • Unified I/O layer: All Bloomberg requests now flow through a single arequest() async entry point in conn.py, replacing scattered session/service management across modules (#218)
  • Pipeline and process modules: Adapted pipeline_core, process, and request_builder to work with the async arequest() foundation (#218)
  • Top-level async exports: All async API variants (abdp, abds, abdh, abdib, abdtick, abql, abeqs, absrch, abqr, abta) exported from xbbg.blp (#218)
  • IO module cleanup: Removed dead code and fixed type annotations across xbbg/io/ (#218)
  • Test coverage expanded: 571 tests total (up from 543), covering all connection-related GitHub issues and all previously untested paths in conn.py
  • xbbg/io/db.py: SQLite database helper module (zero imports across codebase) (#218)
  • xbbg/io/param.py: Legacy parameter/configuration module (zero imports across codebase) (#218)
  • xbbg/io/files.py: File path utility module (zero imports after replacing 6 usages in cache.py and const.py with pathlib.Path) (#218)
  • xbbg/tests/test_param.py: Tests for deleted param module (7 tests) (#218)
  • xbbg/markets/cached/pmc_cache.json: Stale pandas-market-calendars cache file (pmc dependency removed in v0.11.0) (#218)
  • xbbg/tests/__init__.py, examples/feeds/__init__.py: Empty __init__ files (#218)
  • xbbg/tests/xone.db: Stale SQLite test database (#218)
  • regression_testing/: Standalone v0.7.7 regression test directory (6 files); all 9 test scenarios already covered by xbbg/tests/test_live_endpoints.py with stricter assertions (#218)
  • Mock session leak in tests: Added autouse _reset_session_manager fixture in conftest.py to prevent MagicMock sessions from persisting in the SessionManager singleton across test modules, which caused infinite __getattr___get_child_mock recursion and stack overflow on Windows (#213)
  • interval parameter leaked as Bloomberg override: interval was not in PRSV_COLS, causing it to be sent to Bloomberg as an override field instead of being used locally for bar sizing (#145)
  • README Data Storage section: Clarified that only bdib() (intraday bars) has caching via BarCacheAdapter; all other functions always make live Bloomberg API calls (#215)
  • README async example for Jupyter: Fixed asyncio.run() example that fails in notebooks (which already have a running event loop) by adding await-based and nest_asyncio alternatives (#216)
  • Unused imports in tests: Removed import os from test_intraday_api.py and import pytest from test_logging.py that caused Ruff F401 lint failures in CI
  • Bump cryptography from 46.0.4 to 46.0.5: Fixes CVE-2026-26007 — subgroup attack due to missing validation for SECT binary elliptic curves (#217)
  • bdtick Arrow conversion failure: Object columns containing blpapi.Name instances caused pa.Table.from_pandas() to fail; now stringified before conversion
  • adjust_ccy field name mismatch: Looked for "Last_Price" but bdh returns lowercase "last_price" since v0.11.1, causing KeyError
  • active_futures two failures: Used nw.coalesce() with a column (last_tradeable_dt) not present in SEMI_LONG format, and called .height (not valid on narwhals DataFrame) instead of .shape[0]
  • Live test assertions: Updated 10 tests in test_live_endpoints.py to match WIDE format default (active since v0.7.x)
  • Duplicate port keyword argument: bbg_service() and bbg_session() used .get() to extract port then forwarded **kwargs still containing it, causing TypeError: got multiple values for keyword argument 'port' on non-default ports (e.g., B-Pipe connections) (#212)
  • Session resource leak: clear_default_session() set _default_session = None without calling session.stop(), leaking OS file descriptors over repeated connect/disconnect cycles (#211)
  • Wrong session removed on retry: send_request() retry path called remove_session(port=port) without server_host, always targeting //localhost:{port} even for remote hosts
  • Inconsistent server_host extraction: get_session() / get_service() checked server_host before server, but connect_bbg() did the opposite, causing different code paths to resolve different hosts when both keys were present
  • Resource leak on start failure: connect_bbg() did not stop the session before raising ConnectionError when .start() failed, leaking C++ resources allocated by the Session() constructor
  • Extended multi-backend support: Added 6 new backends matching narwhals’ full backend support:
    • Eager backends: cudf (GPU-accelerated via NVIDIA RAPIDS), modin (distributed pandas)
    • Lazy backends: dask (parallel computing), ibis (portable DataFrame expressions), pyspark (Apache Spark), sqlframe (SQL-based DataFrames)
    • Total: 13 backends (6 eager + 7 lazy)
  • Backend availability checking: New functions to check and validate backend availability with helpful error messages:
    • is_backend_available(backend) - Check if a backend package is installed
    • check_backend(backend) - Check availability with version validation, raises helpful errors
    • get_available_backends() - List all currently available backends
    • print_backend_status() - Diagnostic function showing all backend statuses
  • Format compatibility checking: New functions to validate format support per backend:
    • is_format_supported(backend, format) - Check if a format works with a backend
    • get_supported_formats(backend) - Get set of supported formats for a backend
    • check_format_compatibility(backend, format) - Validate with helpful errors
    • validate_backend_format(backend, format) - Combined validation for API functions
  • xbbg.ext module: New extension module for v1.0 migration containing helper functions that will be removed from blp namespace
    • xbbg.ext.currency - adjust_ccy() for currency conversion
    • xbbg.ext.dividends - dividend() for dividend history
    • xbbg.ext.earnings - earning() for earnings breakdowns
    • xbbg.ext.turnover - turnover() for trading volume
    • xbbg.ext.holdings - etf_holdings(), preferreds(), corporate_bonds() BQL helpers
    • xbbg.ext.futures - fut_ticker(), active_futures() for futures resolution
    • xbbg.ext.cdx - cdx_ticker(), active_cdx() for CDX index resolution
    • xbbg.ext.yas - yas(), YieldType for fixed income analytics
  • New v1.0-compatible import path: from xbbg.ext import dividend, fut_ticker, ... (no deprecation warnings)
  • Pandas removed as required dependency: xbbg.ext modules now use only stdlib datetime and narwhals, making pandas fully optional
  • Backend enum reorganized: Backends now categorized as eager (full API) vs lazy (deferred execution)
  • Format restrictions: WIDE format only available for eager backends (pandas, polars, pyarrow, narwhals, cudf, modin); lazy backends limited to LONG and SEMI_LONG
  • Version requirements updated: Minimum versions now match narwhals requirements (duckdb>=1.0, dask>=2024.1)
  • xbbg/markets/resolvers.py now re-exports from xbbg.ext.futures and xbbg.ext.cdx for backwards compatibility
  • Internal implementations moved to xbbg/ext/ module; old import paths still work with deprecation warnings
  • BDS output format: Restored v0.10.x backward compatibility for bds() output format (#209)
    • Default format='wide' now returns single data column with ticker as index (pandas) or column (other backends)
    • Field column dropped for cleaner output matching v0.10.x behavior
    • Users can opt-in to new 3-column format with format='long'
  • ibis backend: Updated to use ibis.memtable() instead of deprecated con.read_in_memory()
  • sqlframe backend: Fixed import path to use sqlframe.duckdb.DuckDBSession
  • Field names now lowercase: Restored v0.10.x behavior where bdp(), bdh(), and bds() return field/column names as lowercase (#206)
  • Arrow-first pipeline: Complete rewrite of internal data processing using PyArrow for improved performance
  • Multi-backend support: New Backend enum supporting narwhals, pandas, polars, polars_lazy, pyarrow, duckdb
  • Output format control: New Format enum with long, semi_long, wide options
  • bta(): Bloomberg Technical Analysis function for 50+ technical indicators (#175)
  • bqr(): Bloomberg Quote Request function emulating Excel =BQR() for dealer quote data with broker attribution (#22)
  • yas(): Bloomberg YAS (Yield Analysis) wrapper for fixed income analytics with YieldType enum
  • preferreds(): BQL convenience function to find preferred stocks for an equity ticker
  • corporate_bonds(): BQL convenience function to find active corporate bonds for a ticker
  • set_backend(), get_backend(), set_format(), get_format() configuration functions
  • get_sdk_info() as replacement for deprecated getBlpapiVersion()
  • v1.0-compatible exception classes (BlpError, BlpSessionError, BlpRequestError, etc.)
  • EngineConfig dataclass and configure() function for engine configuration
  • Service and Operation enums for Bloomberg service URIs
  • Treasury & SOFR futures support: TY, ZN, ZB, ZF, ZT, UB, TN, SFR, SR1, SR3, ED futures (#198)
  • Comprehensive logging improvements across critical paths with better error traceability
  • CONTRIBUTING.md and CODE_OF_CONDUCT.md for community standards
  • All API functions now accept backend and format parameters
  • Internal pipeline uses PyArrow tables with narwhals transformations
  • Removed pytz dependency (using stdlib datetime.timezone)
  • Intraday cache now includes interval in path (#80) - different bar intervals cached separately (breaking: existing cache will miss)
  • Internal class renames with backward compatible aliases (YamlMarketInfoProviderMetadataProvider)
  • Logging level adjustments: BBG_ROOT not set promoted to WARNING, cache timing demoted to DEBUG
  • connect() / disconnect() - engine auto-initializes in v1.0
  • getBlpapiVersion() - use get_sdk_info() instead
  • lookupSecurity() - will become blkp() in v1.0
  • fieldInfo() / fieldSearch() - will merge into bfld() in v1.0
  • bta_studies() - renamed to ta_studies() in v1.0
  • getPortfolio() - renamed to bport() in v1.0
  • Helper functions (dividend(), earning(), turnover(), adjust_ccy()) moving to xbbg.ext in v1.0
  • Futures/CDX utilities (fut_ticker(), active_futures(), cdx_ticker(), active_cdx()) moving to xbbg.ext in v1.0
  • Trials mechanism: Eliminated retry-blocking system that caused silent failures after 2 failed attempts
  • pandas-market-calendars dependency: Exchange info now sourced exclusively from Bloomberg API with local caching
  • Import without blpapi installed: Fixed AttributeError when importing xbbg without blpapi (#200)
  • Japan/non-US timezone fix for bdib: Trading hours now correctly converted to exchange’s local timezone (#198)
  • stream() field values: Subscribed field values now always included in output dict (#199)
  • Slow Bloomberg fields: TIMEOUT events handled correctly; requests wait for response with slow_warn_seconds warning (#193)
  • Pipeline data types: Preserve original data types instead of converting to strings (#191)
  • Futures symbol parsing: Fixed market_info() to correctly parse symbols like TYH6TY (#198)
  • get_tz() optimization: Direct timezone strings recognized without Bloomberg API call
  • bdtick timezone fix: Pass exchange timezone to fix blank results for non-UTC exchanges (#185)
  • bdtick timeout: Increased from 10s to 2 minutes for tick data requests
  • Extended BDS test date range to 120 days for quarterly dividends
  • Helper functions now work correctly with LONG format output
  • Logging format compliance fixes (G004, G201)
  • Internal class renames with backward compatible aliases (YamlMarketInfoProvider -> MetadataProvider)
  • Trials mechanism: Eliminated retry-blocking system that caused silent failures after 2 failed attempts
  • pandas-market-calendars dependency: Exchange info now sourced exclusively from Bloomberg API with local caching
  • Import without blpapi installed: Fixed AttributeError when importing xbbg without blpapi (#200)
  • Japan/non-US timezone fix for bdib: Bloomberg returns trading hours in EST; now correctly converted to exchange’s local timezone (#198)
  • get_tz() improvement: Direct timezone strings recognized without Bloomberg API call
  • yas(): Bloomberg YAS (Yield Analysis) wrapper for fixed income analytics with YieldType enum (#202)
  • Treasury and SOFR futures support: TY, ZN, ZB, ZF, ZT, UB, TN, SFR, SR1, SR3, ED futures (#198)
  • stream() field values: Subscribed field values now always included in output dict (#199)
  • Futures symbol parsing: Fixed market_info() to correctly parse symbols like TYH6 -> TY (#198)
  • bqr(): Bloomberg Quote Request function emulating Excel =BQR() for dealer quote data with broker attribution (#22)
  • Slow Bloomberg fields: TIMEOUT events handled correctly; requests wait for response with slow_warn_seconds warning (#193)
  • Pipeline data types: Preserve original data types instead of converting to strings (#191)
  • preferreds(): BQL convenience function to find preferred stocks for an equity ticker
  • corporate_bonds(): BQL convenience function to find active corporate bonds for a ticker
  • bdtick timezone fix: Pass exchange timezone to fix blank results for non-UTC exchanges (#185)
  • bdtick timeout: Increased from 10s to 2 minutes for tick data requests
  • Arrow-first pipeline: Complete rewrite of data processing using PyArrow internally
  • Multi-backend support: New Backend enum supporting narwhals, pandas, polars, polars_lazy, pyarrow, duckdb
  • Output format control: New Format enum with long, semi_long, wide options
  • bta(): Bloomberg Technical Analysis function for 50+ technical indicators
  • set_backend(), get_backend(), set_format(), get_format() configuration functions
  • get_sdk_info() as replacement for deprecated getBlpapiVersion()
  • v1.0-compatible exception classes (BlpError, BlpSessionError, etc.)
  • EngineConfig dataclass and configure() function
  • Service and Operation enums for Bloomberg service URIs
  • All API functions now support backend and format parameters
  • Internal pipeline uses PyArrow tables with narwhals transformations
  • Removed pytz dependency (using stdlib datetime.timezone)
  • connect() / disconnect() - engine auto-initializes in v1.0
  • getBlpapiVersion() - use get_sdk_info()
  • lookupSecurity() - will become blkp() in v1.0
  • fieldInfo() / fieldSearch() - will merge into bfld() in v1.0
  • Re-enabled futures and CDX resolver tests
  • Updated live endpoint tests for LONG format output
  • Code style improvements using contextlib.suppress instead of try-except-pass
  • Extended BDS test date range to 120 days for quarterly dividends
  • Helper functions now work correctly with LONG format output
  • CI/CD improvements with reusable workflows (workflow_call) for release automation
  • Separated pypi_upload workflow for trusted publisher compatibility
  • Trigger release workflows via release event instead of workflow_dispatch
  • Removed Gitter badge (replaced by Discord)
  • Added Discord community link and badge
  • Persist blp.connect() session for subsequent API calls (#165)
  • Updated polars-bloomberg support for BQL, BDIB and BSRCH (#155)
  • Add identifier type prefix to B-Pipe subscription topics (#156)
  • Remove pandas version cap to support Python 3.14 (#161)
  • Resolve RST formatting warning in index.rst (#162)
  • Update Japan equity market hours for TSE trading extension (#163)
  • Add blank lines around latest-release markers in index.rst
  • Remove redundant release triggers from workflows
  • Trigger release workflows explicitly from semantic_version
  • Fix BQL returning only one row for multi-value results (#152)
  • Add etf_holdings() function for retrieving ETF holdings via BQL (#147)
  • Add multi-day support to bdib() (#148)
  • Add multi-day cache support for bdib() (#149)
  • Resolve RST duplicate link targets and Sphinx build warnings
  • Fix BQL options chain metadata issues (#146)
  • CI/CD workflow improvements for trusted publisher compatibility
  • bsrch(): Bloomberg SRCH queries for fixed income, commodities, and weather data (#137)
  • Fixed income securities support: ISIN/CUSIP/SEDOL identifiers for bdib (#136)
  • Server host parameter: Connect to remote Bloomberg servers via server parameter (#138)
  • Interval parameter for subscribe()/live(): Configurable update intervals for real-time feeds
  • Semantic versioning workflow for automated releases
  • Support for GY (Xetra), IM (Borsa Italiana), and SE (SIX) exchanges (#140)
  • Comprehensive bar interval selection guide for bdib function
  • Comprehensive codebase cleanup and restructuring (#144)
  • Improved logging with blpapi integration and performance optimizations (#135)
  • Enhanced BEQS timeout handling with configurable timeout and max_timeouts parameters
  • Updated README with comparison table, quickstart guide, and examples
  • Fix BQL syntax documentation and error handling (#141, #142)
  • Remove 1-minute offset for bare session names in bdtick (#139)
  • Resolve Sphinx build errors and RST formatting issues
  • Comprehensive codebase cleanup and restructuring (#144)
  • Fix BQL syntax documentation and error handling (#141, #142)
  • BQL support: Bloomberg Query Language with QueryRequest and result parsing
  • Sub-minute intervals for bdib: 10-second bars via intervalHasSeconds=True flag
  • bsrch(): Bloomberg SRCH queries for fixed income, commodities, and weather data (#137)
  • Fixed income securities support: ISIN/CUSIP/SEDOL identifiers for bdib (#136)
  • Server host parameter: Connect to remote Bloomberg servers via server parameter (#138)
  • Interval parameter for subscribe()/live(): Configurable update intervals for real-time feeds
  • Support for GY (Xetra), IM (Borsa Italiana), and SE (SIX) exchanges (#140)
  • Standardized Google-style docstrings across codebase
  • Migrate to uv for development with PEP 621 pyproject.toml
  • Improved logging with blpapi integration and performance optimizations (#135)
  • Enhanced BEQS timeout handling with configurable timeout and max_timeouts parameters
  • Remove 1-minute offset for bare session names in bdtick (#139)
  • BQL support: Bloomberg Query Language with QueryRequest and result parsing
  • Sub-minute intervals for bdib: 10-second bars via intervalHasSeconds=True flag
  • pandas-market-calendars integration for exchange session resolution
  • Standardized Google-style docstrings across codebase
  • Migrate to uv for development with PEP 621 pyproject.toml
  • Switch to PyPI Trusted Publishing (OIDC)
  • Exclude tests from wheel and sdist distributions
  • Fix BQL to use correct service name and handle JSON response format
  • Normalize UX* Index symbols; fix pandas ‘M’ deprecation to ‘ME’ in fut_ticker
  • Enhanced Bloomberg connection handling with alternative connection methods
  • Market resolvers for active futures and CDX tickers
  • Replace flake8 with ruff for linting
  • Update Python version requirements and dependencies
  • Clean up CI workflows and documentation
  • Add exchanges support
  • CI/CD configuration updates
  • Corrected typo (thanks to @ShiyuanSchonfeld)
  • Pin pandas version due to pd.to_datetime behaviour change in format_raw
  • Fix TLS Options typo when creating a new connection
  • Additional exchanges support (#83)
  • CI/CD configuration improvements
  • Custom config usage in bdib (contributed by @hceh)
  • Options in blp.live (contributed by @swiecki)
  • Pandas options handling in doctest
  • CI/CD configuration updates
  • Pandas options handling in doctest
  • Typo fix
  • Custom config and reference exchange support (contributed by @hceh)
  • Options in blp.live (contributed by @swiecki)
  • Log folder creation handling
  • Alternative connection method support
  • Custom session argument for Bloomberg connections
  • bdtick with custom time range support
  • Update asset universe
  • Exchange info corrections
  • No manual conversion of timezones
  • BDS fix for edge cases
  • blpapi install URL correction
  • Log folder creation bug
  • Update asset universe
  • Exchange info corrected
  • No manual conversion of timezones
  • bdtick with custom time range support
  • Bug fixes for BDS and blpapi install URL
  • Alternative connection method
  • Add sess as argument for custom Bloomberg session
  • Currency adjusted turnover function
  • Useful fields for live feeds
  • More examples in documentation
  • Standardize IO operations
  • Log levels adjustment
  • Replace os.path with pathlib
  • Performance function improvements
  • Default args of live feeds
  • CCY adjust fix
  • Bug in finding exchange info
  • Log levels adjustment
  • New methods included in __all__
  • CCY adjust fix
  • Currency adjusted turnover function
  • Currency adjusted turnover function
  • Fix bug in finding exchange info
  • Default args of live feeds
  • Logo image for project branding
  • Use async for live data feeds
  • Speed up by caching files
  • Change logic of exchange lookup and market timing
  • Push all values from live subscription
  • Support for Python 3.8
  • Proper caching implementation
  • bdh preserves column orders (both tickers and flds)
  • timeout argument is available for all queries
  • bdtick usually takes longer to respond - can use timeout=1000 for example if keep getting empty DataFrame
  • Add flexibility to use reference exchange as market hour definition
  • No longer necessary to add .yml for new tickers, provided that the exchange was defined in /xbbg/markets/exch.yml
  • Switch CI from Travis to GitHub Actions
  • Tick data availability via bdtick()
  • Speed improvements by removing intermediate layer of generator for processing Bloomberg responses
  • Rewritten library to add subscription, BEQS, simplify interface and remove dependency of pdblp
  • Remove PyYAML dependency due to security vulnerability
  • Add adjust argument in bdh for easier dividend / split adjustments