Skip to content

Get Price Updates for an Instrument

Overview

This feature enables traders to access real-time price updates for specific financial instruments, facilitating various operations related to those instruments.

This page explains how to use the FCLite API to get the latest price data for a specific instrument. You can use the getPriceUpdate method to subscribe to real-time price updates for an instrument, and receive a callback function with the bid and ask prices, the spread, the volume, and the timestamp of each update. You can also use the unsubscribePriceUpdate method to stop receiving price updates for an instrument.

How to receive price updates for an instrument

In this article you will learn how to use the API to receive price updates for an instrument.

To get price updates for an instrument, you need to follow these steps:

  1. Login (see the tutorial here)

  2. Subscribe to the offers manager change event.

  3. Create an offer's state change listener.

  4. Receive price updates for an instrument.

Step 1: Login

Follow the steps in the login tutorial here

Step 2: Subscribe to the offers manager change event

The first step is to subscribe to the offers manager change event. This event is triggered when the offer data has changed, such as when a new offer is added, removed, or updated. You can use the IOffersManager interface to access the methods and properties of the offers manager.

Below you can see some example code for subscribing to the offers manager change event:

Subscribe to the offersmanagerchange

let offersManager = session.getOffersManager();
//subscribe to the offersManager change to get an event when offer data has changed
offersManager.subscribeOfferChange(new OfferChangeListener(instrumentsManager, offersManager))
offersManager.subscribeStateChange(new OffersStateChangeListener(offersManager, instrumentsManager));
let offersManager = session.getOffersManager();
//subscribe to the offersManager change to get an event when offer data has changed
offersManager.subscribeOfferChange(new OfferChangeListener(instrumentsManager, offersManager));
offersManager.subscribeStateChange(new OffersStateChangeListener(offersManager, instrumentsManager));

The first thing we need to do is to add a DIV to our HTML where we will inject the offers data.

<div class="row mt-3" id="offers" style="display: none;">
    <div class="offset-sm-3 col-sm-6 pb-1" style="font-size: larger;">Offers <button id="refreshOffers" class="btn btn-outline-secondary">Refresh</button> <span id="offersState"></span></div>
    <div id="offerList" class="offset-sm-3 col-sm-6 border pt-0 pb-3 mt-0" style="display: none; border-color: #adb5bd; background-color: #fff; max-height: 300px; overflow: auto;">
    </div>
</div>
We also need to add a few variables to the start of the custom.js file.
let lastSelectedOfferId = "";
let offersWorker;
let openPositionWorker;
Next we need to create the worker class that will generate the HTML to be injected into that div
class OffersWorker {
    showOffers() {
        let own = this;
        let offerManager = session.getOffersManager();
        let instrumentManager = session.getInstrumentsManager();
        let instruments = instrumentManager.getAllInstruments();
        let row = document.createElement("div");
        row.className = "row mb-3";
        let col1 = document.createElement("div");
        col1.className = "col-sm-2";
        let col2 = document.createElement("div");
        col2.className = "col-sm-4";
        let col3 = document.createElement("div");
        col3.className = "col-sm-3";
        let col4 = document.createElement("div");
        col4.className = "col-sm-3";

        $("#offerList").empty();

        $(col1).text("ID");
        $(col2).text("Symbol");
        $(col3).text("Bid");
        $(col4).text("Ask");
        $(row).append($(col1));
        $(row).append($(col2));
        $(row).append($(col3));
        $(row).append($(col4));
        row.style.backgroundColor = "#adb5bd";
        $("#offerList").append($(row));

        for (let instrument of instruments) {
            let offer = offerManager.getOfferById(instrument.getOfferId())
            if (offer == null) {
                continue;
            }
            row = document.createElement("div");
            row.className = "row mb-0 pb-0 offer";

            col1 = document.createElement("div");
            col1.className = "col-sm-2";
            $(row).append($(col1));
            $(col1).text(offer.getOfferId());

            col2 = document.createElement("div");
            col2.className = "col-sm-4";
            $(row).append($(col2));
            $(col2).text(instrument.getSymbol());

            col3 = document.createElement("div");
            col3.className = "col-sm-3 bid";
            $(row).append($(col3));
            $(col3).text(offer.getBid());

            col4 = document.createElement("div");
            col4.className = "col-sm-3 ask";
            $(row).append($(col4));
            $(col4).text(offer.getAsk());

            row.id = "offer" + offer.getOfferId();
            row.style.cursor = "pointer";
            $("#offerList").append($(row));
            $(row).click(own.offerClick);
        }
        $("#offerList").show();
    }

    removeDetails() {
        $("#offers div.details").remove();
        $("div.offer").css("background-color", "");
    }

    showOfferDetails(offer) {
        let own = this;
        let id = offer.getOfferId();
        let row = document.createElement("div");
        row.className = "row mb-3 details";
        row.style.cursor = "pointer";
        $(row).click(own.detailsClick);
        $(row).css("background-color", "#dce0e4");
        $("#offer" + id).css("background-color", "#dce0e4");
        $("#offer" + id).after(row);

        this.print(row, [
            ["Quote id", offer.getQuoteId()],
            ["Bid tradable", offer.getBidTradable()],
            ["Ask tradable", offer.getAskTradable()],
            ["High", offer.getHigh()],
            ["Low", offer.getLow()],
            ["Volume", offer.getVolume()],
            ["Time", offer.getTime()],
            ["Pip cost", offer.getPipCost()]
        ]);
    }

    print(row, arr) {
        for (let i = 0; i < arr.length; i++) {
            let elem = arr[i];
            let col1 = document.createElement("div");
            col1.className = "col-sm-6";
            $(row).append($(col1));
            $(col1).text(elem[0] + ":");
            let col2 = document.createElement("div");
            col2.className = "col-sm-6";
            $(row).append($(col2));
            $(col2).text(elem[1]);
        }
    }

    offerClick(event) {
        let id = event.delegateTarget.id;
        id = id.replace("offer", "");
        offersWorker.removeDetails();

        if (lastSelectedOfferId != id) {
            lastSelectedOfferId = id;
            offersWorker.showOfferDetails(session.getOffersManager().getOfferById(id));
        } else {
            lastSelectedOfferId = "";
        }
    }

    detailsClick(event) {
        offersWorker.removeDetails();
        lastSelectedOfferId = "";
    }

    updateState(state) {
        let own = this;
        $('#offersState').text(own.getDataManagerStateString(state));
    }

    getDataManagerStateString(status) {
        return (status.isNotLoaded() ? "Not loaded" : "") +
            (status.isLoading() ? "Loading" : "") +
            (status.isLoaded() ? "Loaded" : "") +
            (status.hasError() ? " (has error)" : "");
    }

    updateOffer(offerId) {
        let me = this;
        let offer = session.getOffersManager().getOfferById(offerId);
        let offerRow = $('#offer' + offer.getOfferId());
        let bidDiv = offerRow.find('.bid');
        bidDiv.removeClass('greater').removeClass('lower').addClass(me.getClass(bidDiv.text(), offer.getBid())).text(offer.getBid());
        let askDiv = offerRow.find('.ask');
        askDiv.removeClass('greater').removeClass('lower').addClass(me.getClass(bidDiv.text(), offer.getAsk())).text(offer.getAsk());
    }

    getClass(oldValue, newValue) {
        if (parseFloat(oldValue) < newValue) {
            return 'greater'
        } else if (parseFloat(oldValue) > newValue) {
            return 'lower'
        }
        return ''
    }

    addOffer(offerId) {
    }
}

See also IOffersManager, getOpenPosition, subscribeStateChange

Step 3: Create an offer's state change listener

The next step is to create an offer's state change listener. This is a function that will be called whenever an offer's state changes, such as when its price, volume, or spread changes. You can use the getOfferById method of the offers manager to get an offer by its ID.

Below, you can see some example code to create an offer's state change listener:

OfferChangeListener

class OfferChangeListener implements FXConnectLite.IOfferChangeListener {
    private isFirstOfferChange: boolean = false;
    private instrumentsManager: FXConnectLite.IInstrumentsManager;
    private offersManager: FXConnectLite.IOffersManager;

    public constructor(instrumentManager: FXConnectLite.IInstrumentsManager, offersManager: FXConnectLite.IOffersManager) {
        this.instrumentsManager = instrumentManager;
        this.offersManager = offersManager;
    }

    onChange(offerInfo: FXConnectLite.OfferInfo): void {
        if (!this.isFirstOfferChange) {
            Printer.print(``);
            Printer.print(`Offer changes:`);
            Printer.print(``);
            Printer.print(OfferFormatter.TITLE);
            this.isFirstOfferChange = true;
            }
        let offer = this.offersManager.getOfferById(offerInfo.getOfferId());
        Printer.print(`${OfferFormatter.format(offer, this.instrumentsManager)}`);
    }
    onAdd(offerInfo: FXConnectLite.OfferInfo): void {
        //do nothing
    }
}
let OffersStateChangeListener = /** @class */ (function () {
    function OffersStateChangeListener(offersManager, instrumentManager) {
        this.offersManager = offersManager;
        this.instrumentManager = instrumentManager;
    }
    OffersStateChangeListener.prototype.printOffers = function (title, offers) {
        let _this = this;
        console.log("");
        console.log(title);
        console.log("");
        console.log(OfferFormatter.TITLE);
        offers.forEach(function (offer) { return console.log(OfferFormatter.format(offer, _this.instrumentManager)); });
    };
    OffersStateChangeListener.prototype.onStateChange = function (state) {
        if (state.isLoaded()) {
            this.printOffers("All initial offers:", this.offersManager.getAllOffers());
        }
    };
    return OffersStateChangeListener;
}());
let OfferChangeListener = /** @class */ (function () {
    function OfferChangeListener(instrumentManager, offersManager) {
        this.isFirstOfferChange = false;
        this.instrumentsManager = instrumentManager;
        this.offersManager = offersManager;
    }
    OfferChangeListener.prototype.onChange = function (offerInfo) {
        if (!this.isFirstOfferChange) {
            console.log("");
            console.log("Offers changes:");
            console.log("");
            console.log(OfferFormatter.TITLE);
            this.isFirstOfferChange = true;
        }
        let offer = this.offersManager.getOfferById(offerInfo.getOfferId());
        console.log("".concat(OfferFormatter.format(offer, this.instrumentsManager)));
    };
    OfferChangeListener.prototype.onAdd = function (offerInfo) {
    //do nothing
    };
    return OfferChangeListener;
}());
class offersStateListener {
    onStateChange(state) {
        offersWorker.updateState(state);
        if (state.isLoaded()) {
            offersWorker.showOffers();
        }
    }
}

class offersChangeListener {
    onChange(offerInfo) {
        offersWorker.updateOffer(offerInfo.getOfferId());
    }

    onAdd(offerInfo) {
        offersWorker.addOffer(offerInfo.getOfferId());
    }
}

See also IOffersManager, getOfferById

Step 4: Receive price updates for an instrument

The final step is to receive price updates for an instrument. You can use the subscribeStateChange() method of the offer object to subscribe to its state changes. This method takes an offer's state change listener as an argument and returns a subscription object. You can also use the refresh() method of the subscription object to manually request a price update.

Below, you can see some example code to receive price updates for an instrument:

Price updates for an instrument

private loadOffers = async (session) => {
    return new Promise<void>((resolve, reject) => {
        if(session.getOffersManager().getState().isLoaded())
            resolve();
        else {
            let completeHandler = new CompleteLoadingHandler(resolve, this.timeout);
            session.getOffersManager().subscribeStateChange(completeHandler);
            session.getOffersManager().refresh();
        }
    })
}
this.loadInstruments = async function (session) {
    return new Promise(function (resolve, reject) {
        let completeHandler = new CompleteLoadingHandler(resolve, this.timeout);
        session.getInstrumentsManager().subscribeStateChange(completeHandler);
        session.getInstrumentsManager().refresh();     
    });
};

After the user clicks the login button, we need to declare in instance of the offersWorker

offersWorker = new OffersWorker();
Next we need to subscribe to the listeners
session.getOffersManager().subscribeStateChange(new offersStateListener());
session.getOffersManager().subscribeOfferChange(new offersChangeListener());
offersWorker.updateState(session.getOffersManager().getState());
Finally we need to add some jQuery to monitor the getOffers button
$('#refreshOffers').click(function () {
    session.getInstrumentsManager().refresh()
    session.getOffersManager().refresh()
});

See also subscribeStateChange, refresh()

When you have a price update for an instrument, you can:

  1. Get available instruments.
  2. Subscribe and Unsubscribe to instruments.
  3. Get historical prices for an instrument.
  4. Create a market order.
  5. Create an entry order.
  6. Get open positions.

Conclusion

You have learned how to use the API to receive price updates for an instrument. Before you can receive price updates, you need to subscribe to the offers manager change event, create an offer's state change listener, and receive price updates for an instrument. You have also learned how to subscribe to the offers manager change event using the IOffersManager interface and how to create an offer's state change listener using the getOfferById method of the offers manager. You can now use this knowledge to receive price updates for instruments on the platform.

Download the sample Node TypeScript, Node JavaScript, Javascript.

Note

Questions and answers

  1. What is an offer and how to create one?

    An offer is the current price value (sell, buy, high, low) for a specific trading instrument. You don’t need to create it yourself; they are created in the library.

  2. What is the correct refresh order for instrumentManager and offersManager?

    instrumentsManager.refresh();

    offersManager.refresh();

    The refresh() command is used for initial initialization and if you need to perform a forced refresh, you should not call refresh periodically. You should listen ChangeListener events for specific manager (for example IOfferChangeListener for OfferManager) to receive an event about data update.

    Example:

    await Promise.all([
        loadManager(session.getInstrumentsManager(), 'Instruments'),
        loadManager(session.getOffersManager(), 'Offers'),
        ...
    ])
    const loadManager = (
        manager: IDataManager,
        name: string
        ): Promise<IDataManager> => {
            console.log('load manager:', { name })
            return new Promise((resolve, reject) => {
                const listener: IDataManagerStateChangeListener = {
                onStateChange: state => {
                if (state.isLoaded()) {
                    console.log('loaded:', { name })
                    manager.unsubscribeStateChange(listener)
                    resolve(manager)
                }
                else if (state.hasError()) {
                    console.log({ failed: name })
                    manager.unsubscribeStateChange(listener)
                    reject(state.getError())
                }
                },
                }
                manager.subscribeStateChange(listener)
                manager.refresh()
            })
        }
    

  3. Should refresh() only be called when manager has entered the not loaded state?

    The refresh() command can be executed in any state. To know the state of the manager, you should call the manager getState() method with this result:

    • NotLoaded - You should call the refresh() method

    • Loaded - The data is already loaded, if you call refresh() again, this will be a forced refresh of the manager.

    • Loading - Ignore this as the refresh() method is in process already

  4. Do I need to wait for managers to go into loaded state before calling instrumentsManager.subscribeInstruments?

    You need to wait for managers to go into loaded state (OffersManager and InstrumentsManager) before calling instrumentsManager.subscribeInstruments.

Table of Contents
Get Price Updates for an Instrument
The article teaches how to receive price updates for an instrument.
Get Historical Prices for an Instrument
The article teaches how to receive historical prices for an instrument.