{
  "format": "siebly-agent-recipe/v1",
  "id": "binance-usdm-algo-orders",
  "title": "Stop Loss using Conditional Algo Orders with Binance USD-M APIs & WebSockets",
  "lastReviewed": "2026-05-12",
  "package": {
    "ecosystem": "npm",
    "name": "binance",
    "install": "npm install binance",
    "docs": "https://siebly.io/sdk/binance/javascript",
    "repository": "https://github.com/tiagosiebler/binance"
  },
  "scope": {
    "runtime": "Node.js LTS",
    "language": "TypeScript",
    "product": "Binance USD-M Futures",
    "defaultMode": "verified Binance USD-M Algo request objects plus EXECUTION_MODE=DRY_RUN_PRIVATE",
    "liveExecutionDefault": false,
    "credentials": "scoped API keys from environment variables only"
  },
  "requiredSources": [
    "https://siebly.io/ai/algo-orders/binance",
    "https://siebly.io/ai/exchange-state/binance",
    "https://siebly.io/sdk/binance/javascript",
    "https://siebly.io/.well-known/agent-skills/siebly-crypto-exchange-api/SKILL.md",
    "https://siebly.io/reference/glossary",
    "https://siebly.io/llms.txt",
    "https://siebly.io/llms-tasks.txt",
    "https://siebly.io/llms-full.txt",
    "https://siebly.io/.well-known/siebly-sdk-catalog.json",
    "https://github.com/tiagosiebler/binance"
  ],
  "sdkSurfacesToVerify": {
    "restClient": "USDMClient",
    "algoMethods": [
      "submitNewAlgoOrder",
      "getOpenAlgoOrders",
      "cancelAlgoOrder"
    ],
    "requestTypes": [
      "FuturesNewAlgoOrderParams",
      "FuturesAlgoConditionalOrderTypes",
      "FuturesAlgoOrderResponse"
    ],
    "userDataTypes": [
      "WsMessageFuturesUserDataAlgoUpdateFormatted",
      "WsMessageFuturesUserDataTradeUpdateEventFormatted",
      "WsMessageFuturesUserDataAccountUpdateFormatted",
      "WsUserDataEvents"
    ],
    "clientOrderId": [
      "clientAlgoId",
      "getOrderIdPrefix(...)",
      "generateNewOrderId(...)"
    ]
  },
  "validExamples": {
    "explicitConditionalTakeProfit": "await usdm.submitNewAlgoOrder({\n  algoType: 'CONDITIONAL',\n  symbol,\n  side: exitSide,\n  positionSide,\n  type: 'TAKE_PROFIT',\n  timeInForce: 'GTC',\n  quantity,\n  price: takeProfitPrice,\n  triggerPrice: takeProfitTriggerPrice,\n  workingType: 'MARK_PRICE',\n  priceProtect: 'true',\n  ...(useReduceOnly ? { reduceOnly: 'true' } : {}),\n  clientAlgoId,\n});",
    "closePositionStopMarket": "await usdm.submitNewAlgoOrder({\n  algoType: 'CONDITIONAL',\n  symbol,\n  side: exitSide,\n  positionSide,\n  type: 'STOP_MARKET',\n  triggerPrice: stopTriggerPrice,\n  workingType: 'MARK_PRICE',\n  priceProtect: 'true',\n  closePosition: 'true',\n  clientAlgoId,\n});"
  },
  "invalidExamples": {
    "invalidTypeAndClosePositionCombination": "// Invalid for the current USD-M Algo Service:\ntype: 'TAKE_PROFIT_LIMIT'\n\n// Invalid close-position combination:\n{\n  closePosition: 'true',\n  quantity,\n  reduceOnly: 'true',\n}"
  },
  "validationRules": [
    "Use algoType=CONDITIONAL for current USD-M Algo conditional requests.",
    "Default fixed take-profit belongs on regular submitNewOrder LIMIT, not this Algo path.",
    "Use type=TAKE_PROFIT only for an explicitly requested conditional take-profit. Do not use strategy-language names such as TAKE_PROFIT_LIMIT unless current package types and Binance docs explicitly support them.",
    "Use type=STOP_MARKET with closePosition=true for a close-position stop-market conditional.",
    "When closePosition=true, omit quantity and reduceOnly unless current Binance docs and package types say otherwise.",
    "When using an explicit quantity-based conditional TP, include quantity and any reduceOnly field only after current docs/types validate the account-mode field mix.",
    "Use [clientAlgoId](https://siebly.io/reference/glossary#custom-order-id) for USD-M Algo conditionals, not newClientOrderId. Treat [clientAlgoId](https://siebly.io/reference/glossary#custom-order-id) as a Binance custom order ID. Generate it with the same SDK order ID utilities as newClientOrderId, preferably generateNewOrderId(...) or client.generateNewOrderId(), and satisfy the same prefix, length, and character checks.",
    "For the simple position manager, [clientAlgoId](https://siebly.io/reference/glossary#custom-order-id) follows the [custom order ID](https://siebly.io/reference/glossary#custom-order-id) rule. Store local meaning in durable context, not in the ID text.",
    "Keep request builders strict: omit undefined optional fields instead of sending them as undefined."
  ],
  "userDataRules": [
    "Use private user-data events to update local account state and plan from that trusted state while the stream remains healthy.",
    "Use REST to hydrate open Algo orders only at startup, reconnect, scoped recovery, or when required evidence is missing or conflicting.",
    "Do not let older terminal Algo history overwrite current open app-owned Algo state or pending confirmations for the same clientAlgoId.",
    "Reconcile formatted Algo updates from eventType plus algoOrder.clientAlgoId, algoOrder.symbol, algoOrder.positionSide, algoOrder.orderType, and algoOrder.algoStatus. Do not look for root clientAlgoId on formatted ALGO_UPDATE.",
    "If an Algo user-data update arrives while reconciliation, buffered replay, planning, or submission is active, defer it to the active workflow; do not start a competing planner.",
    "Idle user-data replans should replay trusted private accountstate before planning. Use REST only at startup, reconnect, sync-required, exception, rejection, unknown-state, or conflicting-state boundaries. If a deferred work item contains only already-applied user-data events and no buffered events remain, the workflow can skip a duplicate replan.",
    "Choose formattedUserDataMessage or formattedMessage for private state processing; do not process both.",
    "Redact user-data [wsKey values](https://siebly.io/reference/glossary#ws-key) because they may contain listen-key-like material."
  ],
  "fixtureCases": [
    {
      "name": "Valid explicit conditional take-profit",
      "expected": "Request uses TAKE_PROFIT, quantity, price, triggerPrice, clientAlgoId, and only account-mode-valid optional reduceOnly fields."
    },
    {
      "name": "Valid close-position stop-market",
      "expected": "Request uses STOP_MARKET, triggerPrice, closePosition=true, and omits quantity and reduceOnly."
    },
    {
      "name": "Invalid strategy-language take-profit type",
      "expected": "Local validation rejects TAKE_PROFIT_LIMIT before Binance can return an invalid order type error."
    },
    {
      "name": "Invalid close-position field mix",
      "expected": "Local validation rejects closePosition=true with quantity or reduceOnly."
    },
    {
      "name": "Scoped open Algo hydration",
      "expected": "Existing app-owned SL or explicit conditional TP Algo orders block duplicate replacement unless replacement is required."
    },
    {
      "name": "Scoped open Algo hydration with stale terminal history",
      "expected": "Current open Algo state wins over older cancelled, expired, rejected, or filled rows for the same clientAlgoId."
    },
    {
      "name": "Algo update during active workflow",
      "expected": "The update is deferred to the active workflow, which replays trusted private state or runs scoped recovery if trust is unresolved."
    },
    {
      "name": "Algo user-data update",
      "expected": "A formatted Algo update reconciles the matching app-owned order from algoOrder.clientAlgoId and other verified algoOrder fields."
    },
    {
      "name": "Algo update missing clientAlgoId path",
      "expected": "The adapter refuses slot mutation and schedules recovery instead of treating the event as an unidentified app-owned Algo slot."
    }
  ],
  "knownRejections": [
    {
      "code": "-1116",
      "message": "Invalid orderType",
      "fix": "Verify the current Algo type enum and use TAKE_PROFIT for a limit take-profit when that is the supported value."
    },
    {
      "code": "-1106",
      "message": "Parameter 'reduceonly' sent when not required",
      "fix": "For closePosition=true stop-market conditionals, omit reduceOnly and quantity."
    },
    {
      "code": "-4116",
      "message": "ClientOrderId is duplicated",
      "fix": "Track in-flight clientAlgoId values and reconcile from trusted private state or scoped open Algo hydration before retrying."
    },
    {
      "code": "-1111",
      "message": "Precision is over the maximum defined for this asset",
      "fix": "Use hydrated symbol filters to quantize and validate price, quantity, and notional before building the request."
    }
  ],
  "safety": [
    "Implement execution for when [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE is enabled and all gates pass, but keep that path disabled by default. [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE is the default execution mode, where the implementation builds and tests sanitized USD-M conditional algo order request objects without submitting to the exchange.",
    "EXECUTION_MODE=LIVE must require explicit user configuration, scoped credentials, and reviewed code.",
    "A rejected DEMO, TESTNET, or LIVE request should enter recoveryRequired for the affected product scope and force reconciliation before retry.",
    "This recipe is not a replacement for Binance API docs or the installed package types."
  ],
  "promptFrameworkCompletionWorkflow": {
    "instruction": "Recursive completion workflow:\n1. Before implementation, save this exact prompt in docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard) and write docs/PLAN.md with phases, invariants, tests or fixtures, docs to update, and acceptance gates.\n2. Review docs/PLAN.md for missing workflows, unsafe assumptions, product/exchange-specific leakage, unclear state ownership, confirmation or recovery gaps, missing tests, and incomplete docs. Update docs/PLAN.md and repeat until one full review pass finds no actionable changes.\n3. Implement one plan phase at a time. After each phase, review changed code, tests, fixtures, docs, generated artifacts, and runtime workflows against docs/PLAN.md and this prompt. Fix gaps and repeat until that phase has no actionable changes before starting the next phase.\n4. After all phases, run a full-depth project review across every workflow, lifecycle, state transition, error path, and artifact. This is not a shallow summary pass. Fix every actionable gap and repeat until a full pass finds no further changes, then record the final review outcome in docs/PLAN.md.",
    "acceptanceRequirement": "docs/PLAN.md records the initial plan, plan-review iterations, phase review outcomes, final full-project review, validation commands, and any documented non-claims. No plan phase or project completion is accepted until the recursive review loop finds no actionable gaps, flaws, or incomplete workflows left to correct."
  }
}
