Polymarket Example Strategies
This page collects complete example strategies for regular Polymarket (platform: polymarket): custom rules on rolling crypto series and on pinned markets, then the built-in panic_fade, mean_reversion and pre_announcement_drift. For what each key does, see All Polymarket parameters.
Each example below saves and compiles as shown. The slugs, IDs and numbers are placeholders chosen to show a shape. Swap in your own market and choose your own values. The examples are not recommendations, and automated strategies can lose money; see Risk & Limits. In the crypto Up/Down examples, Up is YES and Down is NO.
Rolling BTC 15-minute series (custom, recurring)
Follows every 15-minute BTC Up/Down market. It buys Up only in the last one to five minutes, when Up is priced 0.60 to 0.75 with a tight spread, then takes profit or cuts the loss on the YES price. Backtestable: it uses only price, spread, time_to_expiry and position_size.
version: 1
platform: polymarket
strategy: custom
strategy_name: "BTC 15m Up late-window buyer"
market:
recurring:
kind: updown
asset: btc
interval: 15m
risk:
max_position: 10
price_floor: 0.05
price_ceiling: 0.95
max_notional: 8
loop:
interval: 15
rules:
- name: take_profit_up
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: ">=", value: 0.88}
action: sell_yes
- name: cut_loss_up
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: "<=", value: 0.40}
action: sell_yes
- name: buy_up_when_favored
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: time_to_expiry, op: ">", value: "1m"}
- {field: time_to_expiry, op: "<", value: "5m"}
- {field: price, op: ">=", value: 0.60}
- {field: price, op: "<=", value: 0.75}
- {field: spread, op: "<=", value: 0.03}
action: buy_yes
size: 5- Exits come first, because the first matching rule wins.
- The $8
max_notionalapplies to each 15-minute market separately and starts fresh at each rollover: about two 5-share entries at up to 0.75. max_entries_per_marketwould also work on a series, where it counts each market's entries separately. This example relies on theposition_size == 0gate instead.- Shares still held at the close settle with that market.
SOL 5-minute series with dollar P&L exits (custom, series_slug)
Names the series directly. It buys Down when Up is priced 0.72 to 0.85, exits on dollar unrealized_pnl with sell_all, and cancels an unfilled entry just before the close. Backtestable.
version: 1
platform: polymarket
strategy: custom
strategy_name: "SOL 5m Down on stretched Up, dollar P&L exits"
strategy_name_origin: user
market:
series_slug: sol-up-or-down-5m
risk:
max_position: 10
price_floor: 0.05
price_ceiling: 0.95
max_notional: 4
loop:
interval: 10
rules:
- name: take_profit_dollars
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: ">=", value: 0.75}
action: sell_all
- name: stop_loss_dollars
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: "<=", value: -1.0}
action: sell_all
- name: clear_unfilled_entry_near_close
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: "!=", value: 0}
- {field: time_to_expiry, op: "<", value: "90s"}
action: cancel_all
- name: buy_down_when_up_stretched
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: "==", value: 0}
- {field: price, op: ">=", value: 0.72}
- {field: price, op: "<=", value: 0.85}
- {field: time_to_expiry, op: ">", value: "2m"}
- {field: balance, op: ">=", value: 5}
action: buy_no
size: 5priceis the Up (YES) midpoint even though the rule buys Down; the order goes out at the Down (NO) midpoint.- The $4 budget is per 5-minute market.
- The dollar exits need a value for
unrealized_pnl. If the Down book has no bid,unrealized_pnlis unavailable and neither exit can fire until a bid returns. See Fields.
One-shot NO on a pinned market (custom, slug, NO-book fields)
Pins one market, buys NO once using the NO book, then takes profit or stops out with sell_no. max_entries_per_market: 1, max_notional and an active_window bound it. Live only: the book fields and active_window cannot be backtested.
version: 1
platform: polymarket
strategy: custom
strategy_name: "One-shot NO on a pinned event market"
market:
slug: "will-example-fc-win-on-2026-10-04"
active_window:
start: "2026-10-04T09:00:00-04:00"
end: "2026-10-04T14:45:00-04:00"
risk:
max_position: 20
price_floor: 0.05
price_ceiling: 0.95
max_entries_per_market: 1
max_notional: 10
loop:
interval: 20
rules:
- name: take_profit_no
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: no_best_bid, op: ">=", value: 0.55}
action: sell_no
- name: stop_loss_no
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: no_best_bid, op: "<=", value: 0.15}
action: sell_no
- name: buy_no_below_value
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: no_best_ask, op: "<=", value: 0.35}
- {field: no_best_bid, op: ">", value: 0.15}
- {field: no_best_bid, op: "<", value: 0.55}
- {field: spread, op: "<=", value: 0.04}
action: buy_no
size: 20- The entry's
no_best_bidbounds (0.15 to 0.55) keep the exits from firing straight after the entry. Without them the validator rejects the rules as alternating (see What the validator checks). - 20 shares at a NO midpoint of at most 0.35 cost at most $7, inside the $10 budget.
- At
end, the Bot cancels its resting buy and stops entering. Itssell_notake-profit and stop keep running, so a position is still closed by them; otherwise it is held to resolution. - The slug is enough. Adding token IDs would switch off the market lookup and set
time_to_expiryandvolumeto 0. Seemarket.yes_token_idandmarket.no_token_id.
Guarded YES dip buyer (custom, book fields, skip, cancel_all)
Shows rule order, a skip guard, a cancel_all for stale bids and a value_field comparison. Live only: volume and the book fields cannot be backtested.
version: 1
platform: polymarket
strategy: custom
strategy_name: "Guarded YES dip buyer"
market:
slug: "will-example-index-close-above-6000-on-2026-12-31"
risk:
max_position: 10
price_floor: 0.05
price_ceiling: 0.95
max_notional: 5
loop:
interval: 30
rules:
- name: take_profit
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: yes_best_bid, op: ">=", value: 0.50}
action: sell_yes
- name: stand_aside_thin_or_late
when:
any:
- {field: spread, op: ">", value: 0.06}
- {field: volume, op: "<", value: 5000}
- {field: time_to_expiry, op: "<", value: "2h"}
action: skip
- name: pull_stale_bids
when:
all:
- {field: order_count, op: ">", value: 0}
- {field: price, op: ">", value: 0.40}
action: cancel_all
- name: buy_yes_dip
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: yes_best_ask, op: "<=", value: 0.33}
- {field: yes_best_ask, op: "<", value_field: no_best_ask}
action: buy_yes
size: 10- The take-profit sits above the
skipguard. A guard placed first would also block the exit. pull_stale_bidsclears a resting midpoint bid once YES has moved above 0.40, because a resting order blocks the next buy (see How a custom buy is priced and sized).- The $5 budget is never released. Later round trips are cut to what remains and stop once the cut falls below the market minimum.
Token-pinned market (built-in panic_fade)
Pins a market by condition ID and both token IDs, with explicit market metadata. It buys YES once after an 8-cent drop from the 5-minute high and sells on a 4-cent rise or a fall below the floor. The IDs are placeholders; copy the real ones from the market.
version: 1
platform: polymarket
strategy: panic_fade
strategy_name: "Fade one sharp YES dip on a token-pinned market"
market:
condition_id: "0x9c1a4e0b7d2f3a58c6e1b0d4f7a92c3e5b8d1f0a6c4e2b9d7f3a1c5e8b0d2f47"
yes_token_id: "48331043336612883890938759509493159234755048973500640148014422747788308965732"
no_token_id: "93592949212798121127213117304912625505836768562433217537850469496310204567695"
neg_risk: false
tick_size: "0.01"
min_order_size: "5"
risk:
max_position: 5
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 20
params:
panic_threshold: 0.08
fade_size: 5
recovery_exit: 0.04
max_fades: 1- With both token IDs the Bot skips the market lookup, so
time_to_expiryandvolumeread 0;panic_fadereads neither.tick_sizeis used only if the exchange's tick lookup fails, andmin_order_sizesets the smallest order the Bot sends. They are shown here as the fallbacks a token-pinned market uses. - The
condition_idnext to the tokens lets the Bot list and cancel your orders in this market, and lets a backtest settle it. panic_fadedoesn't cap holdings atmax_position; it is set equal tofade_sizehere for clarity.max_fades: 1makes this a single fade.recovery_exitis set explicitly so the backtest uses the same exit as the live Bot. See Backtests.
ETH hourly mean reversion (built-in, recurring)
Buys Up when its price is at or below 0.35, buys Down when Up is at or above 0.65, and sells near 0.50. Backtestable.
version: 1
platform: polymarket
strategy: mean_reversion
strategy_name: "ETH hourly Up/Down reversion"
market:
recurring:
kind: updown
asset: eth
interval: 1h
risk:
max_position: 10
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 30
params:
entry_low: 0.35
entry_high: 0.65
exit_target: 0.50
cooldown: 300- Live order size is the market minimum, usually 5 shares. The backtest uses 10 shares per entry, so backtest trade sizes are double the live size; keep that in mind when comparing results.
- The exit fires only while Up is between 0.48 and 0.52. Otherwise the position rides to the hourly settlement. There is no stop-loss.
cooldownis set because backtests default it to 0 seconds.
Pre-close drift on a pinned market (built-in pre_announcement_drift)
Buys YES once in the 12 hours before the market's end date, then sells that YES when the final 30-minute blackout starts. Backtestable.
version: 1
platform: polymarket
strategy: pre_announcement_drift
strategy_name: "Pre-close YES drift"
market:
slug: "will-example-company-report-record-revenue-q3-2026"
risk:
max_position: 5
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 60
params:
entry_hours_before: 12
blackout_minutes_before: 30
drift_direction: bullish
exit_on_release: true- The market's end date stands in for the announcement time, so pin the market by
slug,condition_idor a series, never by token IDs alone. - Size is 5 shares (
max_positionor 5, whichever is smaller), bought at the YES midpoint. If the entry doesn't fill within two loops it is cancelled and placed again while the window is open. A restart forgets the entry, so it can enter again. blackout_minutes_beforeis required; 0 means no blackout, and thenexit_on_releasenever fires.