1. Bot Identity
| Layer | Strategy Strategy |
|---|
| Bot class | Alpha Strategy |
|---|
| Authority | Trade |
|---|
| Status | PLANNED |
|---|
| Readiness | Spec started |
|---|
| Runs before | Risk guardrail pipeline |
|---|
| Runs after | News materiality feed / Observation bus |
|---|
| Applies to | Polymarket binary markets where a high-confidence news event has just landed and the price has broken out beyond the Bollinger Band threshold, indicating a sustained directional move |
|---|
| Default mode | shadow_only |
|---|
| User-visible | Advanced details only |
|---|
| Developer owner | Polytraders core — Strategy pod |
|---|
2. Purpose
Breakout-Follower is a momentum strategy that enters Polymarket binary markets when a high-confidence news event causes a price breakout beyond configurable Bollinger Band thresholds. It scales in across multiple steps and trails a stop using an ATR multiple, acting as the directional complement to Mean-Reversion Sniper.
3. Why This Bot Matters
Low-confidence news signal
Entering on weak or ambiguous news causes the trade to mean-revert rather than sustain, resulting in a loss on each scale-in step.
Trail stop too tight
A trailing stop set too close to the current price gets triggered by normal volatility before the trend matures, cutting a profitable position prematurely.
No exit discipline on reversal
Without an ATR-based stop, a breakout that fails can become a runaway adverse position as the market reverts toward its pre-news price.
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 |
|---|
| news_confidence_min | 0.8 | 0.65 | 0.5 | Minimum news materiality confidence score (0–1) required before the bot will consider a breakout trade. |
| bollinger_stdev | 2.0 | 1.5 | 1.0 | Number of standard deviations for the Bollinger Band; price must close beyond this band to trigger a breakout signal. |
| scale_in_steps | 3 | 4 | 5 | Number of equal-sized scale-in orders spread across the breakout move. Limits per-step size. |
| trail_atr_multiple | 1.5 | 1.0 | 0.5 | Trailing stop distance as a multiple of the market's ATR. Stops below this level trigger an exit OrderIntent. |
7. Detailed Parameter Instructions
news_confidence_min
What it means
Minimum news materiality confidence score (0–1) required before the bot will consider a breakout trade.
Default
{ "news_confidence_min": 0.8 }
Why this default matters
0.80 ensures the news signal is high-quality before committing capital to a trend-following strategy.
Threshold logic
| Condition | Action |
|---|
| >= 0.80 | Allow breakout evaluation |
| 0.65–0.80 | WARN BREAKOUT_LOW_CONFIDENCE; halve scale-in size |
| < 0.50 | HARD_REJECT BREAKOUT_CONFIDENCE_BELOW_FLOOR |
Developer check
if news_confidence < params.hard: return skip('BREAKOUT_CONFIDENCE_BELOW_FLOOR')
User-facing English
The news signal was not confident enough to justify a breakout trade.
bollinger_stdev
What it means
Number of standard deviations for the Bollinger Band; price must close beyond this band to trigger a breakout signal.
Default
{ "bollinger_stdev": 2.0 }
Why this default matters
2.0 standard deviations filters routine price noise and only signals genuine breakouts.
Threshold logic
| Condition | Action |
|---|
| >= 2.0 | Strong breakout signal |
| 1.5–2.0 | WARN BREAKOUT_WEAK_BAND; reduce size |
| < 1.0 | Reject config — too many false breakouts |
Developer check
if params.bollinger_stdev < params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')
User-facing English
The price movement did not clearly exceed the breakout threshold.
scale_in_steps
What it means
Number of equal-sized scale-in orders spread across the breakout move. Limits per-step size.
Default
{ "scale_in_steps": 3 }
Why this default matters
3 steps provides staged entry without over-committing on the initial signal.
Threshold logic
| Condition | Action |
|---|
| <= 3 steps | Standard scale-in |
| > 5 steps | Reject config — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if params.scale_in_steps > params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')
User-facing English
The trade is entered in equal stages to limit risk on each step.
trail_atr_multiple
What it means
Trailing stop distance as a multiple of the market's ATR. Stops below this level trigger an exit OrderIntent.
Default
{ "trail_atr_multiple": 1.5 }
Why this default matters
1.5× ATR provides a stop wide enough to survive normal volatility while protecting against trend reversals.
Threshold logic
| Condition | Action |
|---|
| >= 1.5× | Standard trail stop |
| 1.0–1.5× | WARN BREAKOUT_TIGHT_TRAIL |
| < 0.5× | Reject config — stop too tight |
Developer check
if params.trail_atr_multiple < params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')
User-facing English
A trailing stop will exit the position if the price reverses by more than the configured amount.
8. Default Configuration
{
"bot_id": "strat.breakout_follower",
"version": "0.1.0",
"mode": "shadow_only",
"defaults": {
"news_confidence_min": 0.8,
"bollinger_stdev": 2.0,
"scale_in_steps": 3,
"trail_atr_multiple": 1.5
},
"locked": {
"news_confidence_min": {
"min": 0.5
},
"bollinger_stdev": {
"min": 1.0
},
"scale_in_steps": {
"max": 5
},
"trail_atr_multiple": {
"min": 0.5
}
}
}
9. Implementation Flow
- Check KillSwitch; if active, emit no OrderIntents.
- FETCH news materiality signal; if confidence < hard (0.50), skip BREAKOUT_CONFIDENCE_BELOW_FLOOR.
- FETCH ws_market book; compute Bollinger Band from recent price history.
- IF price NOT outside bollinger_stdev bands: skip (no breakout).
- Determine breakout direction from news signal.
- Compute per-step size = max_position_pUSD / scale_in_steps.
- For step 1: EMIT IOC OrderIntent in breakout direction.
- Store entry price and current ATR in state; compute initial trail_stop = entry - trail_atr_multiple * ATR.
- On each subsequent tick: check if trail_stop triggered; if so, EMIT exit IOC OrderIntent.
- On new ticks in trend direction: update trail_stop upward (ratchet-only).
- EMIT DecisionReport with intent_emitted=true, reason=BREAKOUT_ENTRY or BREAKOUT_TRAIL_STOP.
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 onNewsTick(market_id, newsSignal):
ks = FETCH internal.killswitch.status
IF ks.active: RETURN
// Gate on news confidence
IF newsSignal.confidence < params.news_confidence_min_hard: // 0.50
EMIT DecisionReport(intent_emitted=false, reason='BREAKOUT_CONFIDENCE_BELOW_FLOOR')
RETURN
mkt = FETCH clob_public.GET('/markets/' + market_id)
IF mkt.closed OR mkt.resolved: RETURN
// Check Bollinger Band breakout
book = FETCH ws_market.book(market_id)
price = book.last_trade_price
bbUpper, bbLower = computeBollingerBands(market_id, params.bollinger_stdev)
IF price <= bbUpper AND price >= bbLower: RETURN // No breakout
// Size computation
sizeMultiplier = 0.5 IF newsSignal.confidence < params.news_confidence_min_warn ELSE 1.0
IF sizeMultiplier < 1.0: WARN('BREAKOUT_LOW_CONFIDENCE')
stepSize = toPusdUnits(params.max_position_usd / params.scale_in_steps * sizeMultiplier)
// Emit step 1 entry
direction = newsSignal.direction
EMIT OrderIntent(market=market_id, outcome=direction, side='buy', price=book.best_ask,
size_pUSD=stepSize, tif='IOC', builder=internalBuilderCode)
atr = FETCH internal.volatilityModel.ATR(market_id)
trailStop = book.last_trade_price - params.trail_atr_multiple * atr
STORE state.position(market_id, {step:1, trail_stop:trailStop, entry_price:price})
EMIT DecisionReport(intent_emitted=true, reason='BREAKOUT_ENTRY', step=1)
SDK calls used
ws_market.subscribe('book', [market_id])fetchClobPublic('/markets/' + market_id)internal.newsAdapter.signal(market_id)internal.volatilityModel.ATR(market_id)buildOrderTypedData(orderParams, {name:'CTFExchange', version:'2', chainId:137})
Complexity: O(1) per news tick per market; O(open_positions) per book tick for trail-stop evaluation
11. Wire Examples
Input — what arrives on the wire
News signal — high confidence breakout — internal (news adapter)
{
"market_id": "0xbf00000000000000000000000000000000000000000000000000000000000001",
"news_confidence": 0.88,
"direction": "YES",
"bollinger_stdev_actual": 2.3,
"atr": 0.03,
"received_at_ms": 1746790800000
}
Output — what the bot emits
OrderIntent — breakout step 1 IOC buy YES
{
"intent_id": "oi_01HBF0000001A",
"market_id": "0xbf00000000000000000000000000000000000000000000000000000000000001",
"outcome": "YES",
"side": "buy",
"price": "0.720",
"size_pUSD": "150.00",
"tif": "IOC",
"builder": {
"code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
"fee_bps": 25
},
"decision": {
"step": 1,
"reasons": [
"BREAKOUT_ENTRY"
]
}
}
12. Decision Logic
APPROVE
news_confidence >= 0.80, price outside Bollinger Bands, market open, KillSwitch inactive.
RESHAPE_REQUIRED
Not applicable — reshaping handled by downstream Risk guardrail.
REJECT
news_confidence < 0.50; no breakout signal; market closed; KillSwitch active.
WARNING_ONLY
news_confidence 0.65–0.80 triggers warning and halved scale-in size.
13. Standard Decision Output
This bot returns a OrderIntent object. See OrderIntent schema.
{
"intent_id": "oi_01HBF0000001A",
"trace_id": "tr_01HBF000TR001",
"market_id": "0xbf00000000000000000000000000000000000000000000000000000000000001",
"outcome": "YES",
"side": "buy",
"price": "0.720",
"size_pUSD": "150.00",
"tif": "IOC",
"post_only": false,
"builder": {
"code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
"fee_bps": 25
},
"negrisk_aware": false,
"decision": {
"news_confidence": 0.88,
"bollinger_stdev_actual": 2.3,
"step": 1,
"trail_stop": 0.68,
"reasons": [
"BREAKOUT_ENTRY"
]
},
"comment": "fees are operator-set at match time in V2 \u2014 feeRateBps is NOT on the signed order"
}
14. Reason Codes
| Code | Severity | Meaning | Action | User-facing message |
|---|
BREAKOUT_ENTRY | INFO | News confidence >= min, price beyond Bollinger Band. Scale-in step 1 OrderIntent emitted. | Emit IOC OrderIntent step 1. | A breakout was detected and a trade was entered. |
BREAKOUT_TRAIL_STOP | INFO | Price reversed beyond trail_atr_multiple * ATR from peak. Exit OrderIntent emitted. | Emit exit IOC OrderIntent. | The trailing stop was triggered and the position was closed. |
BREAKOUT_LOW_CONFIDENCE | WARN | News confidence between 0.65 and 0.80; scale-in size halved. | Emit at 50% size; log warning. | The news signal was moderate; a reduced-size trade was placed. |
BREAKOUT_CONFIDENCE_BELOW_FLOOR | HARD_REJECT | News confidence below 0.50 hard floor. | Skip; no OrderIntent. | The news signal was too weak for a breakout trade. |
KILL_SWITCH_ACTIVE | HARD_REJECT | Global kill switch is active. | Skip all markets; no OrderIntents emitted. | Trading is currently paused. |
15. Metrics & Logs
Metrics emitted
| Metric | Type | Unit | Labels | Meaning |
|---|
polytraders_strat_breakoutfollower_decisions_total | counter | count | verdict, reason_code | Total evaluation cycles by verdict and reason. |
polytraders_strat_breakoutfollower_intents_emitted_total | counter | count | step, outcome | Total OrderIntents by scale-in step and outcome. |
polytraders_strat_breakoutfollower_news_confidence | histogram | score | | Distribution of news confidence scores at entry. |
polytraders_strat_breakoutfollower_eval_latency_ms | histogram | milliseconds | | Latency from news signal to OrderIntent emit. |
Alerts
| Alert | Condition | Severity | Runbook |
|---|
BreakoutFollowerStaleFeed | rate(polytraders_strat_breakoutfollower_decisions_total{reason_code='STALE_MARKET_DATA'}[5m]) > 0.1 | warn | #runbook-breakout-stale |
BreakoutFollowerKillSwitch | rate(polytraders_strat_breakoutfollower_decisions_total{reason_code='KILL_SWITCH_ACTIVE'}[1m]) > 0 | page | #runbook-killswitch |
BreakoutFollowerLowConfidence | rate(polytraders_strat_breakoutfollower_decisions_total{reason_code='BREAKOUT_CONFIDENCE_BELOW_FLOOR'}[10m]) > 0.5 | warn | #runbook-breakout-confidence |
16. Developer Reporting
{
"bot_id": "strat.breakout_follower",
"market_id": "0xbf00000000000000000000000000000000000000000000000000000000000001",
"news_confidence": 0.88,
"bollinger_stdev_actual": 2.3,
"step": 1,
"trail_stop": 0.68,
"intent_emitted": true,
"reason": "BREAKOUT_ENTRY",
"emitted_at_ms": 1746790800000
}
17. Plain-English Reporting
| Situation | User-facing explanation |
|---|
| Breakout trade entered | A high-confidence news event caused the market to break out of its normal range. The strategy entered in the direction of the move. |
| Trail stop triggered | The market reversed beyond the trailing stop level. The position was closed to protect against further loss. |
| News confidence too low | The news signal was not strong enough to justify a breakout trade. |
18. Failure-Mode Block
| main_failure_mode | False breakout: news signal causes a short-lived price spike that reverts before all scale-in steps execute, trapping the position at an unfavorable average entry. |
|---|
| false_positive_risk | Low-quality news signal misidentified as high-confidence produces a breakout entry on a market that subsequently mean-reverts. |
|---|
| false_negative_risk | news_confidence_min set too high filters out genuine breakouts on medium-confidence events. |
|---|
| safe_fallback | If ws_market feed is stale or news signal unavailable, skip without emitting any OrderIntent. |
|---|
| required_dependencies | ws_market, clob_public, internal news feed adapter, internal volatility model (ATR), KillSwitch, internal builder code |
|---|
19. Failure-Injection Recipes
| Scenario | How to inject | Expected behaviour | Recovery |
|---|
NEWS_SIGNAL_UNAVAILABLE | Cut news feed adapter connection | | Automatic when adapter reconnects. |
CONFIDENCE_BELOW_FLOOR | Inject news signal with confidence=0.30 | | Automatic on next high-confidence signal. |
KILL_SWITCH_ON | Set killswitch.active=true | | Automatic on manual KillSwitch reset. |
20. State & Persistence
Cold-start recovery
On cold start, active positions re-read from exec layer; trail stop recomputed from current ATR.
21. Concurrency & Idempotency
| Aspect | Specification |
|---|
| Execution model | actor-per-market |
| Max in-flight | 25 |
| Idempotency key | intent_id |
| Per-call timeout (ms) | 250 |
| Backpressure strategy | drop oldest tick per market_id when queue > 3 |
| Locking / mutual exclusion | per-market_id mutex for trail-stop state |
22. Dependencies
Depends on (must run first)
| Bot | Why | Contract |
|---|
| risk.kill_switch | Checked first; blocks all intent emission when active. | |
Emits to (downstream consumers)
External services
| Service | Endpoint | SLA assumed | On failure |
|---|
| Polymarket CLOB WebSocket (ws_market) | | best-effort | |
| Internal news feed adapter | | internal SLA | |
23. Security Surfaces
Abuse vectors considered
- News signal injection to induce false breakout trades
- ATR manipulation to force trail-stop triggers
Mitigations
- News signals sourced from authenticated internal adapter only
- ATR computed from internal volatility model using CLOB tick history
- Trail stop ratchets only in trend direction — cannot be loosened programmatically
24. Polymarket V2 Compatibility
| Aspect | Value |
|---|
| CLOB version | v2 |
| Collateral asset | pUSD |
| EIP-712 Exchange domain version | 2 |
| Aware of builderCode field | yes |
| Aware of negative-risk markets | no |
| Multi-chain ready | no |
| SDK used | py-clob-client-v2 |
| Settlement contract | CTFExchangeV2 |
| Notes | Bot not yet implemented; designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain). feeRateBps not present on any signed OrderIntent. |
API surfaces declared
clob_publicclob_authws_marketinternal
Networks supported
polygon
25. Versioning & Migration
| Field | Value |
|---|
| spec | 2.0.0 |
| implementation | 0.1.0 |
| schema | 2 |
| released | None |
| planned_release | Q3-2026 |
Migration history
| Date | From | To | Reason | Action taken |
|---|
| 2026-04-28 | n/a | v2-spec | Spec drafted post-CLOB-V2 cutover; bot not yet implemented | Designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain) |
26. Acceptance Tests
Unit Tests
| Test | Setup | Expected result |
|---|
| Enter step 1 when news_confidence=0.88, price beyond 2.0 Bollinger bands | bollinger_stdev=2.0, scale_in_steps=3 | IOC OrderIntent step=1; reason=BREAKOUT_ENTRY |
| Skip when news_confidence=0.40 (< hard 0.50) | news_confidence=0.40 | No OrderIntent; reason=BREAKOUT_CONFIDENCE_BELOW_FLOOR |
| Trail stop triggers exit when price reverts beyond ATR multiple | trail_atr_multiple=1.5, ATR=0.03 | Exit IOC OrderIntent emitted; reason=BREAKOUT_TRAIL_STOP |
Integration Tests
| Test | Expected result |
|---|
| Full cycle: news signal → breakout → scale-in on Polygon testnet | Order has builder.code, no feeRateBps, EIP-712 domain v2 |
Property Tests
| Property | Required behaviour |
|---|
| Trail stop only ratchets in trend direction, never loosens | Always true |
| feeRateBps never present on any signed OrderIntent | Always true |
27. Operational Runbook
Breakout-Follower incidents are typically stale news feeds (blocking new entries) or kill-switch activations. Trail-stop triggers are expected normal behavior and do not require escalation.
On-call actions
| Alert | First step | Diagnosis | Mitigation | Escalate to |
|---|
BreakoutFollowerStaleFeed | | | | |
BreakoutFollowerKillSwitch | | | | |
BreakoutFollowerLowConfidence | | | | |
Manual overrides
Healthcheck
GET /internal/health/breakout-follower -> 200 if News feed age < 5s; ATR model active; KillSwitch inactive.. Red: News adapter down or KillSwitch active..
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 |