Custom Rule Field Catalog
A field is the live value a custom rule condition reads, such as price, position_size or spread, on Kalshi, Polymarket or Polymarket US. The table below lists every field, including the edge data and derived fields you declare, with its units, venue support and backtest support; the sections after it explain how each venue computes each value. For how a condition compares a field, see Conditions.
Built-in fields
| Field | What it reads | Units | Kalshi | Polymarket | Polymarket US | Backtest |
|---|---|---|---|---|---|---|
price | The YES price, computed differently per venue | Dollars, 0 to 1 | Yes | Yes | Yes | Kalshi, Polymarket |
spread | YES ask minus YES bid | Dollars, 0 to 1 | Yes | Yes | Yes | Kalshi, Polymarket |
volume | Traded volume reported by the venue | As the venue reports it: contracts on Kalshi, dollars on Polymarket | Yes | Yes | Yes | Kalshi only, per candle |
time_to_expiry | Time until the market closes | Seconds, written as a duration | Yes | Yes | Yes | Kalshi, Polymarket |
position_size | What you hold in this market, YES and NO combined | Contracts or shares | Yes | Yes | Yes | Kalshi, Polymarket |
yes_position_size | YES contracts you hold | Contracts | Yes | No | No | Kalshi |
no_position_size | NO contracts you hold | Contracts | Yes | No | No | Kalshi |
unrealized_pnl | Profit or loss if you sold the whole position now | Dollars | Yes | Yes | Not recommended | Kalshi, Polymarket |
balance | Available cash | Dollars | Yes | Yes | Yes | Kalshi, Polymarket (simulated) |
order_count | Your resting orders on this market | Count | Yes | Yes | Yes | Simulated, usually 0 |
portfolio_position_count | Markets you hold a position in across your account | Count | Yes | No | No | Kalshi |
yes_best_bid | Best YES bid | Dollars, 0 to 1 | Yes | Yes | No | Kalshi |
yes_best_ask | Best YES ask | Dollars, 0 to 1 | Yes | Yes | No | Kalshi |
no_best_bid | Best NO bid | Dollars, 0 to 1 | Yes | Yes | No | Kalshi |
no_best_ask | Best NO ask | Dollars, 0 to 1 | Yes | Yes | No | Kalshi |
paired_best_bid_sum | YES bid plus NO bid | Dollars, 0 to 2 | Yes | No | No | Kalshi |
paired_best_ask_sum | YES ask plus NO ask | Dollars, 0 to 2 | Yes | No | No | Kalshi |
edge.<alias>.<field> | A value from an external data source you declared | Provider units | Yes | No | Yes | Kalshi, per field |
derived.<name> | A metric you declared, such as distance from the strike | Units of its input | Yes | No | No | Kalshi |
A field that is not available on your venue is rejected when you save. Rejections look like field "yes_position_size" is only supported for Kalshi strategies or field "no_best_ask" is only supported for Kalshi and regular Polymarket strategies. Field names are case-sensitive: Price is an unknown field. Polymarket US custom strategies cannot be backtested at all.
On Kalshi, position_size, the side positions and unrealized_pnl describe this Bot's attributed inventory, including positions explicitly adopted at deployment. Manual trades and other Bots' positions are excluded. balance, order_count and portfolio_position_count remain account-wide. On the other venues, position fields read your account holdings. In paper trading these values come from the paper session instead: balance is paper cash, which starts at the paper starting balance ($1,000 by default).
price
The market's YES price in dollars. Each venue computes it differently:
- Kalshi: the best YES bid. With no YES bid, the most recent trade price, or 0.00 if there are no trades.
- Polymarket: the YES token midpoint, (best bid + best ask) / 2. It falls back to the best ask, then the best bid, then the last trade.
- Polymarket US: the last trade price, falling back to the venue's current price, then the bid/ask midpoint.
- Backtest: the candle's last-trade close, else the bid/ask midpoint.
What price means on each venue
price <= 0.43 is true on Kalshi but false on Polymarket, on Polymarket US and in a backtest. On Kalshi, buy_yes is sent at yes_best_ask and sells go at yes_best_bid, so gate on those when the exact price matters. On Polymarket, buys are limit orders at the midpoint (for buy_yes, the same number as price) and sells go at the bid.price is always the YES side, even in a buy_no rule. A NO position gains when price falls. On Kalshi, buy_yes is sent at yes_best_ask, not at price, so use the order book fields for exact entry and exit prices there. On Polymarket, a buy is placed at the token midpoint (for buy_yes, the same number as price) and sells at the bid.
spread
YES ask minus YES bid, in dollars (0.03 is 3 cents, not 3%). A missing ask counts as 1.00 and a missing bid as 0.00, so a one-sided or empty book reads as a very wide spread. That makes spread <= 0.03 entry gates fail safe when the book is thin. In backtests it is the candle's closing spread.
volume
Traded volume as the venue reports it.
- Kalshi live: total contracts traded in this market so far (it only grows).
- Kalshi backtest: volume traded during that candle only. The same threshold therefore behaves very differently in a backtest and live.
- Polymarket: the market's lifetime volume in dollars, from Polymarket's market data. It is read when the Bot picks up the market and is not refreshed while it trades that market (on a rolling series it is read again for each new market), so it does not grow during a run. Polymarket backtests reject strategies that read
volume. If you select a Polymarket market by token IDs only,volumereads 0; select it by slug, condition ID or series instead. - Polymarket US: the market's volume as a whole number.
time_to_expiry
Time left until the market closes: the close time on Kalshi, the end date on Polymarket and Polymarket US. Write thresholds as durations, such as {field: time_to_expiry, op: "<=", value: "5m"}.
It never goes negative. When the venue gives no close time (or the close has passed) it reads 0, so "near close" exits such as <= "5m" fire and entry gates such as > "20m" block. On Polymarket, selecting a market by token IDs only leaves the close time unknown. In backtests it is the time from the candle to the market close.
position_size
How much you hold in this market, YES and NO combined:
- Kalshi: the absolute size of this Bot's attributed net position on this market, capped at what the account still holds on that side. Kalshi nets YES and NO in one market, so buying NO while holding YES reduces the YES position.
- Polymarket: your YES token balance plus your NO token balance. It can be fractional, and the two tokens are held independently. If a token balance cannot be read on a tick, that token counts as 0 for the tick, so
position_sizecan briefly read lower than what you hold: aposition_size == 0entry can match, and aposition_size > 0exit can miss that tick. Keeprisk.max_notionalset on Polymarket custom strategies as a backstop. - Polymarket US: the absolute size of your net position.
Gate entries with position_size == 0 and exits with position_size > 0. Behavior validation uses exactly this field to tell "flat" from "holding", so exits that are gated on it are the ones the checker can analyze.
yes_position_size and no_position_size
Kalshi only. The YES contracts and the NO contracts attributed to this Bot in this market, capped at the account's holdings on that side. Because Kalshi nets the two sides, at most one of them is non-zero. Use them for side-aware exits: yes_position_size > 0 with yes_best_bid and sell_yes, or no_position_size > 0 with no_best_bid and sell_no.
Behavior validation cannot analyze side-position conditions, so a rule that uses one is left out of the range checks. It will not stop you from writing yes_position_size > 0 → sell_yes, which sells right after every entry. Always add a price, P&L or time condition to a side-aware exit.
unrealized_pnl
The profit or loss, in dollars, if you sold your whole position in this market right now. It is 0 when you are flat. It is a total for the position, not per contract: 10 contracts that each move 2 cents change it by $0.20, so scale thresholds with your size.
- Kalshi: this Bot's held contracts times the held side's best bid, minus their remaining entry cost and entry fees. Other Bots' inventory and costs are excluded. If the side you hold has no bid, it is marked at $0, which reads as a large loss. A P&L stop can then match, but its sell needs a bid, so it errors on each tick until a bid appears.
- Polymarket: held tokens times each token's best bid, minus the entry cost and fees of the tokens you still hold, from your trade history (in paper trading, from the paper session's own fills, entry fees included). If the P&L cannot be worked out on a tick (no bid on a held side, or, on a live Bot, a trade history that cannot be read or whose recent trades do not account for every token you hold, such as a position built from older trades), the value is unavailable for that tick and the decision log notes it: P&L conditions are false, whatever the operator, and your other rules, exits included, still run.
- Polymarket US: not recommended. The value is read from the venue's position record and does not reliably represent profit or loss, and it is always 0 in paper trading. Build Polymarket US exits on
priceinstead. - Backtest: liquidation value at the bid minus cost and fees.
Right after a buy fills, unrealized_pnl starts slightly below 0, not at 0: the position is marked at the bid, you paid the ask (Kalshi) or about the midpoint (Polymarket), and fees are subtracted. A 1-contract Kalshi buy with a 0.04 spread reads about -$0.04 minus fees. Keep each P&L stop wider than the spread you allow on entry, for example with a spread condition on the entry, or the stop can fire on the tick after you buy. Behavior validation models this moment as P&L 0, so it does not warn about a stop that is too tight; it does reject an exit such as unrealized_pnl >= 0 that matches at P&L 0 (see Exits that fire right after entry).
balance
Your available cash in dollars: the account balance on Kalshi, collateral buying power on Polymarket, buying power on Polymarket US. On Polymarket and Polymarket US it reads 0.00 if the balance cannot be read, so a guard like balance < 20 → skip stands aside rather than trading blind.
In backtests, a strategy that reads balance starts with a simulated $1,000 (editable in the Backtest tab), buys it cannot afford are blocked, and sells and settlements add cash back. Strategies that do not read balance get no cash constraint in backtests.
order_count
How many of your orders are resting on this market right now. It counts all your orders on the market, including manual orders and other Bots. cancel_all only cancels this Bot's orders, so a rule like order_count > 0 → cancel_all can fire on every tick while a manual order rests. On Polymarket, if your open orders cannot be read on a tick, order_count can undercount for that tick, so an order_count == 0 gate can pass while an order rests.
In ordinary backtests buys fill or skip immediately, so order_count is always 0 there. Only Kalshi composite-order backtests simulate resting orders.
portfolio_position_count
Kalshi only. The number of different markets in which your Kalshi account currently holds a position (all Bots and manual trades). It is useful to cap how many markets you hold at once with a series or market.selection: all, for example portfolio_position_count < 3 on the entry. Kalshi also has a dedicated cap, risk.max_portfolio_positions, that blocks entries into a new market once your account is active in that many.
Polymarket and Polymarket US never supply the value, so it is rejected there with field "portfolio_position_count" is only supported for Kalshi strategies.
Order book fields
yes_best_bid, yes_best_ask, no_best_bid and no_best_ask read the top of the book, in dollars. Kalshi and Polymarket only; Polymarket US rejects them.
- Kalshi: from one order book snapshot. Kalshi quotes asks through the opposite side's bids, so
yes_best_askis 1 minus the best NO bid andno_best_askis 1 minus the best YES bid. A Kalshibuy_yesis sent atyes_best_askand abuy_noatno_best_ask. - Polymarket: the YES token's and the NO token's own order books.
A field is unavailable when its side of the book is empty, so conditions on it are false. Use the bid fields for exits (what you can sell at) and the ask fields for entries (what you pay). On Polymarket these fields are live-only: backtests reject them.
paired_best_bid_sum and paired_best_ask_sum
Kalshi only. yes_best_bid + no_best_bid and yes_best_ask + no_best_ask from the same snapshot, unavailable if either side is empty. They are mostly used to gate paired YES/NO composite quotes. Whenever both sides of a Kalshi book exist, the bid sum equals 1 minus spread and the ask sum equals 1 plus spread, so on their own they carry the same information as spread.
Edge data fields
edge.<alias>.<field> reads a value from an external data source (Coinbase prices and indicators, NWS weather, the FOMC/CPI economic calendar). Declare the alias under the top-level edge: block and list the field in that alias's fields; otherwise the rule is rejected (edge alias "x" not declared, edge field "f" not listed in alias "x", or edge field must be edge.<alias>.<field>). Edge fields work in custom strategies on Kalshi and Polymarket US. Regular Polymarket rejects the edge block.
- Values are numbers in the provider's units:
change_15mof0.003is +0.3%, NWS humidity of0.70is 70%. - Text fields (NWS
precip_typeandalert_severity, calendarnext_event_typeandprevious_event_type) take==or!=with one of the field's values, such as{field: edge.nyc.alert_severity, op: "==", value: warning}. Values are case-sensitive, and ordering operators, numbers andvalue_fieldare rejected. See Text fields. - If a whole alias is stale, every field of it is unavailable and new entries are blocked for that market; exits still run. A single value that cannot be computed is unavailable too.
Providers, field lists, units, refresh rules and backtest coverage are in Edge Data.
Derived metrics
derived.<name> reads a metric declared under the top-level derived: block, such as the signed distance between a Coinbase price and the Kalshi market's strike. Kalshi custom strategies only. If the strike or the input value is unavailable, derived fields read as unavailable, new entries are blocked, and this Bot's resting entry orders on the market are canceled. See Edge Data.