Polymarket Market Selection
This page covers the market block for regular Polymarket (platform: polymarket): each selector, which markets a Bot can trade, and what carries over when a rolling series moves to its next market. For every key and its allowed values, see All Polymarket parameters. Polymarket US uses different selectors; see Polymarket US market selection.
A Polymarket Bot trades exactly one binary market at a time. You choose it with one concrete selector. All five below can be deployed; event_slug and query cannot.
| Selector | What it pins | Rolls to the next market? | Market details the Bot knows | Backtest |
|---|---|---|---|---|
slug | One market | No | End date, tick, minimum size, volume (looked up once at start) | Yes |
condition_id | One market | No | Same as slug | Yes |
yes_token_id + no_token_id | One market | No | None: no end date, volume 0; minimum size from your YAML (default 5); tick from the exchange, else your YAML (default 0.01) | Yes, but marked to the last book price instead of settlement |
series_slug | The current market in a series | Yes | Looked up for each market | Yes |
recurring | The current crypto Up/Down market | Yes | Looked up for each market | Yes |
event_slug, query | Nothing | Not deployable | Discovery only | No |
If you set more than one selector, the Bot picks one in a fixed order when it starts:
Which selector the Bot uses
event_slug or query set?series_slug or recurring set?yes_token_id and no_token_id set?time_to_expiry and volume read 0. The tick comes from the exchange (your tick_size, default 0.01, only if that fails); the minimum size comes from your min_order_size (default 5).slug set?condition_id set?Every market the Bot looks up (checks 2, 4 and 5) must have exactly two outcomes labelled Yes/No or Up/Down and must not be negative-risk. Otherwise the Bot exits at startup with a configuration error.
Backtests resolve selectors in a different order: a series first, then condition_id or slug, then yes_token_id. A strategy that sets both a slug and a token pair can therefore trade a different path live than in a backtest. Set one selector unless you have a reason not to.
Which markets can be traded
The Bot accepts a market only if it has exactly two outcomes labelled Yes/No or Up/Down and it is not negative-risk. Anything else makes the Bot exit at startup with a configuration error. That rules out markets whose outcomes are names (a team or a candidate) and grouped multi-outcome markets such as temperature ranges or championship winners.
A token-pinned market skips this check, because the Bot never looks the market up. Make sure the IDs belong to a Yes/No or Up/Down market and are not swapped.
market.slug
The slug from a polymarket.com market URL. Use the market's slug, not the event's.
- The Bot looks the market up once at startup. From that it takes the YES and NO tokens, the end date (used by
time_to_expiry), the tick size, the minimum order size, the fee flag and the market's volume. - The Bot stays on this market. After the market closes it keeps looping with
time_to_expiryat 0 and empty books until you stop it. - Rolling crypto markets have a separate slug for every window (for example
btc-updown-15m-plus a start time). Pinning one of those trades that single window only. Useseries_slugorrecurringto follow the series. - If a token pair is also set, the token pair wins and the slug is only a label in logs.
market.condition_id
Pins a market by its condition ID (0x…). The Bot looks it up once at startup, exactly like slug, and never rolls over. Backtests prefer condition_id over slug when both are set.
market.yes_token_id and market.no_token_id
The two outcome tokens, as long decimal strings. You must set both; one alone fails with Polymarket token selectors must include both market.yes_token_id and market.no_token_id.
With both set, the Bot uses them as given and does not look the market up. That has consequences:
- There is no end date, so
time_to_expiryis always 0. Rules ontime_to_expirynever see the real time left, andpre_announcement_driftnever enters. volumeis always 0.- The tick size comes from the exchange, or from
market.tick_size(default 0.01) if that fails. The minimum order size comes frommarket.min_order_size(default 5). - Outcome labels are not checked. Swapping the two IDs silently swaps YES and NO.
If you pin by tokens, add the market's condition_id too. Live, the token pair still decides which market is traded, but the Bot uses the condition ID to list and cancel your orders and to read this market's trade history, which max_notional, max_entries_per_market and unrealized_pnl depend on. Without it the Bot only sees your most recent trades across all markets and can miss this market's buys. The budget and entry cap then undercount, and unrealized_pnl can be unavailable, so conditions on it stay false.
A slug next to the tokens is only a label live. Backtests use a condition_id or slug ahead of the tokens, so either one lets a backtest settle the market.
market.series_slug
Follows a rolling Polymarket series, such as the crypto Up/Down markets. The Bot always trades the open market in the series that ends soonest.
- Rollover. From 10 seconds before the current market's end date, the Bot re-checks the series on every loop. On the first check after the end date it switches to the next market.
- Next market not listed yet. That loop logs an error and the Bot tries again on the next loop. If no market is open when the Bot first starts, it exits.
- The slug is not checked against Polymarket when you save. A typo saves fine and the Bot exits at startup.
- If you also set
recurring, the two must resolve to the same series.
See Rolling series: what carries over for what resets when the Bot switches markets.
market.recurring
A shorthand for Polymarket's crypto Up/Down series. Studio turns it into a series_slug, and the Bot then behaves exactly as with series_slug.
market:
recurring:
kind: updown
asset: btc
interval: 15m| Asset (also accepts) | 5m | 15m | 1h | 4h | 1d |
|---|---|---|---|---|---|
btc (bitcoin) | btc-up-or-down-5m | btc-up-or-down-15m | btc-up-or-down-hourly | btc-up-or-down-4h | btc-up-or-down-daily |
eth (ethereum, ether) | eth-up-or-down-5m | eth-up-or-down-15m | eth-up-or-down-hourly | eth-up-or-down-4h | eth-up-or-down-daily |
sol (solana) | sol-up-or-down-5m | sol-up-or-down-15m | solana-up-or-down-hourly | sol-up-or-down-4h | solana-up-or-down-daily |
xrp (ripple) | xrp-up-or-down-5m | xrp-up-or-down-15m | xrp-up-or-down-hourly | xrp-up-or-down-4h | xrp-up-or-down-daily |
doge (dogecoin) | doge-up-or-down-5m | doge-up-or-down-15m | doge-up-or-down-hourly | doge-up-or-down-4h | dogecoin-up-or-down-daily |
hype (hyperliquid) | hype-up-or-down-5m | hype-up-or-down-15m | hype-up-or-down-hourly | hype-up-or-down-4h | hype-up-or-down-daily |
bnb (binance) | bnb-up-or-down-5m | bnb-up-or-down-15m | bnb-up-or-down-hourly | bnb-up-or-down-4h | bnb-up-or-down-daily |
kindis optional and must beupdown.assetandintervalare required and case-insensitive. Other assets, such as ADA or AVAX, are rejected.intervalalso accepts5min,5mins,15min,15mins,hour,hourly,dailyandday. Spaces and hyphens are ignored, so15 minworks.4hhas no aliases;30m,60m,4hourandweeklyare rejected.- Studio builds the series name from this table. Whether a given series has an open market at a given time is up to Polymarket.
# Rejected: 30-minute Up/Down series are not a supported interval
# error: must be one of 5m, 15m, 1h, 4h, or 1d
version: 1
platform: polymarket
strategy: mean_reversion
market:
recurring:
kind: updown
asset: btc
interval: 30m
risk:
max_position: 5
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 30
params:
entry_low: 0.35
entry_high: 0.65market.event_slug and market.query
Studio can use these while it searches for a market with you, but you cannot deploy them. They fail validation with a message that they are discovery-only, on their own or next to a concrete selector. Remove both once the market is chosen.
# Rejected: an event slug identifies an event, not one tradable market
# error: discovery-only
version: 1
platform: polymarket
strategy: mean_reversion
market:
event_slug: "example-election-2026"
risk:
max_position: 5
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 30
params:
entry_low: 0.35
entry_high: 0.65A leftover search key next to a concrete selector is rejected too, because the Bot would refuse to start:
# Rejected: remove event_slug once a concrete selector such as slug is set
# error: remove them once a concrete market.slug
version: 1
platform: polymarket
strategy: mean_reversion
market:
slug: "example-election-2026-candidate-a"
event_slug: "example-election-2026"
risk:
max_position: 5
price_floor: 0.10
price_ceiling: 0.90
loop:
interval: 30
params:
entry_low: 0.35
entry_high: 0.65market.neg_risk
Optional, and only false is accepted. true fails with negative-risk/multi-outcome Polymarket markets are not supported. Setting false changes nothing at runtime: the Bot separately refuses any market Polymarket reports as negative-risk.
market.tick_size
The fallback price increment: 0.1, 0.01, 0.001 or 0.0001. Any other value is rejected. The Bot always asks the exchange for the live tick first. Your value is used only for a token-pinned market, and only if that request fails. For slug, condition_id and series selectors it has no effect.
market.min_order_size
The fallback minimum order size in shares, used only for a token-pinned market (default 5). For other selectors the Bot uses the market's own minimum. Write it as a positive number, such as 5 or "5". Anything else, such as "abc" or 0, fails with Polymarket min_order_size must be a positive number.
Rolling series: what carries over
With series_slug or recurring, one Bot trades a chain of markets. This is what happens at the switch, using a 15-minute BTC series and a 15-second loop:
Rollover in a BTC 15-minute series
- Market A: 12:00 to 12:15
- Market B: 12:15 to 12:30
position_sizeandorder_counttime_to_expiry(about 900 s again) andvolume- The
max_notionalbudget - The entry count behind
max_entries_per_market - Built-in memory: cooldown, fade count and price history, momentum history, the drift entry
- Shares still held in market A: not sold or redeemed by the Bot
Keep three things in mind:
- Limits and memory are per market. The
max_notionalbudget and themax_entries_per_marketcount are read from the current market's trade history, so they start fresh in every market; neither is a lifetime limit for the series. Built-in strategies also start each market with fresh memory: the cooldown, the fade count and price history, the momentum samples and the drift entry. - Orders don't follow you. An entry still resting when the window closes belongs to the old market.
- Leftover shares stay where they are. When the Bot moves on, it does not sell or redeem shares still held in the old market. They settle with that market; manage them in your Polymarket account.
Built-in strategies also keep some of their own memory across the switch, such as a cooldown or a fade count. See Built-in strategies on Polymarket.