# Prediction Market Price History - Kalshi & Polymarket (`yawning_manuscript/prediction-market-price-history`) Actor

Historical price series for any Kalshi or Polymarket market, both exchanges normalized to one schema. OHLC candles, tick prices, and a per-market summary row so you can find the markets that moved before paying for their full history. No API keys.

- **URL**: https://apify.com/yawning\_manuscript/prediction-market-price-history.md
- **Developed by:** [SignalData](https://apify.com/yawning_manuscript) (community)
- **Categories:**
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Prediction Market Price History — Kalshi & Polymarket Time Series for Backtesting

Historical price series for any **Kalshi** or **Polymarket** market, both exchanges normalized to one schema. OHLC candles where the exchange has them, tick prices where it does not, plus a per-market summary row so you can find the markets that actually moved before paying for their full series.

Find markets by keyword — you do not need to know Kalshi's ticker syntax.

### The problem this solves

Backtesting a prediction-market strategy means answering "what was this trading at three hours before it resolved?" Getting there yourself means: learn that a Kalshi candlestick lives at `/series/{series}/markets/{ticker}/candlesticks` and that the series is the first dash-segment of the ticker; learn that Polymarket history is keyed by a CLOB token id you have to dig out of `clobTokenIds`, and that the Yes leg is not reliably index 0; then reconcile cents against dollars and OHLC against single prices.

That is an afternoon before you have written a line of strategy. This actor is that afternoon, already done.

### Output

#### `price_point`

```json
{
  "type": "price_point",
  "exchange": "kalshi",
  "market_id": "KXHIGHNY-26SEP07-B79.5",
  "question": "Will the maximum temperature be 79-80° on Sep 7, 2026?",
  "timestamp": 1788652800,
  "time_utc": "2026-09-06T00:00:00+00:00",
  "price": 0.47, "open": 0.42, "high": 0.51, "low": 0.40, "close": 0.47,
  "yes_bid": 0.46, "yes_ask": 0.48,
  "volume": 1200, "open_interest": 8800
}
```

Polymarket rows carry the same fields with `price`/`close` filled and OHLC null, so a single dataframe holds both exchanges without special-casing.

#### `market_summary`

One row per market, sorted by widest range first:

```json
{
  "type": "market_summary",
  "market_id": "KXHIGHNY-26SEP07-B79.5",
  "points": 168, "first_price": 0.20, "last_price": 0.44,
  "min_price": 0.10, "max_price": 0.65, "range": 0.55, "change": 0.24,
  "first_time_utc": "2026-09-01T00:00:00+00:00",
  "last_time_utc": "2026-09-07T23:00:00+00:00"
}
```

Turn `includePricePoints` off and you get **only** these rows — a cheap scan to find which of 200 markets are worth pulling in full. Then re-run with points on for just those.

### Example input

Everything the New York temperature series did last month, hourly:

```json
{ "kalshiSeriesTicker": "KXHIGHNY", "status": "settled",
  "historyDays": 30, "granularityMinutes": 60, "maxMarkets": 50 }
```

Cheap scan first — summaries only, no per-tick billing:

```json
{ "search": ["fed", "cpi", "rates"], "maxMarkets": 200,
  "includePricePoints": false, "includeSummary": true }
```

Exact markets, daily granularity, both exchanges:

```json
{ "kalshiTickers": ["KXHIGHNY-26SEP07-B79.5"],
  "polymarketTokenIds": ["32338220190071351435772801779725302244575775216413325951443816017994629993401"],
  "granularityMinutes": 1440, "historyDays": 365 }
```

### Pricing

| Record | Price |
|---|---|
| `price_point` | $0.0003 |
| `market_summary` | $0.002 |

A year of daily prices for 50 markets is about 18,000 points ≈ **$5.50**. A summary-only scan of 200 markets is **$0.40**.

### Pairs with

- **Kalshi & Polymarket Market Data + Cross-Exchange Price Gaps** — live prices and arbitrage gaps.
- **Weather Data for Prediction Markets** — the NWS settlement values these temperature markets resolve against. Join price history to the actual outcome and you have a labelled dataset.

### Notes and limits

- Kalshi has shipped both a nested (`price.open`) and a flat candlestick shape, and both cents and dollars. Everything is normalized to dollars in 0–1 whichever arrives.
- Polymarket returns a single price per timestamp, not OHLC.
- A market with no trading in the requested window returns no rows and is logged, not treated as an error.
- Polymarket's price API only accepts a window of about a week per request, so longer ranges are walked in week-sized chunks and stitched together for you. You can ask for a year and it just works.
- Kalshi has no title search and tens of thousands of open markets, so a keyword may not reach the ones you want. Targeting a series (`kalshiSeriesTicker`, e.g. `KXHIGHNY`) or exact tickers is the reliable path; the run warns you when a keyword finds nothing.
- Every cost is bounded by `maxMarkets` × `maxPointsPerMarket`, so a wide date range cannot surprise you.
- Discovery scanning is not billed — only the rows you receive.

### Support

Open an issue on the actor page. Requests for other exchanges or extra fields are welcome.

# Actor input Schema

## `search` (type: `array`):

Find markets whose question contains one of these, then pull history for each, e.g. "temperature", "fed", "election". Leave empty if you are giving exact tickers below.

## `exchanges` (type: `array`):

Which exchanges to search when discovering markets.

## `kalshiTickers` (type: `array`):

Full market tickers, e.g. KXHIGHNY-26SEP07-B79.5. Overrides search when set.

## `polymarketTokenIds` (type: `array`):

The Yes-leg token id of a market. Overrides search when set.

## `kalshiSeriesTicker` (type: `string`):

Restrict discovery to one series, e.g. KXHIGHNY for New York daily high temperature.

## `status` (type: `string`):

Settled markets are what you want for backtesting - you know how they resolved.

## `historyDays` (type: `integer`):

Counting back from the end date.

## `startDate` (type: `string`):

YYYY-MM-DD. Overrides Days of history.

## `endDate` (type: `string`):

YYYY-MM-DD. Defaults to now.

## `granularityMinutes` (type: `string`):

Minutes per data point. 60 = hourly, 1440 = daily. Finer granularity means more rows and more cost.

## `maxMarkets` (type: `integer`):

How many markets to pull history for.

## `maxPointsPerMarket` (type: `integer`):

Cost ceiling per market. Points are billed individually.

## `includePricePoints` (type: `boolean`):

Turn off to get only the per-market summary rows - a cheap way to find which markets moved before paying for their full series.

## `includeSummary` (type: `boolean`):

One row per market: first, last, min, max, range and change. Sorted widest range first.

## `concurrency` (type: `integer`):

How many markets to fetch history for at the same time. Lower it if the exchange rate-limits you.

## Actor input object example

```json
{
  "search": [
    "temperature"
  ],
  "exchanges": [
    "kalshi",
    "polymarket"
  ],
  "kalshiTickers": [],
  "polymarketTokenIds": [],
  "status": "any",
  "historyDays": 30,
  "granularityMinutes": "60",
  "maxMarkets": 25,
  "maxPointsPerMarket": 1000,
  "includePricePoints": true,
  "includeSummary": true,
  "concurrency": 4
}
```

# Actor output Schema

## `dataset` (type: `string`):

Every price point and market summary row this run produced.

## `csv` (type: `string`):

The same rows as a CSV, ready for a dataframe.

## `overview` (type: `string`):

The dataset with the Price points and Market summaries views.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "search": [
        "temperature"
    ],
    "kalshiTickers": [],
    "polymarketTokenIds": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("yawning_manuscript/prediction-market-price-history").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "search": ["temperature"],
    "kalshiTickers": [],
    "polymarketTokenIds": [],
}

# Run the Actor and wait for it to finish
run = client.actor("yawning_manuscript/prediction-market-price-history").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "search": [
    "temperature"
  ],
  "kalshiTickers": [],
  "polymarketTokenIds": []
}' |
apify call yawning_manuscript/prediction-market-price-history --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yawning_manuscript/prediction-market-price-history"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/f8SidhTQlO7g5pbC2/builds/P5qbZi2YbxPKTZSuS/openapi.json
