Polytraders Dev Guide
internal
v3 spine Phase 1 · Shared contracts 9 demo-wired · 0 shadow-ready · 0 production-live · 100 pending · 109 total 15/33 infra tasks the plan status board
HomeBy LayerStrategy3.1 Maker-Tight

3.1 Maker-Tight

Strategy Alpha Strategy Trade LIVE General live capital · Direct P6 · One simple strategy pending flagship stub

Maker-Tight is a passive market-making strategy that posts resting maker orders inside the current touch when market conditions are benign (low volatility, adequate volume, clean order flow). It quotes both YES and NO sides at a configurable edge (edge_bps) from the mid-price, sized to clip_size_usd. When spread is too tight to earn the edge, or when order-flow imbalance signals toxic flow, the bot skips the cycle and cancels any open quotes. This is a user-controlled execution tool for posting maker liquidity on predictive-event markets — not a directional betting strategy. Maker rebates (20–25% of platform fees, paid in pUSD) contribute to the overall return profile.

v3 readiness

Docs27/27
donehow scored
Impl12/15
in progresshow scored
Backtest3/4
in progresshow scored
Runtime0/8
pendinghow scored

A bot is done when all four scores are. What does done mean?

v3.5 · wired registry id strat.maker_tight

Reference market-making strategy. Six SEARCH_SPACE parameters. Reference optimizer run pending.

Source: @polytraders/bots · src/strategy/maker_tight.js · Impl 12/15 · Backtest 3/4

1. Bot Identity

LayerStrategy  Strategy
Bot classAlpha Strategy
AuthorityTrade
StatusLIVE
ReadinessGeneral live
Runs beforeRisk guardrail pipeline
Runs afterMarket scanner / opportunity feed
Applies toLiquid binary markets where 24h volume ≥ min_volume_24h_usd, spread > min_spread_bps, and no toxic order flow is detected
Default modegeneral_live
User-visibleAdvanced details only
Developer ownerPolytraders core — Strategy pod

2. Purpose

Maker-Tight is a passive market-making strategy that posts resting maker orders inside the current touch when market conditions are benign (low volatility, adequate volume, clean order flow). It quotes both YES and NO sides at a configurable edge (edge_bps) from the mid-price, sized to clip_size_usd. When spread is too tight to earn the edge, or when order-flow imbalance signals toxic flow, the bot skips the cycle and cancels any open quotes. This is a user-controlled execution tool for posting maker liquidity on predictive-event markets — not a directional betting strategy. Maker rebates (20–25% of platform fees, paid in pUSD) contribute to the overall return profile.

3. Why This Bot Matters

  • Quoting into toxic flow without detection

    Informed takers repeatedly fill the maker side immediately after posting, resulting in adverse selection losses that erode the quoted spread over time.

  • Posting quotes when spread < min_spread_bps

    Quoting inside an already-tight spread earns no edge; the maker rebate does not cover the risk of being adversely selected on a fast-moving market.

  • Inventory skew not applied

    Without skewing quotes toward the short side as inventory builds, the bot accumulates a directional position that violates the passive-maker intent and increases settlement risk.

  • feeRateBps hardcoded on signed maker order (V1 pattern)

    CLOB V2 rejects orders with feeRateBps. Maker fees are operator-set at match time; the signed order must not contain this field. Maker fee_bps is capped at 50 bps.

4. Required Polymarket Inputs

InputSourceRequired?Use
Live order book — best bid, best ask, mid-pricews_market (CLOB WebSocket)YesCompute current spread (ask - bid) and mid-price to determine quoting levels.
Order-flow imbalance over last N secondsws_market (trade tape)YesDetect toxic flow: if taker-initiated buy volume >> sell volume, the market is directional and maker posting is paused.
24h trading volume in pUSDclob_publicYesOnly post on markets meeting min_volume_24h_usd; illiquid markets have wide spreads that attract toxic flow.
Running inventory position on each marketclob_auth (open positions)YesCompute inventory skew factor; shift bid and ask prices toward the direction that reduces open inventory.

5. Required Internal Inputs

InputSourceRequired?Use
KillSwitch active flagKillSwitchYesCancel all open maker quotes and emit no new OrderIntents if KillSwitch is active.
Builder code bytes32internal configYesInjected into builder field on every maker OrderIntent for attribution. Maker fee_bps ≤ 50.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
edge_bps1063Minimum edge in basis points from mid-price at which the bot will post a quote. Quotes are placed at mid ± edge_bps/2.
clip_size_usd200400600Size in pUSD of each individual maker quote (bid or ask). Both sides are quoted at this size unless inventory skew applies.
inventory_skew_factor0.30.60.9Coefficient applied to shift quote prices toward reducing open inventory. At 0.3, a long YES position shifts the YES ask down and the YES bid up proportionally.
min_volume_24h_usd25000015000050000Minimum 24h trading volume (in pUSD) required for this strategy to post on a market. Below this threshold the spread is likely structural rather than temporary.

7. Detailed Parameter Instructions

edge_bps

What it means

Minimum edge in basis points from mid-price at which the bot will post a quote. Quotes are placed at mid ± edge_bps/2.

Default

{ "edge_bps": 10 }

Why this default matters

10 bps covers expected adverse selection on benign low-vol markets. Below 6 bps the edge is unlikely to persist long enough to fill; below 3 bps (hard floor) the bot will not quote regardless of config.

Threshold logic

ConditionAction
edge_bps ≥ 10Post quotes at mid ± edge_bps/2
6 ≤ edge_bps < 10WARN MAKER_TIGHT_EDGE_MARGINAL; post at reduced clip size (50%)
edge_bps < 3 (hard floor)SKIP — MAKER_TIGHT_SPREAD_TOO_TIGHT

Developer check

if edge_bps < params.hard: return skip('MAKER_TIGHT_SPREAD_TOO_TIGHT')

User-facing English

The market spread is too narrow to post competitively. Quoting was skipped for this cycle.

clip_size_usd

What it means

Size in pUSD of each individual maker quote (bid or ask). Both sides are quoted at this size unless inventory skew applies.

Default

{ "clip_size_usd": 200 }

Why this default matters

200 pUSD per side keeps individual quote impact small on typical Polymarket binary books. The Risk guardrail pipeline may further reduce this.

Threshold logic

ConditionAction
≤ 200 pUSDNormal single-side quote
200–600 pUSDWARN; risk guardrail will reshape if above portfolio budget
> 600 pUSDReject config change — PARAMETER_CHANGE_REQUIRES_APPROVAL

Developer check

if params.clip_size_usd > params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')

User-facing English

Each quote was sized to keep the order visible but not dominant on the market.

inventory_skew_factor

What it means

Coefficient applied to shift quote prices toward reducing open inventory. At 0.3, a long YES position shifts the YES ask down and the YES bid up proportionally.

Default

{ "inventory_skew_factor": 0.3 }

Why this default matters

0.3 provides a moderate skew that discourages further inventory accumulation without widening quotes so aggressively that they never fill.

Threshold logic

ConditionAction
≤ 0.3Normal skew
0.3–0.6WARN MAKER_TIGHT_HIGH_SKEW; inventory is being aggressively managed
> 0.9Hard ceiling; config rejected

Developer check

bidPrice = mid - edge_half - skew * inventory_ratio; askPrice = mid + edge_half - skew * inventory_ratio

User-facing English

Quote prices were adjusted to help balance the current position.

min_volume_24h_usd

What it means

Minimum 24h trading volume (in pUSD) required for this strategy to post on a market. Below this threshold the spread is likely structural rather than temporary.

Default

{ "min_volume_24h_usd": 250000 }

Why this default matters

Markets with < $250K daily volume tend to have wide, illiquid spreads that attract informed takers rather than uninformed flow. Posting on them is adverse-selection-prone.

Threshold logic

ConditionAction
volume_24h ≥ 250,000 pUSDEligible to post
150,000–250,000 pUSDWARN MAKER_TIGHT_LOW_VOLUME; post at 50% clip size
< 50,000 pUSD (hard floor)SKIP — MAKER_TIGHT_SPREAD_TOO_TIGHT (volume too low)

Developer check

if volume_24h < params.hard: return skip('MAKER_TIGHT_SPREAD_TOO_TIGHT')

User-facing English

This market does not have enough daily trading activity for safe maker quoting.

8. Default Configuration

{
  "bot_id": "strat.maker_tight",
  "version": "2.1.0",
  "mode": "general_live",
  "defaults": {
    "edge_bps": 10,
    "clip_size_usd": 200,
    "inventory_skew_factor": 0.3,
    "min_volume_24h_usd": 250000
  },
  "locked": {
    "edge_bps": {
      "min": 3
    },
    "clip_size_usd": {
      "max": 600
    },
    "inventory_skew_factor": {
      "max": 0.9
    }
  }
}

9. Implementation Flow

  1. Check KillSwitch active flag; if active, cancel all open maker quotes and emit no new OrderIntents.
  2. Subscribe to ws_market book and trade-tape streams for all eligible markets.
  3. Filter markets: 24h volume ≥ min_volume_24h_usd (clob_public). Skip low-volume markets.
  4. On each book tick: compute mid = (best_bid + best_ask) / 2; spread_bps = (best_ask - best_bid) / mid * 10000.
  5. If spread_bps < 2 * edge_bps: skip cycle — spread too tight to earn edge; emit DecisionReport intent_emitted=false MAKER_TIGHT_SPREAD_TOO_TIGHT (sampled 1/100).
  6. Compute order-flow imbalance over last 30s from trade tape. If taker-buy_volume / total_volume > toxic_flow_threshold: skip cycle — MAKER_TIGHT_TOXIC_FLOW_DETECTED.
  7. Fetch open YES/NO position from clob_auth to compute inventory_ratio = current_position / max_inventory.
  8. Compute skewed bid/ask prices: bidPrice = mid - edge_bps/2/10000 - skew * inventory_ratio; askPrice = mid + edge_bps/2/10000 - skew * inventory_ratio.
  9. Apply edge_bps warning threshold: if edge_bps < 6, reduce clip to 50%.
  10. Emit OrderIntent YES (post_only=true, side=buy, price=bidPrice, tif=GTC, builder={code, fee_bps: 30}).
  11. Emit OrderIntent NO (post_only=true, side=buy, price=ask_of_NO=1-bidPrice, tif=GTC, builder={code, fee_bps: 30}).
  12. Note: fees are operator-set at match time in V2 — feeRateBps is NOT on the signed order. Maker fee_bps ≤ 50.
  13. Emit DecisionReport with intent_emitted=true, edge_bps, inventory_ratio, skew applied.

10. Reference Implementation

Subscribes to CLOB WebSocket book and trade-tape streams, checks spread and flow conditions, and emits GTC post_only maker OrderIntents inside the touch when conditions are benign.

Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. Translate to TS/Python/Go/Rust.

FUNCTION onBookTick(market_id, bookTick):
  // --- 0. KillSwitch gate ---
  ks = FETCH internal.killswitch.status
  IF ks.active:
    CANCEL_OPEN_QUOTES(market_id)
    RETURN

  // --- 1. Volume filter ---
  vol24h = FETCH clob_public.GET('/markets/' + market_id + '/volume')
  IF vol24h < params.min_volume_24h_usd_hard:  // 50,000 pUSD
    SKIP 'MAKER_TIGHT_SPREAD_TOO_TIGHT' (volume)
    RETURN

  // --- 2. Spread check ---
  mid        = (bookTick.best_bid + bookTick.best_ask) / 2
  spread_bps = (bookTick.best_ask - bookTick.best_bid) / mid * 10000
  IF spread_bps < 2 * params.edge_bps_hard:  // 3 bps hard floor
    // sample 1/100 for observability
    IF random() < 0.01:
      EMIT DecisionReport(intent_emitted=false, reason='MAKER_TIGHT_SPREAD_TOO_TIGHT')
    RETURN

  // --- 3. Toxic flow detection ---
  tape = FETCH ws_market.tradeTape(market_id, window_s=30)
  takerBuyRatio = tape.taker_buy_volume / (tape.total_volume + 1e-9)
  IF takerBuyRatio > 0.75:
    EMIT DecisionReport(intent_emitted=false, reason='MAKER_TIGHT_TOXIC_FLOW_DETECTED')
    RETURN

  // --- 4. Inventory skew ---
  position    = FETCH clob_auth.GET('/positions?market=' + market_id)
  inventoryRatio = position.yes_notional / params.max_inventory_usd
  skew        = params.inventory_skew_factor * inventoryRatio
  edgeHalf    = params.edge_bps / 2 / 10000

  bidPrice    = round(mid - edgeHalf - skew, 4)
  askPrice    = round(mid + edgeHalf - skew, 4)

  // --- 5. Warning threshold ---
  clipSize = toPusdUnits(params.clip_size_usd)
  IF params.edge_bps < 6:
    WARN('MAKER_TIGHT_EDGE_MARGINAL')
    clipSize = toPusdUnits(params.clip_size_usd * 0.5)

  // --- 6. Emit maker OrderIntents (V2: no feeRateBps; builder field; post_only=true) ---
  // Maker fee_bps <= 50 (V2 maker cap)
  EMIT OrderIntent(
    market_id  = market_id,
    outcome    = 'YES',
    side       = 'buy',
    price      = bidPrice,
    size_pUSD  = clipSize,
    tif        = 'GTC',
    post_only  = true,
    builder    = { code: config.builder_code, fee_bps: 30 },
    negrisk_aware = false
  )
  EMIT OrderIntent(
    market_id  = market_id,
    outcome    = 'YES',
    side       = 'sell',
    price      = askPrice,
    size_pUSD  = clipSize,
    tif        = 'GTC',
    post_only  = true,
    builder    = { code: config.builder_code, fee_bps: 30 },
    negrisk_aware = false
  )

  EMIT DecisionReport(
    intent_emitted = true,
    edge_bps       = params.edge_bps,
    inventory_ratio = inventoryRatio,
    skew_applied   = (skew != 0),
    reasons        = ['MAKER_TIGHT_QUOTING']
  )

SDK calls used

  • ws_market.subscribe('book', [market_id])
  • ws_market.subscribe('trade_tape', [market_id])
  • fetchClobPublic('/markets/' + market_id + '/volume')
  • clob_auth.GET('/positions?market=' + market_id)
  • toPusdUnits(rawFloat)
  • buildOrderTypedData(orderParams, { name: 'CTFExchange', version: '2', chainId: 137 })
  • internal.killswitch.status()
  • internal.builder_code

Complexity: O(1) per market book tick

11. Wire Examples

Input — what arrives on the wire

WebSocket book tick — benign market, spread 16 bpsws_market

{
  "market_id": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd",
  "best_bid": "0.619",
  "best_ask": "0.629",
  "mid": "0.624",
  "spread_bps": "16.0",
  "taker_buy_ratio_30s": "0.52",
  "volume_24h_pusd": "480000",
  "received_at_ms": 1746789800000
}

Output — what the bot emits

OrderIntent — maker bid (YES buy, post_only, GTC)

{
  "intent_id": "oi_01HX9MKRT1A4Z1B",
  "trace_id": "tr_01HX9MKRT1A4VR5",
  "market_id": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd",
  "outcome": "YES",
  "side": "buy",
  "price": "0.619",
  "size_pUSD": "200.00",
  "tif": "GTC",
  "post_only": true,
  "builder": {
    "code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
    "fee_bps": 30
  },
  "negrisk_aware": false,
  "decision": {
    "edge_bps": 10.0,
    "inventory_ratio": 0.12,
    "skew_applied": true,
    "reasons": [
      "MAKER_TIGHT_QUOTING"
    ]
  },
  "comment": "fees are operator-set at match time in V2 — feeRateBps is NOT on the signed order"
}

DecisionReport — skipped (spread too tight), sampled 1/100

{
  "report_id": "dr_01HX9MKRT1BZZZ",
  "bot_id": "strat.maker_tight",
  "market_id": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd",
  "intent_emitted": false,
  "spread_bps": 3.2,
  "reasons": [
    "MAKER_TIGHT_SPREAD_TOO_TIGHT"
  ],
  "sampled": true,
  "evaluated_at_ms": 1746789801000
}

12. Decision Logic

APPROVE

spread_bps > 2 * edge_bps, volume_24h ≥ min_volume_24h_usd, no toxic flow detected, KillSwitch inactive, inventory_ratio < 1.0. Emit bid + ask OrderIntents as GTC post_only maker orders.

RESHAPE_REQUIRED

Not applicable — strat bots emit OrderIntents; reshaping is handled downstream by the Risk guardrail pipeline.

REJECT

spread_bps < 2 * edge_bps hard floor; volume too low; toxic flow detected; KillSwitch active; stale feed. Cancel open quotes and emit DecisionReport intent_emitted=false.

WARNING_ONLY

edge_bps between 3 and 6, or volume between 50K and 150K pUSD, triggers warning and 50% size reduction before emitting.

13. Standard Decision Output

This bot returns a OrderIntent object. See OrderIntent schema.

{
  "intent_id": "oi_01HX9MKRT1A4Z1B",
  "trace_id": "tr_01HX9MKRT1A4VR5",
  "market_id": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd",
  "outcome": "YES",
  "side": "buy",
  "price": "0.619",
  "size_pUSD": "200.00",
  "tif": "GTC",
  "post_only": true,
  "builder": {
    "code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
    "fee_bps": 30
  },
  "negrisk_aware": false,
  "decision": {
    "edge_bps": 10.0,
    "inventory_ratio": 0.12,
    "skew_applied": true,
    "reasons": [
      "MAKER_TIGHT_QUOTING"
    ]
  },
  "comment": "fees are operator-set at match time in V2 \u2014 feeRateBps is NOT on the signed order"
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
MAKER_TIGHT_QUOTINGINFOSpread is adequate, volume passes filter, no toxic flow detected. Maker bid+ask OrderIntents emitted.Emit two GTC post_only OrderIntents.Maker quotes were posted inside the market spread.
MAKER_TIGHT_SPREAD_TOO_TIGHTINFOMarket spread is narrower than 2 * edge_bps hard floor, or volume is below min_volume_24h_usd hard floor. Quoting is not viable.Skip; emit DecisionReport intent_emitted=false (sampled 1/100).The market spread was too tight to post a competitive quote.
MAKER_TIGHT_TOXIC_FLOW_DETECTEDWARNTaker-initiated buy volume over the last 30s exceeds the toxic flow threshold (0.75 ratio). Directional flow detected.Skip; cancel open quotes; emit DecisionReport intent_emitted=false.Strong directional trading was detected. Maker quotes were paused to avoid adverse selection.
MAKER_TIGHT_EDGE_MARGINALWARNedge_bps is between the warning threshold (6) and the hard floor (3). Quoting at reduced clip size.Emit OrderIntents at 50% clip size; log warning.Market conditions are borderline. Maker quotes were posted at reduced size.
MAKER_TIGHT_HIGH_SKEWWARNinventory_skew_factor is above the warning threshold (0.6). Inventory is being aggressively managed.Continue quoting; log warning; monitor inventory_ratio.Quote prices were significantly adjusted to help balance the current position.
MAKER_TIGHT_LOW_VOLUMEWARN24h volume is between the warning (150K) and hard floor (50K). Market is less liquid than preferred.Emit at 50% clip size; log warning.This market has lower than usual activity. Quote sizes were reduced.
STALE_MARKET_DATAHARD_REJECTBook snapshot older than 5s or position data unavailable.Cancel open quotes; no new OrderIntents.Market data was too old. Quotes were cancelled.
KILL_SWITCH_ACTIVEHARD_REJECTGlobal kill switch is active.Cancel all open quotes; no new OrderIntents.Trading is currently paused.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_strat_makertight_decisions_totalcountercountverdict, reason_codeTotal evaluation cycles by intent_emitted (true/false) and reason code.
polytraders_strat_makertight_spread_bpshistogrambasis_pointsmarket_idDistribution of observed market spread in bps at each evaluation, including skipped cycles.
polytraders_strat_makertight_inventory_ratiogaugeratiomarket_idCurrent inventory ratio (yes_notional / max_inventory) per market.
polytraders_strat_makertight_intents_emitted_totalcountercountsideTotal maker OrderIntents emitted by side (buy bid / sell ask).
polytraders_strat_makertight_toxic_flow_skips_totalcountercountmarket_idNumber of cycles skipped due to toxic flow detection per market.
polytraders_strat_makertight_eval_latency_mshistogrammillisecondsWall-clock latency from book tick to OrderIntent emit.

Alerts

AlertConditionSeverityRunbook
MakerTightHighToxicFlowRaterate(polytraders_strat_makertight_toxic_flow_skips_total[10m]) > 5warn#runbook-makertight-toxic-flow
MakerTightHighInventorypolytraders_strat_makertight_inventory_ratio > 0.8warn#runbook-makertight-inventory
MakerTightStaleFeedrate(polytraders_strat_makertight_decisions_total{reason_code='STALE_MARKET_DATA'}[5m]) > 0.1warn#runbook-makertight-stale-feed
MakerTightKillSwitchBlockingrate(polytraders_strat_makertight_decisions_total{reason_code='KILL_SWITCH_ACTIVE'}[1m]) > 0page#runbook-killswitch

Dashboards

  • Grafana — Strategy / MakerTight spread distribution and quote throughput
  • Grafana — Strategy / MakerTight inventory ratio and toxic flow skip rate

16. Developer Reporting

{
  "bot_id": "strat.maker_tight",
  "market_id": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd",
  "mid": 0.624,
  "best_bid": 0.619,
  "best_ask": 0.629,
  "spread_bps": 16.0,
  "edge_bps": 10.0,
  "inventory_ratio": 0.12,
  "skew_applied": true,
  "bid_price": 0.619,
  "ask_price": 0.629,
  "clip_size_pusd": 200.0,
  "toxic_flow": false,
  "intent_emitted": true,
  "reason": "MAKER_TIGHT_QUOTING",
  "emitted_at_ms": 1746789800000
}

17. Plain-English Reporting

SituationUser-facing explanation
Maker quote postedA resting order was placed inside the market's current spread to provide liquidity. It will fill if a taker crosses the price.
Quote skipped — spread too tightThe market's current bid-ask spread is too narrow to post a quote at a worthwhile price. Quoting was skipped for this cycle.
Quote skipped — directional flow detectedRecent trading activity showed a strong directional pattern. Posting a maker order in these conditions increases the risk of being traded against by better-informed participants.
Quotes adjusted for inventory balanceQuote prices were shifted slightly to encourage trades that bring the current position back toward neutral.

18. Failure-Mode Block

main_failure_modeAdverse selection: quoted maker orders fill repeatedly immediately after posting because of undetected informed flow, resulting in a directional inventory that cannot be profitably unwound.
false_positive_riskToxic flow detector is overly sensitive, triggering MAKER_TIGHT_TOXIC_FLOW_DETECTED on normal short-term imbalances and causing the bot to skip valid quoting opportunities.
false_negative_riskOrder-flow imbalance window too long (e.g. 60s) causes the bot to miss a brief but high-intensity informed-flow episode, posting quotes that fill immediately at a loss.
safe_fallbackIf book data is stale (last_seen > 5s) or clob_auth position read fails, cancel all open quotes and emit no new OrderIntents. Fail closed on missing inventory state.
required_dependenciesws_market book and trade-tape stream, clob_public 24h volume, clob_auth open positions, KillSwitch active flag, internal builder code

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
STALE_WS_FEEDPause ws_market WebSocket; let last_seen age beyond 5sAutomatic on WebSocket reconnect; quotes re-posted on next clean tick.
TOXIC_FLOW_SPIKEInject mock trade tape with taker_buy_ratio=0.85 for 30sAutomatic when taker_buy_ratio falls below 0.75 over next 30s window.
SPREAD_COLLAPSESet mock best_bid=0.623, best_ask=0.624 (spread = 1.6 bps < 2*edge_bps=20 bps)Automatic when spread widens above threshold.
KILL_SWITCH_ONSet killswitch.active=trueAutomatic on manual KillSwitch reset.
POSITION_READ_FAILBlock clob_auth GET /positionsAutomatic on clob_auth reconnect.

20. State & Persistence

Cold-start recovery

On cold start, open quote IDs are re-fetched from clob_auth. Inventory is re-read from clob_auth. Book state is rebuilt from first ws_market tick.

21. Concurrency & Idempotency

AspectSpecification
Execution modelactor-per-market
Max in-flight40
Idempotency keyintent_id
Per-call timeout (ms)100
Backpressure strategydrop oldest pending tick per market_id when queue depth > 5
Locking / mutual exclusionper-market_id mutex for inventory state read/write and open quote tracking

22. Dependencies

Depends on (must run first)

BotWhyContract
risk.kill_switchChecked first; cancels all open quotes and blocks new intent emission when active.

Emits to (downstream consumers)

External services

ServiceEndpointSLA assumedOn failure
Polymarket CLOB WebSocket (ws_market)best-effort
Polymarket CLOB auth API (positions)99.95%

23. Security Surfaces

On-chain contract calls

ContractMethodNetworkEffect
CTFExchangeV2polygon

Abuse vectors considered

  • Quote stuffing: adversary places and cancels orders to artificially move the mid-price seen by Maker-Tight
  • Inventory manipulation: feeding a spoofed position to inflate inventory_ratio and widen quotes
  • Open maker orders left live after KillSwitch activation

Mitigations

  • Book tick staleness check (> 5s) cancels quotes before accepting an adversarial price update
  • Inventory ratio is read from clob_auth (authenticated), not from ws_market (public feed)
  • KillSwitch cancels all open quotes immediately on activation
  • V2 order timestamp(ms) prevents replay of old signed maker orders
  • post_only=true prevents inadvertent taker fills on latency spikes

24. Polymarket V2 Compatibility

AspectValue
CLOB versionv2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldyes
Aware of negative-risk marketsno
Multi-chain readyno
SDK usedpy-clob-client-v2
Settlement contractCTFExchangeV2
NotesAll maker orders use post_only=true to qualify for maker rebates (20–25% of platform fees, paid in pUSD). builder.fee_bps is capped at 30 bps, well within the V2 maker maximum of 50 bps. feeRateBps is not present on any signed order — operator-set at match time.

API surfaces declared

clob_publicclob_authws_marketinternal

Networks supported

polygon

25. Versioning & Migration

FieldValue
spec2.0.0
implementation2.1.0
schema2
released2026-04-28

Migration history

DateFromToReasonAction taken
2026-04-28v1 (USDC.e, feeRateBps on signed order)v2 (pUSD, fees operator-set at match time, maker fee_bps ≤ 50)CLOB V2 cutoverSwitched to py-clob-client-v2. Removed feeRateBps from all signed maker order construction — fees are operator-set at match time by CTFExchangeV2. Updated collateral denomination to pUSD. Injected builder field (bytes32) on every OrderIntent. Confirmed maker fee_bps cap of 50 bps. EIP-712 Exchange domain version updated from '1' to '2'. Verified maker rebate flow (20–25% of platform fee, paid in pUSD).

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Post bid+ask when spread > 2*edge_bps and volume > min_volumespread=16bps, edge=10bps, volume_24h=500000, toxic_flow=falseTwo OrderIntents (bid + ask) emitted with post_only=true
Skip when spread < 2*edge_bps hard floor (spread = 4bps, edge = 3bps)spread=4bps, edge=3bpsNo OrderIntents; DecisionReport intent_emitted=false, reason=MAKER_TIGHT_SPREAD_TOO_TIGHT
Skip when toxic flow detectedtaker_buy_ratio=0.82 (> 0.75 threshold)No OrderIntents; reason=MAKER_TIGHT_TOXIC_FLOW_DETECTED
Apply inventory skew correctlymid=0.624, edge_bps=10, inventory_ratio=0.4, skew_factor=0.3bidPrice = 0.624 - 0.005 - 0.3*0.4*0.001 (skew reduces bid); askPrice shifted symmetrically
Reduce clip size when edge is marginal (6 bps warning threshold)edge_bps=6, clip_size_usd=200OrderIntents emitted with size=100; WARN MAKER_TIGHT_EDGE_MARGINAL
Skip when KillSwitch active; cancel open quoteskillswitch.active=true, open_quotes=[quote1, quote2]No new OrderIntents; cancellation of open quotes emitted

Integration Tests

TestExpected result
Full cycle: ws_market tick → spread check → two signed V2 maker OrderIntents submitted to CLOB as post_only=trueBoth orders contain builder.code (bytes32), no feeRateBps, post_only=true, EIP-712 domain version '2'
Sampled 1/100 skip events generate DecisionReport with intent_emitted=falseExactly ~1% of SPREAD_TOO_TIGHT skips emit a DecisionReport

Property Tests

PropertyRequired behaviour
post_only=true on every maker OrderIntent; bot never submits taker ordersAlways true
feeRateBps field is never present on any emitted OrderIntentAlways true — V2 fees are operator-set at match time
Builder fee_bps is always ≤ 50 (maker max)Always true

27. Operational Runbook

Maker-Tight incidents are typically elevated toxic flow detection (causing missed quoting) or high inventory ratios requiring manual review. Quote failures due to stale feeds should resolve automatically.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
MakerTightHighToxicFlowRate
MakerTightHighInventory
MakerTightStaleFeed
MakerTightKillSwitchBlocking

Manual overrides

Healthcheck

GET /internal/health/maker-tight -> 200 if ws_market feed last_seen < 5s, clob_auth reachable, KillSwitch inactive, and at least one market quoted in last 60s.

28. Promotion Gates

A bot does not advance to the next readiness state until every gate below is green. Gates are observable from production data — no subjective sign-off.

Promote to Shadow

GateHow measuredThreshold
All unit tests pass including post_only invariant and toxic flow detectionCI test run100% pass
feeRateBps absence verified; maker fee_bps ≤ 50 verified in integration testIntegration test asserting V2 order schemaPass

Promote to Limited live

GateHow measuredThreshold
p99 eval latency < 100ms over 24hpolytraders_strat_makertight_eval_latency_ms histogramp99 < 100ms
Inventory_ratio stays below 0.7 over 48h shadow runpolytraders_strat_makertight_inventory_ratio gaugemax < 0.7

Promote to General live

GateHow measuredThreshold
E2E: book tick → two signed V2 post_only GTC OrderIntents submitted and resting on CLOB testnetE2E testPass
Sampled 1/100 DecisionReport for skipped cycles verified in integration testIntegration testPass

29. Developer Checklist

Ready-to-ship score: 27/27 sections complete · 100%

RequirementStatus
Purpose defined✓ done
Required inputs listed✓ done
Parameters defined✓ done
Defaults defined✓ done
Warning thresholds defined✓ done
Hard thresholds defined✓ done
Safe fallback defined✓ done
Structured output defined✓ done
Developer log defined✓ done
Plain-English explanation✓ done
Unit tests defined✓ done
Integration tests defined✓ done
Property tests defined✓ done
Failure-mode block complete✓ done
Reference implementation pseudocode✓ done
Wire examples (input + output)✓ done
Reason codes listed✓ done
Metrics & logs defined✓ done
State & persistence defined✓ done
Concurrency & idempotency defined✓ done
Dependencies declared✓ done
Security surfaces declared✓ done
Polymarket V2 compatibility declared✓ done
Version & migration history declared✓ done
Operational runbook defined✓ done
Promotion gates defined✓ done
Failure-injection recipes defined✓ done