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 LayerExecution2.9 CancelReplaceOptimizer

2.9 CancelReplaceOptimizer

Execution Execution Utility Reshape PLANNED Spec started capital · Direct P5 · Execution rails pending stub

CancelReplaceOptimizer selects the cheapest path to modify a resting order: amend-in-place if queue priority is preserved, or cancel-then-replace if the delta exceeds the amend threshold. It enforces rate-limit budgets across cancel and amend operations.

v3 readiness

Docs27/27
donehow scored
Impl0/15
pendinghow scored
Backtest0/4
pendinghow scored
Runtime0/8
pendinghow scored

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

1. Bot Identity

LayerExecution  Execution
Bot classExecution Utility
AuthorityReshape
StatusPLANNED
ReadinessSpec started
Runs beforeOrder signing and CLOB V2 submission
Runs afterPartialFillHandler or strategy-driven requote signal
Applies toAny request to modify a resting order's price or size
Default modeshadow_only
User-visiblesummary-only
Developer ownerPolytraders core — Execution pod

Operational profile

Modes supportedquarantine

2. Purpose

CancelReplaceOptimizer selects the cheapest path to modify a resting order: amend-in-place if queue priority is preserved, or cancel-then-replace if the delta exceeds the amend threshold. It enforces rate-limit budgets across cancel and amend operations.

3. Why This Bot Matters

  • Always using cancel-then-replace

    Loses queue position on every requote, resulting in consistently worse fills on passive strategies where queue position matters.

  • Amend threshold set too wide

    Large price changes that would trigger queue-position loss are processed as amends, causing the strategy to hold a stale order at a position that was meant to be cancelled.

  • Rate limit not enforced across cancels

    A burst of cancel-replace operations hits the CLOB V2 rate limit, causing 429 errors and leaving orders unmodified at stale prices.

No worked examples on this bot yet. Worked examples are optional but strongly recommended — they turn an abstract failure mode into something a developer can verify in a fixture.

4. Required Polymarket Inputs

InputSourceRequired?Use
CLOB V2 amend endpoint semanticsclob_authYesDetermine whether amend preserves queue priority for the given price/size delta.
Market tick sizeclob_publicYesCompute tick distance between current and target price for amend vs. cancel-replace decision.

5. Required Internal Inputs

InputSourceRequired?Use
Requote instruction with current order_id, target price, target sizeexec.partialfillhandler or strat layerYesReceive the requested modification and current order parameters.
Rate-limit budget stateinternal rate-limit trackerYesCheck remaining cancel and amend budget before issuing operations.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
amend_threshold_ticks248Maximum tick distance between current and target price for which an amend-in-place is preferred over cancel-then-replace.
preserve_queue_when_possibleTruePrefer amend-in-place over cancel-then-replace whenever the CLOB V2 amend semantics permit queue priority to be preserved.
burst_max_per_s101520Maximum number of cancel or amend operations per second across all orders.
fallback_strategycancel_replaceFallback when amend endpoint is unavailable: cancel_replace (issue cancel then new order) or hold (leave resting, no modification).

7. Detailed Parameter Instructions

amend_threshold_ticks

What it means

Maximum tick distance between current and target price for which an amend-in-place is preferred over cancel-then-replace.

Default

{ "amend_threshold_ticks": 2 }

Why this default matters

Amending within 2 ticks typically preserves queue priority on CLOB V2; larger moves force a queue-position reset anyway.

Threshold logic

ConditionAction
delta_ticks <= 2Amend in place (queue priority preserved)
2 < delta_ticks <= 4WARN — amend may lose queue priority; proceed
delta_ticks > 8 (hard)Always cancel-then-replace; CANCEL_REPLACE_FORCED

Developer check

if deltaTicks > params.amend_threshold_ticks: cancelReplace(order)

User-facing English

Your order was adjusted to improve your position in the market.

preserve_queue_when_possible

What it means

Prefer amend-in-place over cancel-then-replace whenever the CLOB V2 amend semantics permit queue priority to be preserved.

Default

{ "preserve_queue_when_possible": true }

Why this default matters

Preserving queue position is generally better for passive strategies; only disable if the strategy always wants a fresh queue position.

Threshold logic

ConditionAction
preserve_queue=true AND delta within thresholdAmend in place
preserve_queue=falseAlways cancel-then-replace regardless of delta

Developer check

if not params.preserve_queue_when_possible: cancelReplace(order)

User-facing English

Your order's position in the queue was preserved where possible.

burst_max_per_s

What it means

Maximum number of cancel or amend operations per second across all orders.

Default

{ "burst_max_per_s": 10 }

Why this default matters

CLOB V2 rate limits restrict cancel/amend to ~20/s; staying at 10/s leaves budget for other exec operations.

Threshold logic

ConditionAction
ops_per_s <= 10Normal
10 < ops_per_s <= 15WARN — approaching rate limit
ops_per_s > 20 (hard)Shed requests; CANCEL_REPLACE_RATE_LIMIT_SHED

Developer check

if opsThisSecond > params.burst_max_per_s: shedRequest()

User-facing English

Order updates were briefly delayed to stay within exchange limits.

fallback_strategy

What it means

Fallback when amend endpoint is unavailable: cancel_replace (issue cancel then new order) or hold (leave resting, no modification).

Default

{ "fallback_strategy": "cancel_replace" }

Why this default matters

cancel_replace is always possible when amend is unavailable; hold risks leaving a stale order.

Threshold logic

ConditionAction
amend unavailable AND fallback=cancel_replaceCancel and resubmit new order
amend unavailable AND fallback=holdLeave order resting; emit WARN

Developer check

if amendFailed: cancelReplace(order) if params.fallback_strategy == 'cancel_replace'

User-facing English

Your order was updated using an alternative method to keep it competitive.

8. Default Configuration

{
  "bot_id": "exec.cancelreplaceoptimizer",
  "version": "0.1.0",
  "mode": "shadow_only",
  "defaults": {
    "amend_threshold_ticks": 2,
    "preserve_queue_when_possible": true,
    "burst_max_per_s": 10,
    "fallback_strategy": "cancel_replace"
  },
  "locked": {
    "amend_threshold_ticks": {
      "max": 8
    },
    "burst_max_per_s": {
      "max": 20
    }
  }
}

9. Implementation Flow

  1. Receive requote instruction: {order_id, current_price, target_price, target_size, market_id}.
  2. Fetch tick size from clob_public; compute delta_ticks = abs(target_price - current_price) / tick_size.
  3. Check rate-limit budget; if burst_max_per_s exceeded, shed request and emit CANCEL_REPLACE_RATE_LIMIT_SHED.
  4. If preserve_queue_when_possible and delta_ticks <= amend_threshold_ticks: attempt amend via clob_auth PATCH /order/{id}.
  5. If amend succeeds: emit ExecutionReport(AMEND_IN_PLACE); done.
  6. If amend fails or delta_ticks > amend_threshold_ticks: cancel via clob_auth DELETE /order/{id}; submit new order at target_price/target_size.
  7. Emit ExecutionReport with path_taken (amend or cancel_replace), delta_ticks, and rate_limit_budget_remaining.

10. Reference Implementation

Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. IF/THEN/ELSE = decision. Translate directly to TypeScript, Python, Go, or Rust.

FUNCTION optimizeCancelReplace(instruction):
  // 1. Fetch tick size
  market = FETCH clob_public.GET('/markets/' + instruction.market_id)
  tickSize = market.minimum_tick_size
  deltaTicks = abs(instruction.target_price - instruction.current_price) / tickSize

  // 2. Rate limit check
  IF rateLimiter.opsThisSecond >= params.burst_max_per_s:
    EMIT ExecutionReport(CANCEL_REPLACE_RATE_LIMIT_SHED, WARN)
    RETURN

  // 3. Decide path
  IF params.preserve_queue_when_possible
     AND deltaTicks <= params.amend_threshold_ticks:
    // Attempt amend
    result = clob_auth.PATCH('/order/' + instruction.order_id,
                              {price: instruction.target_price,
                               size: instruction.target_size})
    IF result.ok:
      EMIT ExecutionReport(AMEND_IN_PLACE)
      RETURN
    // Amend failed — fall through to cancel-replace

  // 4. Cancel-then-replace
  clob_auth.DELETE('/order/' + instruction.order_id)
  newOrder = buildOrderTypedData({
    price: instruction.target_price,
    size: instruction.target_size,
    builder: instruction.builder_code,
    timestamp: now_ms()
  })
  clob_auth.POST('/order', sign(newOrder))
  EMIT ExecutionReport(CANCEL_REPLACE_EXECUTED)

SDK calls used

  • clob_public.GET('/markets/' + market_id)
  • clob_auth.PATCH('/order/' + order_id, {price, size})
  • clob_auth.DELETE('/order/' + order_id)
  • clob_auth.POST('/order', signed_new_order)
  • buildOrderTypedData({price, size, builder_code, timestamp})

Complexity: O(1) per requote instruction

11. Wire Examples

Input — what arrives on the wire

Requote instructionexec.partialfillhandler

{
  "order_id": "0xdddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000eeee1111",
  "market_id": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
  "current_price": 0.62,
  "target_price": 0.63,
  "target_size_usd": 250,
  "builder_code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
  "collateral": "pUSD"
}

Output — what the bot emits

ExecutionReport — amend in place

{
  "report_id": "rep_4d5e6f7a8b9c0d1e",
  "bot_id": "exec.cancelreplaceoptimizer",
  "path_taken": "amend_in_place",
  "delta_ticks": 1,
  "original_price": 0.62,
  "target_price": 0.63,
  "collateral": "pUSD",
  "evaluated_at_ms": 1746770200000
}

12. Decision Logic

APPROVE

Amend succeeds within amend_threshold_ticks; queue priority preserved.

RESHAPE_REQUIRED

Cancel-then-replace path: order modified at cost of queue priority.

REJECT

Rate limit budget exhausted; request shed. Or KillSwitch active.

WARNING_ONLY

delta_ticks between warning and hard threshold; WARN emitted but amend proceeds.

13. Standard Decision Output

This bot returns a ExecutionReport object. See ExecutionReport schema.

{
  "report_id": "rep_4d5e6f7a8b9c0d1e",
  "trace_id": "trc_3c4d5e6f7a8b9c0d",
  "bot_id": "exec.cancelreplaceoptimizer",
  "order_id": "0xdddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000eeee1111",
  "path_taken": "amend_in_place",
  "delta_ticks": 1,
  "original_price": 0.62,
  "target_price": 0.63,
  "collateral": "pUSD",
  "builder_code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
  "evaluated_at_ms": 1746770200000
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
AMEND_IN_PLACEINFOOrder amended without cancelling; queue priority preserved.Emit ExecutionReport; no further action.
CANCEL_REPLACE_EXECUTEDINFOOrder cancelled and resubmitted at new price/size.Emit ExecutionReport.Your order was updated to a new price.
CANCEL_REPLACE_FORCEDRESHAPEDelta exceeds amend_threshold_ticks; cancel-replace forced.Cancel and resubmit.Your order price changed significantly and was resubmitted.
CANCEL_REPLACE_RATE_LIMIT_SHEDWARNburst_max_per_s exceeded; request shed.Drop request; emit WARN; retry on next tick.Your order update was briefly delayed.
KILL_SWITCH_ACTIVEHARD_REJECTKillSwitch active; no cancel or amend operations.Halt all operations.Trading is currently paused.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_exec_cancelreplaceoptimizer_ops_totalcountercountpath_takenTotal cancel-replace operations by path (amend_in_place vs cancel_replace).
polytraders_exec_cancelreplaceoptimizer_delta_tickshistogramcountDistribution of price delta in ticks on each requote instruction.
polytraders_exec_cancelreplaceoptimizer_rate_limit_sheds_totalcountercountTotal requests shed due to burst_max_per_s rate limit.

Alerts

AlertConditionSeverityRunbook
CROHighRateLimitShedrate(polytraders_exec_cancelreplaceoptimizer_rate_limit_sheds_total[1m]) > 1P2#runbook-cro-rate-limit
CROHighDeltaTickshistogram_quantile(0.95, rate(polytraders_exec_cancelreplaceoptimizer_delta_ticks_bucket[5m])) > 5P3#runbook-cro-delta-ticks

16. Developer Reporting

{
  "order_id": "0xdddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000eeee1111",
  "delta_ticks": 1,
  "amend_threshold_ticks": 2,
  "path_taken": "amend_in_place",
  "rate_limit_budget_remaining": 8,
  "amend_success": true
}

17. Plain-English Reporting

SituationUser-facing explanation
Order amended in placeYour order was updated to a new price while keeping its place in the queue.
Order cancelled and resubmittedYour order price changed by more than a small amount, so it was cancelled and a new order was submitted.
Order update delayed — rate limitYour order update was briefly delayed because the exchange has a limit on how many changes can be made per second.

18. Failure-Mode Block

main_failure_modeAmend endpoint returns success but CLOB V2 actually cancels and recreates the order (losing queue position), causing the strategy to believe queue was preserved when it was not.
false_positive_riskAmending within the tick threshold when the book has moved and queue position is already lost anyway, wasting an amend operation.
false_negative_riskAlways cancelling-and-replacing when amend would have preserved queue priority, causing systematic queue-position loss on passive strategies.
safe_fallbackIf amend endpoint returns error, fall back to cancel-then-replace per fallback_strategy config. If both fail, emit WARN and leave order resting.
required_dependenciesclob_auth amend/cancel endpoints, clob_public tick size, rate-limit budget tracker

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
AMEND_ENDPOINT_UNAVAILABLEBlock PATCH /order endpoint; leave DELETE and POST availableAmend endpoint restored; subsequent requotes attempt amend first
BURST_RATE_LIMIT_HITSubmit 25 requote instructions in 1 second (burst_max_per_s=10)Automatic on next second
KILL_SWITCH_DURING_AMENDSet killswitch.active=true mid-amend sequenceManual KillSwitch reset

20. State & Persistence

Cold-start recovery

Rate counter resets on restart; conservative: assume full burst budget used until first tick completes.

21. Concurrency & Idempotency

AspectSpecification
Execution modelsingle-threaded rate-gated queue
Max in-flight20
Idempotency keyorder_id + target_price + target_size
Per-call timeout (ms)500
Backpressure strategyShed excess beyond burst_max_per_s; WARN emitted
Locking / mutual exclusionper-instance atomic counter for rate limiting

22. Dependencies

Depends on (must run first)

BotWhyContract
exec.partialfillhandlerPrimary source of requote instructions for partial remainder chasing.Receives cancel+new instruction; executes optimal path.

Emits to (downstream consumers)

BotWhyContract
gov.builder_attributionEvery new replacement order carries builder_code for attribution logging.builder_code bytes32 present on every signed replacement order.

External services

ServiceEndpointSLA assumedOn failure
CLOB V2 auth APIhttps://clob.polymarket.com99.95% / 200ms p99Retry amend once; fall back to cancel-replace; emit WARN on persistent failure.
CLOB V2 public APIhttps://clob.polymarket.com99.9% / 200ms p99If tick size unavailable, use last-known tick size; emit WARN.

23. Security Surfaces

Abuse vectors considered

  • Flooding with rapid requote instructions to exhaust rate limit budget and suppress legitimate order modifications
  • Injecting a requote with a target_price far from market to trigger a forced cancel-replace that loses queue priority

Mitigations

  • burst_max_per_s enforced atomically; excess requests shed with WARN before hitting CLOB rate limit
  • target_price validated against PriceBandValidator before requote is accepted

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
NotesReplacement orders carry the same builder_code bytes32 for continuous attribution. CLOB V2 amend semantics differ from V1; queue-priority preservation must be verified per V2 API docs.

API surfaces declared

clob_authclob_publicinternal

Networks supported

polygon

25. Versioning & Migration

FieldValue
spec2.0.0
implementation0.1.0
schema2
releasedNone
planned_releaseQ4-2026

Migration history

DateFromToReasonAction taken
2026-04-28n/av2-specSpec drafted post-CLOB-V2 cutover; bot not yet implementedDesigned against V2 schema (pUSD, builder codes, V2 EIP-712 domain)

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Amend chosen when delta_ticks <= amend_threshold_ticksdelta_ticks=1, amend_threshold_ticks=2path_taken=amend_in_place
Cancel-replace when delta_ticks > amend_threshold_ticksdelta_ticks=5, amend_threshold_ticks=2path_taken=cancel_replace
Rate-limit shed when burst_max_per_s exceededops_this_second=11, burst_max_per_s=10CANCEL_REPLACE_RATE_LIMIT_SHED; request dropped

Integration Tests

TestExpected result
Amend endpoint failure → fallback to cancel-replaceclob_auth PATCH returns 4xx; fallback cancel+resubmit executed; ExecutionReport path_taken=cancel_replace
Sequential amends within rate budgetAll amends processed within burst_max_per_s; no shedding

Property Tests

PropertyRequired behaviour
path_taken is always either amend_in_place or cancel_replace — never bothAlways true
Target order price after modification always equals target_price rounded to tick_sizeAlways true

27. Operational Runbook

CancelReplaceOptimizer incidents are typically rate-limit sheds (strategy generating too many requotes) or amend-endpoint failures causing unexpected cancel-replaces.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
CROHighRateLimitShedIdentify which strategy is generating excess requotes; reduce requote frequency or increase burst_max_per_s temporarily.Exec pod lead
CROHighDeltaTicksInvestigate why strategies are requesting large price moves; may indicate stale quote data.Strategy pod lead

Manual overrides

  • polytraders bot force-cancel-replace exec.cancelreplaceoptimizer --order <order_id> --price <price> — Manual cancel-replace needed when amend endpoint is persistently unavailable.

Healthcheck

GET /internal/health/cancelreplaceoptimizer → green if clob_auth reachable, rate_limit_shed_rate < 0.1/min, amend success rate > 80%; red if clob_auth unreachable, rate_limit_shed_rate > 1/min, amend success rate < 50%

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
Rate-limit enforcement unit tests pass: no more than burst_max_per_s ops processed in any 1s windowCI test runZero violations

Promote to Limited live

GateHow measuredThreshold
Amend success rate > 80% over 48h shadow run (when delta <= threshold)polytraders_exec_cancelreplaceoptimizer_ops_total by path_taken> 80% amend_in_place

Promote to General live

GateHow measuredThreshold
Rate limit shed rate < 0.01/min over 7-day limited-livepolytraders_exec_cancelreplaceoptimizer_rate_limit_sheds_total< 0.01/min

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