# Kalshi Weather Price History (`danthedataman/kalshi-weather-price-history`) Actor

Read hourly or daily candles for up to 12 named Kalshi weather markets in a UTC window of up to 48 hours. Export prices, bids, asks, volume and open interest as exact decimal strings, with event and response provenance.

- **URL**: https://apify.com/danthedataman/kalshi-weather-price-history.md
- **Developed by:** [Eli J](https://apify.com/danthedataman) (community)
- **Categories:** Developer tools, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Kalshi Weather Price History

### What Kalshi Weather Price History does

Export **Kalshi weather price history**: hourly or daily candlestick price
history for Kalshi markets in the Climate and Weather category. Name up to 12
markets, a UTC window of up to 48 hours and a period of 60 or 1440 minutes:
each candle the public Kalshi Trade API returns for that window becomes one
flat typed dataset row, with prices, bids, asks, volume and open interest kept
as the exact decimal strings the source sent.

#### How each market is read

A run that names at least one market reads Kalshi's historical cutoff once.
Then, market by market in input order, it reads the live market detail (and,
only when that answers 404, the historical market detail), the market's own
event and that event's series. A market whose series' primary category is not
exactly `Climate and Weather` gets no candle request. A market that settled
before the cutoff is read from the historical candle route; any other market is
read from the live candle route. An event or series is read once per run and
shared by every market that belongs to it.

#### Rows per market

One row per candle the source actually returned, in input order and ascending
`endPeriodTs`. Both window bounds select candles by their end time, inclusively,
so a first period can begin before `startTime`. A 48-hour window holds at most
49 hourly or 3 daily candle ends, so one market yields at most 49 hourly or 3
daily rows. Actual counts are usually lower and depend on the source, which can
skip periods: the prefilled market and window returned 35 hourly candles when
captured. A skipped period is never filled in and no price is inferred.

### How to export Kalshi weather price history

1. Name the Kalshi market tickers in `marketTickers`, at most 12.
2. Set `startTime` and `endTime` in UTC, as `YYYY-MM-DDTHH:MM:SSZ`, at most 48
   hours apart.
3. Choose `periodInterval`: `60` for hourly or `1440` for daily candles.
4. Start the run.
5. Read the candle rows from the run's default dataset, and any failures from
   its `ERRORS` key-value record.

Two public example tasks carry ready inputs for one Austin weather market:
[hourly candles](https://apify.com/danthedataman/kalshi-weather-price-history/examples/kalshi-austin-july-2026-hourly-candles)
and
[daily candles](https://apify.com/danthedataman/kalshi-weather-price-history/examples/kalshi-austin-daily-price-candles).

### Pricing

#### How much does it cost to export Kalshi weather-market candles?

A run is charged per dataset row plus the platform's automatic
`apify-actor-start` event, which is charged separately when the run starts; an
empty or invalid input still incurs that start event. The number of start
events depends on the run's memory, one event per GB with a minimum of one
event, and the default run memory is 512 MB, so a run at the default memory is
charged one start event. A failure, note or notice is never a dataset row, so
it is never charged as one. One market's rows come to at most 49 hourly or 3
daily dataset rows before the start event, and actual counts are usually lower.
Each row and each start event is charged at the rate in the current Pricing
section of this Actor's Apify Store listing.

### Input

| Field | Type | Prefill | Rule |
| --- | --- | --- | --- |
| `marketTickers` | array | `["KXHIGHAUS-26JUL12-T97"]` | Kalshi market tickers, read in the order given. At most 12 entries, counted before duplicates are removed; the first occurrence of a ticker wins. Each entry is used exactly as typed: 1 to 200 uppercase ASCII letters, digits, dots or hyphens, starting with a letter or digit. |
| `startTime` | string | `2026-07-11T14:00:00Z` | Window start in UTC, written exactly as `YYYY-MM-DDTHH:MM:SSZ` with a real calendar date and time. Required when a market is named. |
| `endTime` | string | `2026-07-13T05:59:00Z` | Window end in the same format: later than `startTime`, at most 172800 seconds (48 hours) after it, and not later than the moment the run starts. Required when a market is named. |
| `periodInterval` | integer | `60` | Candle period in minutes: `60` for hourly or `1440` for daily candles. Required when a market is named. |

No field has a default. With no market named and every supplied field valid,
the run makes no request and writes no rows.

A malformed input is reported by field name only: the run fails before any
request, and its `ERRORS` record names the field and the rule it broke, never
the value you sent.

The hourly example task uses the four prefills as its input:

```json
{
  "marketTickers": ["KXHIGHAUS-26JUL12-T97"],
  "startTime": "2026-07-11T14:00:00Z",
  "endTime": "2026-07-13T05:59:00Z",
  "periodInterval": 60
}
```

The daily example task differs only in `periodInterval` `1440`.

#### Requests and time

Every request is one GET to the public Kalshi Trade API, counted before it is
sent. Nothing is retried and no redirect is followed.

- The prefilled market, with the live detail answering: 5 requests (cutoff,
  live detail, event, series and candles).
- The same market when the live detail answers 404 and the historical detail
  is read instead: 6 requests.
- Whatever the input: at most 61 requests, 1 for the cutoff plus up to 5 per
  market for 12 markets; a shared event or series only lowers the count.

Request starts are at least 3 seconds apart, so a 61-request run has at least
180 seconds between its first and last start. That is a bound on the span of
the starts, not time added on top of response durations: a response slower
than 3 seconds needs no extra wait.

Each request has a configured 30-second timeout for each blocking operation,
such as the connection attempt. It is a blocking operation timeout, not a
whole-response deadline. The platform's default run timeout is 300 seconds,
and a long run is not guaranteed to finish within it.

### Output

One row per candle in the default dataset, `recordType` `marketCandle`, with 41
columns. Prices, bids and asks are USD decimal strings with up to 6 decimal
places, and volume and open interest are contract counts with 2 decimal places;
each is kept exactly as the source sent it and never converted to a number or
rounded.

When captured, the hourly example input returned 35 rows and the daily example
input returned 2; source responses determine actual counts.

An excerpt of one hourly row from the example input, showing only the columns
whose values that input fixes:

```json
{
  "recordType": "marketCandle",
  "marketTicker": "KXHIGHAUS-26JUL12-T97",
  "periodInterval": 60,
  "priceCurrency": "USD",
  "quantityUnit": "contracts"
}
```

| Column | Type | Meaning |
| --- | --- | --- |
| `recordType` | string | Literal `marketCandle` |
| `rowKey` | string | `<marketTicker>:<periodInterval>:<endPeriodTs>`, unique per row |
| `marketTicker` | string | The market ticker you named |
| `eventTicker` | string | The market's event ticker |
| `seriesTicker` | string | The event's series ticker |
| `eventTitle` | string | Event title, as returned |
| `yesSubTitle` | string | YES subtitle, as returned |
| `strikeType` | string or null | Source text, not interpreted |
| `marketStatus` | string | Market status, as returned |
| `marketResult` | string | Market result, as returned; an empty string is kept |
| `settlementTs` | string or null | Settlement time, verbatim source text |
| `settlementValueDollars` | string or null | USD decimal string: the YES/LONG contract payout, not observed weather |
| `expirationValue` | string | Source settlement text, verbatim, not a labelled temperature; an empty string is kept |
| `marketDetailRoute` | string | `live` or `historical`: the detail request that answered |
| `marketCapturedAt` | string | UTC receipt time of that market detail, `YYYY-MM-DDTHH:MM:SSZ` |
| `eventSettlementSources` | array or null | The market's own event's settlement sources, members `{name, url}` as returned |
| `eventCapturedAt` | string | UTC receipt time of the event; markets sharing an event share its first receipt time |
| `candleRoute` | string | `live` or `historical`: the candle route this run's cutoff selected |
| `historicalCutoffTs` | string | This run's historical cutoff, verbatim |
| `periodInterval` | integer | Candle period in minutes, `60` or `1440` |
| `endPeriodTs` | integer | Unix seconds: the inclusive end of the candle period |
| `periodEnd` | string | The same instant as `YYYY-MM-DDTHH:MM:SSZ` |
| `priceOpen` | string or null | Open price, USD decimal string |
| `priceHigh` | string or null | High price, USD decimal string |
| `priceLow` | string or null | Low price, USD decimal string |
| `priceClose` | string or null | Close price, USD decimal string |
| `priceMean` | string or null | Mean price, USD decimal string |
| `pricePrevious` | string or null | Previous price, USD decimal string, under the definition of the route that answered |
| `yesBidOpen` | string | YES bid open, USD decimal string |
| `yesBidHigh` | string | YES bid high, USD decimal string |
| `yesBidLow` | string | YES bid low, USD decimal string |
| `yesBidClose` | string | YES bid close, USD decimal string |
| `yesAskOpen` | string | YES ask open, USD decimal string |
| `yesAskHigh` | string | YES ask high, USD decimal string |
| `yesAskLow` | string | YES ask low, USD decimal string |
| `yesAskClose` | string | YES ask close, USD decimal string |
| `volume` | string | Volume in contracts, decimal string |
| `openInterest` | string | Open interest in contracts, decimal string |
| `priceCurrency` | string | Literal `USD` |
| `quantityUnit` | string | Literal `contracts` |
| `candlesCapturedAt` | string | UTC receipt time of that market's candle response |

#### Null prices

A null price is a source null or an omitted optional live value; it does not by
itself establish that no trade occurred. The historical route documents its
open, high, low, close and mean prices as null if no trades occurred, while the
live route says only that they may be null if there was no trade during the
period, and a live candle can omit a price key while keeping other trading
values. No price is filled in, carried forward or inferred from bids, asks or
volume.

`pricePrevious` follows the definition of the route that answered, and neither
definition is a missing open, high, low or close:

- Historical candle route: "Close price from the previous candlestick period (in dollars). Null if this is the first candlestick or no prior trade exists."
- Live candle route: "Last traded YES contract price on the market before the candlestick period (in dollars). May be null if there were no trades before the period."

#### Settlement fields

`expirationValue` is the source's settlement text, kept verbatim. It is not a
labelled temperature, and this Actor does not parse a temperature out of it.

`settlementValueDollars` is the YES/LONG contract payout as a USD decimal
string, not an observed weather value.

### Related Actors

| Actor | Fit | What it exports |
| --- | --- | --- |
| [UFCStats Fight & Round Stats](https://apify.com/danthedataman/ufcstats-fight-round-stats) | Fight and round statistics | UFCStats fight and round statistics as flat rows with fighter IDs, event dates and locations, from event or fight URLs; CSV or JSON. |
| [Tennis Abstract Data API](https://apify.com/danthedataman/tennis-abstract-data-api) | Tennis match history | ATP and WTA player match histories from Tennis Abstract, including scores, opponents, surfaces and available serve and return statistics, filtered by season, surface or head-to-head opponent; JSON, CSV or Excel. |
| [Google Trends Data API](https://apify.com/danthedataman/google-trends-data-api) | Keyword interest | Google Trends interest over time, interest by region and related/rising queries for your keywords, location and date range, plus the Trending Now board by country; JSON, CSV or Excel. |
| [Clutch Scraper: Agency Directory](https://apify.com/danthedataman/clutch-agency-directory) | Agency research | B2B agency listings from Clutch.co directories: company names, websites, ratings, review counts, locations, rates, headcounts and service mix; JSON, CSV or Excel. |
| [Google Ads Archive: Ads Transparency Export](https://apify.com/danthedataman/google-ads-archive) | Ad-creative research | Advertiser ad records from Google's Ads Transparency Center: creative format, available images, first and last shown dates and source links, for selected advertisers and a region; JSON, CSV or Excel. |

### FAQ and support

#### Does it export daily and hourly candles?

Yes. Set `periodInterval` to `60` for hourly or `1440` for daily candles; no
other period is accepted.

#### How many markets and how long a window can one run read?

Up to 12 markets, counted before duplicates are removed, and a window of at
most 172800 seconds (48 hours) from `startTime` to `endTime`.

#### Why are some prices null?

A null price is a source null or an omitted optional live value, not by itself
proof that no trade occurred; nothing is filled in. `pricePrevious` follows the
definition of the route that answered. Both are described under Null prices in
the Output section.

#### Are `expirationValue` and `settlementValueDollars` measured weather?

No. `expirationValue` is the source's settlement text, kept verbatim and not
parsed into a temperature, and `settlementValueDollars` is the YES/LONG contract
payout, not an observed weather value.

#### Is a run that names no market charged?

A run with no market named makes no request and writes no rows, so no row is
charged, but the platform's `apify-actor-start` event is still charged.

#### When a market produces no rows

Failures are never dataset rows. Each one is recorded in the run's `ERRORS`
key-value record as an object with exactly four keys, `target`, `id`,
`errorClass` and `message`, and the key-value store schema lists every class.
Per market, `market-not-found`, `event-not-found`, `series-not-found`,
`not-weather`, `candles-not-found`, `blocked`, `transport` and
`unreadable-response` are failures, and `no-candles` is a note, not a failure,
for a market whose candle request returned an empty list. At run level,
`invalid-input` and `cutoff-unavailable` fail the run before any market is read,
while `rate-limited` (the source answered HTTP 429), `request-ceiling` and
`charge-limit` are notices that stop further requests and end the run normally;
a `rate-limited` or `request-ceiling` notice names the markets it left
unprocessed.

The run log reports markets selected, markets with rows, markets with no
candles, markets failed, rows pushed and requests sent. Rows are counted as
delivered, never as offered, and when the platform does not report how many
rows the last push delivered, the log says that count is unknown.

#### Data rights

The data comes from Kalshi's public Trade API. Kalshi's
[Data Terms of Service](https://kalshi-public-docs.s3.amazonaws.com/kalshi-data-terms-of-service.pdf)
and
[Developer Agreement](https://assets.kalshi.com/Kalshi-Developer-Agreement.pdf)
restrict commercial redistribution, AI/ML use and API data sharing without
written authorization from Kalshi. This Actor grants no data-use rights and does
not confirm that your use is permitted; you are responsible for your use of the
data.

Developer Agreement section 6.4 also says "You must obtain prior written approval from Kalshi prior to releasing any statements"
relating to Kalshi or its API, including promotional or marketing materials.
That is an additional unresolved conflict, recorded here as a disclosure, not
as permission. Disclosing these conflicts does not cure them.

This Actor reads no page behind a login, uses no credential and writes nothing
back to the source.

#### Support

Report a problem or ask a question in the Issues tab of this Actor's Apify
Store page.

# Changelog

This Actor's version history is a separate document: https://apify.com/danthedataman/kalshi-weather-price-history/changelog.md

# Actor input Schema

## `marketTickers` (type: `array`):

Kalshi market tickers to read, for example <code>KXHIGHAUS-26JUL12-T97</code>. At most 12 entries, counted before duplicates are removed; the first occurrence of a ticker wins and markets are read in that order. Each entry is used exactly as typed: 1 to 200 uppercase ASCII letters, digits, dots or hyphens, starting with a letter or digit, with no trimming and no case change. Only markets whose series carries the primary category Climate and Weather produce rows. Left empty, the run makes no request and writes no rows.

## `startTime` (type: `string`):

Start of the UTC window, written exactly as <code>YYYY-MM-DDTHH:MM:SSZ</code>. Candles are selected by their end time: a candle ending at or after this moment is included, so the first period can begin before it. Required when a market is named.

## `endTime` (type: `string`):

End of the UTC window, in the same format. A candle ending at or before this moment is included. It must be later than <b>Window start</b>, at most 172800 seconds (48 hours) after it, and not later than the moment the run starts. Required when a market is named.

## `periodInterval` (type: `integer`):

Candle period in minutes: <code>60</code> for hourly candles or <code>1440</code> for daily candles. No other value is accepted. Required when a market is named.

## Actor input object example

```json
{
  "marketTickers": [
    "KXHIGHAUS-26JUL12-T97"
  ],
  "startTime": "2026-07-11T14:00:00Z",
  "endTime": "2026-07-13T05:59:00Z",
  "periodInterval": 60
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `errors` (type: `string`):

Per-market failures, no-candles notes and run-level notices, when there are any; never result rows.

# 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 = {
    "marketTickers": [
        "KXHIGHAUS-26JUL12-T97"
    ],
    "startTime": "2026-07-11T14:00:00Z",
    "endTime": "2026-07-13T05:59:00Z",
    "periodInterval": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("danthedataman/kalshi-weather-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 = {
    "marketTickers": ["KXHIGHAUS-26JUL12-T97"],
    "startTime": "2026-07-11T14:00:00Z",
    "endTime": "2026-07-13T05:59:00Z",
    "periodInterval": 60,
}

# Run the Actor and wait for it to finish
run = client.actor("danthedataman/kalshi-weather-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 '{
  "marketTickers": [
    "KXHIGHAUS-26JUL12-T97"
  ],
  "startTime": "2026-07-11T14:00:00Z",
  "endTime": "2026-07-13T05:59:00Z",
  "periodInterval": 60
}' |
apify call danthedataman/kalshi-weather-price-history --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,danthedataman/kalshi-weather-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/vQ8GNbNqeaCJOL4rA/builds/yf0fcZnpbgNZdQbAG/openapi.json
