InventoryUnwinder
InventoryUnwinder detects when a position has breached its concentration or capital limit — either because an OrderIntent would push it over, or becau
What it does
InventoryUnwinder detects when a position has breached its concentration or capital limit — either because an OrderIntent would push it over, or because an existing position is already over the limit (e.g. after a parameter change or strategy crash). When a breach is detected it generates unwind OrderIntents targeting the source bot, using the NegRiskAdapter on Polygon for negRisk markets, and routes them back into the execution pipeline. It can also hard-reject incoming intents that would worsen an already-breached position. Builder codes from the original strategy are preserved on unwind intents for attribution. Fail-closed: if position data is unavailable, all new intents for the affected market are rejected.
Pipeline placement
Applies to: Any OrderIntent that would push a position beyond concentration or capital limits; also fires on position-scan cycle to
Why it matters
| If this fails | Consequence |
|---|---|
| Concentration limit breach not unwound | A position that exceeds the declared inventory band creates directional exposure larger than the strategy risk envelope can justify, leading to losses that compound if the market moves against the position. |
| Capital limit not enforced on position growth | Without an active unwind, capital can become trapped in a single position, reducing the portfolio's ability to respond to other opportunities or drawdowns. |
| NegRisk market unwind without NegRiskAdapter | For multi-outcome negRisk markets, naively selling YES tokens may not fully close the position or may leave residual NO exposure. The NegRiskAdapter burn-and-redeem path must be used to correctly exit. |
| Strategy crash leaves open inventory | If a strategy halts mid-session with open inventory, the position will remain on the book indefinitely unless InventoryUnwinder detects and liquidates it. |
Inputs
Polymarket inputs
| Input | Source | Required | Use |
|---|---|---|---|
| Current open positions per market — size, side, cost basis | clob_auth | required | Detect whether a position is within its inventory band or has breached concentration limits requiring unwind. |
| Order book top-of-book (bid/ask) for target market | clob_public | required | Determine unwind execution price and whether passive unwind is feasible at the current top-of-book. |
| Market metadata — negRisk flag, enableNegRisk, condition ID | gamma | required | Identify whether the market uses the NegRiskAdapter for unwind (negRisk markets must burn NO → pUSD via NegRiskAdapter). |
| On-chain position balance for NegRisk markets | onchain | optional | Verify the on-chain token balance before constructing NegRiskAdapter unwind transactions for negRisk multi-outcome markets. |
Internal inputs
| Input | Source | Required | Use |
|---|---|---|---|
| Per-strategy inventory band configuration | internal | required | Max allowed net position size per market per strategy. Unwind is triggered when position exceeds max_inventory_band. |
| Source bot builder code (bytes32) for the breached position | internal | required | Carry original strategy builder code on unwind OrderIntents so attribution flows back to the position's source bot. |
| KillSwitch active flag | KillSwitch | required | If KillSwitch is active, block all new intents and begin emergency unwind of all open inventory. |
| PortfolioGuard per-market budget remaining | PortfolioGuard | required | Confirm the unwind size does not itself breach portfolio limits (unwinds always reduce exposure, so they typically pass). |
Authority
What this bot is permitted to do
State
Readiness
General live
Status
live
Class
Guardrail
Default mode
general_live
Developer owner
Polytraders core — Risk pod
Capital impact
Direct
Reason codes emitted
| Code | Severity | Meaning | Action |
|---|---|---|---|
| KILL_SWITCH_ACTIVE | HARD_REJECT | Global kill switch is active; all incoming intents are rejected and emergency unwind of all open inventory begins. | Immediately return HARD_REJECT and trigger startEmergencyUnwindAll(). |
| STALE_MARKET_DATA | HARD_REJECT | Position data from clob_auth or market metadata from Gamma is unavailable or stale. | Return HARD_REJECT; retry on next fresh fetch. |
| INVENTORY_UNWINDER_BAND_BREACH | HARD_REJECT | Position is at or above max_inventory_band and the incoming intent would increase it further. | Return HARD_REJECT; emit unwind OrderIntents to reduce position back to handback threshold. |
| INVENTORY_UNWINDER_RESHAPE | RESHAPE | Incoming intent would push the position above max_inventory_band but the position is currently below the hard ceiling. | Return RESHAPE_REQUIRED with constraints.max_size_usd = max_inventory_band - current_position. |
| INVENTORY_UNWINDER_BAND_WARN | WARN | Position (after this intent) would be between the warning and hard thresholds. | Attach annotation to APPROVE; do not block. Log for monitoring. |
| INVENTORY_UNWINDER_NEGRISK_UNWIND | INFO | Unwind is proceeding via the NegRiskAdapter path (burn NO tokens → pUSD). | Log the on-chain burn transaction reference and pUSD recovered. |
| INVENTORY_UNWINDER_UNWIND_COMPLETE | INFO | Position has been reduced to or below the handback threshold; control returned to the originating strategy. | Emit DecisionReport(UNWIND_COMPLETE) and resume accepting new intents from the source bot. |
Related bots in Risk Guardrail
Used by
Reverse index — strategies that currently reference risk.inventoryunwinder. If you change this bot's authority or reason codes, these strategies must re-pass shadow.
| Strategy | State | Activity |
|---|---|---|
| BTC weekly — close-aware quotes | demo-wired | last triggered 3m ago |
| Fed Rates — surprise drift | frozen | last triggered 10m ago |
Showing 2 of 2 · demo-wired ≠ production-live
Why this matters
Risk Guardrail bots does NOT propose intents or sign orders; only permits or blocks. Understanding the authority boundary prevents misuse and makes promotion-gate reviews faster and more reliable. View raw spec JSON →