# JavaScript

Source: https://docs.interop.io/adapters/bloomberg/mdf-bridge/javascript/index.html

## Initialization

The BBG Market Data library is available as an NPM package - [`@interopio/bbg-market-data`](https://www.npmjs.com/package/@interopio/bbg-market-data). To install it, run the following command in your project directory:

```cmd
npm install @interopio/bbg-market-data
```

The BBG Market Data API depends on the io.Connect [Interop](https://docs.interop.io/desktop/capabilities/data-sharing/interop/overview/index.md) object, an instance of which must be passed to the `BBGMarketData()` factory function. The function also accepts as a second parameter a configuration object that controls logging behavior and can also provide an optional custom logger implementation. The configuration object can also specify the interval at which to attempt reconnection to the Bloomberg Adapter if a connection doesn't exist or is interrupted.

> ⚠️ *Note that if you already have an initialized the io.Connect API in your app, you must reuse it and not create a new instance.*

```javascript
import BBGMarketData, { BBGMarketDataAPI } from "@interopio/bbg-market-data";

const io = await IODesktop();
const bbgMarketData: BBGMarketDataAPI = BBGMarketData(io.interop, { connectionPeriodMsecs: 7000 });
```

The configuration object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `debug` | `boolean` | Whether to enable debugging mode. Defaults to `false`. |
| `connectionPeriodMsecs` | `number` | Interval in milliseconds at which to attempt reconnection to the Bloomberg Adapter. Defaults to `5000`. |

## Connection

To receive updates about changes in the connection between the BBG Market Data API and the Bloomberg Adapter, you can use the `onConnectionStatusChanged()` method. It accepts a callback with which you can handle changes in the connection status and returns an unsubscribe function that you can invoke to stop receiving updates about the connection status:

```javascript
function handleConnectionChanges (status: ConnectionStatus): void {

    if (status === ConnectionStatus.Connected) {
        // Connected.
    } else {
        // Disconnected.
    };
};

const unsubscribe: UnsubscribeFunction = bbgMarketData.onConnectionStatusChanged(handleConnectionChanges);
```

## Handling Requests

A request to a Bloomberg service must first be created. After creating a request instance, you can optionally provide callbacks for handling response data, errors, subscription failures, request status changes and request related events. After that, the request is sent to the Bloomberg service. A request can also be closed if its status is `Opened` or `Active`.

### Creating Requests

The following example demonstrates creating a `HistoricalDataRequest` using the `createHistoricalDataRequest()` method of the API:

```javascript
const requestArgs: HistoricalDataRequestArguments = {
    securities: ["IBM US Equity", "MSFT US Equity"],
    fields: ["LAST_PRICE"],
    startDate: "20190101",
    endDate: "20191231"
};

const request: HistoricalDataRequest = bbgMarketData.createHistoricalDataRequest(requestArgs);
```

### Opening Requests

To actually send the request to the Bloomberg service, invoke the `open()` method of the request instance. Requests can be opened/reopened when they have a `Created`, `Closed`, `Failed` or `Completed` status. When the request is pending (its status is `Opened` or `Active`), `open()` will immediately throw an error.

```javascript
// Request options.
const openOptions: OpenRequestOptions = {
    session: Session.LargeHistoricalRequests,
    aggregateResponse: false
};

// Send the actual request to the Bloomberg service.
await request.open(openOptions);
```

A request object can be one of two general types - `SubscriptionRequest` or `Request`, depending on whether the created request is a subscription request (e.g., [Market Data Subscription](#request_types-market_data_subscription)) or a non-subscription request (all other types of requests for data, fields, user entitlements, etc.). Both types of objects have an `open()` method which accepts an optional `OpenSubscriptionRequestOptions` or an `OpenRequestOptions` object as an argument respectively.

The `OpenSubscriptionRequestOptions` object passed to the `open()` method of a `SubscriptionRequest` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `session` | `Session.Default` \| `Session.CreateNew` \| `Session.RealTime` \| `BloombergSession` | The type of session to use. For subscription requests, defaults to `RealTime`. See also [Session Types](#sessions-session_types). |

The `OpenRequestOptions` object passed to the `open()` method of a `Request` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `session` | `Session.Default` \| `Session.CreateNew` \| `Session.DataRequests` \| `Session.LargeHistoricalRequests` \| `BloombergSession` | The type of session to use. For non-subscription requests, defaults to `DataRequests`. See also [Session Types](#sessions-session_types). |
| `aggregateResponse` | `boolean` | Whether to return an aggregated response. If `true` (default), `open()` returns a `Promise` which resolves with the aggregated response which is then passed to the callback attached to the `onData()` method of the request object. If `false`, the `Promise` resolves immediately and the partial responses are passed to the callback attached to the `onData()` method of the request object. |

As opening a request is asynchronous, if any issue occurs (e.g., the Bloomberg Adapter fails to open the Bloomberg core service), the error will be delivered asynchronously to the request `onError()` callback.

### Closing Requests

To close a request, invoke the `close()` method of a request instance. A request can be closed only if its status is `Opened` or `Active`. Otherwise, `close()` will just resolve. If any issues occur when attempting to close the request, the `close()` method rejects with an error.

```javascript
try {
    await request.close();
    // Request closed successfully. Now can be reopened.
} catch (error) {
    // Unable to close the request. Check error.
};
```

### Response Data

To handle response data, attach a callback to the `onData()` method of the request instance. The method returns an `UnsubscribeFunction`. The `onData()` method handles data from real-time subscriptions and data from partial responses from static reference data requests.

When handling data from a non-subscription request, the data is wrapped in a `ResponseData` object. The Boolean property `isLast` is set to `false` when the response contains a Bloomberg `PARTIAL_RESPONSE` event and is set to `true` when the response contains a Bloomberg `RESPONSE` event. After a `RESPONSE` event, no more events will be received and the app can now process the returned data accordingly.

Handling partial response data from static reference data requests:

```javascript
const handleResponse = (response: ResponseData<HistoricalData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);
```

If you want to directly get the final aggregated response from a static reference data request, you can await the `Promise` returned from the `open()` method of the request instance. (This applies only if you haven't explicitly set the `aggregateResponse` property of the optional object passed to `open()` to `false`):

```javascript
const response: HistoricalData[] | undefined = await request.open();

if (response) {
    // Handle aggregated response.
};
```

When handling data from a subscription request, the data for each subscription is wrapped in a `SubscriptionData` object.

Handling data from real-time subscription requests:

```javascript
const handleSubscriptionsData = (subscriptionsData: Array<SubscriptionData>): void => {
    // Handle subscription updates.
};

request.onData(handleSubscriptionsData);
```

### Response Errors

To handle errors in a response, attach a callback to the `onError()` method of the request instance. The method returns an `UnsubscribeFunction`. An error can be returned when:

- Unable to invoke the Bloomberg Adapter.
- The Bloomberg Adapter has thrown an exception.
- The Bloomberg Adapter wasn't able to create the request to the Bloomberg service and returns an unsuccessful result.
- An active request to a Bloomberg service has failed (e.g., a "RequestFailure" message was received for a non-subscription request).

### Request Status

To track the current request status, attach a callback to the `onStatus()` method of the request instance. The method returns an `UnsubscribeFunction`.

There are six statuses:

- `Created` - The request has been created but not sent to a Bloomberg service.
- `Opened` - The actual request has been sent to a Bloomberg service, but isn't active yet. Response still not available.
- `Active` - The request has been sent to a Bloomberg service successfully. Responses may be received.
- `Failed` - The request has failed to open or an error is received from a Bloomberg service.
- `Closed` - The request was closed before completing. No more responses will be received.
- `Completed` - The request was completed successfully. No more responses will be received.

### Request Events

If you want to receive all Bloomberg events related to the current request, you can attach a callback to the `onEvent()` method of the request instance. The method returns an `UnsubscribeFunction`.

```javascript
const handleBloombergEvent = (event: BloombergEvent): void => {
    // Track all events related to the current request.
};

request.onEvent(handleBloombergEvent);
```

## Request Types

### Market Data Subscription

A Market Data Subscription request enables retrieval of streaming data for securities that are priced intraday by using the Bloomberg API Subscription paradigm. It uses the Bloomberg API core service `//blp/mktdata`. The subscriber receives updates once a field value changes at the source. Desired fields must explicitly be listed in the subscription to receive updates for them. It's required for each subscription to have a `security` property and at least one field in the `fileds` property. A full range of options (like `subscriptionId`, `intervalInSeconds`, `delayed`) can be specified in the `Subscription`.

The following example demonstrates creating and opening a Market Data Subscription request:

```javascript
const subscriptions: Array<Subscription> = [
    {
        security: "IBM US Equity",
        fields: ["LAST_PRICE", "BID", "ASK"],
        // Interval for receiving conflated data.
        intervalInSeconds: 2,
        // Whether the received data to be real-time or delayed.
        delayed: false
    }
];

// Creating the request.
const request: SubscriptionRequest = bbgMarketData.createMarketDataRequest(subscriptions);

const handleSubscriptionsData = (subscriptionsData: Array<SubscriptionData>): void => {
    // Handle subscription updates.
};

request.onData(handleSubscriptionsData);

// The callback in the `onFail()` method will be invoked when a subscription for a security
// fails on the Bloomberg side. E.g., you may have sent a request with
// five subscriptions for five different securities and two of the subscriptions fail.
const handleSubscriptionsError = (subscriptionErrors: Array<SubscriptionError>): void => {
    // Handle subscription errors.
};

request.onFail(handleSubscriptionsError);

// The callback in the `onError()` method will be invoked whenever an error occurs with
// the request itself. E.g., error in creating or sending the request.
const handleRequestError = (error): void => {
    // Handle request error.
};

request.onError(handleRequestError);

// Sending the request to a Bloomberg service.
await request.open();
```

Each subscription must have a unique ID. If not explicitly set, the library assigns one:

```javascript
import { CorrelationId, Subscription } from "@interopio/bbg-market-data";

const subscriptions: Subscription[] = [
    // This subscription has explicitly assigned ID.
    {
        subscriptionId: new CorrelationId(),
        security: "IBM US Equity",
        fields: ["LAST_PRICE", "BID", "ASK"]
    },

    // A `subscriptionId` will be assigned automatically for this subscription.
    {
        security: "MSFT US Equity",
        fields: ["LAST_PRICE", "BID", "ASK"]
    }
];
```

### Historical Data

A Historical Data request enables the retrieval of end-of-day data for a set of securities and fields over a specified period, which can be set to daily, monthly, quarterly, semi-annually or annually by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/refdata`.

At least one value in the `securities` and in the `fields` properties is required along with a `startDate` and an `endDate`. A range of other options can be specified in the `HistoricalDataRequestArguments` object. To create a Historical Data request, use the `createHistoricalDataRequest()` method:

```javascript
const requestArgs: HistoricalDataRequestArguments = {
    securities: ["IBM US Equity", "MSFT US Equity"],
    fields: ["LAST_PRICE"],
    startDate: "20190101",
    endDate: "20191231"
};

// Creating the request.
const request: HistoricalDataRequest = bbgMarketData.createHistoricalDataRequest(requestArgs);

const handleResponse = (response: ResponseData<HistoricalData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Reference Data

A Reference Data request retrieves the current data available for a security/field pair by using the Bloomberg Request/Response paradigm.
It uses the Bloomberg API core service `//blp/refdata`.

At least one value in the `securities` and in the `fields` properties is required. A range of other options can be specified in the `ReferenceDataRequestArguments` object. To create a Reference Data request, use the `createReferenceDataRequest()` method.

```javascript
const requestArgs: ReferenceDataRequestArguments = {
    securities: ["IBM US Equity"],
    fields: ["LAST_PRICE"]
};

// Creating the request.
const request: ReferenceDataRequest = bbgMarketData.createReferenceDataRequest(requestArgs);

const handleResponse = (response: ResponseData<ReferenceData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Instrument List

The Instrument List request performs a search for securities based on a specified search string. This functionality resembles the `SECF <GO>` function of the Bloomberg Professional Service. It uses the Bloomberg API core service `//blp/instruments`.

Specifying a search string and a maximum number of results is required. A range of other options can be specified in the `InstrumentListRequestArguments` object. To create an Instrument List request, use the `createInstrumentListRequest()` method:

```javascript
const requestArgs: InstrumentListRequestArguments = {
    query: "VOD",
    maxResults: 5
};

// Creating the request.
const request: InstrumentListRequest = bbgMarketData.createInstrumentListRequest(requestArgs);

const handleResponse = (response: ResponseData<InstrumentListData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Intraday Bar

The Intraday Bar request enables retrieval of summary intervals for intraday data covering five event types: trade, bid, ask, best bid, and best ask. The data is retrieved for a specified period of time by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/refdata`.

It's required to specify a `security` and `eventType`. Also, `startDateTime` and `endDateTime` points in UTC must be specified. A range of other options can be specified in the `IntraDayBarRequestArguments` object. To create an Intraday Bar request, use the `createIntraDayBarRequest()` method:

```javascript
const requestArgs: IntraDayBarRequestArguments = {
    security: "IBM US Equity",
    eventType: IntraDayEventType.ASK,
    startDateTime: "2019-01-01T13:00:00",
    endDateTime: "2019-12-31T13:00:00"
};

// Creating the request.
const request: IntraDayBarRequest = bbgMarketData.createIntraDayBarRequest(requestArgs);

const handleResponse = (response: ResponseData<IntraDayBarData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Intraday Tick

The Intraday Tick request enables retrieval of tick-by-tick intraday data covering five event types: trade, bid, ask, best bid, and best ask. The data is retrieved for a specified period of time by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/refdata`.

It's required to specify a `security` and `eventType`. Also, `startDateTime` and `endDateTime` points in UTC must be specified. A range of other options can be specified in the `IntraDayTickRequestArguments` object. To create an Intraday Tick request, use the `createIntraDayTickRequest()` method:

```javascript
const requestArgs: IntraDayTickRequestArguments = {
    security: "IBM US Equity",
    // This can be a list of all event types.
    eventTypes: [IntraDayEventType.ASK, IntraDayEventType.BID],
    startDateTime: "2019-01-01T13:00:00",
    endDateTime: "2019-01-31T13:00:00"
};

// Creating the request.
const request: IntraDayTickRequest = bbgMarketData.createIntraDayTickRequest(requestArgs);

const handleResponse = (response: ResponseData<IntraDayTickData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Snapshot

The Snapshot request enables retrieval of static market list snapshot data by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/mktlist`.

It's required to specify a `security`. To create a Snapshot request, use the `createSnapshotRequest()` method:

```javascript
const requestArgs: SnapshotRequestArguments = {
    security: "VOD LN Equity"
};

// Creating the request.
const request: SnapshotRequest = bbgMarketData.createSnapshotRequest(requestArgs);

const handleResponse = (response: ResponseData<SnapshotData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Field List

The Field List request returns all fields of the same type by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/apiflds`. Possible `fieldType` values include:

- `All` - returns all fields in the API Data Dictionary;
- `Static` - returns all static fields contained in the API Data Dictionary;
- `RealTime` - returns all real-time fields contained in the API Data Dictionary;

A range of options can be specified in the `FieldListRequestArguments` object. To create a Field List request, use the `createFieldListRequest()` method:

```javascript
const requestArgs: FieldListRequestArguments = {
    fieldType: FieldType.RealTime
};

// Creating the request.
const request: FieldListRequest = bbgMarketData.createFieldListRequest(requestArgs);

const handleResponse = (response: ResponseData<FieldListData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### Field Search

The Field Search request returns all fields matching a specified search criterion by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/apiflds`.

A range of options can be specified in the `FieldSearchRequestArguments` object. To create a Field Search request, use the `createFieldSearchRequest()` method:

```javascript
const requestArgs: FieldSearchRequestArguments = {
    searchSpec: "mkt"
};

// Creating the request.
const request: FieldSearchRequest = bbgMarketData.createFieldSearchRequest(requestArgs);

const handleResponse = (response: ResponseData<FieldSearchData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

### User Entitlements

The User Entitlements request returns a list of entitlement IDs by using the Bloomberg Request/Response paradigm. It uses the Bloomberg API core service `//blp/apiauth`. To create a User Entitlements request, use the `createUserEntitlementsRequest()` method:

```javascript
const requestArgs: UserEntitlementsRequestArguments = {
    uuid: 1000
};

// Creating the request.
const request: UserEntitlementsRequest = bbgMarketData.createUserEntitlementsRequest(requestArgs);

const handleResponse = (response: ResponseData<UserEntitlementsData>): void => {
    if (response.isLast) {
        // Handle the final response.
    } else {
        // Handle partial responses.
    }
};

request.onData(handleResponse);

// Sending the request to a Bloomberg service.
await request.open();
```

## Session

Bloomberg sessions are essentially data stream connections. These are logical connections and the Bloomberg API supports failover between physical connections. During failover, the API will handle re-subscriptions.

Each instance of the BBG Market Data library has two default sessions - one for subscription requests and one for static reference data requests. Their lifetime is bound to the lifetime of the provided io.Connect [Interop](https://docs.interop.io/desktop/capabilities/data-sharing/interop/overview/index.md) instance.

> ⚠️ *Note that opening and closing a Bloomberg session is expensive both for the client app and for Bloomberg servers, so it's strongly recommended to use the default sessions when opening a request.*

### Session Types

There are five predefined session types accessible through the `Session` enumeration:

| Session | Description |
|---------|-------------|
| `Session.RealTime` | Session for real-time subscriptions. Default for subscription requests. |
| `Session.DataRequests` | Session for static reference data. Default for non-subscription requests. |
| `Session.LargeHistoricalRequests` | Dedicated session for a large volume data request. |
| `Session.CreateNew` | Creates a new session which closes immediately after the request is completed. |
| `Session.Default` | Explicitly states that the default session should be used. |

```javascript
// A Historical Data `request` instance has already been created
// and the respective callbacks for handling data and errors have been attached to it.

// Explicitly states that the default session should be used.
const defaultSessionOptions = { session: Session.Default };
await request.open(defaultSessionOptions);

// This request will be opened on a short-lived dedicated session.
const newSessionOptions = { session: Session.CreateNew };
await request.open(newSessionOptions);
```

The `BloombergSession` type describes custom sessions created with the `create()` method of the `sessions` object of the API:

```javascript
const customSession: BloombergSession = await bbgMarketData.sessions.create();
```

### Custom Sessions

Default sessions are created with the default Bloomberg session options and default Bloomberg session identity options. These can be overridden during the library initialization. To use custom session settings, create a `SessionOptions` and a `SessionIdentityOptions` objects and set the required options to be supplied when the actual Bloomberg session is created.

```javascript
import IODesktop from "@interopio/desktop";
import BBGMarketData, { BBGMarketDataAPI, SessionOptions, SessionSettings, SessionIdentityOptions } from "@interopio/bbg-market-data";

const options: SessionOptions = {
    // Your custom Bloomberg session options.
};

const identityOptions: SessionIdentityOptions = {
    // Your custom Bloomberg session identity options.
};

const sessionSettings: SessionSettings = {
    options,
    identityOptions
};

const io = await IODesktop();
const bbgMarketData: BBGMarketDataAPI = BBGMarketData(io.interop, { sessionSettings });
```

The `SessionIdentityOptions` object has the following shape:

```javascript
const identityOptions: SessionIdentityOptions = {
    authToken: string;
    authApplication: string;
    correlationId: string;
    authUser: {
        authUserWithAutoLogon: boolean;
        authUserWithADProperty: string;
        authUserWithManualOptions: {
            userId: string;
            ipAddress: string;
        }
    }
};
```

> ⚠️ *Note that `authToken` and `authUser`/`authApplication` are mutually exclusive. For instance, if you specify a value for `authToken`, the values for both `authUser` and `authApplication` will be ignored.*

Besides the default predefined sessions, for advanced scenarios, you can create custom sessions. These sessions can be closed explicitly, otherwise they will also share the lifetime of the provided io.Connect [Interop](https://docs.interop.io/desktop/capabilities/data-sharing/interop/overview/index.md) instance. The reason for this is that you can group requests in different Bloomberg sessions to avoid delaying a fast stream with a slow one.

To create a custom session, use the `create()` method of the `sessions` object of the API, optionally providing custom session settings:

```javascript
import BBGMarketData, {
    BBGMarketDataAPI,
    SessionOptions,
    SessionSettings,
    SessionIdentityOptions
} from "@interopio/bbg-market-data";

const io = await IODesktop();
const bbgMarketData: BBGMarketDataAPI = BBGMarketData(io.interop);

const options: SessionOptions = {
    // Your custom Bloomberg session options.
};

const identityOptions: SessionIdentityOptions = {
    // Your custom Bloomberg session identity options.
};

const sessionSettings: SessionSettings = {
    options,
    identityOptions,
};

// Sessions settings are optional.
const largeDataSession: BloombergSession = await bbgMarketData.sessions.create(sessionSettings);

// A large and slow historical data request.
const requestArgs = { /* ... */ };
const request = bbgMarketData.createHistoricalDataRequest(requestArgs);

const openOptions = { session: largeDataSession };
await request.open(openOptions);

// You can also use the custom session for other requests.
```

To close a custom session, use the `close()` method of the `sessions` object of the API, providing the name of the session to close:

```javascript
// You can explicitly close a custom session by its name.
await bbgMarketData.sessions.close(largeDataSession.name);
```
