Skip to content

Get Closed Positions

Overview

The "Get a List of Closed Positions" feature lets traders to access a detailed record of their closed positions. By using this functionality, users can review past transactions, assess trading performance, and gather essential data to refine their strategies. Closed positions are positions that have been exited from the market and have a final profit or loss. You can get a list of all closed positions, or filter them by instrument or time.

How to Get a List of Closed Positions

In this article you will learn how to get a list of closed positions using the closed positions manager. To get a list of closed positions, you need to follow these steps:

  1. Login (see the tutorial here).

  2. Create a closed positions manager.

  3. Create a closed position listener.

  4. Create a position change listener.

  5. Create a printer class.

Step 1: Login

Follow the steps in the login tutorial here.

Step 2: Creating a closed position manager and listener

A closed position listener is a class that implements the IClosedPositionChangeListener interface. It has one method: onClosedPositionChange. The method is called when a new position is closed or an existing position is updated.

Below, you can see some example code for creating the Closed positions listener:

Closed positions manager and closed position listener

let closedPositionsManager = session.getClosedPositionsManager(); // get closed position manager
let closedPositionChangeListener = new ClosedPositionChangeListener(closedPositionsManager); // create listener
closedPositionsManager.subscribeClosedPositionChange(closedPositionChangeListener); // subscribe
let closedPositionsManager = session.getClosedPositionsManager();
let positionWorker = new PositionWorker();
let closedPositionChangeListener = new ClosedPositionChangeListener(closedPositionsManager, positionWorker);
closedPositionsManager.subscribeClosedPositionChange(closedPositionChangeListener);

Before we create the manager, we first need to update our index.html to add the scripts that we are about to add to the project.
So, in the head of your HTML, you need to add this snippet. If you are using the login sample code or writing it from scratch, then you should have already added all the common scripts. You will need to add only these new ones.

<!-- The scripts below are belong to this particular sample. Make sure they aren't copied from another samples. -->
<script src="positions/closed-position-change-listener.js"></script>
<script src="positions/position-table-builder.js"></script>
<script src="positions/position-worker.js"></script>
At the start of our index.js file we will need to declare some global variables that we will use in the example.
const sessionFactory = FXConnectLite.FXConnectLiteSessionFactory;
const LoggerFactory = FXConnectLite.LoggerFactory;

document.addEventListener('DOMContentLoaded', () => {
    let session = sessionFactory.create('GetClosedPositionsSample');
    session.setLogger(LoggerFactory.createLogger(LoggerFactory.LEVEL_DEBUG));

    let closedPositionsManager = session.getClosedPositionsManager();
    let closedPositionsWorker = new PositionWorker();

    session.subscribeConnectionStatusChange(new ConnectionStatusChangeListener(session, closedPositionsManager));
    closedPositionsManager.subscribeStateChange(new ClosedPositionsStateListener(closedPositionsManager, closedPositionsWorker));

    bindConnectionRelatedEvents(session, () => closedPositionsManager.refresh());
});
Next we will create an ClosedPositionsWorker positions\position-worker.js class file which will be responsible for collecting all the details for each order and passing them to the Order 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);
    }
}

To use the closed position listener, you need to subscribe it to the closed positions manager using the subscribeClosedPositionChange method.

See also IClosedPositionsManager, subscribeClosedPositionChange.

Step 3: Creating a position change listener

A position change listener is a class that implements the IPositionChangeListener interface. It has one method: onPositionChange(). The method is called when a position is opened, closed, or modified.

Below, you can see some example code for creating the position change listener:

Position change listener

class ClosedPositionChangeListener implements FXConnectLite.IClosedPositionChangeListener {
    private closedPositionsManager: FXConnectLite.IClosedPositionsManager;

    constructor(closedPositionsManager: FXConnectLite.IClosedPositionsManager) {
        this.closedPositionsManager = closedPositionsManager;
    }

    onChange(closedPositionInfo: FXConnectLite.ClosedPositionInfo): void {
        Printer.print(`Closed position ${closedPositionInfo.getId()} changed`)

        ClosedPositionPrinter.print(this.closedPositionsManager.getClosedPosition(closedPositionInfo.getId()));
    }

    onAdd(closedPositionInfo: FXConnectLite.ClosedPositionInfo): void {
        Printer.print(`Closed position ${closedPositionInfo.getId()} added`)

        ClosedPositionPrinter.print(this.closedPositionsManager.getClosedPosition(closedPositionInfo.getId()));
    }

    onRefresh(): void {
        Printer.print(`Closed positions refreshed`)
        ClosedPositionPrinter.printAll(this.closedPositionsManager.getClosedPositionsSnapshot());
        }
}
class ClosedPositionChangeListener {
    constructor(closedPositionsManager, positionWorker) {
        this.closedPositionsManager = closedPositionsManager;
        this.positionWorker = positionWorker;
    }


    onAdd(closedPositionInfo) {
        let positionId = closedPositionInfo.getId();
        let position = this.closedPositionsManager.getClosedPosition(positionId);

        this.positionWorker.showPositionDetails(position);
    }


    onChange(closedPositionInfo) {
        let positionId = closedPositionInfo.getId();
        let position = this.closedPositionsManager.getClosedPosition(positionId);

        this.positionWorker.showPositionDetails(position);
    }


    onRefresh() {
        let snapshot = this.closedPositionsManager.getClosedPositionsSnapshot();

        this.positionWorker.showPositionsDetails(snapshot);
    }
}
class closedPositionsStateListener {
    onStateChange(state) {
        closedPositionsWorker.updateState(state);
        if (state.isLoaded()) {
            closedPositionsWorker.showClosedPositions();
        }
    }
}

To use the position change listener, you need to register it to the closed positions manager using the registerPositionChangeListener() method.

See also IClosedPositionsManager, getClosedPosition, getClosedPositionsSnapshot.

Step 4: Getting a List of Closed Positions

To get a list of closed positions, you can use one of these methods:

You can use the printer function to print the details of each closed position.

Step 5: Creating a printer class

A printer class is a class that takes a closed position as an argument and prints its properties and logs.

ClosedPositionPrinter

class ClosedPositionPrinter {

    public static print(closedPosition: FXConnectLite.ClosedPosition): void {
        Printer.print(``)
        Printer.print(`TradeID = ${closedPosition.getTradeID()}`)
        Printer.print(`AccountId = ${closedPosition.getAccountId()}`)
        Printer.print(`AccountName = ${closedPosition.getAccountName()}`)
        Printer.print(`AccountKind = ${closedPosition.getAccountKind()}`)
        Printer.print(`OfferId = ${closedPosition.getOfferId()}`)
        Printer.print(`Amount = ${closedPosition.getAmount()}`)
        Printer.print(`BuySell = ${closedPosition.getBuySell()}`)

        Printer.print(`OpenRate = ${closedPosition.getOpenRate()}`)
        Printer.print(`OpenTime = ${closedPosition.getOpenTime()}`)
        Printer.print(`OpenQuoteId = ${closedPosition.getOpenQuoteId()}`)
        Printer.print(`OpenOrderId = ${closedPosition.getOpenOrderId()}`)
        Printer.print(`OpenOrderReqId = ${closedPosition.getOpenOrderReqId()}`)
        Printer.print(`OpenOrderRequestTXT = ${closedPosition.getOpenOrderRequestTXT()}`)

        Printer.print(`CloseRate = ${closedPosition.getCloseRate()}`)
        Printer.print(`CloseTime = ${closedPosition.getCloseTime()}`)
        Printer.print(`CloseQuoteId = ${closedPosition.getCloseQuoteId()}`)
        Printer.print(`CloseOrderId = ${closedPosition.getCloseOrderId()}`)
        Printer.print(`CloseOrderReqId = ${closedPosition.getCloseOrderReqId()}`)
        Printer.print(`CloseOrderRequestTXT = ${closedPosition.getCloseOrderRequestTXT()}`)

        Printer.print(`Commission = ${closedPosition.getCommission()}`)
        Printer.print(`RolloverInterest = ${closedPosition.getRolloverInterest()}`)
        Printer.print(`TradeIdOrigin = ${closedPosition.getTradeIdOrigin()}`)
        Printer.print(`ValueDate = ${closedPosition.getValueDate()}`)
        Printer.print(`CloseOrderParties = ${closedPosition.getCloseOrderParties()}`)
        Printer.print(`PL = ${closedPosition.getPL()}`)
        Printer.print(`NetPL = ${closedPosition.getNetPL()}`)
        Printer.print(`PLPips = ${closedPosition.getPLPips()}`)
        Printer.print(`GrossPL = ${closedPosition.getGrossPL()}`)
        Printer.print(``)
    }

    public static printAll(closedPositions: FXConnectLite.ClosedPosition[]): void {
        Printer.print(`Current closed positions snapshot:`);
        Printer.print(`Number of closed positions: ${closedPositions.length}`);
        closedPositions.forEach(closedPosition => {
            ClosedPositionPrinter.print(closedPosition);
        });
    }
}
class PositionWorker {
    showPositionDetails(closedPosition) {
        let message = `
        TradeID = ${closedPosition.getTradeID()}
        AccountId = ${closedPosition.getAccountId()}
        AccountName = ${closedPosition.getAccountName()}
        AccountKind = ${closedPosition.getAccountKind()}
        OfferId = ${closedPosition.getOfferId()}
        Amount = ${closedPosition.getAmount()}
        BuySell = ${closedPosition.getBuySell()}
        OpenRate = ${closedPosition.getOpenRate()}
        OpenTime = ${closedPosition.getOpenTime()}
        OpenQuoteId = ${closedPosition.getOpenQuoteId()}
        OpenOrderId = ${closedPosition.getOpenOrderId()}
        OpenOrderReqId = ${closedPosition.getOpenOrderReqId()}
        OpenOrderRequestTXT = ${closedPosition.getOpenOrderRequestTXT()}
        CloseRate = ${closedPosition.getCloseRate()}
        CloseTime = ${closedPosition.getCloseTime()}
        CloseQuoteId = ${closedPosition.getCloseQuoteId()}
        CloseOrderId = ${closedPosition.getCloseOrderId()}
        CloseOrderReqId = ${closedPosition.getCloseOrderReqId()}
        CloseOrderRequestTXT = ${closedPosition.getCloseOrderRequestTXT()}
        Commission = ${closedPosition.getCommission()}
        RolloverInterest = ${closedPosition.getRolloverInterest()}
        TradeIdOrigin = ${closedPosition.getTradeIdOrigin()}
        ValueDate = ${closedPosition.getValueDate()}
        CloseOrderParties = ${closedPosition.getCloseOrderParties()}
        PL = ${closedPosition.getPL()}
        NetPL = ${closedPosition.getNetPL()}
        PLPips = ${closedPosition.getPLPips()}
        GrossPL = ${closedPosition.getGrossPL()}
        `;

        console.log(message);
    }


    showPositionsDetails(positions) {
        console.log('Current closed positions snapshot:');
        console.log(`Number of closed positions: ${positions.length}`);

        positions.forEach((position) => {
            this.showPositionDetails(position);
        });
    }
}

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 Name', position.getAccountName() ],
            [ 'Account Kind', position.getAccountKind() ],
            [ 'Offer ID', position.getOfferId() ],
            [ 'Amount', position.getAmount() ],
            [ 'Buy/Sell', position.getBuySell() ],
            [ 'Open Rate', position.getOpenRate() ],
            [ 'Open Time', position.getOpenTime() ],
            [ 'Open Quote ID', position.getOpenQuoteId() ],
            [ 'Open Order ID', position.getOpenOrderId() ],
            [ 'Open Order Request ID', position.getOpenOrderReqId().substring(0, 25) + '...' ],
            [ 'Close Rate', position.getCloseRate() ],
            [ 'Close Time', position.getCloseTime() ],
            [ 'Close Quote ID', position.getCloseQuoteId() ],
            [ 'Close Order ID', position.getCloseOrderId() ],
            [ 'Close Order Request ID', position.getCloseOrderReqId() ],
            [ 'Close Order Request TXT', position.getCloseOrderRequestTXT() ],
            [ 'Commission', position.getCommission() ],
            [ 'Rollover Interest', position.getRolloverInterest() ],
            [ 'Trade ID Origin', position.getTradeIdOrigin() ],
            [ 'Value Date', position.getValueDate() ],
            [ 'Close Order Parties', position.getCloseOrderParties() ],
            [ 'P/L', position.getPL() ],
            [ 'Net P/L', position.getNetPL() ],
            [ 'P/L Pips', position.getPLPips() ],
            [ 'Gross P/L', position.getGrossPL() ]
        ]);
    }

    #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();
    }
}

See also ClosedPosition.

When you have a list of all closed positions, you can:

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

Conclusion

You have learned how to use the closed positions manager to get a list of closed positions. You have created a closed positions manager, a closed position listener, a position change listener, and a printer function. You have subscribed the closed position listener to the closed positions manager using the subscribeClosedPositionChange method. You can now use this knowledge to build your own applications that work with closed positions.

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