Skip to content

No order idempotency check — duplicate orders on retry #91

@atxinsky

Description

@atxinsky

Summary

When the system retries order placement (e.g. after failing to verify a stop-loss), there is no deduplication check. This results in multiple identical orders being placed on the exchange, creating real financial risk.

Impact (observed in Demo)

During ETHUSDT Demo trading:

  • 3 duplicate stop-loss orders placed at the same price
  • 3 duplicate limit orders placed at the same price
  • User had to manually cancel redundant orders on Binance UI
  • In a live account, duplicate stop-losses would cause overselling beyond intended position size

Root Cause

The order placement flow in CcxtBroker and the AI engine's retry logic have no guard against:

  1. Same-direction, same-price duplicates — Before placing an order, the system doesn't check if an equivalent order already exists
  2. Retry without cancel-first — When verification fails (partly due to Conditional/stop orders invisible to getOrders — broker state blind spot #90 conditional order blindness), the system retries placement without canceling the previous attempt

Suggested Fix

Add a pre-flight check before placeOrder:

async placeOrder(params: OrderParams): Promise<Order> {
  // 1. Fetch all active orders for this symbol (including conditional - see #90)
  const existing = await this.getAllActiveOrders(params.symbol);
  
  // 2. Check for equivalent order (same side, same type, price within tolerance)
  const duplicate = existing.find(o => 
    o.side === params.side && 
    o.type === params.type &&
    Math.abs(o.price - params.price) / params.price < 0.001  // 0.1% tolerance
  );
  
  if (duplicate) {
    log.warn(`Duplicate order detected, skipping: ${duplicate.id}`);
    return duplicate;  // Return existing instead of creating new
  }
  
  // 3. Proceed with placement
  return this.exchange.createOrder(...);
}

Severity

High — This is a live-trading-blocking bug. Duplicate stop-losses directly cause overselling, which can result in unintended short positions or margin liquidation.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions