Kalshi Perps Markets and Execution
This page covers three blocks of a Kalshi Perps strategy (platform: kalshi_perps): markets, the perpetual markets the Bot trades; loop, how often it checks them; and execution, how it places entries and bounds exits. A tick is one of those checks; see What happens on every tick for its order, and All Kalshi Perps parameters for every key in one table.
Markets and loop
markets
One to five markets, with no ticker listed twice. Each market is checked separately on every tick, in list order, with its own position, take-profit and stop-loss, crossover memory and setups. Sizing applies to each market: with three markets, up to three positions can be open at once, each at least one entry of margin_usd × leverage (more if your rules add), all on one shared margin account.
Three things to know:
- A failing market doesn't hold up the rest. If anything goes wrong while the Bot handles a market, such as a failed account request, only that market is skipped for the tick: the markets after it still get their exit checks and strategy. A ticker that looks right but that Kalshi doesn't list fails on every tick with
unknown perps market, and the other markets keep running. - Entries on several markets in one tick can be paced. The Bot waits at least 1 second between order attempts, and a close restarts that wait too (see Deployment risk limits). If a second market wants to enter on the same tick, its entry can be skipped; a comparison-based entry tries again on the next tick, but a crossover entry waits for the next crossover.
- Close a position before removing its market. If you remove a market with Update Bot while the Bot holds a position there, the Bot stops tracking that position. No take-profit, stop-loss or rule will ever close it, and the Bot's status line lists it under
dropped_markets.
markets[].ticker
A Kalshi perpetual ticker: KX, then capital letters or digits, then PERP, such as KXBTCPERP. Lowercase fails with ticker must look like KXBTCPERP. Studio checks only the shape. It doesn't check that Kalshi lists the market.
These are the markets Kalshi listed when this page was checked in July 2026. Kalshi can add or remove markets, so ask Studio to search perps markets for the current list, prices and leverage caps.
| Ticker | Asset | Coinbase MACD fields |
|---|---|---|
KXBTCPERP | Bitcoin | Yes (BTC-USD) |
KXETHPERP | Ether | Yes (ETH-USD) |
KXSOLPERP | Solana | Yes (SOL-USD) |
KXXRPPERP | XRP | Yes (XRP-USD) |
KXDOGEPERP | Dogecoin | Yes (DOGE-USD) |
KXSUIPERP | Sui | Yes (SUI-USD) |
KXZECPERP | Zcash | Yes (ZEC-USD) |
KXBCHPERP | Bitcoin Cash | Yes (BCH-USD) |
KXLTCPERP | Litecoin | Yes (LTC-USD) |
KXLINKPERP | Chainlink | Yes (LINK-USD) |
KXNEARPERP | NEAR | Yes (NEAR-USD) |
KXHYPEPERP | Hyperliquid | No |
KXKSHIBPERP | Shiba Inu, per 1,000 | No |
KXADAPERP (Cardano, ADA-USD) also supports MACD fields if Kalshi lists it. See Coinbase MACD fields.
While it runs, the Bot reads each market's price, bid and ask, tick size, whether fractional contracts are allowed, and the current leverage cap from Kalshi's market list.
loop.interval
Seconds the Bot waits between ticks. The default is 60, which also applies when loop is left out or set to 0. The minimum is 10, and there is no maximum. The real period is the interval plus the time the tick itself takes. loop has no other key.
The interval sets how often the Bot cancels expired resting entries, checks take-profit, stop-loss and the ATR stop, and runs the strategy. Keep in mind:
- Candle signals change once per candle. An indicator on 1h candles moves once an hour. A shorter interval mostly means exits and new candle closes are noticed sooner.
- Prices refresh at most once a minute.
mark_price,bidandaskcome from Kalshi's market list, which the Bot re-reads at most every 60 seconds. With an interval under 60, those prices, and the take-profit and stop-loss checks that use them, don't change on every tick. - Coinbase MACD is fresher. The MACD fields are refreshed every few seconds, so a shorter interval notices a 1m MACD crossover sooner.
- Setups.
loop.intervalis also the shortest allowedsetups[].expires_after_seconds.
Execution
execution controls how the Bot places entries: open_long, open_short, add and archetype entries. Leave it out for immediate (taker) entries with a 0.5% slippage bound. Every exit, in either mode, is an immediate reduce-only order bounded by max_slippage_pct. That covers take-profit, stop-loss, the ATR stop, close, reduce and archetype exits.
Where the Bot prices its orders
- Taker limit, circle (immediate-or-cancel)
- Resting entry, diamond (limit mode)
- Best bid and ask (dashed)
KXBTCPERP book with the bid at $6.4473 and the ask at $6.4484 (price tick $0.0001), the default max_slippage_pct: 0.5 and an illustrative limit_offset_pct: 0.1. A taker order fills at the best prices available up to its limit, and the rest is cancelled at once. With the default offset of 0.05, resting entries would sit at $6.4440 (long) and $6.4517 (short). Kalshi Perps has no market orders.execution.entry_mode
taker(default): an immediate-or-cancel limit order priced through the book, up tomax_slippage_pctpast the best price. It fills right away at the best prices available up to that limit, and anything unfilled is cancelled. Kalshi Perps has no true market order.limit: a resting order placedlimit_offset_pctbehind the best price: below the bid for a long, above the ask for a short. The Bot cancels it on the first tick afterlimit_ttl_seconds. While it rests, the Bot places no other entry on that market.
The value is case-sensitive: LIMIT fails with must be taker or limit. A misspelled key such as entry_mod: limit is ignored, and the Bot runs in taker mode.
Note: A market never has more than one of the Bot's resting entries. An unfilled entry doesn't change the Bot's position, so while one rests, a new entry or add on that market is skipped with
resting entry still working; a comparison-based entry tries again on the next tick, and a crossover entry waits for the next crossover. Before every limit entry the Bot asks Kalshi for its resting orders, so an entry that filled, or that you cancelled in the Kalshi app, stops blocking at once. If Kalshi can't be asked, the entry is skipped withcould not check for a resting entry.
execution.max_slippage_pct
How far past the best price a taker order may be priced, in percent. A taker buy is a limit at ask × (1 + x ÷ 100), rounded down to the price tick. A taker sell is a limit at bid × (1 − x ÷ 100), rounded up. With a $6.4484 ask and the default 0.5, a taker buy is priced at $6.4806 or better.
- Default 0.5, also used when it is 0.
- Checked in both modes: it must be above 0 and at most 5. In limit mode it doesn't touch entries, but every exit still uses it, so a negative value (which would price every close away from the book) or one past Kalshi's price limits (which would get every close rejected) is refused when you save.
- The bid and ask it starts from can be up to 60 seconds old.
- If Kalshi reports no best price and no mark for the market, a taker order (a taker entry or any exit) is skipped with
no price or zero size.
execution.limit_offset_pct
How far behind the best price a resting entry sits, in percent. Checked only in limit mode, where it must be 0 to 5.
- A long rests at bid × (1 − x ÷ 100), rounded down to the price tick. A short rests at ask × (1 + x ÷ 100), rounded up.
- With a $6.4473 bid, a $6.4484 ask and an offset of 0.1, a long rests at $6.4408 and a short at $6.4549. With the default 0.05, they rest at $6.4440 and $6.4517.
0is replaced by the default 0.05, so an offset of exactly zero can't be expressed.- The number of contracts is worked out from the ask (long) or bid (short), not from the resting price.
- A long rests behind the bid and a short behind the ask. If that side of the book is empty, the entry is skipped with
no top-of-book for limit.
execution.limit_ttl_seconds
How long a resting entry may wait, in seconds. Checked only in limit mode, where it must be 30 to 86400. It defaults to 300 when left out or set to 0.
- The Bot cancels an expired order at the start of the next tick, so an order's real lifetime rounds up to the loop cadence.
- A clean stop, including the one before a redeploy or update, cancels the Bot's resting orders. Positions stay open.
- If the Bot stops without a clean shutdown, such as a crash, its resting orders stay on the book. When it starts again it takes them back and gives each a fresh time limit of this length. If Kalshi can't be reached at that moment, the Bot takes them back the next time it checks before a limit entry.
- It is how long an unfilled entry waits before it is replaced. The next entry on that market goes out only after this one fills, expires or is cancelled, so with
limit_ttl_secondsequal toloop.intervalan unfilled entry is re-priced on every tick, and with a longer one it keeps its price for longer.
When a close doesn't go through
Exits are immediate-or-cancel, so they can fail to fill. What happens next depends on the exit and on why it failed:
- Accepted but not filled. Take-profit, stop-loss, the ATR stop and
closerules written as state comparisons try again on the next tick while their condition still holds. - Rejected by Kalshi, for example a price outside Kalshi's allowed range. The Bot then stops attempting whole-position closes on that market, including take-profit, stop-loss, the ATR stop,
closerules and archetype exits, until your account's position in that market changes. The log showsreduce_only close rejected by the venue. Network errors and Kalshi server errors are not treated this way; they retry on the next tick. - Your account no longer holds this Bot's side, because you or another Bot closed it. The close is skipped with
shared account carries no reducible size for this Botuntil the account's position changes. Closes are always limited to what the shared account can actually reduce. - Your account holds less than one contract of this Bot's side. The close is skipped with
reducible size rounds to zero contracts, and stays skipped on that market until the account's position there changes. Close the remainder yourself in the Kalshi app if needed.
Warning: While Kalshi keeps rejecting a close, the Bot retries it only every 5 minutes, and each rejection counts toward your API error limit. If you see
reduce_only close rejected by the venue, check the position and close it yourself if needed.