Position Tracking
A position in AEX represents your net exposure in a contract for the current trading session. As your orders fill, the add-in accumulates fill data and updates your position in real time. Two custom functions let you read this data directly in Excel:
AEX.POSITION— reads a single property for one contract (streaming)AEX.POSITIONS— returns all positions as a spill table (streaming)
Positions are scoped to the current trading session and reset at session close.
AEX.POSITION
Returns a single streaming property of a position for a specific contract.
=AEX.POSITION(contractCode, property)
| Parameter | Type | Description |
|---|---|---|
contractCode | string | 7-character contract code, e.g. BPK1AH6 |
property | string | Property name (see below) |
Returns: number (streaming). Returns #N/A if no position exists for the contract yet.
Available Properties
| Property | Type | Description |
|---|---|---|
netQty | number | Net position in MW. Positive = net long; negative = net short |
long | number | Total volume bought (filled buy orders) in MW |
short | number | Total volume sold (filled sell orders) in MW |
avgBuyPx | number | Volume-weighted average price of all buy fills in $/MWh |
avgSellPx | number | Volume-weighted average price of all sell fills in $/MWh |
avgOpenPx | number | Average open price for the current net position in $/MWh |
pnl | number | Unrealised profit and loss for the session |
Examples
=AEX.POSITION("BPK1AH6","netQty") ' Net position: +10 means long 10 MW
=AEX.POSITION("BPK1AH6","long") ' Total long volume filled
=AEX.POSITION("BPK1AH6","short") ' Total short volume filled
=AEX.POSITION("BPK1AH6","avgBuyPx") ' Average buy price
=AEX.POSITION("BPK1AH6","avgSellPx") ' Average sell price
=AEX.POSITION("BPK1AH6","avgOpenPx") ' Average open price
=AEX.POSITION("BPK1AH6","pnl") ' Unrealised P&L
AEX.POSITIONS
Returns all current positions as a streaming spill array. The first row is a header row.
=AEX.POSITIONS()
Parameters: none
Returns: matrix (streaming, spill array)
The spill array has the following columns:
| Column | Description |
|---|---|
Contract | Contract ID |
Net Qty | Net position in MW |
Long | Total long volume in MW |
Short | Total short volume in MW |
Avg Buy | Volume-weighted average buy price in $/MWh |
Avg Sell | Volume-weighted average sell price in $/MWh |
Avg Open | Average open price in $/MWh |
PnL | Unrealised P&L |
The table updates in real time as fills arrive. It includes only contracts where at least one fill has occurred in the current session.
Enter =AEX.POSITIONS() in a cell with at least 8 blank columns to the right and enough blank rows below for your expected number of positions. The spill range expands automatically as new contracts are filled.
How P&L Is Calculated
The pnl property reflects unrealised profit and loss based on fill activity within the current session. It is calculated from the fills accumulated in the order store — the difference between buy and sell activity weighted by volume.
AEX is a market for electricity CFDs. P&L shown in the add-in reflects intra-session fill activity. Settlement calculations follow the contract terms and are performed by the exchange separately.
Session Scope
Position data is scoped to the current trading session:
- Positions initialise to zero at the start of each session.
- The
positionStoreis updated as fill events arrive over the WebSocket connection. - When the session closes, positions freeze at their final values until the next session begins.
- If the add-in reconnects mid-session, the server sends a snapshot of current positions to restore the store.
AEX.POSITION returns #N/A for a contract if no fills have occurred for that contract yet in the session.
Building a Position Blotter
The simplest blotter uses AEX.POSITIONS as a live table:
- Select an empty cell — for example,
A1. - Enter
=AEX.POSITIONS(). - The table spills across 8 columns and grows downward as positions are filled.
For a more structured blotter, combine AEX.POSITION with a static list of contract codes:
' Column A: your contract codes (static list)
' Column B: net quantity
' Column C: P&L
B2: =AEX.POSITION(A2,"netQty")
C2: =AEX.POSITION(A2,"pnl")
D2: =AEX.POSITION(A2,"avgOpenPx")
This approach gives you control over the layout and lets you add your own calculated columns — for example, mark-to-market using AEX.LAST:
' Mark-to-market: net position × (last price − average open price)
=AEX.POSITION(A2,"netQty") * (AEX.LAST(A2) - AEX.POSITION(A2,"avgOpenPx"))
AEX.LAST and AEX.POSITION are both streaming. A cell that combines them updates automatically whenever either value changes.
Next Steps
- Custom Functions Reference — full reference including
AEX.FILLSfor fill history - ORDERTRACK Formula — create and manage orders that generate fills
- Task Pane — the Fills tab shows a live fill history alongside position data