Python fixed income
YAS, BQR, curves, and bond workflows in Python.
Recipes and analytics
Engine methods.Recipes wrap multi-request Bloomberg workflows in the shared Rust recipe layer, the same implementation behind the Python xbbg.ext helpers, and return typed Arrow tables.
WARNING
Recipes send ordinary Bloomberg requests. They need the same connectivity and entitlements as the underlying fields and services.
Engine. They resolve to an Apache Arrow Table by default, or to JSON rows with backend: 'json'. backend: 'polars' rejects with a TypeError before any Bloomberg request.string | readonly string[] accept one security or a list. Dates accept every DateLike input; see Output Formats.BlpError hierarchy, and results keep the Bloomberg RequestIds of every contributing request.keyColumn: ticker by default (deprecated), or security. The tables below use the default name.import { connect } from '@xbbg/core';
const engine = await connect();
// Yield and spread analysis (YAS); yieldType 1 is yield to maturity
const yas = await engine.yas('US912810TM69 Govt', 'YAS_BOND_YLD', {
settleDt: '2024-01-15',
yieldType: 1,
price: 99.5,
});
// Dealer quotes with broker attribution
const quotes = await engine.bqr('US037833FB15@MSG1 Corp', {
startDatetime: '2024-06-03T14:30:00',
endDatetime: '2024-06-03T15:00:00',
});
// Issuer debt through BQL debt() universes
const preferreds = await engine.preferreds('BAC US Equity');
const bonds = await engine.corporateBonds('AAPL', { ccy: 'USD', fields: ['name', 'cpn'] });
// Curve and government security lookups on //blp/instruments
const curves = await engine.bcurves('YCSW0023 Index');
const govts = await engine.bgovts('USD');
console.log(yas, quotes, preferreds, bonds, curves, govts);| Method | Options |
|---|---|
yas(tickers, fields, options) | settleDt, yieldType, spread, yieldVal, price, benchmark, sent as the YAS_SETTLE_DT, YAS_YLD_FLAG, YAS_YLD_SPREAD, YAS_BOND_YLD, YAS_BOND_PX, and YAS_BNCHMRK_BOND overrides |
bqr(ticker, options) | startDatetime, endDatetime, eventTypes (default BID and ASK), includeBrokerCodes (default true) |
preferreds(equityTicker, options) | fields added to the default id and name |
corporateBonds(ticker, options) | ccy filter and extra fields |
bcurves(query), bgovts(query) | kwargs for further request elements |
yieldType is Bloomberg's YAS_YLD_FLAG: 1 yield to maturity, 2 to call, 3 to refunding, 4 to next put, 5 to worst, 6 to worst refunding, 7 Euro yield to worst, 8 Euro yield to worst refunding, 9 to average life. Other values are rejected.bqr returns sorted, normalized quote rows (event_type, price, broker_buy, broker_sell, ...). It fails when Bloomberg returns quotes without the requested broker attribution; pass includeBrokerCodes: false to opt out.preferreds and corporateBonds take a company equity ticker; a bare ticker such as 'AAPL' gets US Equity appended. The corporate-bond activeOnly option was removed in 1.6.0 because it never filtered anything.import { connect } from '@xbbg/core';
const engine = await connect();
const front = await engine.futTicker('ES1 Index', '2024-03-01');
const active = await engine.activeFutures('CL1 Comdty', '2024-03-01', { freq: 'M' });
const curve = await engine.futuresCurve('ES1 Index', { maxContracts: 6 });
// The series on the run on a date, with an explicit version such as V1
const series = await engine.cdxTicker('CDX IG CDSI GEN 5Y Corp', '2024-03-01');
// The latest series that had also traded by that date
const traded = await engine.activeCdx('CDX IG CDSI GEN 5Y Corp', '2024-03-01', { lookbackDays: 10 });
console.log(front, active, curve, series, traded);futTicker resolves a generic future to the specific contract for a date and returns one row holding it in the key column. activeFutures uses Bloomberg's historical FUT_CUR_GEN_TICKER mapping when available, otherwise compares front and next contract volume within the maturity month. freq: 'Q' (or 'QE') selects quarterly candidates; anything else is monthly.futuresCurve(genTicker, { asof, chainField, fields, maxContracts }) builds the futures chain with contract metadata, mid prices, and annualized carry.cdxTicker resolves the series whose CDS_FIRST_ACCRUAL_START_DATE is the latest on or before the date, so results never move backwards as the date advances, and appends the version Bloomberg reports for that series. { versionless: true } returns the legacy alias without the version. activeCdx differs only between a roll and the new series' first trade; lookbackDays (default 10) is a minimum activity window.The fixed CDX field bundles run through bdp on the engine set by configure():
import { CDX_PRICING_FIELDS, configure, ext } from '@xbbg/core';
configure({ host: 'localhost', port: 8194 });
const info = await ext.cdx.acdx_info('CDX IG CDSI GEN 5Y Corp');
const pricing = await ext.cdx.acdx_pricing('CDX IG CDSI GEN 5Y Corp', { recoveryRate: 40 });
const risk = await ext.cdx.acdx_risk('CDX IG CDSI GEN 5Y Corp', { recoveryRate: 40 });
console.log(CDX_PRICING_FIELDS, info, pricing, risk);recoveryRate (or recovery_rate) is a percentage, so 40 means 40%, and is sent as the CDS_RR override. The bundles are exported as CDX_INFO_FIELDS, CDX_PRICING_FIELDS, and CDX_RISK_FIELDS.
import { connect } from '@xbbg/core';
const engine = await connect();
const dividends = await engine.dividend(['AAPL US Equity'], '2023-01-01', '2023-12-31', {
dvdType: 'all',
});
const trailingYield = await engine.dividendYield('AAPL US Equity', '2023-01-01', '2023-12-31', {
dividendTypes: ['Regular Cash'],
});
const turnover = await engine.turnover(['AAPL US Equity'], '2024-01-01', '2024-01-31', {
ccy: 'USD',
});
const holdings = await engine.etfHoldings('SPY US Equity');
const members = await engine.indexMembers('SPX Index', { field: 'INDX_MWEIGHT', asof: '2024-01-02' });
const surface = await engine.volSurface('SPX Index', '2024-01-02', '2024-01-05', {
preset: 'MONEYNESS_30D',
includeDerived: true,
riskFreeRate: 0.05,
});
console.log(dividends, trailingYield, turnover, holdings, members, surface);| Method | Behavior |
|---|---|
dividend(tickers, start, end, { dvdType }) | Bulk dividend or split history with Bloomberg's column labels. dvdType is 'all' (default, DVD_Hist_All), 'dvd', 'split', 'gross', 'adjust', 'adj_fund', 'with_amt', 'dvd_amt', 'gross_amt', 'projected', or a Bloomberg bulk field name |
dividendYield(tickers, start, end, { dividendTypes, windowDays }) | Trailing realized dividends and yield per date over windowDays (default 365), optionally filtered by dividend type |
turnover(tickers, start, end, { ccy, factor }) | TURNOVER by date, falling back to volume times VWAP when Bloomberg has no turnover. ccy converts from local currency, then factor (default 1) scales |
etfHoldings(etfTicker, { fields }) | ETF constituents through BQL, with extra fields |
indexMembers(index, { field, asof }) | Members through INDX_MWEIGHT, INDX_MEMBERS, or INDX_MEMBERS3, as of a date |
volSurface(tickers, start, end, options) | Tidy implied-volatility surface history. preset is 'MONEYNESS_30D' (default), 'MONEYNESS_60D', 'MONEYNESS_3M', 'MONEYNESS_6M', 'MONEYNESS_12M', or 'DELTA_1M_2M', or a list of them; fields adds field names, or { [field]: VolFieldSpec } descriptions, to the preset fields; asDecimal (default true) divides Bloomberg's percent-quoted values by 100; includeDerived (default false) adds derived values using riskFreeRate (absolute values above 1 are read as percent) and dividendYieldField |
import { connect } from '@xbbg/core';
const engine = await connect();
const resolved = await engine.resolveIsins(['US0378331005', 'INVALIDISIN000'], { backend: 'json' });
const issuers = await engine.issuerIsins(['US037833FB15', 'INVALIDISIN000'], { backend: 'json' });
console.log(resolved, issuers);Both keep input order and mark each row resolved or unresolved with an error message. resolveIsins maps equity ISINs to tickers (input_order, input_isin, lookup_ticker, parsekyable_des, primary_exchange, resolved_ticker, status, error); ISINs whose Bloomberg parse key is not an equity, such as preferreds or bonds, are unresolved. issuerIsins maps bond ISINs to the issuer's equity (bond_ticker, parent_ticker, issuer_equity_isin, plus the same identification and status columns).
import { connect } from '@xbbg/core';
const engine = await connect();
// QQQ US Equity -> QQQNV Index (NAV) and QXV Index (iNAV)
const relationships = await engine.etfNavRelationships(['QQQ US Equity', 'AT1 LN Equity']);
const snapshot = await engine.etfNavSnapshot(['QQQ US Equity', 'AT1 LN Equity']);
const history = await engine.etfNavHistory(['QQQ US Equity', 'AT1 LN Equity'], '2026-06-01', '2026-07-01');
// Validates every mapping, then streams LAST_PRICE on the iNAV tickers
const inav = await engine.subscribeEtfInav('QQQ US Equity');
try {
for await (const tick of inav) {
console.log(tick.topic, tick.get('LAST_PRICE'));
break;
}
} finally {
await inav.unsubscribe();
}
console.log(relationships, snapshot, history);etfNavRelationships reads Bloomberg's own ETF_NAV_TICKER and ETF_INAV_TICKER relationships instead of guessing ticker suffixes, normalizes them to Index securities, and validates them. Columns: input_order, etf_ticker, then nav_ticker, nav_market_sector_des, nav_name, nav_validation_error, and the same four for inav_. Either leg can be null.etfNavSnapshot and etfNavHistory return nav_value and inav_value (history adds date). When an ETF has no daily NAV index, the NAV falls back to the fund's FUND_NET_ASSET_VAL; nav_source_ticker and nav_source_field record the source of every row.subscribeEtfInav checks every relationship before opening anything: duplicate inputs, missing or invalid iNAV legs, and iNAV tickers shared by several ETFs reject with BlpValidationError. The stream's topics are the iNAV tickers, so add() and remove() take iNAV tickers. fields defaults to ['LAST_PRICE'].import { connect } from '@xbbg/core';
const engine = await connect();
const usd = await engine.currencyConversion('700 HK Equity', 'USD', '2024-01-01', '2024-01-31');
console.log(usd);currencyConversion requests daily PX_LAST history with Bloomberg's CRNCY override set to the target currency.
Bloomberg publishes imbalance and auction data only on the listing where the auction runs. These helpers route each ticker or ISIN to that venue and check Bloomberg's answer before returning data.
import { AuctionFields, connect, imbalanceSide } from '@xbbg/core';
const engine = await connect();
// SPY US Equity -> SPY UP Equity, IBM US Equity -> IBM UN Equity
const venues = await engine.resolveVenues(['SPY US Equity', 'IBM US Equity', 'US0378331005']);
const snapshot = await engine.auctionSnapshot(['IBM US Equity'], {
fields: [...AuctionFields.imbalance, ...AuctionFields.quotes],
});
const auction = await engine.subscribeAuction(['SPY US Equity', 'IBM US Equity'], {
fields: AuctionFields.default,
onDelayed: 'raise',
});
try {
for await (const tick of auction) {
console.log(tick.topic, imbalanceSide(tick.str('IMBALANCE_INDIC_RT') ?? ''));
break;
}
} finally {
await auction.unsubscribe();
}
console.log(venues, snapshot);resolveVenues(securities, { pcsOverrides }) resolves composite equities and ETFs to their primary listing and preferreds to a validated pricing-source topic, and respects explicit venues. Rows keep input order and duplicates: input_order, security, status (resolved, unresolved, unsupported, or mismatch), error, lookup, kind, composite, venue_topic, venue_figi, method, exch_code, mic, pricing_source.auctionSnapshot(securities, { fields, pcsOverrides }) resolves and validates the venue inside one reference-data request and returns venue_topic plus the requested fields, typed from Bloomberg field metadata. It never falls back to composite data; unresolved and mismatched rows have null data fields.subscribeAuction and streamAuction resolve every input before opening one venue subscription. Unresolved, unsupported, or mismatched inputs, and distinct inputs that land on the same venue, reject with BlpValidationError. Venue topics are aliased to your original strings automatically, so caller-supplied aliases are rejected; add() takes resolved venue topics with aliases and remove() takes your original labels. Only subscribeAuction accepts rows: false for a polled board.AuctionFields holds read-only, stream-valid field groups: imbalance, indicative, state, halts, results, composite, quotes, and default (the first five groups, 39 fields). An empty or omitted fields uses default. AuctionFields.zeroPriceFields lists price fields that use zero as an "unavailable" sentinel; auction subscriptions default zeroAsNull to those fields among the requested ones, so latest() shows null instead of 0.imbalanceSide(code) maps venue imbalance codes, ignoring case and surrounding spaces: BUY, MBUY, RBUY to 'buy'; SELL, MSEL, RSEL to 'sell'; NOIM, NIMB to 'none'; anything else to null.pcsOverrides maps exchange names to preferred pricing sources, for example { 'NEW YORK': 'SNY2' }; every venue is still validated before use.import { BlpRequestError, connect, type ResultMetadata } from '@xbbg/core';
const engine = await connect();
console.log(await engine.seatType()); // 'BPS', 'NONBPS', or 'INVALID'
console.log(await engine.identityIsAuthorized('//blp/mktdata'));
// Entitlement IDs returned with the data, checked against the identity
const ticks = (await engine.bdtick('AAPL US Equity', {
start: '2024-01-15T14:30:00',
end: '2024-01-15T15:00:00',
returnEids: true,
backend: 'json',
})) as Array<Record<string, unknown>> & ResultMetadata;
const eids = [...new Set(Object.values(ticks.eidData ?? {}).flat())];
if (eids.length > 0) {
const report = await engine.checkEntitlements('//blp/refdata', eids);
console.log(report.entitled, report.failedEids);
}
// Delayed-data status per security
const status = await engine.delayStatus(['VOD LN Equity', 'AAPL US Equity'], { backend: 'json' });
console.log(status);
// Refuse delayed snapshots outright
try {
await engine.bdp(['VOD LN Equity'], ['PX_LAST'], { onDelayed: 'raise' });
} catch (error) {
if (error instanceof BlpRequestError) console.error(error.message);
}seatType(), checkEntitlements(service, eids), and identityIsAuthorized(service) authorize lazily with the engine's auth settings, or as the Desktop logon user without them. The first call can take a few seconds, and transient failures can be retried.returnEids: true works on bdp, bds, bdh, bdib, and bdtick; the IDs arrive in eidData on the result container, not in the rows. Bloomberg returns EIDs only for exchanges the requester is entitled to, so a delayed security comes back with none; delayStatus reports its feed EIDs.delayStatus(tickers, { checkIdentity, backend }) is also available as the top-level delayStatus and blp.adelayStatus. It sends one reference-data request and returns one row per unique ticker:| Column | Meaning |
|---|---|
ticker (or security, per keyColumn) | Requested security |
delayed | This session receives delayed data; null when unknown |
delay_minutes | Minutes behind real time; null when real time or unknown |
exchange_delay | Raw EXCHANGE_DELAY text |
exch_code | EXCH_CODE |
realtime_eid1 to realtime_eid4 | FEED_EID1 to FEED_EID4 (Int64, bigint in JS) |
delayed_eid | FEED_DELAYED_EID1 |
realtime_entitled | The identity is entitled to every real-time EID |
delayed_entitled | The identity is entitled to the delayed EID |
error | Bloomberg security error message, else null |
checkIdentity: true fills the two entitlement columns through one //blp/mktdata entitlement check, which needs an authorized identity (SAPI or B-PIPE auth, or an EMRS-enrolled Desktop user). Without it, delayStatus works on any Desktop session. The onDelayed request policy is described in Output Formats.
import { connect } from '@xbbg/core';
const engine = await connect();
const info = await engine.fieldInfo(['PX_LAST', 'VOLUME']);
const found = await engine.fieldSearch('implied volatility');
const types = await engine.resolveFieldTypes(['PX_LAST', 'SECURITY_NAME']);
const unknown = await engine.validateFields(['PX_LAST', 'NOT_A_FIELD']); // names Bloomberg does not recognize
const operations = await engine.bops('//blp/refdata');
const request = await engine.bschema('//blp/refdata', 'HistoricalDataRequest');
const elements = await engine.listValidElements('//blp/refdata', 'HistoricalDataRequest');
const periodicities = await engine.getEnumValues(
'//blp/refdata',
'HistoricalDataRequest',
'periodicitySelection',
);
const screen = await engine.beqs('MyScreen', { asof: '2024-01-02' });
const grid = await engine.bsrch('FI:SOVR');
const rsi = await engine.bta('AAPL US Equity', 'rsi', {
startDate: '2024-01-01',
endDate: '2024-06-30',
studyParams: { period: 9 },
});
const lookup = await engine.blkp('IBM');
console.log(info, found, types, unknown, operations, request, elements, periodicities);
console.log(screen, grid, rsi, lookup);bflds({ fields }) or bflds({ searchSpec }) (also as fieldInfo and fieldSearch), resolveFieldTypes(fields, overrides, defaultType) (resolved Arrow type names keyed by field), getFieldInfo(field) (cached entry only, no request), validateFields(fields), isFieldValidationEnabled(), clearFieldCache(), and saveFieldCache(). fieldInfo() and bflds() results end with an id column holding Bloomberg's field id (for example PR005) next to the canonical field mnemonic; ids Bloomberg refused are keys of the result's fieldErrors map, even when no rows came back.getSchema(service), getOperation(service, operation), listOperations(service) (also bops), bschema(service, operation?), getEnumValues, listValidElements, and the cache controls getCachedSchema, invalidateSchema, clearSchemaCache, and listCachedSchemas.beqs(screen, { asof, screenType, group }) (defaults 'PRIVATE' and 'General'), bsrch(searchSpec, { overrides }), bta(ticker, study, { startDate, endDate, periodicity, interval, studyParams }) (study names such as 'rsi', 'macd', 'boll', 'sma'; daily by default), blkp(query), and bport(portfolio, fields).ext ext holds pure helpers that run in the native addon without contacting Bloomberg, plus the CDX bundles above:
import { ext } from '@xbbg/core';
console.log(ext.parseTicker('ES1 Index')); // { prefix: 'ES', index: 1, asset: 'Index' }
console.log(ext.parseCdxTicker('CDX IG CDSI GEN 5Y Corp')); // { index: 'CDX IG CDSI', series: 'GEN', ... }
console.log(ext.getMarketRule('XNYS')); // { preMinutes: 330, postMinutes: 240, isContinuous: false }
console.log(ext.getDvdTypes()); // dividend type aliases and their Bloomberg fieldsThe API Surface lists every ext helper.
YAS, BQR, curves, and bond workflows in Python.
The same shared recipes through xbbg.ext.
Venue routing, snapshots, and auction boards in Python.
EIDs, identity checks, and delayed data in Python.
These recipes as bounded agent tools.
Bloomberg tools over the Model Context Protocol.