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:
-
Login (see the tutorial here)
-
Subscribe to the offers manager change event.
-
Create an offer's state change listener.
-
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>
custom.js file.
let lastSelectedOfferId = "";
let offersWorker;
let openPositionWorker;
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();
session.getOffersManager().subscribeStateChange(new offersStateListener());
session.getOffersManager().subscribeOfferChange(new offersChangeListener());
offersWorker.updateState(session.getOffersManager().getState());
$('#refreshOffers').click(function () {
session.getInstrumentsManager().refresh()
session.getOffersManager().refresh()
});
See also subscribeStateChange, refresh()
When you have a price update for an instrument, you can:
- Get available instruments.
- Subscribe and Unsubscribe to instruments.
- Get historical prices for an instrument.
- Create a market order.
- Create an entry order.
- 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
-
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.
-
What is the correct refresh order for
instrumentManagerandoffersManager?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 listenChangeListenerevents for specific manager (for exampleIOfferChangeListenerforOfferManager) 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() }) } -
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 managergetState()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
-
-
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 (
OffersManagerandInstrumentsManager) before callinginstrumentsManager.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. |