Prediction markets put a price on questions like "Will the Fed hike in December?" or "How many rate cuts this year?". On Kalshi, a regulated US prediction market, each contract pays $1 if the outcome happens, so a price of $0.70 reads as roughly a 70% chance. If you follow macro news, build forecasting models or just want to see how the market's view changed after a speech or a data release, you want those prices in a table, with a history.

Kalshi has a public market data API, and it's free. The work is in the glue. The API has no text search, so to find "every Fed market" you page through events and their nested markets and filter them yourself. Prices come back as dollar strings in fields like yes_bid_dollars. Price candles need the series ticker as well as the market ticker, and one candle request returns at most 5,000 candles, so longer histories need several windows. None of this is hard, but it's an afternoon of code before you see your first chart.

This tutorial uses an Apify Actor that does that part and hands you flat rows you can load straight into pandas.

Disclosure: I built and maintain this Actor. It is a paid tool ($1.00 per 1,000 results). I've tried to be as clear about what it can't do as about what it can.

What you can do with the data

  • Track one question over time. Pull daily candles for every outcome of "Fed decision in Dec 2026?" and plot how the odds moved.
  • Screen a whole category. Get the 100 most traded Economics or Crypto markets with bid, ask, spread, 24h volume and open interest.
  • Build your own odds history. Run a snapshot on a schedule and append it to a CSV or database. The scrapedAt field tells you when each row was taken.

Step 1: Set up a run in Apify Console

Open Kalshi Markets Scraper and click Try for free. The main fields:

Field What it does
What to scrape (mode) markets (current odds, volume, open interest), trades (executed trades) or priceHistory (OHLC candles). Default markets.
Search keywords (searchTerms) Keeps markets whose title, outcome or ticker contains one of the keywords, e.g. fed or bitcoin.
Categories (categories) Kalshi categories such as Economics, Crypto, Politics, Sports.
Market status (status) open (default), closed, settled or all.
Sort by (sortBy) volume24h (default), volume, openInterest, closingSoon or none (fastest).
Max results (maxItems) Default 100.
Market / Event / Series tickers (marketTickers, eventTickers, seriesTickers) Target exact markets instead of searching. Market tickers are required for price history. kalshi.com URLs work too.
Closes within (days) (closesWithinDays) Only markets that close soon.
Include order book (includeOrderbook) Adds bid levels. One extra request per market, so slower.
Candle interval (candleInterval) and History length (days) (historyDays) For price history: 1, 60 or 1440 minutes, up to 3,650 days back. Defaults 1440 and 30.

No Kalshi account or API key is needed.

Step 2: Run it and export

For this article I ran two small jobs. The first one searched for fed in the Economics category:

{ "searchTerms": ["fed"], "categories": ["Economics"], "maxItems": 20, "includeRules": false } 

It scanned all open markets and saved the 20 most traded matches in about 50 seconds. Here is one of them, with a few fields removed (values unchanged):

{ "marketTicker": "KXRATECUTCOUNT-26DEC31-T0", "eventTicker": "KXRATECUTCOUNT-26DEC31", "seriesTicker": "KXRATECUTCOUNT", "title": "Will the Fed cut rates 0 times?", "outcome": "Exactly 0 cuts", "eventTitle": "Number of rate cuts in 2026?", "category": "Economics", "status": "active", "impliedProbability": 0.956, "yesBid": 0.955, "yesAsk": 0.957, "spread": 0.002, "lastPrice": 0.957, "previousPrice": 0.963, "priceChange": -0.006, "volume": 2946424.88, "volume24h": 8391.93, "openInterest": 1158040.04, "closeTime": "2027-01-01T04:59:00Z", "mutuallyExclusive": true, "url": "https://kalshi.com/markets/kxratecutcount", "scrapedAt": "2026-11-02T13:25:39Z" } 

impliedProbability is the midpoint between the best yes bid and ask (or the last trade if the book is one-sided). The most traded market in the sample was "Hike 25bps" in the "Fed decision in Dec 2026?" event, at 0.695, with "Fed maintains rate" at 0.285.

The second job pulled 30 days of daily candles for that "Hike 25bps" market:

{ "mode": "priceHistory", "marketTickers": ["KXFEDDECISION-26DEC-H25"], "candleInterval": "1440", "historyDays": 30 } 

It took about 3 seconds and saved 30 candles. One of them:

{ "marketTicker": "KXFEDDECISION-26DEC-H25", "seriesTicker": "KXFEDDECISION", "periodMinutes": 1440, "periodEnd": "2026-10-29T04:00:00Z", "open": 0.74, "high": 0.83, "low": 0.73, "close": 0.78, "volume": 153342.99, "openInterest": 289294.14 } 

This candle covers October 28, the day of the October Fed decision. Volume jumped to about 153K contracts from about 12K the day before, and open interest went from about 167K to about 289K. The price touched 0.83 and closed at 0.78, then closed at 0.70 the next day. A single snapshot would have missed all of that, which is why the history mode is worth having.

Step 3: Do it from Python

pip install apify-client pandas matplotlib 

First get every outcome of one event, then the daily history of each outcome:

from apify_client import ApifyClient import pandas as pd client = ApifyClient("YOUR_APIFY_TOKEN") actor = client.actor("pipiagent/kalshi-markets-scraper") # 1. Current odds for every outcome of the December Fed decision run = actor.call(run_input={ "eventTickers": ["KXFEDDECISION-26DEC"], "sortBy": "none", "includeRules": False, }) markets = pd.DataFrame(client.dataset(run.default_dataset_id).iterate_items()) print(markets.sort_values("impliedProbability", ascending=False)[ ["outcome", "impliedProbability", "yesBid", "yesAsk", "volume24h", "openInterest"] ]) # 2. Daily candles for the last 90 days of each outcome run = actor.call(run_input={ "mode": "priceHistory", "marketTickers": markets["marketTicker"].tolist(), "candleInterval": "1440", "historyDays": 90, "maxItems": 2000, }) candles = pd.DataFrame(client.dataset(run.default_dataset_id).iterate_items()) candles["periodEnd"] = pd.to_datetime(candles["periodEnd"]) names = dict(zip(markets["marketTicker"], markets["outcome"])) close = candles.pivot(index="periodEnd", columns="marketTicker", values="close").rename(columns=names) print(close.tail(10)) close.plot(title="Fed decision in Dec 2026: daily close by outcome") # Days with unusual volume, per outcome volume = candles.pivot(index="periodEnd", columns="marketTicker", values="volume").rename(columns=names) print(volume[volume > 3 * volume.median()].dropna(how="all")) 

The last block flags days when volume was more than three times the usual level. On my 30-day test of the "Hike 25bps" market, it picked out October 15 and the run of days around the October meeting.

To build your own snapshot history, schedule the first call (for example every hour in Apify's scheduler) and append each run to a file with markets.to_csv("fed_odds.csv", mode="a", header=False, index=False).

What it costs

You pay per saved result: $1.00 per 1,000 results. One market, one trade or one candle is one result. There is no start fee and no monthly rental, and filters run before saving, so you don't pay for markets you filtered out.

  • My two test runs: 20 markets ($0.02) and 30 candles ($0.03).
  • 90 days of daily candles for 5 outcomes (450 candles): $0.45.
  • An hourly snapshot of the top 100 markets: 2,400 results a day, $2.40 a day.

You can also set a maximum charge per run in the run options, and the Actor stops when it reaches that amount.

Limitations

  • Keyword search is a simple text match. A market is kept when its title, outcome, ticker or event title contains your keyword, so short keywords can catch unrelated markets. Adding a category, as above, keeps results clean.
  • A full scan takes about a minute. Searching all 100,000+ open markets takes time (50 seconds in my test). With tickers or sortBy: "none" it finishes in seconds.
  • Ticker inputs skip the filters. If you give market or event tickers, you get those markets as they are; keyword and category filters don't apply.
  • Auto-generated parlay markets are left out. If you need those, this Actor isn't the right tool.
  • Order books show bids only. That's how Kalshi books work: a yes ask at price X is the same order as a no bid at 1 - X.
  • History is candles, not snapshots of every field. Candles give open, high, low, close, mean, closing bid and ask, volume and open interest per period. For spread or order book history, schedule snapshot runs.
  • It's read-only. It can't place trades.

Related tools

To see what news moved a market, Google News Scraper exports articles by keyword with date ranges, so you can line up headlines with the volume spikes. If you follow companies rather than macro events, SEC EDGAR Scraper exports filings and financial statements.

The input form and more examples are on the Kalshi Markets Scraper store page. If something doesn't work the way this article says, open an issue there and I'll look into it.