{
  "format": "siebly-agent-implementation-manifest/v1",
  "id": "binance-position-manager",
  "title": "Binance Manual Position Manager Agent Manifest",
  "task": "binance-manual-position-manager",
  "version": 1,
  "lastReviewed": "2026-04-29",
  "purpose": "Single start file for coding agents building the Binance Spot plus USD-M manual position manager. Use it to reduce source-hopping before implementation.",
  "canonicalArtifacts": {
    "manifest": "https://siebly.io/.well-known/agent-manifests/binance-position-manager/latest.json",
    "guide": "https://siebly.io/ai/binance-position-manager",
    "recipe": "https://siebly.io/.well-known/recipes/binance-position-manager.json",
    "integrationKit": "https://siebly.io/.well-known/integration-kits/binance-position-manager/latest.json",
    "usdmAlgoGuide": "https://siebly.io/ai/binance-usdm-algo-orders",
    "usdmAlgoRecipe": "https://siebly.io/.well-known/recipes/binance-usdm-algo-orders.json",
    "sdkGuide": "https://siebly.io/sdk/binance/typescript",
    "agentSkill": "https://siebly.io/.well-known/agent-skills/siebly-crypto-exchange-api/SKILL.md"
  },
  "authorityOrder": [
    "Use this manifest to build the first local checklist.",
    "Use the integration kit as the maintained conformance source for field matrices, fixtures, event policy, redaction, and logs.",
    "Use the recipe and guide for explanatory context.",
    "Use installed binance package declarations and current Binance API docs as the final authority for exact request shapes."
  ],
  "package": {
    "ecosystem": "npm",
    "name": "binance",
    "install": "npm install binance",
    "versionPolicy": "Use the latest available binance package in the generated project. Record the installed version for source verification only; installed declarations and current docs are the authority for exact request shapes.",
    "docs": "https://siebly.io/sdk/binance/typescript",
    "repository": "https://github.com/tiagosiebler/binance"
  },
  "requiredFirstSteps": [
    "Install dependencies and record the installed binance package version.",
    "Run or create the local source-verification script below.",
    "Write SOURCE_VERIFICATION.md with exact methods, types, files, and package version checked.",
    "Generate a short implementation checklist from this manifest and the integration kit before editing exchange code.",
    "Implement dry-run planning and conformance fixtures before live submission."
  ],
  "sourceVerificationScript": {
    "filename": "scripts/verify-binance-position-manager-surfaces.mjs",
    "command": "node scripts/verify-binance-position-manager-surfaces.mjs",
    "scriptLines": [
      "import fs from 'node:fs';",
      "import path from 'node:path';",
      "import { createRequire } from 'node:module';",
      "",
      "const require = createRequire(import.meta.url);",
      "const packageJsonPath = require.resolve('binance/package.json');",
      "const packageRoot = path.dirname(packageJsonPath);",
      "const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));",
      "const sdk = await import('binance');",
      "",
      "const requiredExports = [",
      "  'MainClient',",
      "  'USDMClient',",
      "  'WebsocketClient',",
      "  'generateNewOrderId',",
      "  'getOrderIdPrefix',",
      "];",
      "",
      "const missingExports = requiredExports.filter((name) => !(name in sdk));",
      "const declarationTargets = [",
      "  'RestClientOptions',",
      "  'FuturesNewOrderParams',",
      "  'FuturesNewAlgoOrderParams',",
      "  'FuturesAlgoConditionalOrderTypes',",
      "  'FuturesAlgoOrderResponse',",
      "  'formattedUserDataMessage',",
      "  'subscribeSpotUserDataStream',",
      "  'subscribeUsdFuturesUserDataStream',",
      "  'closeAll',",
      "];",
      "",
      "const report = {",
      "  package: 'binance',",
      "  installedVersion: packageJson.version,",
      "  packageRoot,",
      "  ok: missingExports.length === 0,",
      "  exports: Object.fromEntries(requiredExports.map((name) => [name, name in sdk])),",
      "  missingExports,",
      "  declarationTargetsToInspect: declarationTargets,",
      "  nextStep:",
      "    'Open installed package declarations and confirm the declarationTargets, USD-M Algo literals, WebSocket event names, closeAll signature, and optional-field behavior before coding.',",
      "};",
      "",
      "console.log(JSON.stringify(report, null, 2));",
      "if (!report.ok) process.exit(1);"
    ],
    "expectedReportShape": {
      "package": "binance",
      "installedVersion": "string",
      "ok": "boolean",
      "exports": "MainClient, USDMClient, WebsocketClient, generateNewOrderId, and getOrderIdPrefix booleans",
      "declarationTargetsToInspect": "RestClientOptions, FuturesNewOrderParams, FuturesNewAlgoOrderParams, FuturesAlgoConditionalOrderTypes, FuturesAlgoOrderResponse, user-data helpers and events, closeAll"
    },
    "requiredFollowUp": "After the script runs, manually inspect installed declarations for method signatures, valid USD-M Algo type literals, closeAll(force?) shape, optional-field handling, and user-data event fields."
  },
  "mustVerifyInstalledSdk": {
    "clients": [
      "MainClient",
      "USDMClient",
      "WebsocketClient"
    ],
    "restOptions": [
      "strictParamValidation",
      "filterUndefinedParams",
      "beautifyResponses"
    ],
    "idUtilities": [
      "getOrderIdPrefix",
      "generateNewOrderId"
    ],
    "privateStreamHelpers": [
      "subscribeSpotUserDataStream",
      "subscribeUsdFuturesUserDataStream"
    ],
    "privateEvents": [
      "formattedUserDataMessage",
      "formattedMessage",
      "reconnecting",
      "reconnected",
      "exception",
      "closeAll"
    ],
    "spotMethods": [
      "getExchangeInfo",
      "getAccountInformation",
      "getOpenOrders",
      "getAllOrders",
      "getAccountTradeList",
      "submitNewOrder",
      "cancelOrder",
      "testNewOrder"
    ],
    "usdmMethods": [
      "getExchangeInfo",
      "getPositionsV3",
      "getAllOpenOrders",
      "getOpenAlgoOrders",
      "getAccountTrades",
      "getAllOrders",
      "getAccountInformationV3",
      "getCurrentPositionMode",
      "getMultiAssetsMode",
      "getFuturesSymbolConfig",
      "getNotionalAndLeverageBrackets",
      "submitNewOrder",
      "cancelOrder",
      "testOrder",
      "submitNewAlgoOrder",
      "cancelAlgoOrder"
    ],
    "declarationTargets": [
      "RestClientOptions",
      "NewSpotOrderParams",
      "FuturesNewOrderParams",
      "FuturesNewAlgoOrderParams",
      "FuturesAlgoConditionalOrderTypes",
      "FuturesAlgoOrderResponse",
      "WsMessageFuturesUserDataAlgoUpdateFormatted",
      "WsMessageFuturesUserDataTradeUpdateEventFormatted",
      "WsUserDataEvents"
    ]
  },
  "requestBuilders": {
    "spotRegularManagedOrder": {
      "clientIdField": "newClientOrderId",
      "requiredFields": [
        "symbol",
        "side",
        "type",
        "quantity"
      ],
      "optionalOmitWhenUndefined": [
        "price",
        "timeInForce"
      ],
      "notes": [
        "Use Spot filters from hydrated exchangeInfo before formatting quantities/prices."
      ]
    },
    "usdmRegularDca": {
      "clientIdField": "newClientOrderId",
      "requiredFields": [
        "symbol",
        "side",
        "type",
        "quantity",
        "price",
        "timeInForce"
      ],
      "optionalOmitWhenUndefined": [
        "positionSide",
        "reduceOnly"
      ],
      "notes": [
        "Use regular submitNewOrder for exposure-increasing DCA.",
        "For one-way shorts, outbound positionSide remains BOTH while side is SELL above entry."
      ]
    },
    "usdmAlgoTakeProfit": {
      "clientIdField": "clientAlgoId",
      "validType": "TAKE_PROFIT",
      "requiredFields": [
        "symbol",
        "side",
        "positionSide",
        "type",
        "quantity",
        "price",
        "triggerPrice",
        "timeInForce",
        "clientAlgoId"
      ],
      "forbiddenFields": [
        "type=TAKE_PROFIT_LIMIT"
      ],
      "optionalOmitWhenUndefined": [
        "reduceOnly",
        "workingType",
        "priceProtect"
      ]
    },
    "usdmAlgoClosePositionStop": {
      "clientIdField": "clientAlgoId",
      "validType": "STOP_MARKET",
      "requiredFields": [
        "symbol",
        "side",
        "positionSide",
        "type",
        "triggerPrice",
        "closePosition",
        "clientAlgoId"
      ],
      "forbiddenFields": [
        "quantity",
        "reduceOnly"
      ],
      "notes": [
        "closePosition=true stop-market exits omit quantity and reduceOnly unless current docs and package types explicitly change.",
        "In hedge mode with positionSide LONG or SHORT, omit reduceOnly for Algo TP/SL."
      ]
    }
  },
  "regularVersusAlgoDecisionTree": [
    "DCA limit add -> regular submitNewOrder with newClientOrderId.",
    "USD-M quantity take-profit -> Algo submitNewAlgoOrder with type=TAKE_PROFIT and clientAlgoId.",
    "USD-M close-all stop-loss -> Algo submitNewAlgoOrder with type=STOP_MARKET, closePosition=true, clientAlgoId, no quantity, no reduceOnly.",
    "Hedge-mode TP/SL -> omit reduceOnly for positionSide LONG or SHORT.",
    "Current open Algo state -> hydrate with getOpenAlgoOrders separately from regular open orders.",
    "Algo cancel -> cancelAlgoOrder, and stale -2011 stops retrying when open-Algo hydration proves absence."
  ],
  "eventFieldsToClassify": [
    "wsMarket",
    "wsKey",
    "eventType",
    "symbol",
    "positionSide",
    "newClientOrderId",
    "clientAlgoId"
  ],
  "implementationSkeleton": [
    {
      "module": "ConfigLoader",
      "owns": "env, JSON config, defaults, live acknowledgement"
    },
    {
      "module": "RedactedLogger",
      "owns": "structured errors, redaction, compact summaries"
    },
    {
      "module": "DecimalFormatter",
      "owns": "tickSize/stepSize fixed decimal strings"
    },
    {
      "module": "ClientIdFactory",
      "owns": "SDK-prefix deterministic lifecycle/generation IDs"
    },
    {
      "module": "BinanceAdapter",
      "owns": "verified SDK REST and WebSocket calls"
    },
    {
      "module": "InMemoryStore",
      "owns": "replacement snapshots, app-owned state, lifecycle recovery"
    },
    {
      "module": "Planner",
      "owns": "cleanup, SL, TP, DCA intents and normalized comparisons"
    },
    {
      "module": "ProductWorkflow",
      "owns": "single per-product hydrate/replay/plan/submit lock"
    },
    {
      "module": "PrivateStreamSupervisor",
      "owns": "user-data buffering, debounce, reconnect handling"
    },
    {
      "module": "CliCommands",
      "owns": "doctor/status/inspect/dry-run/live command gates"
    }
  ],
  "conformanceFixtureNames": [
    "accepted_submissions_settle_to_zero_intents",
    "binance_precision_float_tail_rejected_locally",
    "hydrated_close_position_algo_normalizes_to_desired",
    "same_position_hydration_preserves_lifecycle_epoch",
    "manual_same_side_add_advances_replacement_generation",
    "full_close_clears_lifecycle_after_cleanup_settled",
    "hedge_opposite_side_coexists",
    "full_close_cleans_app_owned_orders",
    "workflow_active_user_data_defers_replan",
    "protective_orders_before_dca",
    "log_position_counters_are_unambiguous",
    "safe_status_ignores_live_env"
  ],
  "executableFixtureSchemaExample": {
    "name": "manual-same-side-add-replaces-exits",
    "product": "usdm",
    "initialSnapshot": {
      "positions": [
        {
          "symbol": "BTCUSDT",
          "exchangePositionSide": "LONG",
          "managedStrategySide": "LONG",
          "quantity": "0.001",
          "averageEntry": "76000.0",
          "lifecycleEpoch": "L1",
          "replacementGeneration": 0
        }
      ],
      "openOrders": [
        {
          "role": "DCA",
          "step": 1,
          "lifecycleEpoch": "L1",
          "replacementGeneration": 0
        }
      ],
      "openAlgoOrders": [
        {
          "role": "SL",
          "step": 1,
          "lifecycleEpoch": "L1",
          "replacementGeneration": 0
        },
        {
          "role": "TP",
          "step": 1,
          "lifecycleEpoch": "L1",
          "replacementGeneration": 0
        }
      ]
    },
    "event": {
      "type": "manual_same_side_add",
      "symbol": "BTCUSDT",
      "exchangePositionSide": "LONG",
      "newQuantity": "0.002",
      "newAverageEntry": "76100.0"
    },
    "expectedPlanner": {
      "replacementGeneration": 1,
      "cancelRoles": [
        "DCA",
        "SL",
        "TP"
      ],
      "submitRolesInOrder": [
        "SL",
        "TP",
        "DCA"
      ],
      "untouchedOppositeSideOrders": true,
      "settlesToIntentCount": 0
    }
  },
  "knownDangerousNearMisses": [
    "TAKE_PROFIT_LIMIT instead of USD-M Algo TAKE_PROFIT.",
    "reduceOnly sent with closePosition=true.",
    "newClientOrderId used for Algo orders instead of clientAlgoId.",
    "client IDs invented without the SDK prefix.",
    "positionSide=BOTH treated as managed LONG instead of exchange one-way side.",
    "fallback filters used after exchangeInfo hydration should have provided real filters.",
    "binary float tails stringified into live order requests.",
    "formattedMessage and formattedUserDataMessage both processed without dedupe.",
    "user-data confirmations allowed to start overlapping product workflows.",
    "accepted REST submissions not inserted as provisional local state.",
    "DCA left live after manual full close.",
    "opposite hedge side cancelled or replaced by symbol-only logic.",
    "replacement generation not advanced on manual same-side add.",
    "same-process fresh position reuses lifecycle after full close cleanup settled.",
    "raw request bodies, listen keys, signed URLs, or raw order intents logged.",
    "private account-event idleness treated as WebSocket failure."
  ],
  "goodLogTraceCatalogue": [
    "startup flat -> stream requested -> REST hydrate openManagedPositions=0 -> planner intentCount=0",
    "manual open -> user-data schedules reconcile -> REST hydrate openManagedPositions=1 -> planner emits SL,TP,DCA",
    "accepted submissions -> provisional local orders inserted -> own-order confirmations deferred",
    "follow-up hydration -> regularOpenOrders=1 and openAlgoOrders=2 or configured TP ladder count -> planner intentCount=0",
    "manual close -> cleanup app-owned orders -> hydration shows no position and no app-owned orders -> lifecycle cleared",
    "hedge long-plus-short -> rawPositionRows=2 and openManagedPositions=2 -> opposite side preserved",
    "manual same-side add -> replacementGeneration advances once -> changed side replaced -> next planner intentCount=0"
  ],
  "finalAcceptanceGate": [
    "SOURCE_VERIFICATION.md exists and names the installed SDK version plus exact declarations inspected.",
    "A local checklist generated from this manifest is completed before live execution.",
    "Conformance fixtures run before live mode is enabled.",
    "Public-only doctor/status commands cannot place, cancel, or amend even with live .env settings.",
    "Live order placement remains disabled until explicit user configuration and reviewed code."
  ]
}
