{
  "format": "siebly-integration-kit/v1",
  "id": "bybit-position-manager",
  "title": "Bybit Position Management Integration Kit",
  "lastReviewed": "2026-05-12",
  "package": {
    "ecosystem": "npm",
    "name": "bybit-api",
    "install": "npm install bybit-api",
    "versionPolicy": "Use the latest available bybit-api package in the generated project. Record the installed version in the README dependency notes.",
    "docs": "https://siebly.io/sdk/bybit/javascript",
    "repository": "https://github.com/tiagosiebler/bybit-api"
  },
  "agentImplementationManifest": "https://siebly.io/.well-known/agent-manifests/bybit-position-manager/latest.json",
  "conformancePack": "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json",
  "primarySpec": {
    "id": "exchange-state-management-spec",
    "title": "Exchange State Management",
    "href": "https://siebly.io/ai/exchange-state",
    "purpose": "Exchange-neutral runtime spec for private account, order, and position state workflows, including DCA/TP/SL managers.",
    "architecture": {
      "reusable": "order_account_position_state_machine",
      "lane": "ws_symbol_side_action_gated"
    },
    "role": "Primary implementation spec. Other artifacts support, specialize, or test this workflow; they do not replace it."
  },
  "artifactOrder": [
    "https://siebly.io/ai/exchange-state",
    "https://siebly.io/.well-known/prompts/bybit-position-manager/latest.md",
    "https://siebly.io/.well-known/recipes/bybit-position-manager.json",
    "https://siebly.io/ai/exchange-state/bybit",
    "https://siebly.io/.well-known/integration-kits/bybit-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/bybit-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/index.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/types.ts",
    "https://siebly.io/.well-known/integration-kits/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/schema.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/fixtures.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/runner.ts",
    "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json"
  ],
  "spec": [
    "Install the latest available bybit-api package and record the installed version as SDK surface metadata only.",
    "Verify RestClientV5, WebsocketClient, linear ws.subscribeV5(['order', 'execution', 'position', 'wallet'], 'linear', true), Spot private subscription shape, lifecycle events, closeAll(true), and REST method names from installed declarations before coding.",
    "Build path: primary spec -> selected exchange recipe -> integration kit for exact fields, event shapes, and errors -> applicable [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) after implementation. [conformance packs](https://siebly.io/reference/glossary#conformance-pack) are machine-readable fixture sources, not first-read design prose. Use manifests and runtime kits only for advanced reusable-runtime scaffolding; use general SDK pages, examples, catalogs, and llms-full only when installed package source leaves a method or request shape unresolved.",
    "Start with startup/recovery hydration and EXECUTION_MODE=DRY_RUN_PRIVATE DCA/TP/SL intents. The finished project must implement DEMO, TESTNET, or LIVE order placement, amend, and cancel for the selected Bybit product where supported, but exchange writes remain disabled unless EXECUTION_MODE=DEMO, TESTNET, or LIVE and all matching gates pass.",
    "Startup hydration loads filters, positions or inputs for local position tracking, open orders, fills or executions, wallet or margin state, account mode, risk/readiness state, and stored contexts.",
    "For Bybit linear startup/restart hydration, call getPositionInfo with settleCoin for each configured settlement coin, defaulting to USDT and USDC. Never call getPositionInfo with only category=linear; use symbol only for deliberately narrow scoped recovery, and filter configuredSymbols locally after settleCoin hydration.",
    "For Bybit linear active-order startup/restart hydration, either capture and preserve a redacted raw getActiveOrders({ category: \"linear\", settleCoin, openOnly: 0 }) response proving regular and conditional StopOrder rows are both returned for the account mode, or defensively fetch orderFilter=\"Order\" and orderFilter=\"StopOrder\" separately for each settleCoin and merge by orderId/orderLinkId.",
    "Connect private account-level WebSockets only after scope and credentials are explicit. Buffer private events until startup/recovery hydration and replay are complete. During normal private event bursts, apply every event to [Account State](https://siebly.io/reference/glossary#accountstate) immediately, then use a short [event-burst wait](https://siebly.io/reference/glossary#event-burst-wait) before planning. Do not enter REST recovery just because private order, execution, fill, or position events arrived. If the private stream is healthy and [Account State](https://siebly.io/reference/glossary#accountstate) has ingested the matching order evidence plus the matching position or account evidence, continue from private-stream account state without REST hydration. For products without exchange-provided position rows, locally derived position evidence fills the same role.",
    "Implement the event-driven private-state loop (ws_symbol_side_action_gated). Private events update [Account State](https://siebly.io/reference/glossary#accountstate), record the [affected scope](https://siebly.io/reference/glossary#affected-scope), give related events a short bounded window to arrive, and one [workflow owner](https://siebly.io/reference/glossary#workflow-owner) chooses one [action family](https://siebly.io/reference/glossary#action-family). Accepted mutations stay [pending confirmation](https://siebly.io/reference/glossary#pending-confirmation) until [private confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) or [scoped recovery](https://siebly.io/reference/glossary#scoped-recovery), and REST state fetches happen only at trust boundaries.",
    "Prefer RestClientV5 throwExceptions=true for order, amend, cancel, and pre-check workflows; if disabled, classify every response by retCode === 0.",
    "Use [orderLinkId](https://siebly.io/reference/glossary#custom-order-id) values as [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) for DCA, TP, SL, cancel, and amend workflows. Pre-register context before EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE submission, persist context by default for order-capable runs, then use private events with orderLinkId to look up SlotKey/intent context.",
    "Distinguish operatorPaused, recoveryRequired, syncRequired subjects, and privateStreamReady. RecoveryRequired or syncRequired blocks normal cleanup, protective, DCA, and [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE submission until scoped REST hydration plus buffered replay restores trusted account state. Deterministic stale-target no-ops avoid entering recovery when account state already proves convergence.",
    "For linear managed SL, default to close-all Market StopOrder: qty=\"0\", reduceOnly=true, closeOnTrigger=true, triggerDirection 2 for long SL and 1 for short SL, triggerBy=MarkPrice unless configured, positionIdx matching the position side, and no price field.",
    "Normalize hydrated Bybit active-order defaults by slot kind before desired-vs-active comparison and classify slots as keep, amend, cancel_place, cancel, or place so accepted app-owned orders converge to intentCount=0 instead of cancel/recreate churn.",
    "Run each EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE reconciliation pass through one action family: resync uncertain state first if required, cleanup, concurrent protective SL/TP place or amend after contexts are registered, pending confirmation, and later DCA only if private stream evidence or scoped recovery hydration confirms the position still exists. EXECUTION_MODE=DRY_RUN_PRIVATE records candidates only. DEMO, TESTNET, or LIVE may submit exchange mutations after all gates pass.",
    "Map EXECUTION_MODE=DEMO to demoTrading=true and testnet=false, and map EXECUTION_MODE=TESTNET to Bybit testnet routing. Do not use Bybit WebSocket API order commands for demo endpoint trading."
  ],
  "subjectTrust": {
    "subjects": [
      "order trust",
      "position trust",
      "filter trust",
      "context trust",
      "readiness trust"
    ],
    "rules": [
      "Split trust by subject: order trust, position trust, filter trust, context trust, and readiness trust.",
      "A TP/SL/DCA order update proves only order trust; it does not prove position trust, position size, entry/cost basis, exposure, or replacement eligibility.",
      "For products with exchange-provided position rows, order/fill events are triggers; replacement planning waits for matching position trust from private position or account updates or scoped recovery.",
      "For products without exchange-provided position rows, derive local position state from fills/executions, fees, account events, balance updates, and documented matching rules before managed exits, exposure changes, or re-hedging."
    ]
  },
  "symbolScope": [
    "If configuredSymbols is blank, absent, or empty, auto-detect eligible open positions.",
    "When symbols are configured, treat them as an allowlist: manage matching detected positions only and ignore or log out-of-scope private events without mutation.",
    "Sample symbols from docs, tests, prompts, or quickstarts are examples only; never use them as runtime defaults."
  ],
  "riskGeometry": [
    "For broad TP/SL/DCA position managers, use percentage-based strategy inputs by default: derive TP, DCA, and SL prices plus DCA size from trusted entry and position size before order planning.",
    "Absolute TP/DCA/SL prices or DCA quantities are advanced per-symbol operator overrides, not the primary config model. If allowed, they must be explicit, scoped, compatible with percentage defaults, and validated through the same filters and risk geometry.",
    "Startup validation rejects missing, invalid, contradictory, or non-finite strategy inputs before private clients, WebSocket subscriptions, hydration, or exchange mutation.",
    "Validate risk geometry before exchange mutation: for long positions, TP is above entry, DCA is below entry, and SL is below DCA; for short positions, TP is below entry, DCA is above entry, and SL is above DCA.",
    "Reject missing or invalid TP/DCA/SL strategy outputs before order placement. After derivation or override, quantize prices and quantities with hydrated exchange filters before final validation.",
    "After quantization, revalidate risk geometry, min/max, and notional rules; reject only if the quantized TP/DCA/SL values are equal, crossed, or otherwise violate geometry or filters before [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE order placement.",
    "Risk geometry validation uses the trusted entry price or explicit operator override, hydrated tick/lot filters, and the managed side before any place/amend/cancel request."
  ],
  "identityChainReview": {
    "cleanPassesRequired": 3,
    "chain": [
      "config scope",
      "product/environment/account",
      "symbol",
      "position mode",
      "managed side",
      "exchange position identity",
      "accountstate position state (native or locally derived)",
      "planner scope",
      "slot scope",
      "custom order ID",
      "durable context",
      "exchange request",
      "REST acceptance",
      "private order/execution/position event",
      "trusted active order",
      "subject trust state",
      "confirmation tracker",
      "recovery scope",
      "cleanup/protective/DCA replanning"
    ],
    "requiredRule": "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes.",
    "passMustTrace": "Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary."
  },
  "identityMismatchPolicy": {
    "scope": "Trace category, environment, account, symbol, position mode, managed side, positionIdx, durable context, orderLinkId, active order, private order/execution/position event, confirmation tracker, recovery scope, and replanning together.",
    "accountAndPositionMode": [
      "Prefer auto-detection from observed exchange/accountstate identity when the evidence is clear.",
      "Do not block only because configured mode text differs from observed mode; record the mismatch and follow observed identity.",
      "Refuse mutation only while mode evidence is unresolved, stale, or contradictory."
    ],
    "durableContext": [
      "Saved durable context without matching trusted active-order evidence remains unresolved until scoped active-order recovery confirms absence or terminal state.",
      "Active app-owned order without saved context refuses mutation unless an explicit adoption path is configured and fixture-proven.",
      "Terminal order rows are not active protective confirmations.",
      "Filled DCA steps are completed step identity, not active orders, and completed DCA state survives restart."
    ],
    "positionRowsAndRisk": [
      "Flat hedge private position rows are state rows, not close lifecycle events unless previous state was open for that same scoped side.",
      "A flat row on one hedge side must not emit a close notice or cleanup for the opposite open side.",
      "One-way flat rows require previous managed-side identity before close/noop decisions.",
      "Hedge-risk controls block exposure-increasing DCA, not protective TP/SL repair."
    ],
    "recoveryScopes": [
      "Filter-only recovery restores filters and must not prune durable order contexts.",
      "Open-order recovery may confirm or prune contexts only with explicit active-order evidence.",
      "Startup mutation waits until private stream confirmation can be observed."
    ],
    "fixtureNames": [
      "bybit_stale_context_wrong_position_idx_enters_recovery",
      "bybit_active_app_order_without_context_refuses_mutation_or_adopts_explicitly",
      "bybit_context_without_active_order_is_inconclusive_until_recovery",
      "bybit_flat_hedge_row_with_opposite_open_does_not_emit_closed_notice",
      "bybit_one_way_flat_row_uses_previous_side_identity",
      "bybit_completed_dca_state_survives_restart_without_active_order",
      "bybit_filter_only_recovery_does_not_prune_contexts",
      "bybit_open_order_recovery_prunes_absent_contexts",
      "bybit_late_private_event_routes_to_current_or_terminal_scope",
      "bybit_duplicate_slots_same_role_step_resolve_without_extra_place",
      "bybit_pending_confirmation_blocks_duplicate_dca_place",
      "bybit_terminal_dca_fill_then_planner_tick_reprotects_only_after_position_update",
      "bybit_position_mode_auto_detects_observed_exchange_identity",
      "bybit_hedge_risk_blocks_dca_but_allows_protective_repair"
    ]
  },
  "finalAcceptanceGate": [
    "Trace the full identity chain: config scope -> product/environment/account -> symbol -> position mode -> managed side -> exchange position identity -> accountstate position state (native or locally derived) -> planner scope -> slot scope -> custom order ID -> durable context -> exchange request -> REST acceptance -> private order/execution/position event -> trusted active order -> subject trust state -> confirmation tracker -> recovery scope -> cleanup/protective/DCA replanning.",
    "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes.",
    "Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary.",
    "Every accepted lifecycle claim needs an executable fixture; behaviors without fixtures must be listed as unsupported or unverified.",
    "Core [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) cover context write failure before submit, early private confirmation before REST accept, one-way side flips, pending duplicate place/cancel guards, and decimal/default-equivalent active-order convergence.",
    "The [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE submission paths are implemented for order-capable projects where supported, but they remain disabled until the required identity-chain, subject-trust, symbol-scope, and risk-geometry fixtures exist and pass."
  ],
  "customOrderIdRegistry": "order-context registry maps [orderLinkId](https://siebly.io/reference/glossary#custom-order-id) values to SlotKey/intent context before submission; private events echo orderLinkId to resolve context without parsing ID text.",
  "criticalWriteConformance": {
    "mustPassBeforeLive": [
      "bybit_position_open_reacts_without_timer",
      "bybit_private_stream_exception_prevents_service_ready",
      "bybit_private_topic_updates_can_complete_readiness_without_args_ack",
      "bybit_subscribe_response_req_id_topics_can_mark_ready",
      "bybit_private_stream_reconnect_clears_exception_before_ack_readiness",
      "bybit_private_position_replay_drives_planning_without_rest_rehydrate",
      "bybit_normal_state_check_uses_accountstate_not_rest",
      "bybit_reconnect_uses_rest_hydration_before_resume",
      "bybit_private_event_burst_groups_to_single_reconcile",
      "bybit_order_execution_position_wallet_out_of_order_converges",
      "bybit_accepted_submissions_settle_to_zero_intents",
      "bybit_golden_live_convergence_trace_settles_after_deferred_dca",
      "bybit_position_open_places_protective_then_dca_after_ws_confirmation",
      "bybit_pending_confirmation_does_not_unlock_dependent_action_family",
      "bybit_semantic_ws_logs_emitted_after_ingest",
      "bybit_symbol_side_queue_groups_private_event_burst",
      "bybit_order_active_confirmation_before_rest_acceptance_no_stale_pending",
      "bybit_rest_acceptance_does_not_downgrade_trusted_private_order",
      "bybit_terminal_order_status_is_not_open_order_confirmation",
      "bybit_execution_fill_is_not_open_order_confirmation",
      "bybit_position_close_between_exit_action_and_dca_skips_dca",
      "bybit_dca_never_submitted_from_stale_pre_close_plan",
      "bybit_conditional_sl_requires_trigger_direction",
      "bybit_hedge_normalized_position_idx_maps_to_bybit_request_idx",
      "bybit_one_way_short_uses_position_idx_zero",
      "bybit_tp_is_reduce_only_limit_with_expected_time_in_force",
      "bybit_position_update_timestamp_does_not_rotate_slots",
      "bybit_full_close_cleanup_cancels_only_app_owned_orders",
      "bybit_one_way_short_then_long_fresh_scope_cleans_old_side",
      "bybit_hedge_same_symbol_sides_do_not_cross_cancel",
      "bybit_startup_wipe_rebuild_cancels_app_orders_before_rebuild",
      "bybit_startup_adopts_active_contexts_and_prunes_absent_contexts",
      "bybit_default_dca_active_order_does_not_advance_next_step",
      "bybit_ambiguous_event_routes_bounded_fallback_then_exact_scope",
      "bybit_linear_close_all_sl_request_is_valid",
      "bybit_same_side_position_add_amends_same_slots_without_cancel_first",
      "bybit_same_slot_update_submits_amends_without_cancel_gap",
      "bybit_cancel_first_replacement_converges_before_place",
      "bybit_amend_rejection_enters_recovery_without_blind_cancel_place",
      "bybit_retcode_nonzero_blocks_failed_slot_or_enters_recovery",
      "bybit_submission_rejection_requires_resync_without_permanent_pause",
      "bybit_order_link_id_context_lookup_routes_private_event",
      "bybit_lost_order_link_id_registry_rebuilds_from_trusted_state",
      "bybit_protective_sl_tp_pre_registered_and_dispatched_concurrently_by_default",
      "bybit_partial_protective_reject_blocks_failed_slot_and_surfaces_error",
      "bybit_unknown_submit_outcome_enters_recovery_after_configured_timeout",
      "bybit_recovery_required_blocks_normal_actions_until_hydration_succeeds",
      "bybit_hydrated_defaults_do_not_churn",
      "bybit_deferred_replan_owner_only",
      "bybit_sub_unit_tick_formats_trigger_price_correctly",
      "bybit_single_digit_price_tick_formats_correctly",
      "bybit_large_price_tick_formats_correctly",
      "bybit_integer_quantity_lot_formats_correctly",
      "bybit_fractional_quantity_lot_formats_correctly",
      "bybit_rejected_order_link_id_is_not_retried_without_state_change",
      "bybit_rejected_order_link_id_can_retry_after_request_change",
      "bybit_duplicate_order_link_id_preflights_place_intent_without_blocking_cleanup",
      "bybit_stale_context_wrong_position_idx_enters_recovery",
      "bybit_active_app_order_without_context_refuses_mutation_or_adopts_explicitly",
      "bybit_context_without_active_order_is_inconclusive_until_recovery",
      "bybit_flat_hedge_row_with_opposite_open_does_not_emit_closed_notice",
      "bybit_one_way_flat_row_uses_previous_side_identity",
      "bybit_completed_dca_state_survives_restart_without_active_order",
      "bybit_filter_only_recovery_does_not_prune_contexts",
      "bybit_open_order_recovery_prunes_absent_contexts",
      "bybit_late_private_event_routes_to_current_or_terminal_scope",
      "bybit_duplicate_slots_same_role_step_resolve_without_extra_place",
      "bybit_pending_confirmation_blocks_duplicate_dca_place",
      "bybit_terminal_dca_fill_then_planner_tick_reprotects_only_after_position_update",
      "bybit_position_mode_auto_detects_observed_exchange_identity",
      "bybit_hedge_risk_blocks_dca_but_allows_protective_repair"
    ],
    "conformancePack": "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json",
    "requiredOutcome": "Create local behavior-contract tests from the [Conformance Pack](https://siebly.io/reference/glossary#conformance-pack) and keep EXECUTION_MODE=DEMO, TESTNET, or LIVE submission unavailable until these cases pass."
  },
  "sdkSurfaceChecklist": [
    "Install the latest available bybit-api package and record the installed version as metadata only.",
    "Run or create the SDK/API surface check script before editing exchange code.",
    "Inspect installed TypeScript declarations and package exports for exact methods, request fields, response shapes, lifecycle events, and shutdown methods; use SDK docs, endpoint maps, and examples only to resolve unclear request shapes.",
    "Write README SDK surface notes with exact methods, types, files, examples, and package version checked."
  ],
  "sdkSurfaceCheckScriptShape": {
    "filename": "scripts/verify-bybit-position-manager-surfaces.mjs",
    "command": "node scripts/verify-bybit-position-manager-surfaces.mjs",
    "scriptLines": [
      "import { createRequire } from 'node:module';",
      "const require = createRequire(import.meta.url);",
      "const pkg = require('bybit-api/package.json');",
      "const bybit = await import('bybit-api');",
      "const requiredExports = ['RestClientV5', 'WebsocketClient'];",
      "const report = {",
      "  package: 'bybit-api',",
      "  installedVersion: pkg.version,",
      "  exports: Object.fromEntries(requiredExports.map((name) => [name, Boolean(bybit[name])])),",
      "  manualInspectionTargets: ['submitOrder', 'cancelOrder', 'amendOrder', 'preCheckOrder', 'getInstrumentsInfo', 'getPositionInfo', 'getActiveOrders', 'getHistoricOrders', 'getExecutionList', 'getWalletBalance', 'getAccountInfo', 'getRiskLimit', 'subscribeV5', 'closeAll', 'orderLinkId', 'positionIdx', 'triggerDirection', 'closeOnTrigger', 'orderFilter', 'retCode'],",
      "};",
      "console.log(JSON.stringify(report, null, 2));",
      "if (!report.exports.RestClientV5 || !report.exports.WebsocketClient) process.exitCode = 1;"
    ],
    "reportMustInclude": [
      "installed bybit-api version",
      "RestClientV5 and WebsocketClient export availability",
      "declaration targets inspected before coding",
      "private topic subscription shape",
      "REST method names and response retCode shape",
      "closeAll signature"
    ]
  },
  "canonicalSources": [
    "https://siebly.io/ai/exchange-state",
    "https://siebly.io/.well-known/prompts/bybit-position-manager/latest.md",
    "https://siebly.io/.well-known/recipes/bybit-position-manager.json",
    "https://siebly.io/ai/exchange-state/bybit",
    "https://siebly.io/.well-known/integration-kits/bybit-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/bybit-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/index.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/types.ts",
    "https://siebly.io/.well-known/integration-kits/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/schema.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/fixtures.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/runner.ts",
    "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json",
    "https://siebly.io/ai/exchange-state",
    "https://siebly.io/.well-known/recipes/exchange-state-management.json"
  ],
  "fallbackSources": [
    "https://siebly.io/sdk/bybit/javascript",
    "https://siebly.io/sdk/bybit/javascript/tutorial",
    "https://siebly.io/llms-tasks.txt",
    "https://siebly.io/llms.txt",
    "https://siebly.io/.well-known/siebly-sdk-catalog.json",
    "https://github.com/tiagosiebler/bybit-api",
    "https://github.com/sieblyio/crypto-api-examples/tree/master/examples/Bybit"
  ],
  "sdkSurface": {
    "restClient": "RestClientV5",
    "websocketClient": "WebsocketClient",
    "privateSubscribe": "ws.subscribeV5(['order', 'execution', 'position', 'wallet'], 'linear', true)",
    "websocketEvents": [
      "open",
      "response",
      "update",
      "reconnect",
      "reconnected",
      "exception"
    ],
    "shutdown": "closeAll(true) or current documented closeAll variant",
    "rest": [
      "getInstrumentsInfo",
      "getPositionInfo",
      "getActiveOrders",
      "getHistoricOrders",
      "getExecutionList",
      "getWalletBalance",
      "getAccountInfo",
      "getRiskLimit",
      "submitOrder",
      "cancelOrder",
      "amendOrder",
      "preCheckOrder"
    ],
    "customClientIdField": "orderLinkId",
    "positionIdentityField": "positionIdx"
  },
  "startupHydrationPolicy": {
    "linearPositions": "For Bybit linear startup/restart hydration, call getPositionInfo with settleCoin for each configured settlement coin, defaulting to USDT and USDC. Never call getPositionInfo with only category=linear; use symbol only for deliberately narrow scoped recovery, and filter configuredSymbols locally after settleCoin hydration.",
    "linearActiveOrders": "For Bybit linear active-order startup/restart hydration, either capture and preserve a redacted raw getActiveOrders({ category: \"linear\", settleCoin, openOnly: 0 }) response proving regular and conditional StopOrder rows are both returned for the account mode, or defensively fetch orderFilter=\"Order\" and orderFilter=\"StopOrder\" separately for each settleCoin and merge by orderId/orderLinkId.",
    "symbolScope": "configuredSymbols filters local mutation scope after broad settleCoin hydration; symbol-only REST hydration is reserved for deliberately narrow scoped recovery."
  },
  "requestFieldMatrix": [
    {
      "role": "DCA limit add",
      "category": "linear",
      "fields": "category, symbol, side, orderType=Limit, qty, price, timeInForce, positionIdx, orderLinkId",
      "normalizeAgainstHydration": "Converge on identity, side, qty, price, and active-order kind; trigger-only fields, closeOnTrigger=false, reduceOnly=false defaults, and empty triggerBy/orderFilter are diagnostic after those fields match."
    },
    {
      "role": "TP limit reduce",
      "category": "linear",
      "fields": "category, symbol, side, orderType=Limit, qty, price, timeInForce, reduceOnly=true, positionIdx, orderLinkId",
      "normalizeAgainstHydration": "Converge on identity, side, qty, price, active-order kind, and reduce-only semantics; false-like hydrated defaults are diagnostic after role, step, and kind match."
    },
    {
      "role": "SL conditional market",
      "category": "linear",
      "fields": "category, symbol, side, orderType=Market, qty=\"0\", triggerPrice, triggerDirection, triggerBy=MarkPrice unless configured, orderFilter=StopOrder, reduceOnly=true, closeOnTrigger=true, positionIdx, orderLinkId; omit request price",
      "normalizeAgainstHydration": "Compare triggerPrice, triggerDirection, triggerBy, orderFilter, closeOnTrigger, reduceOnly, positionIdx, side, role, step, and kind before suppressing replacement."
    },
    {
      "role": "Spot TP/DCA",
      "category": "spot",
      "fields": "category, symbol, side, orderType, qty, price when applicable, timeInForce, orderLinkId",
      "normalizeAgainstHydration": "No derivatives-only positionIdx, reduceOnly, or closeOnTrigger assumptions unless current Bybit docs support them for the selected spot order filter."
    }
  ],
  "eventReconciliationPolicy": [
    "Private order, execution, position, and wallet updates are inputs to accountstate and the symbol-side workflow, not direct planner calls.",
    "Order/execution/position/wallet bursts wait for a short bounded window by affected symbol-side so related events can arrive before one reconcile runs from accountstate.",
    "Emit semantic logs for private ingestion: private_ws_event_received, accountstate_event_applied, affected_scope_recorded, symbol_side_reconcile_started, action_family_selected, submission_accepted_pending_confirmation, private_ws_confirmation_applied, workflow_reconcile_complete.",
    "Normal private event bursts should not force full REST hydration while accountstate remains trusted.",
    "Order and execution events prove order/fill evidence only. Linear replacement planning waits for matching private position trust or scoped recovery.",
    "Late private events route to the current matching context or terminal context. They must not mutate a newer slot generation.",
    "Order/execution/position events reconcile when idle after the short event-burst wait; wallet-only clusters may use the same bounded delay.",
    "Subscription acknowledgement, private update, reconnect, and timer events that arrive during an active workflow record bounded follow-up reasons. The owner workflow schedules one deferred reconcile when it finishes.",
    "Do not recursively append reason strings such as workflow_active_user_data_workflow_active_user_data.",
    "After reconnect or exception, enter recoveryRequired or syncRequired, REST hydrate, replay buffered events, and only then resume new exposure.",
    "If recoveryRequired becomes true during a pass, finish as blocked or recovery and do not log workflow_finished from a stale pre-recovery snapshot."
  ],
  "trustedStatePolicy": {
    "restHydrationReasons": [
      "startup",
      "reconnect",
      "reconnected",
      "exception",
      "sync_required",
      "submission_recovery",
      "conflicting_state"
    ],
    "normalPrivateEventPolicy": "Replay into accountstate and plan without REST hydration while accountstate is trusted.",
    "identityRecoveryPolicy": "Durable-context mismatches, missing active-order evidence, stale positionIdx, late events, and contradictory mode evidence enter scoped recovery or refuse mutation before any exchange call.",
    "submissionActionFamilies": [
      "recovery",
      "cleanup",
      "protective",
      "dca",
      "noop",
      "blocked"
    ],
    "recoveryState": {
      "recoveryRequired": true,
      "operatorPaused": false,
      "blocksNewExposure": true,
      "blocksNormalPhasesUntilHydrated": true,
      "requiresScopedHydration": true,
      "clearsBy": [
        "scoped_rest_hydration",
        "buffered_private_event_replay",
        "coherent_accountstate_read"
      ]
    }
  },
  "retCodePolicy": {
    "classifier": "const assertBybitOk = (response, context) => {\n  if (response?.retCode === 0) return response.result;\n\n  throw new BybitBusinessError({\n    context,\n    retCode: response?.retCode,\n    retMsg: response?.retMsg,\n    result: response?.result,\n    time: response?.time,\n  });\n};",
    "rules": [
      "Prefer throwExceptions=true so non-zero retCode responses throw through one structured SDK/API error path.",
      "If throwExceptions=false, retCode === 0 is business acceptance.",
      "If throwExceptions=false, retCode !== 0 is rejection or unknown state even when the promise resolved.",
      "Thrown Bybit business/API errors or manually classified non-zero retCode responses enter recoveryRequired with operatorPaused=false; they are not a permanent operator pause by default.",
      "Preserve retCode, retMsg, result, time, sanitized request context, category, symbol, positionIdx, role, and orderLinkId in structured logs.",
      "Stop later non-sent intents in the current action family after a Bybit business rejection. If a concurrent protective sibling was already sent, reconcile/adopt confirmed equivalent protection and block/surface the failed slot."
    ]
  },
  "commandSafety": [
    "Doctor, inspect, status, readback, and SDK/API inspection commands force EXECUTION_MODE=PUBLIC or READ_ONLY_PRIVATE.",
    "EXECUTION_MODE=DEMO, TESTNET, or LIVE order placement, amend, and cancel require explicit config and acknowledgement.",
    "Unowned manual orders are never canceled or amended by default.",
    "Only app-owned orderLinkId values may be touched by cleanup or replacement logic."
  ],
  "conformanceFixtureNames": [
    "bybit_position_open_reacts_without_timer",
    "bybit_private_stream_exception_prevents_service_ready",
    "bybit_private_topic_updates_can_complete_readiness_without_args_ack",
    "bybit_subscribe_response_req_id_topics_can_mark_ready",
    "bybit_private_stream_reconnect_clears_exception_before_ack_readiness",
    "bybit_private_position_replay_drives_planning_without_rest_rehydrate",
    "bybit_normal_state_check_uses_accountstate_not_rest",
    "bybit_reconnect_uses_rest_hydration_before_resume",
    "bybit_private_event_burst_groups_to_single_reconcile",
    "bybit_order_execution_position_wallet_out_of_order_converges",
    "bybit_accepted_submissions_settle_to_zero_intents",
    "bybit_golden_live_convergence_trace_settles_after_deferred_dca",
    "bybit_position_open_places_protective_then_dca_after_ws_confirmation",
    "bybit_pending_confirmation_does_not_unlock_dependent_action_family",
    "bybit_semantic_ws_logs_emitted_after_ingest",
    "bybit_symbol_side_queue_groups_private_event_burst",
    "bybit_order_active_confirmation_before_rest_acceptance_no_stale_pending",
    "bybit_rest_acceptance_does_not_downgrade_trusted_private_order",
    "bybit_terminal_order_status_is_not_open_order_confirmation",
    "bybit_execution_fill_is_not_open_order_confirmation",
    "bybit_position_close_between_exit_action_and_dca_skips_dca",
    "bybit_dca_never_submitted_from_stale_pre_close_plan",
    "bybit_conditional_sl_requires_trigger_direction",
    "bybit_hedge_normalized_position_idx_maps_to_bybit_request_idx",
    "bybit_one_way_short_uses_position_idx_zero",
    "bybit_tp_is_reduce_only_limit_with_expected_time_in_force",
    "bybit_position_update_timestamp_does_not_rotate_slots",
    "bybit_full_close_cleanup_cancels_only_app_owned_orders",
    "bybit_one_way_short_then_long_fresh_scope_cleans_old_side",
    "bybit_hedge_same_symbol_sides_do_not_cross_cancel",
    "bybit_startup_wipe_rebuild_cancels_app_orders_before_rebuild",
    "bybit_startup_adopts_active_contexts_and_prunes_absent_contexts",
    "bybit_default_dca_active_order_does_not_advance_next_step",
    "bybit_ambiguous_event_routes_bounded_fallback_then_exact_scope",
    "bybit_linear_close_all_sl_request_is_valid",
    "bybit_same_side_position_add_amends_same_slots_without_cancel_first",
    "bybit_same_slot_update_submits_amends_without_cancel_gap",
    "bybit_cancel_first_replacement_converges_before_place",
    "bybit_amend_rejection_enters_recovery_without_blind_cancel_place",
    "bybit_retcode_nonzero_blocks_failed_slot_or_enters_recovery",
    "bybit_submission_rejection_requires_resync_without_permanent_pause",
    "bybit_order_link_id_context_lookup_routes_private_event",
    "bybit_lost_order_link_id_registry_rebuilds_from_trusted_state",
    "bybit_protective_sl_tp_pre_registered_and_dispatched_concurrently_by_default",
    "bybit_partial_protective_reject_blocks_failed_slot_and_surfaces_error",
    "bybit_unknown_submit_outcome_enters_recovery_after_configured_timeout",
    "bybit_recovery_required_blocks_normal_actions_until_hydration_succeeds",
    "bybit_hydrated_defaults_do_not_churn",
    "bybit_deferred_replan_owner_only",
    "bybit_sub_unit_tick_formats_trigger_price_correctly",
    "bybit_single_digit_price_tick_formats_correctly",
    "bybit_large_price_tick_formats_correctly",
    "bybit_integer_quantity_lot_formats_correctly",
    "bybit_fractional_quantity_lot_formats_correctly",
    "bybit_rejected_order_link_id_is_not_retried_without_state_change",
    "bybit_rejected_order_link_id_can_retry_after_request_change",
    "bybit_duplicate_order_link_id_preflights_place_intent_without_blocking_cleanup",
    "bybit_stale_context_wrong_position_idx_enters_recovery",
    "bybit_active_app_order_without_context_refuses_mutation_or_adopts_explicitly",
    "bybit_context_without_active_order_is_inconclusive_until_recovery",
    "bybit_flat_hedge_row_with_opposite_open_does_not_emit_closed_notice",
    "bybit_one_way_flat_row_uses_previous_side_identity",
    "bybit_completed_dca_state_survives_restart_without_active_order",
    "bybit_filter_only_recovery_does_not_prune_contexts",
    "bybit_open_order_recovery_prunes_absent_contexts",
    "bybit_late_private_event_routes_to_current_or_terminal_scope",
    "bybit_duplicate_slots_same_role_step_resolve_without_extra_place",
    "bybit_pending_confirmation_blocks_duplicate_dca_place",
    "bybit_terminal_dca_fill_then_planner_tick_reprotects_only_after_position_update",
    "bybit_position_mode_auto_detects_observed_exchange_identity",
    "bybit_hedge_risk_blocks_dca_but_allows_protective_repair"
  ],
  "goldenRuntimeTrace": {
    "startup": [
      "subscribe private order/execution/position/wallet topics",
      "REST hydrate instruments, account mode, wallet, positions, active orders, executions, and risk limits",
      "wait for private topic ack or topic updates",
      "replay buffered private events",
      "emit private_ws_event_received/accountstate_event_applied/affected_scope_recorded",
      "plan one affected symbol-side from accountstate",
      "emit cleanup candidate or submit cleanup action if write mode permits",
      "pre-register protective SL/TP contexts and record or dispatch separate SL/TP orders concurrently in protective action family",
      "wait for private stream confirmation or scoped recovery hydration",
      "record or submit DCA in a later DCA action family only if the position still exists and still needs DCA",
      "planner_finished intentCount=0"
    ],
    "normalPrivateBurst": [
      "buffer order/execution/position/wallet events for about 25ms",
      "replay burst into accountstate without REST hydration while trusted",
      "emit semantic WS/accountstate logs and record the affected symbol-side scope",
      "plan one affected symbol-side from accountstate",
      "amend same-slot TP/SL/DCA where possible",
      "planner_finished intentCount=0"
    ],
    "reconnectOrException": [
      "mark stream not ready and set recoveryRequired or syncRequired",
      "keep buffering private events where possible",
      "REST hydrate affected category/symbol/positionIdx scope",
      "wait for topic ack or private topic update",
      "replay buffered events",
      "resume only when accountstate is coherent"
    ]
  },
  "redFlagLogs": [
    "repeated nonzero intentCount with no accountstate change",
    "repeated cancel/place for the same logical slot when amend would work",
    "repeated REST hydration on normal private account-event bursts",
    "positionIdx:0 request for normalized hedge LONG or SHORT",
    "product_paused after a submission rejection without explicit operator stop",
    "duplicate orderLinkId after cancel-first replacement",
    "role, step, side, or strategy state encoded into orderLinkId",
    "DCA submitted from a plan made before an intervening close or fill",
    "app-owned cleanup blocked by duplicate or recent place guards",
    "accepted submit response immediately unlocks DCA before private stream confirmation",
    "workflow_finished logged from a stale pre-recovery snapshot"
  ]
}
