Fixed income
YAS, bond analytics, preferreds, corporate bonds, and BQR.
Analytics recipes
xbbg.ext packages workflows such as futures rolls, CDX series resolution, volatility surfaces, index constituents, and ETF NAV lookups. Most run as shared Rust recipes, so Python and Node.js return the same columns and raise the same errors.
WARNING
Recipes make ordinary Bloomberg requests and need the matching licenses and entitlements.
from xbbg import ext
members = ext.index_members("SPX Index", asof="2024-01-02")
active = ext.active_futures("ES1 Index", "2024-01-15")
surface = ext.vol_surface("SPX Index", start_date="2024-01-02", end_date="2024-01-05")
resolved = ext.resolve_isins(["US0378331005", "INVALIDISIN000"])xbbg.ext. Recipes are not re-exported from xbbg.blp; in 1.8.0 blp.index_members(...), blp.active_futures(...), blp.vol_surface(...), and blp.resolve_isins(...) raise AttributeError. Technical analysis is not part of xbbg.ext: call xbbg.bta (also available as xbbg.blp.bta).a-prefixed async twin, such as ext.aindex_members. Sync helpers work in scripts and in Jupyter, VS Code Interactive, and marimo; inside any other running event loop they raise RuntimeError naming the async function to await (see Async).backend= (Output backends). Resolvers such as fut_ticker return a str.ticker by default, or security with configure(key_column="security") or Engine(key_column="security"). Since 1.8.0, results keyed by ticker emit a FutureWarning, because the next major release makes security the default. The column names in the tables below use the default.dividend, earnings, turnover, etf_holdings, fut_ticker, active_futures, and convert_ccy forward request options such as overrides (including ovr() specs), validate_fields, field_types, return_eids, and Bloomberg override keywords to every request they make. dividend_yield, futures_curve, vol_surface, index_members, resolve_isins, issuer_isins, etf_nav_relationships, etf_nav_snapshot, and etf_nav_history take only their documented arguments and silently ignore other keywords. The CDX analytics and option helpers pass extra keywords to bdp, bds, or bql.BlpError subclasses as request APIs, invalid arguments raise ValueError, and incomplete or inconsistent Bloomberg data raises RuntimeError (Errors and warnings).Bond, YAS, preferred, corporate-bond, and BQR helpers are covered in Fixed income, and the auction helpers in Exchange auctions.
| Area | Helpers | Implementation |
|---|---|---|
| Historical | dividend, dividend_yield, earnings, turnover, etf_holdings | Native recipes |
| ETF NAV and iNAV | etf_nav_relationships, etf_nav_snapshot, etf_nav_history, subscribe_etf_inav | Native recipes, then a subscription |
| Futures | fut_ticker, active_futures, futures_curve | Native recipes |
| CDX series | cdx_ticker, active_cdx | Native recipes |
| CDX analytics | cdx_info, cdx_defaults, cdx_pricing, cdx_risk, cdx_basis, cdx_default_prob, cdx_cashflows, cdx_curve | bdp field bundles and bds bulk fields |
| Volatility | vol_surface, VolSurfacePreset | Native recipe |
| Indices and identifiers | index_members, resolve_isins, issuer_isins | Native recipes |
| Currency | convert_ccy | Native recipe |
| Options | option_info, option_greeks, option_pricing, option_chain, option_chain_bql, option_screen, and enums | bdp, bds, and BQL |
| Technical analysis | xbbg.bta, ta_studies, ta_study_params, generate_ta_stubs | //blp/tasvc studies |
The async names are the same with an a prefix: adividend, aetf_nav_history, asubscribe_etf_inav, afut_ticker, aactive_cdx, acdx_pricing, avol_surface, aconvert_ccy, aoption_chain_bql, xbbg.abta, and so on.
from xbbg import ext
dividends = ext.dividend("AAPL US Equity", start_date="2023-01-01", end_date="2023-12-31")
splits = ext.dividend(["AAPL US Equity", "NVDA US Equity"], "split")
trailing = ext.dividend_yield("AAPL US Equity", start_date="2024-01-02", end_date="2024-06-28")
geo_revenue = ext.earnings("AAPL US Equity", by="Geo", typ="Revenue")
traded_value = ext.turnover(["AAPL US Equity", "VOD LN Equity"], start_date="2024-01-02", end_date="2024-01-31")
holdings = ext.etf_holdings("SPY US Equity")dividend(tickers, typ="all", *, start_date=None, end_date=None, **kwargs) returns dividend or split bulk history with Bloomberg's own sub-field labels (for example Declared Date and Dividend Amount) for every security you pass. typ is a Bloomberg bulk field name or one of these aliases:
typ | Bulk field | typ | Bulk field |
|---|---|---|---|
all | DVD_Hist_All | adj_fund | Eqy_DVD_Adj_Fund |
dvd | DVD_Hist | with_amt | DVD_Hist_All_with_Amt_Status |
split | Eqy_DVD_Hist_Splits | dvd_amt | DVD_Hist_with_Amt_Status |
gross | Eqy_DVD_Hist_Gross | gross_amt | DVD_Hist_Gross_with_Amt_Stat |
adjust | Eqy_DVD_Adjust_Fact | projected | BDVD_Pr_Ex_Dts_DVD_Amts_w_Ann |
dividend_yield(tickers, *, start_date, end_date, dividend_types=None, window_days=365, backend=None) computes trailing realized dividends and yield from DVD_HIST_ALL and PX_LAST. Columns: ticker, date, dividend_amount, trailing_dividend_amount, price, dividend_yield, dividend_type, declared_date, record_date, and payable_date. dividend_types keeps only the listed Bloomberg dividend types; window_days (at least 1) sets the trailing window.
earnings(ticker, by="Geo", typ="Revenue", *, ccy=None, level=None, year=None, periods=None, **kwargs) returns earnings breakdowns with adjacent percentage columns. by is Geo, Product, Q, or A; typ is Revenue, Operating_Income, Assets, Gross_Profit, Capital_Expenditures, IS, BS, or CF (an optional PG_ prefix is accepted); level is 1 or 2; year and periods of 0 omit the override. Other values raise ValueError.
turnover(tickers, *, start_date=None, end_date=None, ccy="USD", factor=1e6, **kwargs) returns traded value in TURNOVER columns with Date32 dates. Securities without Bloomberg TURNOVER fall back to EQY_WEIGHTED_AVG_PX × VOLUME. Values are converted to ccy ("local" skips conversion) and then divided by factor (millions by default; it must be finite and nonzero). end_date defaults to yesterday and start_date to 30 days before end_date.
etf_holdings(etf_ticker, *, fields=None, **kwargs) runs a BQL holdings query that requests id_isin, weights, and id().position plus any extra fields, and returns the columns as BQL labels them. A bare ticker such as "SPY" is completed to SPY US Equity.
The ETF recipes follow Bloomberg's own ETF_NAV_TICKER and ETF_INAV_TICKER relationships instead of guessing ticker suffixes, normalize each target to end in a single Index yellow key, and check that it is a genuine Index security. NAV and iNAV are independently nullable.
import asyncio
from xbbg import ext
# QQQ US Equity -> QQQNV Index / QXV Index; AT1 LN Equity -> no daily NAV / AT1IN Index
relationships = ext.etf_nav_relationships(["QQQ US Equity", "AT1 LN Equity"])
# Mapped Index targets price with PX_LAST; AT1's missing daily NAV falls back to the
# fund's FUND_NET_ASSET_VAL (see nav_source_ticker / nav_source_field on each row)
history = ext.etf_nav_history(["QQQ US Equity", "AT1 LN Equity"], start_date="2026-06-01", end_date="2026-07-01")
async def first_inav_update() -> None:
sub = await ext.asubscribe_etf_inav("QQQ US Equity") # subscribes QXV Index, LAST_PRICE
try:
async for table in sub:
print(table.to_pylist())
break
finally:
await sub.unsubscribe()
asyncio.run(first_inav_update())| Helper | Returns |
|---|---|
etf_nav_relationships(etfs, *, backend=None) | input_order, etf_ticker, then nav_ticker, nav_market_sector_des, nav_name, nav_validation_error and the same four inav_* columns |
etf_nav_snapshot(etfs, *, backend=None) | input_order, etf_ticker, nav_ticker, nav_value, nav_source_ticker, nav_source_field, inav_ticker, inav_value |
etf_nav_history(etfs, *, start_date, end_date, backend=None) | The snapshot columns plus a Date32 date, one row per day, both dates inclusive |
subscribe_etf_inav(etfs, fields="LAST_PRICE", *, raw=False, all_fields=False, backend=None, options=None, conflate=False, tick_mode=False, flush_threshold=None, stream_capacity=None, overflow_policy=None, output=None) | A Subscription on the resolved iNAV tickers |
subscribe_etf_inav validates every mapping before it subscribes and raises ValueError for an empty input, duplicate ETFs, or a missing, invalid, or ambiguous iNAV relationship. Its topics are the iNAV tickers, so add() and remove() expect iNAV tickers, not ETFs. See Streaming for the subscription options.
from xbbg import ext
contract = ext.fut_ticker("ES1 Index", "2024-01-15") # "ESH24 Index"
active = ext.active_futures("CL1 Comdty", "2024-02-14")
quarterly = ext.fut_ticker("ES1 Index", "2024-01-15", freq="Q")
curve = ext.futures_curve("CL1 Comdty", asof="2024-01-15", max_contracts=12)fut_ticker(gen_ticker, dt, **kwargs) resolves a generic ticker to the specific contract for a date. Generated candidates are checked by LAST_TRADEABLE_DT first; when that window cannot supply the contract, Bloomberg's historical FUT_CHAIN_LAST_TRADE_DATES chain (with CHAIN_DATE=dt) is used. Contracts expiring on or before dt are excluded. freq="Q" or "QE" generates quarterly candidates; the default is monthly.
active_futures(ticker, dt, **kwargs) returns Bloomberg's FUT_CUR_GEN_TICKER mapping when it has one. Otherwise it resolves the front and second contracts, keeps the front before its maturity month, and within that month compares each contract's latest non-null VOLUME over a 10-calendar-day window; ties or no observations keep the front. The input must be generic (ES1, not ESH24), or ValueError is raised.
futures_curve(gen_ticker, *, asof=None, chain_field=None, fields=None, max_contracts=None, backend=None) builds the chain from FUT_CHAIN_LAST_TRADE_DATES (or chain_field), as of asof through the CHAIN_DATE override, and prices each contract. Columns: source_ticker, contract_ticker, generic_number, px_bid, px_ask, last_tradeable_dt, mid, and annualized_carry; extra fields follow as text columns.
from xbbg import ext
series = ext.cdx_ticker("CDX IG CDSI GEN 5Y Corp", "2020-06-01") # "CDX IG CDSI S34 V1 5Y Corp"
legacy = ext.cdx_ticker("CDX IG CDSI GEN 5Y Corp", "2020-06-01", versionless=True)
# S45: S46 started accruing on 2026-03-20 but first printed on 2026-03-27
traded = ext.active_cdx("CDX HY CDSI GEN 5Y Corp", "2026-03-24", lookback_days=10)
pricing = ext.cdx_pricing("CDX IG CDSI GEN 5Y Corp", recovery_rate=40)
curve = ext.cdx_curve("CDX IG CDSI GEN 5Y Corp", tenors=["3Y", "5Y", "10Y"])cdx_ticker(gen_ticker, dt, versionless=False) resolves the series as of dt: the highest series whose CDS_FIRST_ACCRUAL_START_DATE is on or before dt, read from Bloomberg rather than assumed from the roll calendar, so the answer never moves backwards as dt advances. The Vn token is the latest version Bloomberg reports for that series (V1 included); versionless=True drops it for legacy aliases.
active_cdx(gen_ticker, dt, lookback_days=10, versionless=False) matches cdx_ticker except between a roll and the new series' first PX_LAST print, when it returns the previous series. lookback_days is a minimum: the activity window always reaches back to the resolved series' first accrual date.
Neither resolver accepts other keyword arguments (TypeError). They raise ValueError for a non-generic ticker or a date before the index's first series, and RuntimeError when Bloomberg's series metadata is missing or inconsistent, or when neither candidate series printed in the window (active_cdx).
| Analytics helper | Data |
|---|---|
cdx_info(ticker, **kwargs) | bdp of ROLLING_SERIES, VERSION, ON_THE_RUN_CURRENT_BD_INDICATOR, CDS_FIRST_ACCRUAL_START_DATE, NAME, NUM_CURRENT_COMPANIES_CCY_TKR, NUM_ORIG_COMPANIES_CRNCY_TKR, PX_LAST |
cdx_pricing(ticker, *, recovery_rate=None, **kwargs) | bdp of PX_LAST, PX_BID, PX_ASK, UPFRONT_LAST, UPFRONT_BID, UPFRONT_ASK, CDS_FLAT_SPREAD, UPFRONT_FEE, PV_CDS_PREMIUM_LEG, PV_CDS_DEFAULT_LEG |
cdx_risk(ticker, *, recovery_rate=None, **kwargs) | bdp of SW_CNV_BPV, SW_EQV_BPV, CDS_SPREAD_MID_MODIFIED_DURATION, CDS_SPREAD_MID_CONVEXITY, RECOVERY_RATE_SEN, CDS_RECOVERY_RT |
cdx_basis(ticker, **kwargs) | bdp of CDS_INDEX_INTRINSIC_VALUE, CDS_INDEX_INTRINSIC_BASIS_VALUE, CDS_IDX_DUR_BASED_INTRINSIC_VAL, CDS_INDEX_DUR_BASED_BASIS_VAL, PX_LAST |
cdx_defaults(ticker, **kwargs) | bds of CDS_INDEX_DEFAULT_INFORMATION |
cdx_default_prob(ticker, **kwargs) | bds of CDS_DEFAULT_PROB |
cdx_cashflows(ticker, **kwargs) | bds of CASHFLOW_SCHEDULE |
cdx_curve(gen_ticker, tenors=None, **kwargs) | bdp across tenors (default 3Y, 5Y, 7Y, 10Y), replacing the tenor token in the ticker |
recovery_rate is a percentage (40 means 40%) sent as the CDS_RR override.
from xbbg import ext
surface = ext.vol_surface(
["SPX Index", "NDX Index"],
start_date="2024-01-02",
end_date="2024-01-31",
preset=[ext.VolSurfacePreset.MONEYNESS_30D, ext.VolSurfacePreset.MONEYNESS_3M],
include_derived=True,
risk_free_rate=0.05,
)vol_surface(tickers, *, start_date, end_date, preset=VolSurfacePreset.MONEYNESS_30D, fields=None, as_decimal=True, include_derived=False, risk_free_rate=None, dividend_yield_field=None, backend=None) returns a tidy historical implied-volatility surface with columns ticker, date, metric, tenor, point_type, point, field, and value.
preset takes a VolSurfacePreset, its string value, or a list: DELTA_1M_2M (25-delta puts and calls at 1M and 2M), MONEYNESS_30D, MONEYNESS_60D, MONEYNESS_3M, MONEYNESS_6M, or MONEYNESS_12M.fields adds custom Bloomberg fields, as names or as a mapping from field name to its metric, tenor, point_type, and point labels.as_decimal=True divides Bloomberg's percent-quoted volatilities and dividend yields by 100.include_derived=True adds spot (PX_LAST) and dividend_yield rows (dividend_yield_field, default EQY_DVD_YLD_12M). With risk_free_rate it also adds risk_free_rate, forward, and discount_factor rows for each tenor; a rate whose absolute value is above 1 is read as a percentage.from xbbg import ext
members = ext.index_members("SPX Index", asof="2024-01-02")
tickers_only = ext.index_members("SPX Index", field="INDX_MEMBERS")
resolved = ext.resolve_isins(["US0378331005", "INVALIDISIN000"])
issuers = ext.issuer_isins(["US037833FB15"])index_members(index, *, field="INDX_MWEIGHT", asof=None, backend=None) reads INDX_MWEIGHT, INDX_MEMBERS, or INDX_MEMBERS3 (other fields raise ValueError). asof is sent as END_DATE_OVERRIDE. Bloomberg's bulk rows come back with the member identifier column renamed to member; other columns keep Bloomberg's labels.
resolve_isins(isins, *, backend=None) looks equity ISINs up through Bloomberg's /ISIN/<id> namespace. Columns: input_order, input_isin, lookup_ticker, parsekyable_des, primary_exchange, resolved_ticker, status (resolved or unresolved), and error. ISINs whose parse key carries another yellow key (Pfd, Corp, Govt, and so on) are unresolved, with the market sector named in error.
issuer_isins(bond_isins, *, backend=None) maps bond ISINs to the issuer's equity ISIN. Columns: input_order, input_isin, lookup_ticker, bond_ticker, parent_ticker, issuer_equity_isin, status, and error.
import xbbg
from xbbg import ext
prices = xbbg.bdh(["VOD LN Equity", "SAP GY Equity"], "PX_LAST", "2024-01-02", "2024-01-31")
in_usd = ext.convert_ccy(prices, ccy="USD")convert_ccy(data, ccy="USD", **kwargs) converts historical data into ccy using each security's CRNCY and daily FX rates. It accepts long data (the key column, ticker or security, plus date and a value column) or wide data whose columns are named by security or security|field, from pandas, Polars, PyArrow, Narwhals, or native results; since 1.8.0, xbbg's default Narwhals results take the direct Arrow path without a warning. Numeric text stays text, integers become Float64, securities already in ccy pass through, and ccy="local" returns the input unchanged. A missing FX rate turns that value into a null; a failed currency or FX request raises instead of returning partly converted data.
from xbbg import ext
calls = ext.option_chain("AAPL US Equity", put_call=ext.PutCall.CALL, strike=ext.StrikeRef.ATM)
puts = ext.option_chain_bql(
"AAPL US Equity",
put_call=ext.PutCall.PUT,
expiry_start="2027-01-01",
expiry_end="2027-03-31",
delta_low=-0.6,
delta_high=-0.4,
min_open_int=1000,
)| Helper | Data |
|---|---|
option_info(ticker, **kwargs) | bdp contract metadata: strike, expiry, exercise type, underlying |
option_greeks(ticker, **kwargs) | bdp Greeks and implied volatility, mid and bid/ask |
option_pricing(ticker, **kwargs) | bdp prices, intrinsic and time value, open interest |
option_chain(underlying, *, put_call=None, expiry_dt=None, strike=None, points=None, periodicity=None, exercise_type=None, expiry_match=None, **kwargs) | bds of CHAIN_TICKERS with chain overrides |
option_chain_bql(underlying, *, put_call=None, expiry_start=None, expiry_end=None, strike_low=None, strike_high=None, ..., get_fields=None, **kwargs) | BQL options() universe filtered by strike, delta, gamma, vega, theta, implied volatility, moneyness, open interest, volume, bid/ask, exchange, exercise type, and extra_filters |
option_screen(tickers, flds=None, **kwargs) | bdp across many option tickers |
The enums are PutCall (CALL, PUT), ChainPeriodicity (WEEKLY, MONTHLY, QUARTERLY, YEARLY, ALL), StrikeRef (ATM), ExerciseType (AMERICAN, EUROPEAN), and ExpiryMatch (EXACT, CLOSEST); the string codes they wrap ("C", "P", "ATM", ...) are accepted too. option_chain_bql requests strike_px(), expire_dt(), ivol(), delta(), open_int(), px_last(), px_bid(), and px_ask() unless you pass get_fields, and forwards other keywords (backend, app_name) to bql.
import xbbg
rsi = xbbg.bta("AAPL US Equity", "rsi", start_date="2024-01-02", end_date="2024-06-28", period=14)
bands = xbbg.bta(["AAPL US Equity", "MSFT US Equity"], "boll", start_date="2024-01-02", end_date="2024-06-28")
print(xbbg.ta_studies()) # ['ado', 'adx', 'al', 'atr', ...]
print(xbbg.ta_study_params("boll")) # {'period': 20, 'upperBand': 2.0, 'lowerBand': 2.0, 'priceSourceClose': 'PX_LAST'}bta(tickers, study, *, start_date=None, end_date=None, periodicity="DAILY", interval=None, **study_params) (async: abta) runs Bloomberg //blp/tasvc studies, one request per security sent concurrently. study is a name from ta_studies() or a Bloomberg ...StudyAttributes name, and study_params override the defaults from ta_study_params(study). periodicity is DAILY, WEEKLY, MONTHLY, or INTRADAY (trade bars of interval minutes, default 60). Pass dates as YYYY-MM-DD or YYYYMMDD strings. The result uses the configured default backend. If some securities fail, each failure is reported as a UserWarning and the others are returned; if all fail, RuntimeError is raised.ta_studies() lists the 54 study names and aliases; ta_study_params(study) returns a study's default parameters (an empty dict for unknown studies).generate_ta_stubs(output_dir=None) reads the //blp/tasvc schema (so it needs a Bloomberg session or a cached schema), writes ta_studies.pyi and ta_studies.py with one TypedDict per study to output_dir (default ~/.xbbg/stubs/), adds that directory to the first existing VS Code, Pyright, or ty configuration it finds in the project (it never creates one), and returns the .pyi path.ticker column emit a FutureWarning; switch with key_column="security". convert_ccy accepts the default Narwhals results directly.dividend keeps Bloomberg's column labels and no longer drops non-equities; etf_holdings keeps the BQL labels instead of renaming columns; turnover returns TURNOVER columns with Date32 dates; convert_ccy raises when a currency or FX request fails instead of returning unconverted data, and missing FX rates become nulls; futures selection is candidate-first with a 10-day volume window.xbbg.ext recipes raise typed BlpError subclasses (BlpTimeoutError, BlpRequestError, BlpValidationError, ...) instead of RuntimeError, so except RuntimeError no longer catches them.cdx_ticker and active_cdx resolve the series as of the requested date (previously they read today's ROLLING_SERIES), raise instead of returning an empty string, no longer accept extra keyword arguments, and treat lookback_days as a minimum.Vn version by default; pass versionless=True for the legacy alias.See the changelog for the full history.
YAS, bond analytics, preferreds, corporate bonds, and BQR.
Venue routing, auction snapshots, and auction streams.
Overrides, ovr(), validation, and sharding.
What recipes raise and how to handle it.