A ticket identifies the current position object; an identifier links its lifecycle
An MT5 Expert Advisor often needs to persist a reference to an open position across callbacks, restarts or reconciliation passes. The tempting choice is POSITION_TICKET because it is the ticket used to select or modify the current position. MetaQuotes documents an important caveat: a position ticket can change because of server-side service operations, and in netting mode it is replaced when a single trade reverses the position. POSITION_IDENTIFIER, by contrast, remains unchanged throughout that position lifecycle [1].
This makes the two values useful for different jobs. Use the current ticket when an API operation explicitly requires the current position ticket. Use POSITION_IDENTIFIER as the durable correlation key when you need to connect the position to the orders and deals that created, modified or closed it. The official documentation states that the same identifier is written into related orders as ORDER_POSITION_ID and related deals as DEAL_POSITION_ID [1]. In a multi-account journal, also namespace this key by server and account; do not assume the identifier alone is globally unique.
Netting and hedging require different assumptions
Account position accounting changes the shape of the problem. In netting modes, only one position can exist for a symbol at a time, and that position can be the result of multiple deals. In retail hedging mode, multiple independent positions can coexist on the same symbol [2]. An EA that was tested only with one accounting model can therefore make a dangerous assumption when moved to another account.
PositionSelect(symbol) is especially easy to misuse in hedging mode. MetaQuotes notes that when several positions exist for the same symbol, PositionSelect selects the one with the lowest ticket [3]. That may be unrelated to the strategy instance you intended to manage. If the design owns multiple positions on one symbol, enumerate positions, filter by the ownership rules you defined such as Magic Number and symbol, then work with the exact ticket and identifier you observed.
Do not treat selected position data as a live pointer
Another subtle source of stale state is selection itself. PositionSelect and PositionSelectByTicket copy position data into the MQL5 program environment. The reference warns that later PositionGet calls can return that copied data even if the underlying position has changed or disappeared, so the position should be selected again immediately before reading the properties you intend to act on [3, 4].
This is a strong reason to make reconciliation idempotent. At each decision boundary, reacquire the position, verify that it still matches the expected symbol, Magic Number, identifier and current volume, then decide whether an action is still necessary. A cached local struct or boolean should not override the broker-side state merely because it was correct a few milliseconds or one callback earlier.
Worked example: a reversal changes the ticket but not the lifecycle ID
Consider a hypothetical netting account. An EA records a position with POSITION_IDENTIFIER 70001 and current POSITION_TICKET 71001. Later, one opposite trade reverses that net position. MetaQuotes documents that the position identifier is preserved through a netting reversal while POSITION_TICKET changes to the ticket of the order that caused the reversal [1]. Suppose, only for this educational example, the new current ticket becomes 72002.
If an external journal keyed the lifecycle only by 71001, it could incorrectly treat the reversed position as an unrelated object or believe the old position simply vanished. A better journal keeps 70001 as the lifecycle key, stores the current ticket as a mutable attribute, and links related orders and deals through ORDER_POSITION_ID and DEAL_POSITION_ID. The numbers here are invented and are not BamaUp account data or trading performance.
Practical acceptance test for restart-safe position reconciliation
On a demo account or controlled tester workflow, record both POSITION_IDENTIFIER and POSITION_TICKET for every strategy-owned position. Then test at least three cases: a normal position update, a netting reversal where applicable, and a restart followed by state reconstruction. In hedging mode, add a case with two same-symbol positions and confirm that the EA does not rely on PositionSelect(symbol) to choose the intended one.
For every test, log the account margin mode, symbol, Magic Number, identifier, current ticket, volume and direction. Re-select the position immediately before reading actionable properties. The MQL5 references cited here were rechecked on 4 October 2026. Server behavior, supported account models and broker rules remain environment-specific, and this identity model does not guarantee fills or strategy performance. Continue with BamaUp's free Auto-Trading Foundations path and EA validation checklist for a broader validation workflow.