Skip to content

Market data

Mostly Right 3.0 uses the same market-data verbs and row fields for Kalshi and Polymarket. Prices are probabilities from 0 to 1, venue-native values remain available in *_native fields, and every row names the venue endpoint that served it.

Terminal window
pip install mostlyrightmd-markets
pnpm add @mostlyrightmd/markets

| Verb | Returns | | --- | --- | | series() | Contract families. Kalshi only. | | events() | Events under those families | | markets() | Individual listed contracts | | market() | One contract selected by ticker, slug, or pasted venue URL | | candles() | Bucketed prices over a time window | | trades() | One row per fill | | orderbook() | The current resting book |

Polymarket has no series tier. polymarket.series() raises VenueCapabilityError and points you to polymarket.events().

from datetime import UTC, datetime
from mostlyright.markets import kalshi, polymarket
kalshi_prices = kalshi.candles(
"KXHIGHNY-26MAY29-T85",
interval="1h",
from_time=datetime(2026, 5, 20, tzinfo=UTC),
to_time=datetime(2026, 5, 30, tzinfo=UTC),
)
polymarket_prices = polymarket.candles(
"highest-temperature-in-nyc-on-may-29",
side="Yes",
interval="1h",
from_time=datetime(2026, 5, 20, tzinfo=UTC),
to_time=datetime(2026, 5, 30, tzinfo=UTC),
)

Both frames use schema.markets.candles.v2 and the same 23 columns. You can concatenate them without renaming fields.

Use the venue modules for the rest of the grammar:

open_markets = kalshi.markets(series="KXHIGHNY", status="open")
fills = kalshi.trades(
"KXHIGHNY-26MAY29-T85",
from_time=datetime(2026, 5, 20, tzinfo=UTC),
to_time=datetime(2026, 5, 30, tzinfo=UTC),
)
book = polymarket.orderbook(
"highest-temperature-in-nyc-on-may-29",
side="Yes",
)

Listing calls require a filter. Pass all=True only when you deliberately want the venue’s full listing response.

The same verbs ship from @mostlyrightmd/markets/market-data in camel case. Returned row keys remain snake case.

import {
kalshiCandles,
kalshiTrades,
polymarketCandles,
polymarketOrderbook,
} from "@mostlyrightmd/markets/market-data";
const kalshiPrices = await kalshiCandles("KXHIGHNY-26MAY29-T85", {
interval: "1h",
fromTime: new Date("2026-05-20T00:00:00Z"),
toTime: new Date("2026-05-30T00:00:00Z"),
});
const polymarketPrices = await polymarketCandles(
"highest-temperature-in-nyc-on-may-29",
{
side: "Yes",
interval: "1h",
fromTime: new Date("2026-05-20T00:00:00Z"),
toTime: new Date("2026-05-30T00:00:00Z"),
},
);
const fills = await kalshiTrades("KXHIGHNY-26MAY29-T85", {
fromTime: new Date("2026-05-20T00:00:00Z"),
toTime: new Date("2026-05-30T00:00:00Z"),
});
const book = await polymarketOrderbook(
"highest-temperature-in-nyc-on-may-29",
{ side: "Yes" },
);
  • candles() and trades() use half-open windows: from_time <= t < to_time.
  • Candle intervals are 1m, 1h, or 1d. Other values raise UnsupportedResolutionError.
  • Prices use probabilities from 0 through 1. Kalshi cents remain in the corresponding *_native field.
  • Volume fields name their unit: volume_contracts and volume_usd. There is no ambiguous volume field.
  • Missing venue data is null, never an invented zero.
  • orderbook() returns the current book. The SDK does not create book history or place orders.

Kalshi automatically tries the live API first and switches to the historical tier only when the live tier returns 404. Rows record kalshi or kalshi.historical as the source. Deep historical requests no longer return a placeholder empty frame.

Polymarket’s Gamma, CLOB, and Data API hosts allow browser requests. Kalshi rejects requests carrying a non-Kalshi Origin, including extension origins, so Kalshi calls need Node, your server, or a proxy. Chrome extension host_permissions do not change that server-side rejection.