A paired buy and sell EA can open both legs correctly and still fail after the first exit. The reason is usually not the entry signal. The lifecycle was never defined.
That distinction matters to a buyer because a clean compile only proves that the code is syntactically valid. It does not prove that the Expert Advisor knows which cycle is active, which leg survived, or whether a restart permits another entry.
The buyer question
Before development starts, the specification should answer one question:
What state is the EA in after one leg closes, and what exact event completes the cycle?
If that answer is vague, the implementation can place a replacement order too early, leave an orphaned position unmanaged, or restart into the wrong state.
Use one explicit lifecycle
A practical model has four states:
- IDLE: no active pair exists and a new cycle may start.
- PAIR_OPEN: both legs belong to the active cycle.
- ONE_LEG_CLOSED: one leg has exited and the remaining leg still belongs to the same cycle.
- CYCLE_COMPLETE: both legs are closed, cleanup is complete, and the EA may return to IDLE.
The names can change. The important part is that every transition has one deterministic trigger.
For example, the transition from PAIR_OPEN to ONE_LEG_CLOSED should be caused by one verified close event for a ticket that belongs to the active cycle. It should not be inferred only from a temporary order count. The transition from ONE_LEG_CLOSED to CYCLE_COMPLETE should require proof that the survivor has closed and that no cycle-owned pending order remains.
A minimal transition table
| Current state | Verified event | Next state | Forbidden side effect |
|---|---|---|---|
| IDLE | entry condition and no active cycle | PAIR_OPEN | opening two cycles |
| PAIR_OPEN | one cycle-owned leg closes | ONE_LEG_CLOSED | replacing the closed leg |
| ONE_LEG_CLOSED | survivor closes | CYCLE_COMPLETE | opening a new pair twice |
| CYCLE_COMPLETE | cleanup persisted | IDLE | losing the completed-cycle record |
This table gives a buyer something more useful than “the bot works.” It defines what can be checked.
Freeze three acceptance tests
1. Normal closure
Both entries fill. Both legs close through their intended exit rules. The EA records the cycle as complete and does not open a replacement until the next valid cycle trigger.
The evidence should include the two entry tickets, both close events, the single cycle identifier, and the final state.
2. One leg closes first
One position hits its stop, target, or included manual-close condition. The surviving leg remains managed by the current cycle. The EA must not treat the account as flat and must not create a duplicate pair.
This is where many apparently simple paired-order requests become ambiguous. “Keep the other trade running” is not enough. The specification still needs to say which management rules remain active and whether another signal is ignored until the survivor closes.
3. Terminal restart
MetaTrader restarts while the pair is open or while one leg remains. The EA reconstructs the same state from durable identifiers and current positions. It must not depend only on variables that disappeared with the terminal session.
A useful restart test records the state before shutdown, starts the terminal again, and compares the reconstructed cycle identifier, leg ownership and permission to open the next pair. Any difference is a failed acceptance case.
The identifiers matter
A stable implementation should be able to answer:
- Which positions belong to the current cycle?
- Which leg is the buy and which is the sell?
- Has either leg already closed?
- Was the close expected, manual, or caused by a broker event?
- Is a new cycle allowed now?
Magic numbers, symbols, comments, ticket mappings and persisted cycle identifiers can all help. The correct combination depends on the platform and scope. What matters is that the reconstruction rule is explicit and testable.
In MT4, order-history scans also need a fixed selection rule. “Take the last closed order” can be wrong when another EA or a manual trade uses the same account. In MT5 hedging mode, position and deal history introduce a different mapping problem. Platform choice is part of the acceptance contract, not a detail to leave until coding.
Warning signs in a specification
The following phrases usually need clarification before coding:
- “Open a new pair when one trade closes.”
- “Keep the other trade running as normal.”
- “Restart the bot after both trades finish.”
- “Avoid duplicate orders.”
Each phrase hides multiple state transitions. Does a partial close count? What happens after a manual close? What if the broker rejects one entry? What if the terminal restarts between the close event and the state update?
These are not reasons to delay the project. They are decisions that can be frozen as safe defaults. For a first version, a reasonable boundary might reject partial closes, keep the survivor under its original stop and target, and permit the next cycle only after both legs and all cycle-owned pending orders are gone.
Scope boundaries prevent revision loops
A clean first version should state which close paths are included. It should also list exclusions such as partial closes, cross-symbol baskets, manual intervention, broker-side order changes, or recovery from edited comments if those cases are not part of the initial scope.
That is not bureaucracy. It gives the buyer and developer the same definition of “done.” A revision is then about a failed agreed case, not a new interpretation of an undefined lifecycle.
What proof should be delivered?
For this kind of EA, a useful handover contains more than the .mq4 or .mq5 file:
- editable source code;
- a clean compile result;
- the transition table used by the implementation;
- logs or screenshots for the three acceptance cases;
- a short change note;
- setup notes covering platform mode, symbol and identifiers.
The source lets the buyer retain control. The matrix makes the behavior reviewable. The evidence separates “compiled” from “accepted.”
A simple pre-coding checklist
Before funding implementation, freeze:
- the four lifecycle states;
- every allowed transition;
- the identifier used to rebuild state;
- the three acceptance tests above;
- the included close paths;
- the excluded edge cases;
- the exact event that allows the next cycle.
Once those points are deterministic, the entry and exit rules become much easier to implement and test.
The full buyer checklist is available here: https://stratcorealpha.com/engineering-notes/mt4-paired-order-lifecycle
Top comments (0)