> ## Documentation Index
> Fetch the complete documentation index at: https://scalarfield.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Polymarket vs kalshi

# Polymarket vs Kalshi

How the two prediction-market venues differ in Scalar Field: chat discovery, scalarlib data functions, `venue.*` / `strategy.*` trading, funding, and settlement.

Both are first-class venues. Chat writes Python in `execute_code`, screens markets, then trades with `venue.trade(...)`. The loop is the same; the APIs, symbols, cash, and fill models are not.

***

## Quick contrast

|                         | Polymarket                                                | Kalshi                                                                      |
| ----------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------- |
| Regulator / structure   | On-chain CLOB (Polygon)                                   | CFTC-regulated exchange                                                     |
| Chat dataset lookup     | `lookupDocumentation("PolymarketData")`                   | `lookupDocumentation("KalshiData")`                                         |
| Screen                  | `screenPolymarkets()`                                     | `screenKalshiMarkets()`                                                     |
| Catalog                 | Always Postgres FTS (`POST /api/v1/db/polymarket/screen`) | Live Kalshi APIs (`POST /api/v1/db/kalshi/screen` → search or GET /markets) |
| Trade handle            | Outcome `token_id` from `token_ids` list                  | `symbol` (YES) or `symbol_no` (NO)                                          |
| Outcomes                | Binary **or** multi-outcome                               | Binary YES / NO only                                                        |
| `venue.trade` account   | `POLYMARKET` or `POLYMARKET_PAPER`                        | `KALSHI` (live only)                                                        |
| Cash                    | PUSD on `WALLET_POL` (live); virtual USDC (paper)         | USD on the user's Kalshi account                                            |
| Connect                 | Managed Polygon wallet                                    | User pastes API Key ID + RSA private key                                    |
| Deposits / withdrawals  | Via Scalar wallet / `deposit_request`                     | At Kalshi only — we never move cash                                         |
| Paper                   | Yes (`POLYMARKET_PAPER`)                                  | No                                                                          |
| Settlement              | Explicit `venue.trade("redeem", ...)` after resolution    | Automatic; history `category: "settlement"`                                 |
| Default market slippage | 500 bps (5%)                                              | 50 bps (0.5%)                                                               |
| Hours                   | 24/7                                                      | Near-24/7; pause Thu 03:00–05:00 ET                                         |
| Stops                   | No                                                        | No                                                                          |
| Resting limits          | Yes (GTC)                                                 | Yes (GTC); market = synthesized IOC                                         |

***

## Chat

Neither venue has a built-in market list in the prompt. The agent must look up docs, then call a screener.

|                       | Polymarket                                                                            | Kalshi                                                                                |
| --------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Lookup name           | `PolymarketData`                                                                      | `KalshiData`                                                                          |
| What the page teaches | Full `screenPolymarkets` params, columns, OHLCV, trades, wallets, positions, profiles | Full `screenKalshiMarkets` params, columns, events, order book, candles, public tape  |
| Trading docs          | `VenueAndStrategy` — `token_ids` into `venue.trade(..., account="POLYMARKET")`        | `VenueAndStrategy` — `symbol` / `symbol_no` into `venue.trade(..., account="KALSHI")` |
| Typical search        | `screenPolymarkets(query="bitcoin", closed=False)`                                    | `screenKalshiMarkets(query="bitcoin", closed=False)`                                  |

Unified helper (both catalogs): `searchPredictionMarkets(query, venue="polymarket"|"kalshi")`. Event tags apply to Polymarket only.

When speaking to the user about Kalshi, describe YES vs NO in plain language. Do not mention internal ticker encodings.

***

## Market discovery (screeners)

### Shared

* `query`, `closed`, `min_volume`, `min_price` / `max_price` (0–1), `start_date` / `end_date` (`YYYY-MM-DD`), `sort_by` (`volume` or `created_at`), `limit`, `offset`
* No Kalshi/Polymarket login required

### `screenPolymarkets` only

| Param                               | Role                                                                               |
| ----------------------------------- | ---------------------------------------------------------------------------------- |
| `market_ids`                        | Bulk lookup by Polymarket market id                                                |
| `event_tags` / `exclude_event_tags` | Category tags (`sports`, `politics`, …)                                            |
| `start_date` / `end_date`           | Market lifecycle: `market_start_date >= start_date`, `market_end_date <= end_date` |
| Default `limit`                     | 50                                                                                 |

Returns (among others): `market_id`, `market_question`, `market_outcomes`, `market_outcome_prices`, `token_ids` (list, one CLOB token per outcome), `winning_outcome_index`, `market_accepting_orders`, `event_title`.

`closed=True` is **not** the same as resolved. Use `winning_outcome_index` (set only when settled).

### `screenKalshiMarkets` only

| Param                            | Role                                                                                                                                                                                                                   |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tickers`                        | Bulk lookup by market ticker                                                                                                                                                                                           |
| `event_ticker` / `series_ticker` | Kalshi event / series                                                                                                                                                                                                  |
| `status`                         | Query filter: `"open"` (default; `None` is the same as omit), `"closed"`, `"settled"`, `"unopened"`, `"paused"`, or aliases `"active"` / `"finalized"`. Other values raise `ValueError`. Ignored when `closed` is set. |
| `start_date` / `end_date`        | Expiration window on `close_time` (`YYYY-MM-DD`, New York calendar days). Not a start/end pair — Kalshi’s lifecycle date is when the contract expires.                                                                 |
| `min_close_ts` / `max_close_ts`  | Same expiration window as Unix seconds                                                                                                                                                                                 |
| Default `limit`                  | 100                                                                                                                                                                                                                    |

Every row also carries **`close_time`** (expiration) and **`created_time`** (when listed). Catalog tables additionally store `open_time`, `updated_time`, and `settled_time`; those are not returned by the screener today.

Returns (among others): `ticker`, `title`, `symbol` (YES trade handle), `symbol_no` (NO trade handle), `yes_bid` / `yes_ask` / `no_bid` / `no_ask`, `last_price`, `volume`, `open_interest`, `close_time`, `created_time`, `price_ranges`, `event_title`.

With `query`, results come from Kalshi's `/v1/search/series` (relevance-ranked, one page). Without `query`, from `GET /markets` (one page; volume sort is within that page).

### `screenKalshiEvents`

Kalshi-only. Lists events (`event_ticker`, `title`, `category`, `status`, `close_time`), optionally with nested `markets`. Polymarket folds event fields into `screenPolymarkets` (`event_id`, `event_title`, `event_slug`).

Event `status` query values are `"open"`, `"closed"`, `"settled"`, or omit/`None` for any. Other values, including `"active"` and `"finalized"`, raise `ValueError` before the request. The filter matches events that have at least one child market in that state. Event-row `status` is often null.

***

## Data functions

Market data is public on both. Polymarket has a larger analytics surface because trades and positions are on-chain.

| Capability           | Polymarket                                                                                       | Kalshi                                                                                                    |
| -------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| Screen markets       | `screenPolymarkets`                                                                              | `screenKalshiMarkets`                                                                                     |
| Screen events        | (via market row)                                                                                 | `screenKalshiEvents`                                                                                      |
| OHLC / OHLCV         | `getPolymarketOHLCV(token_ids, start, end, timeframe)` — `day`, `hour`, `5min`, `15min`, `30min` | `getKalshiCandles(ticker, start, end, period_interval)` — **1, 60, or 1440 minutes only**                 |
| Live book            | `getPolymarketPriceAndBook` / `getLatestSnapshot(token_id)` — full CLOB bids **and** asks        | `getKalshiOrderbook` / `getLatestSnapshot(symbol)` — **bids only** per leg; ask = `1 −` opposite best bid |
| Public trades        | `getPolymarketTrades` — filter by token, wallet, market, side, size, USDC value, time            | `getKalshiTrades(ticker)` — public tape (live then historical) with `is_complete`; no wallet filter       |
| Resolution           | Market row + on-chain resolution                                                                 | `getKalshiMarket` (`result`, `settlement_ts`, `settlement_value_dollars`, `status` disputed/amended)      |
| Wallet leaderboard   | `screenPolymarketWallets`                                                                        | **None** (no public wallet graph)                                                                         |
| Any-wallet positions | `getPolymarketPositions(wallet=...)`                                                             | **None** — use `venue.positions(account="KALSHI")` for the connected user                                 |
| Trader profile       | `getPolymarketProfile(wallet)`                                                                   | **None**                                                                                                  |
| `getLatestSnapshot`  | `last`, `bid`, `ask`, full `bids`/`asks`; volume N/A                                             | `last` (mid), `bid`, `ask`, YES or NO book; volume N/A                                                    |

Kalshi candles try `/series/{series}/markets/{ticker}/candlesticks` first, then `GET /historical/markets/{ticker}/candlesticks` for archived settled markets.

***

## Trading (`venue.*`)

Same entry points: `venue.account`, `venue.positions`, `venue.balances`, `venue.history`, `venue.trade`, `venue.cancel`, `strategy.execute` / `strategy.place_limit`.

### Symbols

```python theme={null}
# Polymarket — one token_id per outcome (Yes, No, or a named outcome)
token_id = screenPolymarkets(query="bitcoin", closed=False).iloc[0]["token_ids"][0]
venue.trade("buy", token_id, 100, account="POLYMARKET")

# Kalshi — separate handles for YES and NO
row = screenKalshiMarkets(query="bitcoin", closed=False).iloc[0]
venue.trade("buy", row["symbol"], 10, account="KALSHI")       # YES
venue.trade("buy", row["symbol_no"], 5, account="KALSHI")     # NO
```

### Order types and fills

|                   | Polymarket                                                                                    | Kalshi                                                                                                                                                          |
| ----------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Market            | Walks the live CLOB; fails `EXCESSIVE_SLIPPAGE` if worst fill > cap                           | **No native market type.** Synthesizes a marketable limit, snaps to `price_ranges`, submits **IOC**. Unfilled remainder is `PARTIALLY_FILLED`, not left resting |
| Limit             | Resting GTC; tick grid (often 0.001); qty may be reduced so `qty × price` is whole cents      | Resting GTC; must sit on `price_ranges`; off-grid prices rejected                                                                                               |
| Stop / stop-limit | Not supported                                                                                 | Not supported                                                                                                                                                   |
| Default slippage  | **500 bps**                                                                                   | **50 bps**                                                                                                                                                      |
| Qty               | Fractional, typically 2 decimals; `ORDER_BELOW_MINIMUM` if too small (often ≥ \~\$1 notional) | Contracts, **min 0.01**, truncated (`ROUND_DOWN`) to 2 dp; `0.001` → 0 → rejected                                                                               |
| Sync              | Live CLOB + paper simulator block until fill or reject                                        | Place path is synchronous IOC/GTC submit                                                                                                                        |
| Paper             | `POLYMARKET_PAPER` — live book, real taker fees, virtual USDC, auto-provisioned               | **None**                                                                                                                                                        |

During the Thursday ET pause, **placement fails** (`TRADING_PAUSED`); **cancels still work**. Kalshi limit TIF is hardwired to GTC (not caller-selectable); market orders are synthesized IOC.

### `venue.account` / cash

|                    | Polymarket live                                                     | Polymarket paper                  | Kalshi                                                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Where cash lives   | `WALLET_POL` (PUSD) — exchange account is positions-only            | Virtual USDC on the paper account | USD **on the Kalshi account** (`cash`, `portfolio_value`). **`buying_power` is omitted** — Kalshi's balance API has no such field; use `cash`. Resting limits may not reduce `cash`. |
| `venue.balances()` | Wallet tokens (PUSD / USDC.E / …)                                   | Paper USDC                        | USD on-exchange                                                                                                                                                                      |
| After a fill       | On-chain lag — wait before re-reading positions                     | Immediate                         | REST portfolio; no chain lag                                                                                                                                                         |
| Dust on full sell  | Possible tiny leftover; treat `abs(market_value) < $0.10` as closed | Same simulator rounding           | Contract qty quantized to 0.01                                                                                                                                                       |

Low Polymarket buying power → chat should emit `deposit_request` with venue `POLYMARKET`. Kalshi funding is **not** a Scalar deposit card — tell the user to fund at Kalshi.

### History

| Category     | Polymarket            | Kalshi                                           |
| ------------ | --------------------- | ------------------------------------------------ |
| `trade`      | CLOB fills            | Fills                                            |
| `transfer`   | `WALLET_POL` on-chain | N/A (we never transfer)                          |
| `settlement` | N/A (use `redeem`)    | Auto-settlement rows (winning contracts pay \$1) |

Kalshi live APIs drop orders/fills older than \~3 months; Scalar merges `/historical/*` so **portfolio** history is not truncated. Public `getKalshiTrades` / `getKalshiCandles` fail over to Kalshi's historical market-data endpoints.

Kalshi trade rows use complement encoding: closing YES at \$0.43 can print as `side=sell`, `outcome=NO`, `price=0.57`, `amount=0.57`. Gross cash is `qty × (1 − recorded_price)` on that shape — `amount` is quoted notional, not proceeds. Full formulas: [Trading on Kalshi](/docs/trading/venues/kalshi).

### Cancel / replace

### Cancel / replace

Both support cancel of resting limits. Kalshi uses V2 `DELETE /portfolio/events/orders/{id}`. Unknown or already-cancelled Kalshi orders can fail with a raw HTTP 410 from a legacy V1 fallback — that is not `CANCEL_NOT_SUPPORTED`. Kalshi `replace_order` is cancel-and-replace (new broker id). Stops are unsupported on both.

***

## Settlement

**Polymarket.** After `market_end_date`, the market stops accepting orders. A closed market may still be awaiting resolution (`winning_outcome_index is None`). Winning tokens are **not** paid until `venue.trade("redeem", token_id, ...)`. Selling a resolved market fails with `MARKET_RESOLVED_USE_REDEEM`. `redeem` is Polymarket-only (`REDEEM_NOT_SUPPORTED` on Kalshi).

**Kalshi.** Winning contracts pay \$1 automatically. No redeem call. Settled positions show up in `venue.history(category="settlement")`. `venue.trade` on a closed/settled/finalized market fails with a ValueError (`… is {status} and cannot be traded`). Strategy layer may surface that as `MARKET_CLOSED`.

***

## Connect and credentials

|                        | Polymarket live                              | Kalshi                                                                       |
| ---------------------- | -------------------------------------------- | ---------------------------------------------------------------------------- |
| What the user connects | Scalar-managed Polygon wallet (`WALLET_POL`) | Their **own** Kalshi API Key ID + PEM private key (shown once on kalshi.com) |
| Storage                | Wallet material                              | Fernet-encrypted key in `kalshi_accounts`                                    |
| Disconnect             | Unlinks wallet use                           | Deletes our copy; key stays active on Kalshi                                 |
| Withdraw / transfer    | Wallet transfers via Scalar                  | Stored key is **never** granted `write::transfer`                            |
| Who holds cash         | User's Scalar wallet                         | User's Kalshi account — Scalar never deposits or withdraws                   |

Paper Polymarket needs no connect.

***

## Strategies (`strategy.*`)

|                               | Both                                                         | Polymarket-specific                     | Kalshi-specific                                          |
| ----------------------------- | ------------------------------------------------------------ | --------------------------------------- | -------------------------------------------------------- |
| `execute(symbol, target_qty)` | Idempotent target position; 24/7 sync fills                  | `symbol` = `token_id`; paper auto-funds | `symbol` = YES/NO handle from the screener; weekly pause |
| `place_limit`                 | Supported; not idempotent                                    | Tick + whole-cent qty rules             | `price_ranges` grid                                      |
| `place_stop`                  | Rejected                                                     | —                                       | —                                                        |
| Slippage arg                  | Optional on `execute`                                        | Default 500 bps                         | Default 50 bps                                           |
| Initial positions             | Claim broker holdings at approval                            | Look up `token_id` or `symbol`          | Same unified `symbol` field                              |
| Paper                         | `POLYMARKET_PAPER` in `SYNC_FILL_VENUES` (in-process ledger) | —                                       | No paper venue                                           |

***

## Fees and ticks

* **Polymarket:** Platform fee plus taker fee; `fee_bps` / `fee_amount` (and taker fields) on the trade response when active. Limit prices usually on a 0.001 grid; live CLOB may reject off-tick (`PRICE_NOT_ON_TICK`).
* **Kalshi:** Exchange `fee_cost` on fills (trade fee + rounding − rebate). `venue.trade()` may omit finalized fees (`average_fee_paid` only when `fill_count > 0`, returned as `fees` not `fee_amount`). Use `venue.history` for fee/cash accounting. Prices snapped to each market's `price_ranges` (often 0.01). Qty min 0.01 contracts, truncated to 2 dp.

Neither venue in this integration supports Kalshi-style perpetual futures / margin.

***

## Frontend vs chat

The Markets explorer (`GET /polymarket/markets` and `GET /kalshi/markets`) and chat **do not share a UI**. Both screens eventually call the same catalog functions (`screenPolymarkets` / `screenKalshiMarkets`). Chat never opens those pages; it only runs scalarlib in the notebook kernel.

***

## What to use when

* **Search a topic, then trade a probability** — same pattern on both; pick the venue the user named (or both via `searchPredictionMarkets`).
* **Copy a wallet / whale flow / leaderboard** — Polymarket only.
* **OHLC finer than 1h except 1m** — Polymarket (`5min` / `15min` / `30min`). Kalshi is 1m / 1h / 1d.
* **Practice without funding** — `POLYMARKET_PAPER`. There is no Kalshi paper.
* **USD in a CFTC venue, cash already on Kalshi** — `KALSHI`.
* **On-chain PUSD / Polygon wallet** — `POLYMARKET` + `WALLET_POL`.
* **Settle a resolved position** — `redeem` on Polymarket; wait for automatic settlement on Kalshi.

***

## Related

* [Trading on Polymarket](/docs/trading/venues/polymarket)
* [Polymarket Data](/docs/market-data/polymarket-data)
* [Trading on Kalshi](/docs/trading/venues/kalshi)
* [Kalshi Data](/docs/market-data/kalshi-data)
* [Supported Brokerages](/docs/trading/supported-brokerages)
