NOONOO TRADINGStart in the bot

Duplicate Orders — Retrying an Unanswered Order Can Double Your Position

You press the order button and the screen freezes. Several seconds pass without a response. Most people press it again. Automated trading code often does the same: it treats no response as failure and resends the request. The problem is that the first order may already have filled.

“No Response” Does Not Mean “The Order Was Never Sent”

An order request travels in two directions: from you to the exchange, and from the exchange back to you with the result. If only the return path fails, the screen still shows nothing.

Three Actual States Behind No Response

① The request never reached the exchange.
  → No order; retrying is safe.

② The exchange received it and is processing it.
  → An order will be created.

③ It already filled, but the response was lost.
  → An order exists; retrying creates two.

─────────────
What you see locally:
  All three cases look identical.
  (Timeout or empty response.)

You cannot selectively retry only case ① from that response because the cases are indistinguishable. This has the same root as the issue discussed in WebSocket disconnection: silence is not information. Unlike a price query, however, an order is a request that moves money, so sending it again has a different cost.

The Numbers Created by One Retry

If the same request is sent twice and both succeed, the account takes on twice the planned quantity. With leveraged contracts, the guide also describes liquidation moving closer when exposure rises relative to available margin.

When 0.1 Contracts Become 0.2

Plan
  BTC long 0.1 · Entry 100,000
  Notional 10,000 · 20× leverage
  Margin 500

First order → Response timeout
Second order → Success response

Actual fills
  0.1 + 0.1 = 0.2 contracts
  Notional 20,000
  Margin 1,000 (double)

─────────────
If price falls 3%:
  Planned loss −300
  Actual loss −600

The bot's internal record:
  Still says 0.1 contracts.

The last line is worse than merely doubling the loss. Since the internal record contains only 0.1, the bot closes only 0.1 when exiting. The remaining 0.1 stays in the account unmanaged. Believing it has no position, the bot enters again on the next signal while the abandoned quantity continues to generate changing PnL.

The guide explains that liquidation moves closer if notional doubles relative to margin: the same balance can tolerate only half the adverse price movement. However accurately you calculated the stop-loss, a quantity that differs from the plan makes that calculation apply to a different position.

The Core Solution: Give the Order Your Own Label

Most exchanges let you include an identifier you choose when placing an order, commonly called a client order ID. The guide describes sending the same identifier twice as causing the exchange to reject the second request.

With and Without an Order Label

Without a label:
  First: “Buy 0.1 long” → Filled.
  Second: “Buy 0.1 long” → Filled again.
  To the exchange: Two different orders.

With a label:
  First: “Long 0.1 · ID bot-9f3a” → Filled.
  Second: “Long 0.1 · ID bot-9f3a
  → Rejected with a duplicate error.

─────────────
Naming rules:
  · Keep it fixed for that one trade.
  · It must not change on a retry.
  · Do not regenerate it from time or randomness alone.
    (A new name on every retry is equivalent to no label.)

The most common mistake is the last one. Creating a new identifier every time you send defeats its purpose. A retry is another attempt at the same order, so the name must stay the same. Generate the name once when the signal occurs, store it, and reuse that stored name for retries.

The guide treats a duplicate rejection as confirmation that the order was already accepted, rather than a failure. If a duplicate error is handled like a generic error and retried again, the problem returns. It recommends distinguishing error codes and treating duplicates as success before proceeding.

When You Cannot Use a Label: Query Before Retrying

Some exchanges or libraries do not support client order IDs. In that case, the guide gives one sequence: query before sending again.

The Guide's Retry Sequence

Send order → No response
  ↓ Wait 1–2 seconds
Query open orders
Query recent fills
  ↓
Does the intended order exist?
  Yes → Do not retry; update records only.
  No → Then send again.

─────────────
What never to do:
  No response → Resend immediately
  → Resend again on failure
  → Three attempts = Up to three times the position

Identifying the intended order requires looking at direction, quantity, price, and time together. These queries themselves add requests, so space them out to avoid rate-limit errors (429). The guide argues that the cost of rate limiting is not comparable with the cost of doubling a position: skipping verification costs more.

When Cancellation and Replacement Overlap

Traders often cancel and replace a limit order when price moves away. The gap between those two operations creates room for inconsistency.

A Cancel-Replace Race

12:00:00 Limit long at 99,000 accepted
12:00:04 Price moves → Cancellation requested
12:00:04 Almost simultaneously, the order fills
12:00:05 Cancellation response: “No such order”
12:00:05 Bot concludes: It was canceled
12:00:05 New limit order at 98,500 accepted

─────────────
Result:
  Filled at 99,000 + Pending at 98,500
  Position known to the bot = 0

Response:
  Failed or ambiguous cancellation → No replacement order
  → Start by querying the position again.

“I canceled it, so it must be gone” is an assumption. When a cancellation response is ambiguous, check the actual state instead of sending another order. Position reconciliation explains how to periodically align records with reality. Partial fills make it more complicated: replacing an order after only 0.04 of 0.1 has filled can leave an awkward remaining quantity.

Duplicates Caused by People and Processes

The network is not the only source of trouble. Running the same bot twice can double every order.

Common Duplicate Execution Scenarios

· You edited the code and started it again,
  but the old process never stopped.

· You run the same bot on both a PC and a server.

· The screen looks frozen, so you press the button twice.

· A restart script does not check for another running instance.

─────────────
Symptoms:
  · Every trade has exactly twice the intended quantity.
  · The same signal appears twice in the log.
  · Fees are twice the expected amount.

Response:
  Check for duplicate execution on startup.
  If another instance is running, exit immediately.

This can be hard to notice during the first few days because profits appear doubled too. It becomes obvious only during losses. Make a habit of checking how many processes are running when starting automated trading.

Checklist

Connection methods and authentication are covered in the exchange API integration guide, and key management in API keys. For duplicate orders specifically, the checklist is below.

What to Include

· Assign each order a fixed label.
· Reuse the same label on retries.
· The guide recommends treating duplicate errors as success.
· If labels are unavailable, query before retrying.
· Set an upper limit on retry attempts.
· If cancellation is ambiguous, do not replace the order.
· Check for duplicate instances on startup.
· Periodically reconcile with actual positions.

─────────────
One line to remember:
  Orders differ from queries.
  Asking again does not create exposure,
  but placing an order again does.

Validate in an order that makes mistakes easier to reverse. The guide recommends deliberately creating a timeout with a small amount and checking that the retry logic leaves only one order. Testing for the first time at full live size makes the cost of verification as large as the position.

Summary

No response does not mean order failure.
Not received, processing, and already filled look identical locally.
One retry can double quantity and margin.
Internal records may retain the original size, leaving half unmanaged.
A different quantity invalidates the planned stop-loss calculation.
The guide describes a fixed order label as enabling exchange duplicate prevention.
A new label on every retry has no effect.
The guide treats a duplicate error as confirmation of receipt.
Without a label, use query → retry.
Do not replace after an ambiguous cancellation response.
Running two bot instances can double every order.

The central idea is to build a system where sending the same request multiple times has only one result. That protects the account from duplicate execution when the network is unstable. Refining the strategy comes afterward.

Caution

The quantities, prices, margin amounts, leverage, and waiting periods in this article are hypothetical examples illustrating the structure, not actual measurements from a particular exchange. Client order ID names, length limits, validity periods, duplicate error codes, cancellation responses, and query limits vary by exchange. Check your exchange's documentation and test with a small amount. Leveraged trading can lose all principal, and you are responsible for investment decisions and their consequences.

NOONOO TRADING invites you to follow live trading in our free chat.

Start in the bot

📈 OKX trading fee discount for new registrations

Register for the OKX Fee Discount →