Get Open Positions
Overview
The "Get a List of Open Positions" feature provides traders with a convenient way to access real-time information about their current open positions. This tool provides a comprehensive overview of active trades, including details like entry prices, quantities, and profit or loss status. By using this feature, traders can keep a close eye on their existing positions, make timely decisions, and implement risk management strategies effectively.
How to get a list of open positions
In this article you will learn how to use the API to get a list of open positions.
You need to follow these steps:
-
Login (see the tutorial here)
-
Create an open positions manager.
-
Create Event Listeners
-
Get detailed information about all open positions.
-
Login (see the tutorial here)
-
Create an open positions manager.
-
Create Event Listeners
-
Get detailed information about all open positions.
-
Login (see the tutorial here)
-
Create an open positions manager.
-
Create Event Listeners
-
Get detailed information about all open positions.
-
Connection manager updates.
Step 1: Login
Follow the steps in the login tutorial here
Step 2: Create an open positions manager
The second step is to create an instance of the open positions manager. This is an object that provides methods for managing open positions. You can use the IOpenPositionsManager interface to access its methods and properties.
Below, you can see some example code to create an instance of the open positions manager:
let openPositionsManager = session.getOpenPositionsManager();
let openPositionsManager = session.getOpenPositionsManager();
Before we create the manager, we first need to update our HTML to add the JavaScript files that we will be adding. So, in the head in your HTML, you need to add this snippet making sure not to include any files twice.
<script src="common/table-builder.js"></script>
<script src="instruments/instrument-state-listener.js"></script>
<script src="positions/open-position-change-listener.js"></script>
<script src="positions/position-table-builder.js"></script>
<script src="positions/position-worker.js"></script>
<script src="offers/offer-change-listener.js"></script>
index.js file we will need to declare some global variables that we will use in the example.
Then create the instance of the open positions manager
const sessionFactory = FXConnectLite.FXConnectLiteSessionFactory;
const LoggerFactory = FXConnectLite.LoggerFactory;
document.addEventListener('DOMContentLoaded', () => {
let session = sessionFactory.create('GetOpenPositionsSample');
session.setLogger(LoggerFactory.createLogger(LoggerFactory.LEVEL_DEBUG));
let instrumentsManager = session.getInstrumentsManager();
session.subscribeConnectionStatusChange(new ConnectionStatusChangeListener(session, instrumentsManager));
let openPositionsManager = session.getOpenPositionsManager();
let openPositionsWorker = new PositionWorker();
let openPositionsStateListener = new OpenPositionsStateListener(openPositionsManager, openPositionsWorker);
openPositionsManager.subscribeStateChange(openPositionsStateListener);
let offersManager = session.getOffersManager();
offersManager.subscribeOfferChange(new OfferChangeListener(openPositionsManager));
instrumentsManager.subscribeStateChange(new InstrumentStateListener(offersManager));
bindConnectionRelatedEvents(session, () => {
openPositionsStateListener.isLoaded = false;
openPositionsManager.refresh();
});
});
positions\position-worker.js, file which will be responsible for collecting all the details for each order and passing them to the Open Positions table class which will print the table of data.
class PositionWorker {
constructor() {
this.tableBuilder = new PositionTableBuilder();
}
#getDataManagerStateString(state) {
if (state.isNotLoaded())
return 'not loaded';
if (state.isLoading())
return 'loading';
if (state.isLoaded())
return 'loaded';
return '(has error)';
}
showPositionDetails(position) {
this.tableBuilder.renderPositionDetailsSubtable(position);
}
showPositions(positions) {
this.tableBuilder.renderPositionTable(positions, this);
}
updateState(state) {
document.getElementById('state')
.textContent = this.#getDataManagerStateString(state);
}
}
For more information about the IOpenPositionsManager interface, see the API reference.
Step 3: Create Event Listeners
The next step is to create a position change listener. This is a class that will be used whenever a position is opened, closed, or updated. You can use the getOpenPosition and getOpenPositionsSnapshot methods of the open positions manager to get a single position or a snapshot of all positions.
Below, you can see some example code to create an open position change listener:
OpenPositionChangeListener
class OpenPositionChangeListener implements FXConnectLite.IOpenPositionChangeListener {
private openPositionsManager: FXConnectLite.IOpenPositionsManager;
constructor(openPositionsManager: FXConnectLite.IOpenPositionsManager) {
this.openPositionsManager = openPositionsManager;
}
onChange(openPositionInfo: FXConnectLite.OpenPositionInfo): void {
Printer.print(`OpenPosition ${openPositionInfo.getId()} is changed.`)
OpenPositionPrinter.print(this.openPositionsManager.getOpenPosition(openPositionInfo.getId()));
}
onAdd(openPositionInfo: FXConnectLite.OpenPositionInfo): void {
Printer.print(`OpenPosition ${openPositionInfo.getId()} is added.`)
OpenPositionPrinter.print(this.openPositionsManager.getOpenPosition(openPositionInfo.getId()));
}
onDelete(openPositionInfo: FXConnectLite.OpenPositionInfo): void {
Printer.print(`OpenPosition ${openPositionInfo.getId()} is deleted.`)
}
onRefresh(): void {
Printer.print(`Open positions refreshed`)
OpenPositionPrinter.printAll(this.openPositionsManager.getOpenPositionsSnapshot());
}
}
class OpenPositionsStateListener {
constructor(openPositionsManager, openPositionsWorker) {
this.openPositionsManager = openPositionsManager;
this.openPositionsWorker = openPositionsWorker;
}
onStateChange(state) {
this.openPositionsWorker.updateState(state);
if (state.isLoaded()) {
let positions = this.openPositionsManager.getOpenPositionsSnapshot();
this.openPositionsWorker.showPositions(positions);
}
}
}
Here we will be creating the file positions/open-position-change-listener.js
class OpenPositionsStateListener {
constructor(openPositionsManager, openPositionsWorker) {
this.openPositionsManager = openPositionsManager;
this.openPositionsWorker = openPositionsWorker;
}
onStateChange(state) {
this.openPositionsWorker.updateState(state);
if (state.isLoaded()) {
let positions = this.openPositionsManager.getOpenPositionsSnapshot();
this.openPositionsWorker.showPositions(positions);
}
}
}
For more information, see also IOpenPositionsManager, getOpenPosition, getOpenPositionsSnapshot
Now we can create a listener to offer changes. This is a function that will be called whenever an offer's data changes, such as when its price, volume, or spread changes. You will need this listener if you want to display calculated fields for the positions, such as profit and loss, margin, or pip cost.
Below you can see some example code to create a listener for offer changes:
OfferChangeListener
class OfferChangeListener implements FXConnectLite.IOfferChangeListener {
private openPositionsManager: FXConnectLite.IOpenPositionsManager;
constructor(openPositionsManager: FXConnectLite.IOpenPositionsManager) {
this.openPositionsManager = openPositionsManager;
}
onChange(offerInfo: FXConnectLite.OfferInfo): void {
this.print(offerInfo, `Offer ${offerInfo.getOfferId()} is changed.`);
}
onAdd(offerInfo: FXConnectLite.OfferInfo): void {
this.print(offerInfo, `Offer ${offerInfo.getOfferId()} is added.`);
}
print(offerInfo: FXConnectLite.OfferInfo, text: string): void {
let was: boolean = false;
this.openPositionsManager.getOpenPositionsSnapshot().forEach(openPosition => {
if(openPosition.getOfferId() == offerInfo.getOfferId()) {
if(!was) {
was = true;
Printer.print(text)
}
Printer.print(`Open position:`)
OpenPositionPrinter.print(openPosition);
}
});
}
}
class OfferChangeListener {
constructor(openPositionsManager) {
this.openPositionsManager = openPositionsManager;
// Offer states change constantly, so we add this flag to prevent infinite updates.
this.isLoaded = false;
}
onChange() {
if (this.isLoaded)
return;
this.openPositionsManager.refresh();
this.isLoaded = true;
}
}
This example does not contain pricing updates at this time, it will be added here later.
First we should create the offers listener class offers\offer-change-listener.js
class OfferChangeListener {
constructor(openPositionsManager) {
this.openPositionsManager = openPositionsManager;
// Offer states change constantly, so we add this flag to prevent infinite updates.
this.isLoaded = false;
}
onChange() {
if (this.isLoaded)
return;
this.openPositionsManager.refresh();
this.isLoaded = true;
}
}
We should also declare an instance of the OpenPositionsWorker as soon as the page has finished loading.
Then we should Subscribe to the event by a openPositionsManager subscribeChangeStateListener.
const sessionFactory = FXConnectLite.FXConnectLiteSessionFactory;
const LoggerFactory = FXConnectLite.LoggerFactory;
document.addEventListener('DOMContentLoaded', () => {
let session = sessionFactory.create('GetOpenPositionsSample');
session.setLogger(LoggerFactory.createLogger(LoggerFactory.LEVEL_DEBUG));
let instrumentsManager = session.getInstrumentsManager();
session.subscribeConnectionStatusChange(new ConnectionStatusChangeListener(session, instrumentsManager));
let openPositionsManager = session.getOpenPositionsManager();
let openPositionsWorker = new PositionWorker();
let openPositionsStateListener = new OpenPositionsStateListener(openPositionsManager, openPositionsWorker);
openPositionsManager.subscribeStateChange(openPositionsStateListener);
let offersManager = session.getOffersManager();
offersManager.subscribeOfferChange(new OfferChangeListener(openPositionsManager));
instrumentsManager.subscribeStateChange(new InstrumentStateListener(offersManager));
bindConnectionRelatedEvents(session, () => {
openPositionsStateListener.isLoaded = false;
openPositionsManager.refresh();
});
});
Create a listener for instrument changes:
We should also declare an instance of the Instruments Listener instruments\instrument-state-listener.js and subscribe to it as soon as the page has finished loading.
Then we should Subscript to the instrumentManager subscribeChangestateListener and the getOpenPositionsManager subscribeChangeStateListener.
class InstrumentStateListener {
constructor(offersManager) {
this.offersManager = offersManager;
}
onStateChange(state) {
if (state.isLoaded())
this.offersManager.refresh();
}
}
index.js file we should subscribe to it.
const sessionFactory = FXConnectLite.FXConnectLiteSessionFactory;
const LoggerFactory = FXConnectLite.LoggerFactory;
document.addEventListener('DOMContentLoaded', () => {
let session = sessionFactory.create('GetOpenPositionsSample');
session.setLogger(LoggerFactory.createLogger(LoggerFactory.LEVEL_DEBUG));
let instrumentsManager = session.getInstrumentsManager();
session.subscribeConnectionStatusChange(new ConnectionStatusChangeListener(session, instrumentsManager));
let openPositionsManager = session.getOpenPositionsManager();
let openPositionsWorker = new PositionWorker();
let openPositionsStateListener = new OpenPositionsStateListener(openPositionsManager, openPositionsWorker);
openPositionsManager.subscribeStateChange(openPositionsStateListener);
let offersManager = session.getOffersManager();
offersManager.subscribeOfferChange(new OfferChangeListener(openPositionsManager));
instrumentsManager.subscribeStateChange(new InstrumentStateListener(offersManager));
bindConnectionRelatedEvents(session, () => {
openPositionsStateListener.isLoaded = false;
openPositionsManager.refresh();
});
});
See also IOpenPositionsManager, getOpenPosition, getOpenPositionsSnapshot
Step 4: Get detailed information about all open positions
The next step is to get detailed information about all open positions. You can use the OpenPosition interface to access the properties of an open position, such as its trade ID, amount, direction, instrument, and stop/limit orders.
Below, you can see some example code to get detailed information about all open positions:
Position change listener
class OpenPositionPrinter {
public static print(openPosition: FXConnectLite.OpenPosition): void {
Printer.print(``)
Printer.print(`TradeID = ${openPosition.getTradeID()}`)
Printer.print(`AccountId = ${openPosition.getAccountId()}`)
Printer.print(`AccountName = ${openPosition.getAccountName()}`)
Printer.print(`AccountKind = ${openPosition.getAccountKind()}`)
Printer.print(`OfferId = ${openPosition.getOfferId()}`)
Printer.print(`Amount = ${openPosition.getAmount()}`)
Printer.print(`BuySell = ${openPosition.getBuySell()}`)
Printer.print(`OpenRate = ${openPosition.getOpenRate()}`)
Printer.print(`OpenTime = ${openPosition.getOpenTime()}`)
Printer.print(`OpenQuoteId = ${openPosition.getOpenQuoteId()}`)
Printer.print(`OpenOrderId = ${openPosition.getOpenOrderId()}`)
Printer.print(`OpenOrderReqId = ${openPosition.getOpenOrderReqId()}`)
Printer.print(`OrderRequestTXT = ${openPosition.getOpenOrderRequestTXT()}`)
Printer.print(`Commission = ${openPosition.getCommission()}`)
Printer.print(`RolloverInterest = ${openPosition.getRolloverInterest()}`)
Printer.print(`TradeIdOrigin = ${openPosition.getTradeIdOrigin()}`)
Printer.print(`ValueDate = ${openPosition.getValueDate()}`)
Printer.print(`Parties = ${openPosition.getParties()}`)
Printer.print(`PL = ${openPosition.getPL()}`)
Printer.print(`PLPips = ${openPosition.getPLPips()}`)
Printer.print(`GrossPL = ${openPosition.getGrossPL()}`)
Printer.print(`CloseRate = ${openPosition.getCloseRate()}`)
Printer.print(`StopRate = ${openPosition.getStopRate()}`)
Printer.print(`LimitRate = ${openPosition.getLimitRate()}`)
Printer.print(`StopOrderId = ${openPosition.getStopOrderID()}`)
Printer.print(`LimitOrderId = ${openPosition.getLimitOrderID()}`)
Printer.print(`UsedMargin = ${openPosition.getUsedMargin()}`)
Printer.print(`Dividends = ${openPosition.getDividends()}`)
Printer.print(``)
}
public static printAll(openPositions: FXConnectLite.OpenPosition[]): void {
Printer.print(`Current open position snapshot:`);
Printer.print(`Number of open positions is ${openPositions.length}`);
openPositions.forEach(openPosition => {
OpenPositionPrinter.print(openPosition);
});
}
}
class PositionWorker {
showPositionDetails(position) {
let message = `
TradeID = ${position.getTradeID()}
AccountId = ${position.getAccountId()}
AccountName = ${position.getAccountName()}
AccountKind = ${position.getAccountKind()}
OfferId = ${position.getOfferId()}
Amount = ${position.getAmount()}
BuySell = ${position.getBuySell()}
OpenRate = ${position.getOpenRate()}
OpenTime = ${position.getOpenTime()}
OpenQuoteId = ${position.getOpenQuoteId()}
OpenOrderId = ${position.getOpenOrderId()}
OpenOrderReqId = ${position.getOpenOrderReqId()}
OpenOrderRequestTXT = ${position.getOpenOrderRequestTXT()}
CloseRate = ${position.getCloseRate()}
Commission = ${position.getCommission()}
RolloverInterest = ${position.getRolloverInterest()}
TradeIdOrigin = ${position.getTradeIdOrigin()}
ValueDate = ${position.getValueDate()}
Parties = ${position.getParties()}
PL = ${position.getPL()}
NetPL = ${position.getNetPL()}
PLPips = ${position.getPLPips()}
GrossPL = ${position.getGrossPL()}
StopRate = ${position.getStopRate()}
LimitRate = "${position.getLimitRate()}
StopOrderId = ${position.getStopOrderID()}
LimitOrderId = ${position.getLimitOrderID()}
UsedMargin = ${position.getUsedMargin()}
`;
console.log(message);
}
showPositionsDetails(positions) {
console.log('Current open positions snapshot:');
console.log(`Number of open positions: ${positions.length}`);
positions.forEach((position) => {
this.showPositionDetails(position);
});
}
}
export default PositionWorker;
For printing the results of the command, we have first created a file which will contain our TableBuilder class.
Follow the instruction in the Table Builder tutorial here.
Next we will create the file positions\position-table-builder.js which will use the previous Table Builder class and will populate all of the values in the table.
class PositionTableBuilder {
constructor() {
this.builder = new TableBuilder();
}
#getPositionDetails(position) {
return new Map([
[ 'Account ID', position.getAccountId() ],
[ 'Account Kind', position.getAccountKind() ],
[ 'Offer ID', position.getOfferId() ],
[ 'Open Time', position.getOpenTime() ],
[ 'Open Quote ID', position.getOpenQuoteId() ],
[ 'Open Order ID', position.getOpenOrderId() ],
[ 'Open Order Request ID', position.getOpenOrderReqId().substring(0, 25) + '...' ],
[ 'Open Order Request TXT', position.getOpenOrderRequestTXT() ],
[ 'Commission', position.getCommission() ],
[ 'Rollover Interest', position.getRolloverInterest() ],
[ 'Trade ID Origin', position.getTradeIdOrigin() ],
[ 'Value Date', position.getValueDate() ],
[ 'Parties', position.getParties() ],
[ 'P/L', position.getPL() ],
[ 'P/L Pips', position.getPLPips() ],
[ 'Gross P/L', position.getGrossPL() ],
[ 'Close Rate', position.getCloseRate() ],
[ 'Stop Rate', position.getStopRate() ],
[ 'Limit Rate', position.getLimitRate() ],
[ 'Used Margin', position.getUsedMargin() ]
]);
}
#onPositionClick(position, positionWorker) {
let callback = function() {
positionWorker.showPositionDetails(position);
};
this.builder.onRowClick(position.getTradeID(), callback);
}
#renderDataTableRow(position, positionWorker) {
let columns = [
{ className: 'col-sm-3', value: position.getTradeID() },
{ className: 'col-sm-3', value: position.getAccountName() },
{ className: 'col-sm-2', value: position.getBuySell() },
{ className: 'col-sm-2', value: position.getOpenRate() },
{ className: 'col-sm-2', value: position.getAmount() }
];
let row = this.builder.createDataTableRow(columns);
row.onclick = () => this.#onPositionClick(position, positionWorker);
}
#renderNoPositionsMessage() {
let columns = [
{ className: 'col-sm-12', value: 'No Positions' }
];
this.builder.createDataTableRow(columns);
}
#renderPositionTableHeader() {
let columns = [
{ className: 'col-sm-3', value: 'ID' },
{ className: 'col-sm-3', value: 'Account Name' },
{ className: 'col-sm-2', value: 'B/S' },
{ className: 'col-sm-2', value: 'Rate' },
{ className: 'col-sm-2', value: 'Amount' },
];
this.builder.createHeaderTableRow(columns);
}
renderPositionDetailsSubtable(position) {
let details = this.#getPositionDetails(position);
let columns = this.builder.createDataSubtableColumns(details);
let detailsRow = this.builder.createDataSubtable(position.getTradeID(), columns, 'row mb-3 details');
detailsRow.onclick = () => this.builder.removeSubtable();
}
renderPositionTable(positions, positionWorker) {
this.#renderPositionTableHeader();
if (positions.length === 0) {
this.#renderNoPositionsMessage();
} else {
for (let position of positions)
this.#renderDataTableRow(position, positionWorker);
}
this.builder.showContainer();
}
}
Step 5: Connection manager updates
The last thing we need to do is to update the connection manager to listed for posted information to the managers.
in connection_management\connection-management.js we need to update the bindConnectionRelatedEvents method to support the refresh button.
function bindConnectionRelatedEvents(session, refreshFunc) {
document.getElementById('btn-submit')
.onclick = () => login(session);
document.getElementById('btn-logout')
.onclick = () => session.logout();
document.getElementById('btn-refresh')
.onclick = () => refreshFunc();
}
class ConnectionStatusChangeListener {
constructor(session, instrumentsManager) {
this.session = session;
this.instrumentsManager = instrumentsManager;
}
#getConnectionStatusName(status) {
if (status.isConnected())
return 'Connected';
if (status.isConnecting())
return 'Connecting';
if (status.isReconnecting())
return 'Reconnecting';
return 'Disconnected';
}
#showLoginSection() {
document.getElementById('workspace-section')
.style.display = 'none';
document.getElementById('login-section')
.style.display = 'block';
}
#showWorkspaceSection(session, instrumentsManager) {
document.getElementById('login-section')
.style.display = 'none';
document.getElementById('workspace-section')
.style.display = 'block';
document.getElementById('password-expired')
.textContent = session.getSystemSettingsProvider().isPasswordExpired();
instrumentsManager.refresh();
}
onConnectionStatusChange(status) {
document.getElementById('connection-status')
.textContent = this.#getConnectionStatusName(status);
if (status.isConnected())
this.#showWorkspaceSection(this.session, this.instrumentsManager);
if (status.isDisconnected())
this.#showLoginSection();
}
}
See also IOpenPositionsManager, getOpenPosition, getOpenPositionsSnapshot, OpenPosition
When you have a list of all open positions, you can:
- Get available instruments.
- Subscribe and Unsubscribe to instruments.
- Get price updates for an instrument.
- Get historical prices for an instrument.
- Create a market order.
- Create an entry order.
Conclusion
You have learned how to use the API to get a list of open positions. Before you can get a list of open positions, you need to create an instance of the open positions manager, create a position change listener, create a listener for offer changes, and get detailed information about all open positions. You have also learned how to create an instance of the open positions manager using the IOpenPositionsManager interface and how to create a position change listener using the getOpenPosition and getOpenPositionsSnapshot methods of the open positions manager. You can now use this knowledge to manage your open positions on the platform.
Download the sample Node TypeScript, Node JavaScript, JavaScript.
| Table of Contents |
|---|
| Get Open Positions The article teaches how to get a list of open positions. |
| Get Closed Positions The article teaches how to get a list of closed positions. |
| Get Position Details API Command used to get the details of a position |
| Close a Position API Command used to close a position |
| Close All Open Positions API Command used to close all open positions |