Skip to content

Node.js quickstart

From install to first Bloomberg data.

Connect, request reference, historical, bulk, intraday, and BQL data, choose an output backend, and handle errors with @xbbg/core.

WARNING

Every request needs a reachable Bloomberg endpoint and entitlements for the data requested. The examples use a Desktop API session on localhost:8194.

Install ​

bash
npm install @xbbg/core

@xbbg/core needs Node.js 24+ or Bun 1.4+ and the Bloomberg SDK runtime library; see Installation. The samples use top-level await, so run them as ES modules (.mts files, or "type": "module" in package.json).

Choose how to connect ​

Entry pointReturnsWhen the session starts
configure(config) or configure(host, port)The stored configurationOn the first top-level helper call (bdp, blp.abdh, subscribe, ...), off the event loop
connect(config) or Engine.connect(config)Promise<Engine>Immediately, off the event loop
new Engine(host, port) or Engine.withConfig(config)EngineImmediately, blocking the event loop until the session is up (up to the 30-second session timeout)
  • The top-level helpers share one engine built from the last configure() call. Without configure(), they connect to localhost:8194.
  • configure() only stores settings. Invalid values reject the first helper call that builds the engine. Calling configure() again replaces the shared engine and signals the previous one to shut down.
  • Prefer connect() in servers: the synchronous constructor and withConfig() block the event loop while Bloomberg connects.

Reference, historical, and bulk data ​

ts
import { bdh, bdp, bds, configure } from '@xbbg/core';

configure({ host: 'localhost', port: 8194 });

// Reference data: one row per ticker and field in the default long format
const ref = await bdp(['AAPL US Equity', 'MSFT US Equity'], ['PX_LAST', 'SECURITY_NAME']);

// Historical data
const hist = await bdh('SPX Index', ['PX_LAST', 'PX_VOLUME'], {
  start: '2024-01-01',
  end: '2024-12-31',
});

// Bulk data with a Bloomberg override
const dividends = await bds('AAPL US Equity', 'DVD_Hist_All', {
  overrides: { DVD_Start_Dt: '20240101' },
});

console.log(ref, hist, dividends);

Top-level helpers accept a single string or an array for tickers and fields. Engine methods take arrays.

Results name the column that holds each row's security ticker. That default is deprecated because it collides with Bloomberg's TICKER field once names are case-folded: the first result that uses it emits one DeprecationWarning per process (code XBBG_TICKER_KEY_COLUMN), and the next major release makes security the default. Switch now with configure({ keyColumn: 'security' }) or connect({ keyColumn: 'security' }).

Intraday bars and ticks ​

ts
import { bdib, bdtick } from '@xbbg/core';

// 5-minute TRADE bars; naive datetimes are read in New York time
const bars = await bdib('AAPL US Equity', {
  start: '2024-12-02T09:30:00',
  end: '2024-12-02T16:00:00',
  interval: 5,
  requestTz: 'America/New_York',
});

// Trades and quotes for five minutes
const ticks = await bdtick('AAPL US Equity', {
  start: '2024-12-02T09:30:00',
  end: '2024-12-02T09:35:00',
  eventTypes: ['TRADE', 'BID', 'ASK'],
  requestTz: 'America/New_York',
});

console.log(bars, ticks);

bdib defaults to 1-minute TRADE bars and bdtick to TRADE events. Naive datetimes are read as UTC unless requestTz is set, and the returned time column is UTC unless outputTz is set. Output Formats lists the accepted date inputs and time zone labels.

The blp namespace ​

blp groups the top-level helpers and adds Python-style positional forms:

ts
import { blp } from '@xbbg/core';

const hist = await blp.abdh(['SPX Index'], ['PX_LAST'], '2024-01-01', '2024-12-31');
const bars = await blp.abdib('AAPL US Equity', '2024-12-02', 5); // whole day of 5-minute bars
const ticks = await blp.abdtick('AAPL US Equity', '2024-12-02T14:30:00', '2024-12-02T14:31:00');
const bulk = await blp.abds('AAPL US Equity', 'DVD_Hist_All', { DVD_Start_Dt: '20240101' });

console.log(hist, bars, ticks, bulk);
Positional formEquivalent
abdh(tickers, fields, start, end, options)bdh(tickers, fields, { ...options, start, end })
abds(tickers, fields, overrides, options)bds(tickers, fields, { ...options, overrides })
abdib(ticker, dt, interval, options)bdib(ticker, { ...options, interval }) over the calendar day dt, 00:00:00 to 23:59:59 in the request time zone
abdtick(ticker, start, end, options)bdtick(ticker, { ...options, start, end })

abdp, asubscribe, and adelayStatus take the same arguments as bdp, subscribe, and delayStatus. BQL has no top-level helper; call it on an Engine.

Overrides and request options ​

ts
import { bdh, bdp, ovr } from '@xbbg/core';

// The same override for every security
const eur = await bdp('AAPL US Equity', 'CRNCY_ADJ_PX_LAST', {
  overrides: ovr({ EQY_FUND_CRNCY: 'EUR' }),
});

// A default plus per-security overrides
const mixed = await bdp(['AAPL US Equity', 'MSFT US Equity'], 'CRNCY_ADJ_PX_LAST', {
  overrides: ovr({
    EQY_FUND_CRNCY: 'USD',
    'AAPL US Equity': ovr({ EQY_FUND_CRNCY: 'EUR' }),
    'MSFT US Equity': ovr({ EQY_FUND_CRNCY: 'JPY' }),
  }),
});

// Raw Bloomberg request elements go in kwargs
const weekly = await bdh('SPX Index', 'PX_LAST', {
  start: '2024-01-01',
  end: '2024-06-30',
  kwargs: { periodicitySelection: 'WEEKLY' },
});

console.log(eur, mixed, weekly);
  • overrides accepts a plain object, an array of [key, value] entries, or an OverrideSpec built with ovr(). ovr() merges its arguments left to right, later keys win, and Date values become YYYYMMDD.
  • A key whose value is another object or ovr() spec names a security and scopes those overrides to it. Per-security overrides work with bdp, bdh, and bds; beqs, bsrch, and bport reject them with a TypeError.
  • kwargs sets request elements that have no typed option, such as periodicitySelection or maxDataPoints.

Use an Engine ​

ts
import { connect } from '@xbbg/core';

const engine = await connect({ host: 'localhost', port: 8194 });

const ref = await engine.bdp(['AAPL US Equity'], ['PX_LAST']);
const bql = await engine.bql("get(px_last) for('AAPL US Equity')");
const fields = await engine.fieldSearch('vwap');

console.log(ref, bql, fields);

Each Engine has its own request workers, subscription sessions, and shared subscription feeds. Engine also carries the BQL, BEQS, BSRCH, BTA, schema, streaming-service, and recipe methods; see the API Surface.

Choose an output backend ​

ts
import type { Table } from 'apache-arrow';
import { Backend, connect } from '@xbbg/core';

const engine = await connect();

// Default: an Apache Arrow table
const table = (await engine.bdp(['AAPL US Equity'], ['PX_LAST'])) as Table;
console.log(table.numRows, table.schema.fields.map((field) => field.name));

// JSON rows
const rows = (await engine.bdp(['AAPL US Equity'], ['PX_LAST'], {
  backend: Backend.JSON,
})) as Array<Record<string, unknown>>;
console.log(rows[0]?.value);

Request methods return Promise<unknown>; cast the result to the shape of the backend you chose. backend: 'polars' returns a nodejs-polars DataFrame and needs the optional nodejs-polars package. Output Formats covers formats and result metadata.

Subscribe ​

ts
import { asubscribe } from '@xbbg/core';

const sub = await asubscribe(['AAPL US Equity'], ['LAST_PRICE', 'BID', 'ASK']);
try {
  for await (const tick of sub) {
    console.log(tick.topic, tick.get('LAST_PRICE'));
    break; // leaving the loop unsubscribes
  }
} finally {
  await sub.unsubscribe();
}

See Streaming for Arrow reads, shared feeds, boards, and data-loss handling.

Shut down ​

  • Unsubscribe every subscription you open. Leaving a for await loop early also unsubscribes.
  • engine.signalShutdown() stops an engine you created: it closes admission, ends its subscriptions, and signals its sessions to stop. Await subscription cleanup first, and do not use the engine afterwards.
  • engine.isAvailable() reports whether at least one request session is healthy.
ts
import { connect } from '@xbbg/core';

const engine = await connect();
try {
  console.log(await engine.bdp(['AAPL US Equity'], ['PX_LAST']));
} finally {
  engine.signalShutdown();
}

Handle errors ​

ts
import {
  BlpError,
  BlpLimitError,
  BlpRequestError,
  BlpTimeoutError,
  BlpValidationError,
  connect,
} from '@xbbg/core';

const engine = await connect({ requestTimeoutMs: 60_000 });

try {
  await engine.bdp(['AAPL US Equity'], ['PX_LAST']);
} catch (error) {
  if (error instanceof BlpLimitError) {
    console.error('Bloomberg capacity limit reached:', error.message);
  } else if (error instanceof BlpRequestError) {
    console.error(error.service, error.operation, error.code, error.bloomberg_request_ids);
  } else if (error instanceof BlpTimeoutError) {
    console.error('Timed out:', error.bloomberg_request_id);
  } else if (error instanceof BlpValidationError) {
    console.error('Invalid input:', error.element, error.suggestion);
  } else if (error instanceof BlpError) {
    console.error(error.name, error.message);
  } else {
    throw error;
  }
}
ClassRaised for
BlpErrorBase class of every engine and Bloomberg error, including invalid engine configuration
BlpSessionErrorSession start, connection, and service-open failures
BlpRequestErrorBloomberg request failures; carries service, operation, request_id, and code
BlpLimitErrorBloomberg LIMIT and DAILY_CAPACITY_REACHED responses; a subclass of BlpRequestError, so test for it first
BlpValidationErrorInvalid request input; carries element and suggestion
BlpTimeoutErrorTimeouts, including requestTimeoutMs
BlpSubscriptionDataLossErrorA row subscription lost data (code: 'DATALOSS')
BlpInternalErrorEngine-internal failures

Every BlpError carries Bloomberg's support identifiers in bloomberg_request_id and bloomberg_request_ids when the SDK assigned them; request_id is xbbg's own request label. In request methods, argument mistakes caught in JavaScript, such as an ambiguous date string or an unknown backend, reject with a TypeError before any request is sent.

Next steps ​

Configuration

B-PIPE, ZFP, TLS, SOCKS5, auth, timeouts, pools, sharding, and logging.

Recipes

Higher-level workflows on the Engine.

xbbg is independent open-source software and is not affiliated with, endorsed by, sponsored by, or approved by Bloomberg Finance L.P.