Snapshots and Subscriptions

In this tutorial we'll cover market data snapshots and subscriptions; their creation, parameters and how to unsubscribe. Finally, these concepts will be shown together as an interactive example.

This section assumes a connection has been established; see the getting started tutorial as necessary.

Here we'll only cover requests that don't involve navigation; i.e. requests that return the key that was requested. An example of a navigational request would be asking for all option records but only needing to provide the key of the underlying record. Navigation is described further here.

Making a snapshot request

Here's an example of requesting the current bid and ask prices from the MSFT. record (the composite listing for Microsoft). We know the record's symbol, so we can use the getEqual method:

// Initiate a getEqual request to the ContentGateway.
const requestHandle = client.streaming.getEqual({
    key: "MSFT.",
    fieldIds: [activCgApi.FieldId.FID_BID, activCgApi.FieldId.FID_ASK]
});

// Asynchronously iterate records.
for await (const record of requestHandle) {
    console.log(`${record.responseKey.symbol} fields:`);

    // Synchronously iterate fields in the record.
    for (const field of record.fieldData) {
        console.log(`${activCgApi.FieldId[field.id]} = ${field.value}`);
    }

    console.log();
}

key

This property defines the symbol(s) for the record(s) we wish to lookup. Here we are only interested in one record (MSFT.) but if we wanted to also retrieve other records in this request, key can be specified as an array of strings. E.g. ["MSFT.", "AAPL."].

fieldIds

This defines a list of FieldIds the user wants to retrieve (and when subscribing, to receive updates for).

More detailed information about all the available fields can be found one the ACTIV Developer Support site. Be aware that not all fields are available in all tables, so some null values may be returned. You can also view the fields available in each table on the ACTIV Developer Support site, or programmatically using meta-data queries with the API itself.

fieldIds is also optional; if not specified, all fields in the record will be returned.

Making a subscription request

In order to receive updates to the initial record images, some additional parameters need to be provided to the request.

The simplest case is to specify an updateHandler in a subscription property in the request parameters:

function displayFields(record) {
    console.log(`${record.responseKey.symbol} fields:`);

    // Synchronously iterate fields in the record.
    for (const field of record.fieldData) {
        console.log(`${activCgApi.FieldId[field.id]} = ${field.value}`);
    }

    console.log();
}

// Initiate a getEqual request to the ContentGateway.
const requestHandle = client.streaming.getEqual({
    key: "MSFT.",
    fieldIds: [activCgApi.FieldId.FID_BID, activCgApi.FieldId.FID_ASK],
    subscription: {
        updateHandler: (update) => displayFields(update)
    }
});

// Asynchronously iterate records.
for await (const record of requestHandle) {
    displayFields(record);
}

In this case, the same update handler is called for all symbols that were subscribed to in the request. However, it is also possible to specify a per-symbol handler:

function displayFields(record) {
    console.log(`${record.responseKey.symbol} fields:`);

    // Synchronously iterate fields in the record.
    for (const field of record.fieldData) {
        console.log(`${activCgApi.FieldId[field.id]} = ${field.value}`);
    }

    console.log();
}

// Initiate a getEqual request to the ContentGateway.
const requestHandle = client.streaming.getEqual({
    key: "MSFT.",
    fieldIds: [activCgApi.FieldId.FID_BID, activCgApi.FieldId.FID_ASK],
    subscription: {}
});

// Asynchronously iterate records.
for await (const record of requestHandle) {
    requestHandle.setUpdateHandler(record.streamId, (update) => displayFields(update));

    displayFields(record);
}

Note it is possible to both specify the handler in the parameters to the request and then set a different per-symbol handler when processing the initial response (or an update). This might be useful when making a pattern request, for instance. Records that match the pattern that are added to the feed after the initial request has completed will be received as updates (where update.isNewRecord === true) and will be passed to the handler provided in the request parameters. You might then create a new row in a table and a function to update elements in that row, and call setUpdateHandler() to set the function as the update handler.

You will only receive updates for fields specified in the request. Note that for anyone familiar with the classic C++, C# or Java ActivContentGatewayApi, this behavior is different than in those APIs where the field filtering only applied to snapshot responses.

Unsubscribing

The delete method, provided by the IRequestHandle object returned by the request method (getEqual in this case), will cancel subscriptions resulting from the request.

Other request types

Further request types are available in addition to getEqual that might be more suitable for bulk record retrieval, or when the complete symbol isn't known.

Example

Here is a full example of the points covered in this tutorial:

// You may have to update the userId and password fields below.
const userId = "__ACTIV_FEED_USERNAME__";
const password = "__ACTIV_FEED_PASSWORD__";
const url = "ams://cg-ny4-replay.activfinancial.com/ContentGateway:Service";

function displayFields(record) {
    console.log(`${record.responseKey.symbol} fields:`);

    // Synchronously iterate fields in the record.
    for (const field of record.fieldData) {
        console.log(`${activCgApi.FieldId[field.id]} = ${field.value}`);
    }

    console.log();
}

(async function() {
    try {
        console.log("Connecting...");

        const client = await activCgApi.connect({
            url,
            userId,
            password
        });

        console.log("Connected. Initiating data request...");

        // Initiate a getEqual request to the ContentGateway.
        const requestHandle = client.streaming.getEqual({
            key: "MSFT.",
            fieldIds: [activCgApi.FieldId.FID_BID, activCgApi.FieldId.FID_ASK],
            subscription: {
                // We can set an update handler to be called for all symbols we subscribe
                // to from this request.
                // We can alternatively set a per-symbol update handler when we get the
                // initial record image (below).
                // updateHandler: (update) => displayFields(update)
            }
        });

        // Asynchronously iterate records.
        for await (const record of requestHandle) {
            // We can set a per-symbol update handler if we prefer; maybe to a
            // function that will update a specific row in a table.
            requestHandle.setUpdateHandler(record.streamId, (update) => displayFields(update));

            displayFields(record);
        }

        // Let's get two seconds of updates then unsubscribe.
        await activCgApi.asyncSleep(2000);

        console.log("Unsubscribing...");
        requestHandle.delete();
    } catch (e) {
        console.error(`Error: ${e}`);
    }
})();
Try it out in the playground

Also in this Section