Preventing Duplicate Orders During Network Retries
Network failures can make an automated trading system uncertain about whether an order was actually accepted. Client order IDs, idempotency records and broker reconciliation can help systems retry safely without blindly creating duplicate orders.
Automated trading systems often depend on network communication between an application, a broker API and other services. A request can time out even when the broker has already received and processed it. If the software simply sends the same order again, one intended trade can become two.
This is why retry handling is a trading-system design problem, not just a networking problem. A reliable system should be able to identify an order, remember what it has already attempted, and reconcile its internal state with the broker before deciding whether another action is required.
Why Network Retries Can Create Duplicate Orders
A typical order flow looks simple:
- The strategy generates an entry signal.
- The application creates an order request.
- The request is sent to the broker.
- The broker processes the request.
- The application receives an acknowledgement.
The problem appears when the connection fails between steps 3 and 5. The broker may have accepted the order, but the application does not know that yet.
The dangerous timeout scenario
Suppose a strategy wants to buy 100 units. The application sends the order and waits for a response. The network connection then times out.
From the application's point of view, there are several possibilities:
- The broker never received the request.
- The broker received it but did not process it.
- The broker accepted the order but the response was lost.
- The order was accepted and partially or fully executed before the connection failed.
If the application treats every timeout as a failed order and immediately submits another order, it may create a duplicate.
A timeout is not automatically proof that an order was rejected.
Use a Client Order ID to Identify the Intended Order
One of the most useful protections is a client order ID, sometimes called a client-generated order identifier.
The application creates a unique identifier before sending an order. That identifier belongs to the intended order attempt and can be stored in the application's database.
For example:
- Strategy: Range Breakout
- Symbol: ABC
- Side: Buy
- Quantity: 100
- Client Order ID: `RB-2026-08-24-00017`
If the network request fails, the system still knows exactly which intended order it was trying to place.
Why the identifier matters
Without a stable identifier, a retry can look like a completely new request.
With a stable identifier, the system can ask:
"What happened to order RB-2026-08-24-00017?"
This becomes especially useful when the broker or API supports a client-supplied order identifier or another mechanism for safely identifying requests. The exact behaviour depends on the broker API, so the integration must follow that API's documented capabilities and rules.
Store Idempotency Records
An idempotency record is a persistent record that allows the application to recognise that a particular logical operation has already been processed or is already in progress.
For trading software, the logical operation could be:
- Open a position for a strategy.
- Place an entry order.
- Cancel a specific order.
- Submit a particular exit order.
A basic record might contain:
- Client order ID
- Strategy ID
- Symbol
- Side
- Quantity
- Requested price, if applicable
- Current internal status
- Broker order ID, when known
- Creation timestamp
- Last update timestamp
- Retry information
The important point is that this information should not exist only in temporary application memory. If the application restarts, the system still needs to know what it was doing.
Preventing a blind retry
Imagine the application has already created `RB-2026-08-24-00017`.
The first submission times out.
Instead of immediately creating `RB-2026-08-24-00018`, the application can first look up the existing record and determine whether the original operation is unresolved.
This creates a safer sequence:
- Keep the original client order ID.
- Mark the request as pending reconciliation.
- Query the broker for the order or related execution information.
- Match the broker response with the internal record.
- Retry only if the system has sufficient evidence that the original request was not accepted.
This is far safer than treating every network error as permission to create another order.
Broker Reconciliation Is the Missing Step
Reconciliation means comparing what the application believes happened with what the broker reports actually happened.
A trading system should be able to reconcile information such as:
- Open orders
- Order status
- Executed quantity
- Remaining quantity
- Positions
- Cancellations
- Rejections
- Broker order identifiers
Example of reconciliation after a timeout
Suppose the application sends a buy order for 100 units and receives a timeout.
The application records:
`Client Order ID: RB-2026-08-24-00017`
`Internal status: UNKNOWN`
Instead of submitting another buy order immediately, it queries the broker.
The broker reports an accepted order with the matching client identifier and a broker order ID.
The application can then update its record:
`Internal status: OPEN`
`Broker Order ID: 845721`
No duplicate submission is required.
If the broker reports that no matching order exists, the system can then evaluate whether retrying is appropriate.
Order State Should Be Explicit
A robust order-management system should avoid vague states such as simply success or failure.
Useful internal states can include:
- Created
- Submission pending
- Submitted
- Open
- Partially filled
- Filled
- Cancel requested
- Cancelled
- Rejected
- Reconciliation required
- Unknown
The exact state model depends on the application and broker, but the important principle is to represent uncertainty explicitly.
Why "unknown" matters
An unknown state tells the software:
Do not assume. Find out.
This small design decision can prevent a large class of duplicate-order problems.
Idempotency Must Cover More Than Order Placement
Duplicate prevention should also be considered for cancellations, exits and other order actions.
For example, suppose a system sends a cancellation request and the network fails. Retrying without checking the current broker state can create unnecessary requests or cause the application to misunderstand the order's actual status.
Similarly, if an exit signal is processed twice, the system should not blindly submit two exit orders when one successful action already closed the intended position.
A useful design approach is to give every logical action a unique identifier and track its lifecycle.
Handling Partial Fills Correctly
Duplicate prevention becomes more important when an order is partially filled.
Suppose an order requests 100 units, but the broker reports that 40 units have already been executed.
A retry that submits another 100-unit order could increase the total exposure to 140 units.
The application must distinguish between:
- Requested quantity
- Executed quantity
- Remaining quantity
For example:
`Requested: 100`
`Executed: 40`
`Remaining: 60`
The correct next action depends on the strategy and order rules. The software should never assume that the original quantity is still completely outstanding.
Common Design Mistakes
Several implementation patterns can make retry handling unsafe.
Treating every timeout as a rejection
A timeout only tells the application that it did not receive the expected response within the configured period.
It does not necessarily tell the application what happened at the broker.
Generating a new order ID for every retry
If every retry receives a new logical identity, the application loses the connection between the original operation and its retries.
Keeping order state only in memory
A restart can erase information about pending operations. Persistent state is important for recovery.
Ignoring broker-side positions
Order records alone may not provide the complete picture. A system should also consider the broker's current position state when reconciling trading activity.
Assuming APIs behave the same way
Different broker APIs expose different order identifiers, status models, retry behaviour and request limits. Integration logic must be based on the actual API documentation.
A Practical Retry Architecture
A safer architecture can follow this general sequence:
- Create a logical order ID before submission.
- Persist the order intent in the database.
- Submit the request using the supported identification mechanism.
- Record the broker response when received.
- Treat uncertain responses as unresolved, not automatically rejected.
- Reconcile with broker state after a timeout or connection failure.
- Update executed and remaining quantities.
- Retry only when reconciliation supports another submission.
- Log every state transition for audit and troubleshooting.
This approach separates strategy intent from transport uncertainty. The network may fail, but the application's understanding of the intended action remains persistent.
Logging Makes Duplicate Problems Easier to Diagnose
A trading system should maintain useful logs around every order action.
Important fields can include:
- Timestamp
- Strategy ID
- Client order ID
- Broker order ID
- Request type
- Symbol
- Quantity
- Internal status
- Broker status
- Error or timeout information
- Retry count
- Reconciliation result
Logs should help a developer reconstruct what happened without relying on memory or guesswork. Humans already produce enough mysterious production incidents without making the software equally unhelpful.
Testing Retry and Failure Scenarios
Duplicate-order protection should be tested deliberately.
Useful scenarios include:
- Request times out after reaching the broker.
- Response is lost after an order is accepted.
- Broker rejects the order.
- Application restarts during submission.
- Network disconnects during reconciliation.
- Order is partially filled.
- Duplicate signal arrives for the same candle.
- Two application processes attempt the same logical action.
The goal is not merely to test the normal successful path. The important behaviour often appears when communication becomes uncertain.
Why This Matters for Trading Software Development
A trading application is more than a strategy formula. It must also manage communication failures, persistent state, order status and recovery behaviour.
For businesses building automated trading systems, these engineering details can be as important as the entry and exit rules themselves. Suyotech Solutions develops trading software and automation systems with attention to application logic, broker integration, order handling and operational workflows.
Software design can reduce avoidable execution errors, but it cannot eliminate market risk, broker-side conditions, connectivity problems or unexpected external failures. Backtests and automation also cannot guarantee future trading results.
Conclusion
Duplicate orders are often caused by a simple assumption: if the application did not receive a response, the order must not have happened.
A safer approach is to treat order submission as a stateful process. Client order IDs identify the intended operation, idempotency records preserve its history, and broker reconciliation helps determine what actually happened before another action is taken.
If you are planning a custom trading application, broker API integration or automated order-management system, you can contact Suyotech Solutions to discuss the software engineering requirements for your project.
