Custom Rule Example Strategies
This page collects seven complete custom strategies that save as written: three for Kalshi, two for Polymarket and two for Polymarket US. The markets are placeholders and the numbers are small illustrative values, not recommendations: replace them with your own after you understand what each rule does. For what each key, field and action means, start at Custom Rules.
Kalshi: flatten before close with side-aware exits
Buy one cheap YES contract on a rolling Kalshi series, take profit or stop out on the YES bid, flatten 5 minutes before close, and cap how many markets the account holds at once. The exits come first; the entry is last. It holds while the YES bid is between 0.25 and 0.60, and the entry only buys at a YES ask of 0.30 to 0.40, so with a spread of at most 0.03 the bid starts inside that zone. Because the exits use yes_position_size and time_to_expiry, the checker cannot analyze them, so that hold zone is yours to keep.
version: 1
platform: kalshi
strategy: custom
strategy_name: "Hourly bracket: cheap YES with side-aware exits"
market:
series_ticker: KXBTC
risk:
max_position: 3
price_floor: 0.05
price_ceiling: 0.95
max_entries_per_market: 1
loop:
interval: 30
rules:
- name: flatten_near_close
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: time_to_expiry, op: "<=", value: "5m"}
action: sell_all
- name: take_profit_yes
when:
all:
- {field: yes_position_size, op: ">", value: 0}
- {field: yes_best_bid, op: ">=", value: 0.60}
action: sell_yes
- name: stop_loss_yes
when:
all:
- {field: yes_position_size, op: ">", value: 0}
- {field: yes_best_bid, op: "<=", value: 0.25}
action: sell_yes
- name: enter_yes
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: portfolio_position_count, op: "<", value: 3}
- {field: yes_best_ask, op: ">=", value: 0.30}
- {field: yes_best_ask, op: "<=", value: 0.40}
- {field: spread, op: "<=", value: 0.03}
- {field: time_to_expiry, op: ">", value: "20m"}
action: buy_yes
size: 1portfolio_position_count counts every market with a position in the Kalshi account, including other Bots and manual trades.
Kalshi: P&L bracket with a spread and balance gate
Buy NO when YES trades rich, exit on a dollar stop-loss or take-profit, and stand aside when the book is wide or cash is low. The any guard sits below the exits so it never blocks a stop. The checker can analyze every rule here: the Bot holds while P&L is between -$0.15 and +$0.20.
version: 1
platform: kalshi
strategy: custom
strategy_name: "Fade rich YES with a cash and spread guard"
market:
series_ticker: KXHIGHNY
risk:
max_position: 2
price_floor: 0.05
price_ceiling: 0.95
loop:
interval: 30
rules:
- name: stop_loss
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: "<=", value: -0.15}
action: sell_all
- name: take_profit
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: ">=", value: 0.20}
action: sell_all
- name: pause_when_illiquid_or_low_cash
when:
any:
- {field: spread, op: ">", value: 0.05}
- {field: balance, op: "<", value: 20}
action: skip
- name: buy_no_when_yes_rich
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: price, op: ">=", value: 0.80}
- {field: price, op: "<=", value: 0.90}
action: buy_no
size: 1Kalshi: comparing two live fields
Two value_field comparisons on one entry: Coinbase spot above its 1-minute EMA-12, and the YES ask below the NO ask. Both are tested on every tick, not only at the moment they cross. The spread limit keeps the $0.20 stop wider than the spread paid at entry. If the Coinbase alias goes stale, entries are blocked and this Bot's resting entry orders on the market are canceled, while its three exits, which read no Coinbase field, keep running.
version: 1
platform: kalshi
strategy: custom
strategy_name: "15-minute crypto: YES when spot is above EMA-12"
market:
series_ticker: KXBTC15M
risk:
max_position: 2
price_floor: 0.10
price_ceiling: 0.90
max_notional: 5
loop:
interval: 15
edge:
btc:
provider: coinbase
symbol: BTC-USD
fields: [price, ema_12_1m]
refresh: 5s
rules:
- name: exit_before_close
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: time_to_expiry, op: "<=", value: "90s"}
action: sell_all
- name: take_profit
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: ">=", value: 0.15}
action: sell_all
- name: stop_loss
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: unrealized_pnl, op: "<=", value: -0.20}
action: sell_all
- name: buy_yes_on_uptrend
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: edge.btc.price, op: ">", value_field: edge.btc.ema_12_1m}
- {field: yes_best_ask, op: "<", value_field: no_best_ask}
- {field: yes_best_ask, op: "<=", value: 0.55}
- {field: spread, op: "<=", value: 0.05}
- {field: time_to_expiry, op: ">", value: "5m"}
action: buy_yes
size: 1Polymarket: order-book rules
Buy NO from the book on a pinned Polymarket market and exit on the NO bid. The entry requires the NO bid to already sit inside the 0.15 to 0.55 hold zone; without those bounds the validator would reject the rules as an entry/exit loop, because it considers every combination of bid and ask. A cancel_all pulls an unfilled buy once the NO ask moves away. Polymarket backtests do not simulate book fields, so this strategy is live-only.
version: 1
platform: polymarket
strategy: custom
strategy_name: "Pinned market: NO from the book"
market:
slug: "will-example-fc-win-on-2026-10-04"
risk:
max_position: 20
price_floor: 0.05
price_ceiling: 0.95
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: pull_stale_bid
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: ">", value: 0}
- {field: no_best_ask, op: ">", value: 0.40}
action: cancel_all
- 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: 20The buy is a limit order at the NO midpoint, so it may rest. 20 shares clears the common 5-share minimum, and at a midpoint of $0.35 or less they cost at most $7 of the $10 max_notional budget. cancel_all cancels only this Bot's orders, never ones you placed by hand.
Polymarket: backtestable dip buyer that scales out
A recurring 15-minute Up/Down market using only fields Polymarket backtests replay (price, spread, time_to_expiry, position_size, and order_count, which is always 0 in backtests). The entry band (0.30 to 0.40) sits above the 0.25 stop, so the Bot does not stop out on the tick after it buys. sell_yes with size: 5 sells half of a 10-share position. Once that sell fills, position_size is 5, so the scale-out rule cannot fire again; order_count == 0 stops it from placing a second sell while the first one is still resting. In a backtest that sell closes the whole side instead.
version: 1
platform: polymarket
strategy: custom
strategy_name: "15m Up: buy the dip, scale out half"
market:
recurring:
kind: updown
asset: btc
interval: 15m
risk:
max_position: 10
price_floor: 0.05
price_ceiling: 0.95
max_notional: 5
loop:
interval: 15
rules:
- name: exit_near_close
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: time_to_expiry, op: "<=", value: "2m"}
action: sell_all
- name: stop_out
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: "<=", value: 0.25}
action: sell_all
- name: scale_out_half
when:
all:
- {field: position_size, op: ">", value: 6}
- {field: order_count, op: "==", value: 0}
- {field: price, op: ">=", value: 0.60}
action: sell_yes
size: 5
- name: buy_up_dip
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: "==", value: 0}
- {field: price, op: ">=", value: 0.30}
- {field: price, op: "<=", value: 0.40}
- {field: spread, op: "<=", value: 0.02}
- {field: time_to_expiry, op: ">", value: "8m"}
action: buy_yes
size: 10The $5 max_notional applies to each 15-minute market separately; between $0.30 and $0.40, 10 shares cost $3 to $4.
Polymarket US: weather-driven NO
An NWS forecast gates the entry, a second condition cancels an unfilled buy if the forecast turns, and the exits use price because Polymarket US has no sell_yes / sell_no and its unrealized_pnl is not reliable. Studio pre-fills Max contracts per order at 1 from that size (see Size rules), and a larger sell_all would be split to fit anyway. If the NWS alias goes stale, entries are blocked while the price exits keep running. Polymarket US custom strategies cannot be backtested.
version: 1
platform: polymarket_us
strategy: custom
strategy_name: "NYC high temperature: NO on a cool forecast"
market:
slug: "tc-temp-nychigh-2026-10-02-gt60f"
risk:
max_position: 1
price_floor: 0.05
price_ceiling: 0.95
loop:
interval: 60
edge:
weather:
provider: nws
station: KLGA
fields: [forecast_high_f, current_temp_f]
refresh: 5m
rules:
- name: take_profit
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: "<", value: 0.15}
action: sell_all
- name: stop_loss
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: ">", value: 0.75}
action: sell_all
- name: cancel_if_forecast_turns
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: ">", value: 0}
- {field: edge.weather.forecast_high_f, op: ">=", value: 60}
action: cancel_all
- name: enter_no
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: edge.weather.forecast_high_f, op: "<", value: 56}
- {field: edge.weather.current_temp_f, op: "<", value: 58}
- {field: price, op: ">", value: 0.30}
- {field: price, op: "<=", value: 0.60}
action: buy_no
size: 1price is the YES last trade on Polymarket US, and buy_no is sent at 1 minus that price, so the NO position gains as price falls. The entry band (above 0.30, up to 0.60) sits inside the exits' 0.15 to 0.75 hold zone, so the Bot does not stop out right after it buys.
Polymarket US: calendar window with a cash guard
Enter YES in a window before an FOMC statement, cancel an unfilled entry in the final hour, flatten 45 minutes before the statement, and stand aside when buying power is low or the spread is wide. The calendar value is a snapshot taken at each refresh, so it can lag by up to one refresh (5 minutes here), and by up to three refreshes (15 minutes) while the calendar source is failing.
version: 1
platform: polymarket_us
strategy: custom
strategy_name: "Fed-day YES, flat before the statement"
market:
slug: "fed-holds-rates-oct-2026"
risk:
max_position: 1
price_floor: 0.05
price_ceiling: 0.95
loop:
interval: 60
edge:
fed:
provider: economic_calendar
event: FOMC
fields: [seconds_to_next]
refresh: 5m
rules:
- name: flatten_before_statement
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: edge.fed.seconds_to_next, op: "<", value: 2700}
action: sell_all
- name: take_profit
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: ">=", value: 0.85}
action: sell_all
- name: stop_loss
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: price, op: "<", value: 0.40}
action: sell_all
- name: cancel_late_entry
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: ">", value: 0}
- {field: edge.fed.seconds_to_next, op: "<", value: 3600}
action: cancel_all
- name: cash_and_spread_guard
when:
any:
- {field: balance, op: "<", value: 5}
- {field: spread, op: ">", value: 0.04}
action: skip
- name: enter_yes_in_window
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: order_count, op: "==", value: 0}
- {field: edge.fed.seconds_to_next, op: "<=", value: 172800}
- {field: edge.fed.seconds_to_next, op: ">=", value: 3600}
- {field: price, op: ">=", value: 0.55}
- {field: price, op: "<=", value: 0.80}
action: buy_yes
size: 1seconds_to_next is a plain number of seconds (2700 is 45 minutes, 172800 is 48 hours); a duration string is rejected for edge fields. For more on building and refining strategies with Studio's AI, see Prompting.