1. Bot Identity
| Layer | Execution Execution |
|---|
| Bot class | Execution Utility |
|---|
| Authority | Reshape |
|---|
| Status | BETA |
|---|
| Readiness | Limited live |
|---|
| Runs before | Order signing and CLOB V2 submission |
|---|
| Runs after | SmartRouter (ExecutionPlan assembled) and ObservationReport ingestion |
|---|
| Applies to | Every pending ExecutionPlan where toxic-flow signals or adverse RiskVotes are present on the target market |
|---|
| Default mode | limited_live |
|---|
| User-visible | Advanced details only |
|---|
| Developer owner | Polytraders core — Execution pod |
|---|
Operational profile
| Modes supported | quarantine |
|---|
2. Purpose
AntiToxicFill detects toxic order-flow patterns on the target market immediately before order submission and reshapes or cancels the ExecutionPlan to avoid being adversely selected. It monitors three primary toxicity signals: one-sided sweeps through more than three book levels in the last 5 seconds, a cancel-storm on the opposite side, and realised post-fill drift over a rolling window. If an adverse news event is detected within ±30 seconds of a planned fill, the bot enters a cooldown. Depending on signal severity, AntiToxicFill either widens the limit price by requote_widen_bps, reduces the order size by downsize_factor, or cancels the order outright. It cannot alter the trade direction, market, or outcome leg.
3. Why This Bot Matters
Toxic sweep not detected before submission
The system fills against an informed counterparty that has just swept the book on privileged news, resulting in immediate adverse mark-to-market on the filled position.
Cancel-storm ignored on opposite side
Mass cancellations on the opposite side of the book signal that the market is repricing. Submitting a resting order into this environment leads to a fill at a price that is immediately stale.
Post-fill drift not tracked across rolling window
Systematic adverse drift after fills indicates chronic toxic flow on the market. Without reshaping, the strategy will continue to be adversely selected until cumulative losses exceed risk limits.
News-window cooldown not applied
News events arriving within ±30 seconds of a fill represent the highest toxicity risk. Filling in this window without a cooldown leads to significant slippage on information-driven price moves.
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.
6. Parameter Guide
| Parameter | Default | Warning | Hard | What it controls |
|---|
| cooldown_s | 30 | 60 | 120 | Number of seconds to pause order submission after a toxic-flow event or news hit is detected. During cooldown, all ExecutionPlans for the affected market are held; no orders are submitted. |
| requote_widen_bps | 20 | 40 | 100 | Number of basis points to widen the limit price on a RESHAPE action. For a BUY order the price is lowered by requote_widen_bps; for a SELL order the price is raised, creating a more protective limit. |
| downsize_factor | 0.5 | 0.25 | 0.1 | Multiplier (0 to 1) applied to the order size when a RESHAPE is triggered by a RiskVote or strong toxic signal. A factor of 0.5 halves the order; 0.1 reduces it to 10% of original. |
| news_window_s | 30 | 45 | 60 | Symmetric window in seconds around the planned fill time within which an adverse news event triggers a cooldown. Events within [fill_time - news_window_s, fill_time + news_window_s] are treated as contemporaneous with the fill. |
7. Detailed Parameter Instructions
cooldown_s
What it means
Number of seconds to pause order submission after a toxic-flow event or news hit is detected. During cooldown, all ExecutionPlans for the affected market are held; no orders are submitted.
Default
{ "cooldown_s": 30 }
Why this default matters
A 30-second cooldown is long enough to let informed order flow resolve and the book to reprice, while short enough to avoid excessive missed opportunity cost on liquid markets.
Threshold logic
| Condition | Action |
|---|
| No toxic signal detected | No cooldown — proceed to submission |
| Single signal (sweep OR cancel-storm OR drift) detected | Enter cooldown_s pause (default 30s) |
| Multiple signals or news hit detected | Extend to warning threshold (60s) |
| cooldown_s > 120 (hard) | Reject config change — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if cooldown_s > params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')
User-facing English
Trading on this market was briefly paused because unusual activity was detected that could affect your fill price.
requote_widen_bps
What it means
Number of basis points to widen the limit price on a RESHAPE action. For a BUY order the price is lowered by requote_widen_bps; for a SELL order the price is raised, creating a more protective limit.
Default
{ "requote_widen_bps": 20 }
Why this default matters
A 20 bps widen provides protection against short-lived adverse flow while still leaving the order competitive. More than 40 bps risks missing the trade entirely.
Threshold logic
| Condition | Action |
|---|
| No sweep, cancel-storm, or drift detected | No widen — original price used |
| Mild signal: drift_bps < 30 or single cancel-storm | Widen by requote_widen_bps (default 20 bps) |
| Strong signal: drift_bps >= 30 or sweep detected | Widen by warning threshold (40 bps) |
| requote_widen_bps > 100 (hard) | Reject config — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
widenedPrice = BUY ? price * (1 - requote_widen_bps/10000) : price * (1 + requote_widen_bps/10000)
User-facing English
Your order price was adjusted slightly to protect against unfavourable market conditions detected just before submission.
downsize_factor
What it means
Multiplier (0 to 1) applied to the order size when a RESHAPE is triggered by a RiskVote or strong toxic signal. A factor of 0.5 halves the order; 0.1 reduces it to 10% of original.
Default
{ "downsize_factor": 0.5 }
Why this default matters
Halving the order on a toxic signal reduces adverse-selection exposure while still allowing partial participation. Factors below 0.25 leave very small residual orders that incur proportionally higher fees.
Threshold logic
| Condition | Action |
|---|
| No adverse RiskVote and no strong signal | No resize — original size used |
| Adverse RiskVote RESHAPE or strong single signal | Apply downsize_factor (default 0.5) |
| Multiple signals or news hit | Apply warning-level factor (0.25) |
| downsize_factor < 0.1 (hard floor) | Clamp to 0.1 — ANTITOXICFILL_SIZE_FLOOR_APPLIED |
Developer check
finalSize = max(originalSize * downsize_factor, originalSize * 0.1)
User-facing English
The size of your order was reduced because market conditions suggested a lower-risk position size was appropriate.
news_window_s
What it means
Symmetric window in seconds around the planned fill time within which an adverse news event triggers a cooldown. Events within [fill_time - news_window_s, fill_time + news_window_s] are treated as contemporaneous with the fill.
Default
{ "news_window_s": 30 }
Why this default matters
A ±30-second window covers the typical latency between a news event and its full impact on the Polymarket CLOB order book, without being so wide that routine pre-trade news suppresses all activity.
Threshold logic
| Condition | Action |
|---|
| No news event within ±news_window_s | No cooldown triggered by news |
| News event within ±news_window_s | Enter cooldown_s pause — ANTITOXICFILL_NEWS_COOLDOWN |
| news_window_s > 60 (hard) | Reject config — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
newsHit = any(abs(event.ts_ms - fill_planned_ms) <= news_window_s * 1000 for event in news_feed)
User-facing English
A news event was detected close to your planned trade time, so the trade was briefly paused for safety.
8. Default Configuration
{
"bot_id": "exec.antitoxicfill",
"version": "2.0.0",
"mode": "limited_live",
"defaults": {
"cooldown_s": 30,
"requote_widen_bps": 20,
"downsize_factor": 0.5,
"news_window_s": 30
},
"locked": {
"cooldown_s": {
"max": 120
},
"requote_widen_bps": {
"max": 100
},
"news_window_s": {
"max": 60
}
}
}
9. Implementation Flow
- Receive ExecutionPlan from SmartRouter; load associated ObservationReport and RiskVote from the internal bus.
- Check KillSwitch active flag; if active, discard the ExecutionPlan and emit no ExecutionReport.
- Check whether the market is in cooldown (cooldown state keyed by market_id in Redis); if in cooldown, hold the plan and re-evaluate after cooldown expires.
- Fetch CLOB V2 top-10 book snapshot from clob_public; subscribe to ws_market trade tape for the target market.
- Evaluate sweep signal: count book levels consumed on one side in the last 5 seconds using the ws_market trade tape. If > 3 levels consumed, set sweep_detected = true.
- Evaluate cancel-storm signal: count cancel events on the opposite side in the last 5 seconds from the ws_market feed. If cancel_count_5s > cancel_storm_threshold (default 10), set cancel_storm_detected = true.
- Evaluate post-fill drift: compute mean realised drift in bps over the last drift_window_s seconds using the recent fill tape. If drift_bps > drift_threshold_bps, set drift_detected = true.
- Check NewsIngest feed: if any adverse event timestamp falls within ±news_window_s of the planned fill, set news_hit = true.
- Determine action: if news_hit or (sweep_detected AND cancel_storm_detected): enter cooldown, cancel order, emit ANTITOXICFILL_NEWS_COOLDOWN or ANTITOXICFILL_SWEEP_CANCEL_STORM. If single signal or adverse RiskVote: apply downsize_factor and requote_widen_bps, emit RESHAPE. If no signals: approve and pass ExecutionPlan through unchanged.
- On RESHAPE: compute widenedPrice (tick-aligned, using buildOrderTypedData metadata), apply downsize_factor to size, construct updated ExecutionPlan, forward to signing.
- Emit ExecutionReport to polytraders.reports.execution (partition by trace_id, WAL-then-retry, retention 7y) with verdict, reason_code, original and reshaped parameters, and all signal flags.
10. Reference Implementation
On each ExecutionPlan received from SmartRouter, AntiToxicFill evaluates three toxic-flow signals (sweep, cancel-storm, post-fill drift) and a news-event check, then either passes the plan unchanged, reshapes it (widen price, reduce size), or cancels it and enters a market-level cooldown. Emits ExecutionReport to polytraders.reports.execution.
Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. Translate to TS/Python/Go/Rust.
FUNCTION evaluatePlan(plan, observationReport, riskVotes):
// --- 0. KillSwitch gate ---
ks = FETCH internal.killswitch.status
IF ks.active:
EMIT ExecutionReport(plan, HARD_REJECT, KILL_SWITCH_ACTIVE)
RETURN
// --- 1. Cooldown check ---
cooldownKey = 'cooldown:' + plan.market_id
IF FETCH redis.GET(cooldownKey) IS NOT NULL:
EMIT ExecutionReport(plan, HOLD, ANTITOXICFILL_COOLDOWN_ACTIVE)
RETURN // Re-evaluate after TTL
// --- 2. Fetch market book + trade tape ---
book = FETCH clob_public.GET('/book?market=' + plan.market_id + '&depth=10')
tape = FETCH ws_market.recent_fills(plan.market_id, last_n=100)
IF book IS NULL OR tape IS NULL:
// Safe fallback: apply conservative defaults
widenBps = params.requote_widen_bps * 2 // 40 bps default fallback
finalSize = plan.size_usd * params.downsize_factor
EMIT ExecutionReport(plan, RESHAPE, ANTITOXICFILL_FEED_UNAVAILABLE,
reshaped_price=widenPrice(plan, widenBps),
reshaped_size=finalSize)
RETURN
// --- 3. Evaluate sweep signal ---
// Count levels consumed on plan.side in last 5 seconds
recentTrades = [t FOR t IN tape IF now_ms() - t.ts_ms <= 5000
AND t.aggressor_side == plan.side]
levelsConsumed = COUNT DISTINCT price levels in recentTrades
sweepDetected = (levelsConsumed > 3)
// --- 4. Evaluate cancel-storm signal ---
// Count cancels on opposite side in last 5 seconds
oppSide = 'SELL' IF plan.side == 'BUY' ELSE 'BUY'
recentCancels = FETCH ws_market.recent_cancels(plan.market_id, side=oppSide, window_ms=5000)
cancelStormDetected = (COUNT(recentCancels) > 10)
// --- 5. Evaluate post-fill drift ---
driftBps = computeRollingDrift(tape, window_s=params.drift_window_s) // mean bps drift post-fill
driftDetected = (driftBps > params.drift_threshold_bps) // default: 30 bps
// --- 6. Check news feed ---
newsEvents = FETCH internal.newsingest.recent(plan.market_id)
newsHit = ANY(abs(e.ts_ms - plan.planned_fill_ms) <= params.news_window_s * 1000
FOR e IN newsEvents)
// --- 7. Check adverse RiskVote ---
adverseVote = ANY(v.verdict == 'RESHAPE' AND 'toxicity' IN v.tags FOR v IN riskVotes)
// --- 8. Determine action ---
IF newsHit OR (sweepDetected AND cancelStormDetected):
// Hard cancel + cooldown
reason = ANTITOXICFILL_NEWS_COOLDOWN IF newsHit ELSE ANTITOXICFILL_SWEEP_CANCEL_STORM
redis.SET(cooldownKey, 1, EX=params.cooldown_s)
EMIT ExecutionReport(plan, HARD_REJECT, reason)
RETURN
IF sweepDetected OR cancelStormDetected OR driftDetected OR adverseVote:
// Reshape: widen price + downsize
signalStrength = COUNT([sweepDetected, cancelStormDetected, driftDetected, adverseVote])
widenBps = params.requote_widen_bps IF signalStrength == 1 ELSE params.requote_widen_bps_warning
newPrice = widenPrice(plan, widenBps) // BUY: lower; SELL: raise
newPrice = tickAlign(newPrice, book.tick_size) // snap to valid tick
newSize = max(plan.size_usd * params.downsize_factor,
plan.size_usd * 0.1) // clamp to hard floor
reshapedPlan = plan WITH price=newPrice, size_usd=newSize
EMIT ExecutionReport(reshapedPlan, RESHAPE, ANTITOXICFILL_RESHAPE,
widen_bps_applied=widenBps,
downsize_factor_applied=params.downsize_factor)
FORWARD reshapedPlan TO signing
RETURN
// --- 9. Pass through ---
EMIT ExecutionReport(plan, PASS, ANTITOXICFILL_PASS)
FORWARD plan TO signing
Helpers used
| Helper | Signature | Purpose |
|---|
| widenPrice | widenPrice(plan: ExecutionPlan, widenBps: int) -> float | Returns a more protective limit price: BUY orders get a lower price (plan.price * (1 - widenBps/10000)); SELL orders get a higher price. |
| tickAlign | tickAlign(price: float, tickSize: float) -> float | Rounds price to the nearest valid tick using floor for BUY and ceil for SELL to maintain the protective direction. |
| computeRollingDrift | computeRollingDrift(tape: List[Fill], window_s: int) -> float | Computes mean realised post-fill drift in basis points over a rolling window from the trade tape. |
| fetchClobPublic | fetchClobPublic(path: str) -> JSON | Unauthenticated GET against https://clob.polymarket.com; returns parsed JSON or null on error. |
SDK calls used
clob_public.GET('/book?market=' + plan.market_id + '&depth=10')ws_market.subscribe('last_trade_price', plan.market_id)ws_market.subscribe('book', plan.market_id)redis.GET('cooldown:' + plan.market_id)redis.SET('cooldown:' + plan.market_id, 1, EX=cooldown_s)
Complexity: O(1) per ExecutionPlan evaluation; O(F) for rolling drift scan where F = recent fill count (capped at 100)
11. Wire Examples
Input — what arrives on the wire
ExecutionPlan + ObservationReport with sweep signal — exec.smart_router + internal bus
{
"intent_id": "int_3c4d5e6f7a8b9c0d",
"trace_id": "trc_9f8e7d6c5b4a3f2e",
"market_id": "0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e",
"side": "BUY",
"outcome": "YES",
"price": 0.62,
"size_usd": 400,
"order_type": "GTC",
"planned_fill_ms": 1746769800000,
"observation_report": {
"sweep_detected": true,
"sweep_levels_consumed": 4,
"cancel_storm_detected": false,
"cancel_count_5s": 3,
"drift_bps": 8,
"news_hit": false
},
"risk_votes": [
{
"bot_id": "risk.portfolio_guard",
"verdict": "PASS"
}
]
}
Output — what the bot emits
ExecutionReport — RESHAPE (sweep detected, price widened, size halved)
{
"report_id": "rep_a1b2c3d4e5f6a7b8",
"trace_id": "trc_9f8e7d6c5b4a3f2e",
"bot_id": "exec.antitoxicfill",
"market_id": "0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e",
"side": "BUY",
"outcome": "YES",
"verdict": "RESHAPE",
"reason_code": "ANTITOXICFILL_RESHAPE",
"original_price": 0.62,
"reshaped_price": 0.61,
"original_size_usd": 400,
"reshaped_size_usd": 200,
"widen_bps_applied": 20,
"downsize_factor_applied": 0.5,
"collateral": "pUSD",
"eip712_domain_version": "2",
"signals": {
"sweep_detected": true,
"cancel_storm_detected": false,
"drift_detected": false,
"news_hit": false,
"drift_bps": 8
},
"evaluated_at_ms": 1746769800000
}
ExecutionReport — HARD_REJECT (news hit + cooldown applied)
{
"report_id": "rep_b2c3d4e5f6a7b8c9",
"trace_id": "trc_1a2b3c4d5e6f7a8b",
"bot_id": "exec.antitoxicfill",
"market_id": "0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e",
"side": "SELL",
"outcome": "NO",
"verdict": "HARD_REJECT",
"reason_code": "ANTITOXICFILL_NEWS_COOLDOWN",
"original_price": 0.41,
"reshaped_price": null,
"original_size_usd": 300,
"reshaped_size_usd": null,
"collateral": "pUSD",
"cooldown_s_applied": 30,
"signals": {
"sweep_detected": false,
"cancel_storm_detected": false,
"drift_detected": false,
"news_hit": true,
"news_event_delta_ms": -18000
},
"evaluated_at_ms": 1746769850000
}
12. Decision Logic
APPROVE
No toxic signals detected, no adverse RiskVote, no news hit, and market is not in cooldown. ExecutionPlan passes through unmodified. Emit ANTITOXICFILL_PASS.
RESHAPE_REQUIRED
One or more toxic signals (sweep, cancel-storm, or drift) detected, or an adverse RiskVote with toxicity reason received. Apply downsize_factor to size and widen price by requote_widen_bps. Emit ANTITOXICFILL_RESHAPE.
REJECT
News event detected within ±news_window_s, or simultaneous sweep and cancel-storm signals, or KillSwitch active. Enter cooldown_s pause on the market, cancel the ExecutionPlan, emit no order. Emit ANTITOXICFILL_NEWS_COOLDOWN or ANTITOXICFILL_SWEEP_CANCEL_STORM.
WARNING_ONLY
Post-fill drift is in the warning band (above warning threshold but below action threshold). WARN annotation attached to the ExecutionReport; plan proceeds unchanged.
13. Standard Decision Output
This bot returns a ExecutionReport object. See ExecutionReport schema.
{
"report_id": "rep_a1b2c3d4e5f6a7b8",
"trace_id": "trc_9f8e7d6c5b4a3f2e",
"bot_id": "exec.antitoxicfill",
"market_id": "0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e",
"side": "BUY",
"outcome": "YES",
"verdict": "RESHAPE",
"reason_code": "ANTITOXICFILL_RESHAPE",
"original_price": 0.62,
"reshaped_price": 0.608,
"original_size_usd": 400,
"reshaped_size_usd": 200,
"widen_bps_applied": 20,
"downsize_factor_applied": 0.5,
"signals": {
"sweep_detected": true,
"cancel_storm_detected": false,
"drift_detected": false,
"news_hit": false,
"drift_bps": 8
},
"collateral": "pUSD",
"eip712_domain_version": "2",
"evaluated_at_ms": 1746769800000
}
14. Reason Codes
| Code | Severity | Meaning | Action | User-facing message |
|---|
ANTITOXICFILL_PASS | INFO | No toxic-flow signals detected; ExecutionPlan passes through unchanged. | Forward ExecutionPlan to signing without modification. | |
ANTITOXICFILL_RESHAPE | RESHAPE | One or more toxic-flow signals (sweep, cancel-storm, or drift) or an adverse RiskVote detected. Price widened by requote_widen_bps and size reduced by downsize_factor. | Apply widen and downsize to ExecutionPlan; forward reshaped plan to signing. | Your order was adjusted to protect against unusual market activity detected before submission. |
ANTITOXICFILL_NEWS_COOLDOWN | HARD_REJECT | An adverse news event was detected within ±news_window_s of the planned fill. Order cancelled; market enters cooldown. | Cancel ExecutionPlan; apply cooldown_s to market_id in Redis; emit no order. | Trading on this market was briefly paused because a news event was detected near your planned trade time. |
ANTITOXICFILL_SWEEP_CANCEL_STORM | HARD_REJECT | Simultaneous one-sided sweep (>3 levels) and cancel-storm on the opposite side detected. Highest toxicity combination; order cancelled and market enters cooldown. | Cancel ExecutionPlan; apply cooldown_s to market_id; emit no order. | Significant one-sided activity was detected on this market. Your order was cancelled to avoid adverse fills. |
ANTITOXICFILL_COOLDOWN_ACTIVE | EXPLAIN | This market is currently in a toxicity cooldown from a prior event. New ExecutionPlans are held until the cooldown expires. | Hold ExecutionPlan; re-evaluate after cooldown TTL expires. | Your order is waiting for unusual market activity to settle before it is submitted. |
ANTITOXICFILL_SIZE_FLOOR_APPLIED | WARN | downsize_factor computation would have produced a size below the hard floor (10% of original). Size clamped to 10% of original. | Set reshaped_size_usd = original_size_usd * 0.1; log warning. | |
ANTITOXICFILL_FEED_UNAVAILABLE | WARN | ws_market or clob_public feed unavailable; conservative fallback defaults applied (widen 40 bps, downsize 0.5). | Apply fallback reshape parameters; do not block order entirely. | |
KILL_SWITCH_ACTIVE | HARD_REJECT | Global kill switch is active; no orders may proceed. | Discard ExecutionPlan; emit no order. | Trading is currently paused. |
MARKET_CLOSED | HARD_REJECT | Target market is closed or resolved; ExecutionPlan is invalid. | Discard ExecutionPlan; log and emit no order. | The market for this order is no longer active. |
15. Metrics & Logs
Metrics emitted
| Metric | Type | Unit | Labels | Meaning |
|---|
polytraders_exec_antitoxicfill_decisions_total | counter | count | verdict, reason_code | Total ExecutionReport records emitted per verdict (PASS/RESHAPE/HARD_REJECT) and reason code. |
polytraders_exec_antitoxicfill_cooldowns_active | gauge | count | | Number of markets currently in a toxicity cooldown. Rising count indicates sustained toxic-flow environment. |
polytraders_exec_antitoxicfill_drift_bps | histogram | bps | market_id | Distribution of realised post-fill drift in basis points across evaluated ExecutionPlans. |
polytraders_exec_antitoxicfill_sweep_levels | histogram | count | market_id | Distribution of sweep depth (levels consumed in 5s) at evaluation time; >3 triggers RESHAPE or HARD_REJECT. |
polytraders_exec_antitoxicfill_eval_latency_ms | histogram | ms | | Wall-clock latency from ExecutionPlan receipt to ExecutionReport emit. |
polytraders_exec_antitoxicfill_reshape_widen_bps | histogram | bps | | Distribution of price-widen bps actually applied on RESHAPE decisions. |
Alerts
| Alert | Condition | Severity | Runbook |
|---|
AntiToxicFillHighRejectRate | rate(polytraders_exec_antitoxicfill_decisions_total{verdict='HARD_REJECT'}[5m]) / rate(polytraders_exec_antitoxicfill_decisions_total[5m]) > 0.3 | page | #runbook-antitoxicfill-high-reject-rate |
AntiToxicFillCooldownsSpiking | polytraders_exec_antitoxicfill_cooldowns_active > 5 | warn | #runbook-antitoxicfill-cooldowns-spiking |
AntiToxicFillHighDrift | histogram_quantile(0.95, rate(polytraders_exec_antitoxicfill_drift_bps_bucket[5m])) > 30 | warn | #runbook-antitoxicfill-high-drift |
AntiToxicFillEvalLatencyHigh | histogram_quantile(0.99, rate(polytraders_exec_antitoxicfill_eval_latency_ms_bucket[5m])) > 150 | warn | #runbook-antitoxicfill-latency |
Dashboards
- Grafana — Execution / AntiToxicFill
- Grafana — Order quality / toxic-flow signals and cooldown history
16. Developer Reporting
{
"report_id": "rep_a1b2c3d4e5f6a7b8",
"trace_id": "trc_9f8e7d6c5b4a3f2e",
"bot_id": "exec.antitoxicfill",
"market_id": "0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e",
"sweep_levels_consumed": 4,
"sweep_detected": true,
"cancel_storm_count_5s": 3,
"cancel_storm_detected": false,
"drift_bps": 8,
"drift_detected": false,
"news_hit": false,
"adverse_risk_vote": false,
"cooldown_active": false,
"verdict": "RESHAPE",
"reason_code": "ANTITOXICFILL_RESHAPE",
"original_price": 0.62,
"reshaped_price": 0.608,
"original_size_usd": 400,
"reshaped_size_usd": 200,
"requote_widen_bps": 20,
"downsize_factor": 0.5,
"tick_size": 0.01,
"tick_aligned_reshaped_price": 0.61,
"evaluated_at_ms": 1746769800000
}
17. Plain-English Reporting
| Situation | User-facing explanation |
|---|
| Order price widened before submission | Unusual activity was detected on this market just before your order was submitted. The price was adjusted slightly to protect you from filling at a disadvantageous price. |
| Order size reduced before submission | Market conditions suggested an elevated risk of adverse fills. The order size was reduced to limit potential losses. |
| Order paused — news event nearby | A news event was detected close to the time of your planned trade. Trading was briefly paused to let the market adjust before your order was considered again. |
| Order cancelled — toxic flow detected | Significant one-sided activity and widespread order cancellations were detected simultaneously. The order was cancelled to protect you from being adversely selected. |
18. Failure-Mode Block
| main_failure_mode | Failing to detect a sweep because the ws_market feed is lagged or the CLOB book snapshot is stale, allowing a toxic order to be submitted without price widening or size reduction. |
|---|
| false_positive_risk | Triggering a cooldown on a momentary one-sided sweep that immediately reverses (e.g. large benign taker), causing missed opportunity cost. Over-sensitive cancel-storm detection may also fire on normal book refresh activity. |
|---|
| false_negative_risk | Missing a toxic news event because the NewsIngest feed has a latency spike, or because news_window_s is configured too tightly, leading to a fill against an informed counterparty. |
|---|
| safe_fallback | If ws_market feed or clob_public book snapshot is unavailable, apply conservative defaults: downsize_factor=0.5 and requote_widen_bps=40. If NewsIngest is unavailable, proceed without news check but log ANTITOXICFILL_NEWS_FEED_UNAVAILABLE. If KillSwitch status cannot be read, halt submission. |
|---|
| required_dependencies | ws_market trade tape for target market, clob_public top-10 book snapshot, ObservationReport from internal bus, RiskVote from guardrail pipeline, KillSwitch active flag, NewsIngest adverse-event feed (optional — graceful degradation if absent) |
|---|
19. Failure-Injection Recipes
| Scenario | How to inject | Expected behaviour | Recovery |
|---|
WS_MARKET_FEED_STALE | Disconnect ws_market subscription; leave last_seen > 10s | | Feed reconnects; bot reverts to live signal evaluation on next ExecutionPlan |
NEWS_HIT_COOLDOWN | Inject a NewsIngest event with ts_ms = now_ms() - 15000 (15s ago) for the target market; news_window_s=30 | | After 30s, cooldown key expires; next ExecutionPlan evaluated without cooldown |
SWEEP_AND_CANCEL_STORM_SIMULTANEOUS | Inject mock ws_market tape with 5 levels consumed in 2s on BUY side + 15 cancel events on SELL side in 5s | | Automatic after cooldown_s expires |
KILL_SWITCH_ON | Set killswitch.active=true | | Returns to normal on manual KillSwitch reset |
REDIS_COOLDOWN_STORE_DOWN | Kill Redis connection during active cooldown period | | Redis reconnects; cooldown state re-read; normal evaluation resumes |
ADVERSE_RISK_VOTE_DOWNSIZE | Inject RiskVote with verdict=RESHAPE and tags=['toxicity'] from mock portfolio_guard | | Automatic; next plan evaluated fresh |
20. State & Persistence
Cold-start recovery
On restart, cooldown entries are re-read from Redis. Any market with an active cooldown key continues in cooldown. Drift cache is rebuilt from ws_market fill replay on reconnect; first evaluation after restart may use conservative fallback if cache is empty.
21. Concurrency & Idempotency
| Aspect | Specification |
|---|
| Execution model | single-threaded event loop |
| Max in-flight | 50 |
| Idempotency key | trace_id |
| Per-call timeout (ms) | 150 |
| Backpressure strategy | Excess ExecutionPlans queued in memory ring buffer (max 50); oldest entry dropped if ring is full and WARN emitted |
| Locking / mutual exclusion | Redis SETNX per market_id for cooldown write to prevent double-trigger during burst |
22. Dependencies
Depends on (must run first)
| Bot | Why | Contract |
|---|
| exec.smart_router | Provides the ExecutionPlan that AntiToxicFill evaluates and potentially reshapes. | AntiToxicFill must not alter side, market_id, or outcome leg from the original ExecutionPlan. |
| risk.kill_switch | KillSwitch active flag is checked before any evaluation; active flag aborts all processing. | No ExecutionReport is emitted while KillSwitch is active. |
| risk.portfolio_guard | Adverse RiskVotes from PortfolioGuard with toxicity tags trigger downsize_factor application. | If RiskVote verdict is RESHAPE with toxicity reason, AntiToxicFill applies downsize_factor. |
Emits to (downstream consumers)
| Bot | Why | Contract |
|---|
gov.fill_quality_analyzer | | ExecutionReport emitted to polytraders.reports.execution, partitioned by trace_id. |
Sibling bots (same OrderIntent)
| Bot | Why | Contract |
|---|
| exec.queue_warden | QueueWarden manages resting order lifecycle post-submission; AntiToxicFill acts pre-submission. Both consume toxic-flow signals but at different lifecycle stages. | |
External services
| Service | Endpoint | SLA assumed | On failure |
|---|
| Polymarket CLOB V2 (public) | https://clob.polymarket.com | 99.9% / 200ms p99 | |
| Polymarket WebSocket — market feed | wss://ws-subscriptions-clob.polymarket.com/ws/market | best-effort | |
| Internal NewsIngest service | internal://newsingest | 99% / 100ms p99 (internal SLA) | |
23. Security Surfaces
Abuse vectors considered
- Injecting a fabricated ObservationReport with sweep_detected=false to suppress reshaping and allow toxic-fill through at full size
- Flooding the cooldown Redis key with artificial expiry updates to prevent cooldown from being applied
- Replay of stale ObservationReport to trigger a false cooldown on a non-toxic market, causing missed trading opportunities
Mitigations
- ObservationReport messages are HMAC-signed by the emitting bot; AntiToxicFill validates the signature before processing
- Redis cooldown keys use SETNX with TTL; they cannot be extended by external writers without Redis ACL access
- ObservationReport freshness check: reports older than 10 seconds are discarded with STALE_DATA reason code
- ws_market trade tape is fetched directly from Polymarket WebSocket — not from an internal cache that could be tampered with
24. Polymarket V2 Compatibility
| Aspect | Value |
|---|
| CLOB version | v2 |
| Collateral asset | pUSD |
| EIP-712 Exchange domain version | 2 |
| Aware of builderCode field | no |
| Aware of negative-risk markets | no |
| Multi-chain ready | no |
| SDK used | py-clob-client-v2 |
| Settlement contract | CTFExchangeV2 |
| Notes | AntiToxicFill reshapes ExecutionPlans before order signing; it does not sign orders itself. All size and price amounts are denominated in pUSD. The widened price is tick-aligned using the V2 market metadata fetched from clob_public. |
API surfaces declared
clob_publicws_marketinternal
Networks supported
polygon
25. Versioning & Migration
| Field | Value |
|---|
| spec | 2.0.0 |
| implementation | 2.0.0 |
| schema | 2 |
| released | 2026-04-28 |
Migration history
| Date | From | To | Reason | Action taken |
|---|
| 2026-04-28 | v1 | v2 | CLOB V2 cutover | Switched to py-clob-client-v2. Collateral denomination updated from USDC.e to pUSD in all ExecutionReport fields. Removed feeRateBps references from order-reshape logic (fees are now operator-set at match time by CTFExchangeV2). EIP-712 Exchange domain version updated from '1' to '2'. ObservationReport and RiskVote bus topics updated to V2 schema. Cooldown state store key updated to include bot_version=v2 prefix to avoid stale V1 entries. |
26. Acceptance Tests
Unit Tests
| Test | Setup | Expected result |
|---|
| PASS when no signals detected | sweep_detected=false, cancel_storm_detected=false, drift_bps=5, news_hit=false, killswitch=false | ExecutionReport.verdict=PASS, no price or size change |
| RESHAPE when sweep detected: price widened and size halved | sweep_levels=4, sweep_detected=true, cancel_storm_detected=false, original_price=0.62, original_size_usd=400, requote_widen_bps=20, downsize_factor=0.5 | reshaped_price=0.608 (tick-aligned to 0.61), reshaped_size_usd=200, reason_code=ANTITOXICFILL_RESHAPE |
| CANCEL and cooldown when sweep + cancel-storm both detected | sweep_detected=true, cancel_storm_detected=true, news_hit=false | No order submitted; cooldown_s=30 applied on market_id; reason_code=ANTITOXICFILL_SWEEP_CANCEL_STORM |
| CANCEL and cooldown on news hit within news_window_s | news_event_ts_ms = fill_planned_ms - 20000, news_window_s=30 | news_hit=true; order cancelled; cooldown applied; reason_code=ANTITOXICFILL_NEWS_COOLDOWN |
| HARD_REJECT when KillSwitch active | killswitch.active=true | No ExecutionReport emitted; reason_code=KILL_SWITCH_ACTIVE |
| RESHAPE on adverse RiskVote with toxicity reason | risk_vote.verdict=RESHAPE, risk_vote.reason=ANTITOXICFILL_ADVERSE_FLOW, downsize_factor=0.5 | reshaped_size_usd = original_size_usd * 0.5; reason_code=ANTITOXICFILL_RESHAPE |
Integration Tests
| Test | Expected result |
|---|
| End-to-end: ObservationReport sweep signal → RESHAPE → reshaped ExecutionPlan forwarded to signing | Reshaped order has tick-aligned widened price and halved size; ExecutionReport emitted to polytraders.reports.execution |
| News hit: NewsIngest event → cooldown applied → order held → re-evaluated after cooldown_s expires | Order not submitted during cooldown; after cooldown expires and no further signals, order proceeds as PASS |
| Cooldown state survives bot restart (Redis TTL) | After restart, market cooldown entry read from Redis; order still held until TTL expires |
Property Tests
| Property | Required behaviour |
|---|
| AntiToxicFill never alters the trade side, market_id, or outcome leg | Always true — only price, size, and submission timing are modified |
| Reshaped size is always >= original_size_usd * downsize_factor_hard_floor (0.1) | Always true — downsize_factor is clamped to 0.1 minimum |
| No order is submitted to CLOB V2 while a market is in cooldown | Always true — cooldown state checked before every ExecutionPlan evaluation |
27. Operational Runbook
AntiToxicFill incidents fall into two categories: sustained cooldowns causing trading pauses on multiple markets simultaneously (possible false-positive storm or genuine market crisis), and feed unavailability causing conservative fallback reshaping that may be overly restrictive.
On-call actions
| Alert | First step | Diagnosis | Mitigation | Escalate to |
|---|
AntiToxicFillHighRejectRate | Check reason_code breakdown in Grafana. If ANTITOXICFILL_NEWS_COOLDOWN dominates, check NewsIngest feed for false positives. If ANTITOXICFILL_SWEEP_CANCEL_STORM dominates, check Polymarket market conditions. | Sustained HARD_REJECT > 30% indicates either a genuine market-wide toxic event, a false-positive signal loop, or a NewsIngest misconfiguration. | If false positives: temporarily increase cooldown_s to reduce churn, or pause NewsIngest integration. If genuine event: let cooldowns run and alert Strategy pod. | Exec pod lead + Strategy pod if reject rate sustained > 5 minutes |
AntiToxicFillCooldownsSpiking | List active cooldown keys in Redis: redis-cli KEYS 'cooldown:*'. Cross-reference with Polymarket market status page. | More than 5 simultaneous market cooldowns suggests either a broad market event or a systematic false-positive in the sweep detector. | If false positives: run polytraders bot flush-cooldowns exec.antitoxicfill --market <id>. If genuine: let cooldowns expire naturally. | Strategy pod lead for trading-pause decision |
AntiToxicFillHighDrift | Check drift_bps histogram in Grafana. High drift p95 > 30 bps indicates systematic adverse selection on active markets. | Chronic high drift may indicate the drift_threshold_bps parameter needs tuning, or that specific markets are structurally toxic. | Lower drift_threshold_bps for affected markets. Consider blacklisting chronically toxic markets. | Strategy pod lead for market selection review |
AntiToxicFillEvalLatencyHigh | Check p99 eval latency. If > 150ms, check ws_market feed latency and Redis response times. | High latency means toxic signals arrive too late relative to order submission, reducing the effectiveness of reshaping. | Check ws_market WebSocket connection health. Reduce max_in_flight if backpressure is the cause. | Infra on-call if latency sustained > 300ms |
Manual overrides
Healthcheck
GET /internal/health/antitoxicfill → 200 if ws_market feed connected and last message < 5s ago, Redis cooldown store reachable, NewsIngest feed responding, eval latency p99 < 150ms, cooldowns_active <= 3. RED if ws_market feed disconnected or stale > 10s, Redis unreachable, eval latency p99 > 300ms, or cooldowns_active > 10.
29. Developer Checklist
Ready-to-ship score: 27/27 sections complete · 100%
| Requirement | Status |
|---|
| 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 |