Skip to content

mostlyright.markets.polymarket

Polymarket discovery + settlement (US + international).

Public surface:

  • discover() — Gamma API discovery, no auth.
  • settle(event_id)() — settlement engine using internal mostlyright.international.daily_extremes() as the resolution source.

Input validation, all enforced before any HTTP fetch or daily-extremes call:

  • event_id must match the id pattern ([A-Za-z0-9_-]{1,128}).
  • description capped at 16 KB (Polymarket descriptions are concise; oversized payloads indicate hostile input).
  • Resolution-source URLs in the description must resolve to a netloc in RESOLUTION_SOURCE_ALLOWLIST (Wunderground or weather.gov).

Taipei and Hong Kong-lowest markets raise mostlyright.international.DeferredMarketError: this SDK has no CWA or HKO client to read their settlement values from.

AttributeDescription
RESOLUTION_SOURCE_ALLOWLISTNetloc allowlist for Polymarket resolution-source URLs.
POLYMARKET_RESOLUTION_SOURCE_TYPESEnum values for the resolution_source_type column on settlement records.
labelThe polymarket.label namespace singleton (polymarket.label.settlement(...)).
FunctionDescription
candles(url_or_slug, *, side, interval, …)Read one Polymarket outcome’s bucketed price history over a window.
discover(*[, client, sleep_between, …])Discover active Polymarket WEATHER-EVENT markets for the settlement pipeline.
events(*[, status, event, all])Browse Polymarket events — the top tier of this venue’s hierarchy.
market(url_or_slug)Look a Polymarket market up by slug or by a pasted polymarket.com link.
markets(*[, event, status, all])List Polymarket markets, narrowed by event or status.
orderbook(url_or_slug, *, side)Read one Polymarket outcome’s resting book as it stands right now.
series(*args, **kwargs)Always raises: Polymarket has no series tier.
settle(event_id, *[, description, event, …])Resolve a Polymarket weather event to its settlement payload.
settlement_days(entity, from_date, to_date, *)The bare Polymarket settlement-day grid (train == live — the skew guard).
trades(url_or_slug, *, from_time, to_time[, …])Read a Polymarket market’s executed prints over a window.
training_table(entity, from_date, to_date, *)Polymarket leakage-free supervised table over the label="daily_extremes" target.
ExceptionDescription
PolymarketEventError([message, error_code, …])Polymarket event payload is malformed (bad UUID, bad URL, oversized).
PolymarketSettlementError([message, …])Settlement engine couldn’t resolve an event to a bucket.
PolymarketStrikeError([message, error_code, …])A Polymarket event’s contract strike could not be parsed from slug/title.
TooEarlyToSettleError([message, request_id, …])Settlement attempted before the resolution-source’s finalization delay.

mostlyright.markets.polymarket.POLYMARKET_RESOLUTION_SOURCE_TYPES : tuple[str, …]

Section titled “mostlyright.markets.polymarket.POLYMARKET_RESOLUTION_SOURCE_TYPES : tuple[str, …]”

Enum values for the resolution_source_type column on settlement records. hko and cwa name the Hong Kong Observatory and Taiwan CWA sources, for which this SDK has no client yet.

exception mostlyright.markets.polymarket.PolymarketEventError(message=”, , error_code=None, source=None, request_id=None)

Section titled “exception mostlyright.markets.polymarket.PolymarketEventError(message=”, , error_code=None, source=None, request_id=None)”

Bases: MostlyrightError

Polymarket event payload is malformed (bad UUID, bad URL, oversized).

  • Parameters:
    • message (str)
    • error_code (str)
    • source (str | None)
    • request_id (str | None)
  • Return type: None

Subclass override — the stable string enum surfaced via error_code.

exception mostlyright.markets.polymarket.PolymarketSettlementError(message=”, , error_code=None, source=None, request_id=None)

Section titled “exception mostlyright.markets.polymarket.PolymarketSettlementError(message=”, , error_code=None, source=None, request_id=None)”

Bases: MostlyrightError

Settlement engine couldn’t resolve an event to a bucket.

Reasons: no buckets parseable from description, daily_extremes returned no rows for the resolution station/date, or the parsed value didn’t match any bucket.

  • Parameters:
    • message (str)
    • error_code (str)
    • source (str | None)
    • request_id (str | None)
  • Return type: None

Subclass override — the stable string enum surfaced via error_code.

exception mostlyright.markets.polymarket.PolymarketStrikeError(message=”, , error_code=None, source=None, request_id=None)

Section titled “exception mostlyright.markets.polymarket.PolymarketStrikeError(message=”, , error_code=None, source=None, request_id=None)”

Bases: MostlyrightError

A Polymarket event’s contract strike could not be parsed from slug/title.

outcome=True needs the strike to binarize the observed value; a market with no parseable above/below/between <n><C|F> clause cannot be settled to 0/1 and this error is raised loudly (never a silent 0/1).

  • Parameters:
    • message (str)
    • error_code (str)
    • source (str | None)
    • request_id (str | None)
  • Return type: None

Subclass override — the stable string enum surfaced via error_code.

Netloc allowlist for Polymarket resolution-source URLs. Anything else raises PolymarketEventError to prevent silent settlement against an unknown / hostile source.

exception mostlyright.markets.polymarket.TooEarlyToSettleError(message=”, , wait_hours, resolution_source_type, request_id=None, error_code=None)

Section titled “exception mostlyright.markets.polymarket.TooEarlyToSettleError(message=”, , wait_hours, resolution_source_type, request_id=None, error_code=None)”

Bases: MostlyrightError

Settlement attempted before the resolution-source’s finalization delay.

Carries the wait time so the caller can schedule a retry.

  • Parameters:
    • message (str)
    • wait_hours (float)
    • resolution_source_type (str)
    • request_id (str | None)
    • error_code (str)
  • Return type: None

Subclass override — the stable string enum surfaced via error_code.

mostlyright.markets.polymarket.candles(url_or_slug, , side, interval, from_time, to_time)

Section titled “mostlyright.markets.polymarket.candles(url_or_slug, , side, interval, from_time, to_time)”

Read one Polymarket outcome’s bucketed price history over a window.

Paste the link from the post you are reading, or type the slug, and name the side you mean. On this venue a price series belongs to an outcome token rather than to a market, so the slug alone is not enough — the pair is resolved to a token id internally (_resolve_side_token()), and the pasted link is parsed offline and never fetched.

There is no volume here, and none is invented. The venue’s price endpoint serves a timestamp and a price and nothing else, so volume_contracts and open_interest are NULL on every row and there is deliberately no column named volume. Absent is not zero: a 0.0 would assert that nothing traded in that bucket, which the venue never said. The eight bid/ask columns are NULL for the same reason — this endpoint quotes no book.

The candle is flat by construction. The venue serves a LAST PRICE per bucket, not an open/high/low/close, so open, high, low and close all carry that one number. A flat candle here is the data, not a bug.

“*_native“ equals its probability column. Polymarket’s native unit already IS a probability in [0, 1], so there is nothing to convert. The column exists so a frame from this venue and a frame from Kalshi — whose native unit is cents — concatenate without either side losing its own magnitude.

Timestamps are bucket STARTS, as served. This venue stamps a bucket with its start where Kalshi stamps the period end, so nothing is subtracted here; the Kalshi verb subtracts its interval instead and the two frames agree. That the served t is a start rather than an end is a documented assumption; this SDK has not verified it against a settled market.

You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.

  • Parameters:
    • url_or_slug (str) – A Polymarket market slug ("new-rhianna-album-before-gta-vi-926") or a polymarket.com market link. The link is parsed offline and never dereferenced.
    • side (str) – The outcome you want the price series for, as the venue names it ("yes" / "no", or an option label). Case-insensitive.
    • interval (str) – Bucket width — "1m", "1h" or "1d". It reaches the venue as its fidelity parameter, in minutes.
    • from_time (datetime) – tz-aware UTC bounds; from_time must be strictly earlier than to_time.
    • to_time (datetime) – tz-aware UTC bounds; from_time must be strictly earlier than to_time.
  • Return type: DataFrame
  • Returns: A schema.markets.candles.v2 frame, one row per bucket, ascending by bucket_start_utc. The column set is the same one the Kalshi verb returns, so the two concatenate. A window the venue has no ticks for returns an empty frame carrying the full column set, never None and never [].
  • Raises:
    • ContractErrorurl_or_slug does not identify a single market (an EVENT-level link is refused before any request – an event groups many markets and a price series belongs to one), or side is not one of the market’s outcomes.
    • SchemaValidationError – the market’s outcome and token arrays disagree in length, so no side can be resolved safely.
    • TypeError – either bound is a naive datetime.
    • ValueErrorfrom_time is not earlier than to_time.
    • UnsupportedResolutionErrorinterval is outside the supported set. Raised before any request.
>>> from datetime import UTC, datetime
>>> window = candles(
... "new-rhianna-album-before-gta-vi-926",
... side="yes",
... interval="1h",
... from_time=datetime(2026, 6, 1, tzinfo=UTC),
... to_time=datetime(2026, 6, 2, tzinfo=UTC),
... )
>>> window["close"].between(0, 1).all()
True

mostlyright.markets.polymarket.discover(, client=None, sleep_between=None, backend=‘pandas’, return_type=‘dataframe’)

Section titled “mostlyright.markets.polymarket.discover(, client=None, sleep_between=None, backend=‘pandas’, return_type=‘dataframe’)”

Discover active Polymarket WEATHER-EVENT markets for the settlement pipeline.

Not the same verb as mostlyright.discover(), which searches the cross-domain catalog and answers with catalog entries. This one is venue-local and weather-only: it walks the Gamma event feed, keeps the events whose city resolves to a settlement station, and returns the settlement metadata the Polymarket settle path needs. To browse the venue hierarchy generally — every category, not just weather — use events() and markets().

  • Parameters:
    • client (Client | None) – Optional httpx.Client for connection reuse.
    • sleep_between (float | None) – Optional per-request politeness sleep. Tests should pass 0 to skip the delay. Default uses the client module’s built-in 0.2s.
    • backend (str)
    • return_type (str)
  • Return type: DataFrame
  • Returns: pd.DataFrame with one row per active weather event. Requires the [polymarket] extra (raises SourceUnavailableError otherwise). Columns:
    • event_id (str): Polymarket event id.
    • slug (str): Polymarket slug.
    • title (str): event title.
    • city (str | None): lowercased city key from polymarket_city_stations.json if a match was found, else None.
    • icao (str | None): resolved ICAO for the city (high vs low aware), or None if no city / unknown city.
    • temperature_extreme (str | None): "high" / "low" / "ambiguous" per the per-event resolver, or None if unresolved.
    • end_time (str | None): event.endDate ISO timestamp.
    • resolution_source_type (str | None): wunderground / noaa_wrh / other from the description URL.
  • Raises:
    • httpx.HTTPStatusError – Gamma API returned non-2xx.
    • SourceUnavailableError[polymarket] extra not installed.

mostlyright.markets.polymarket.events(, status=None, event=None, all=False)

Section titled “mostlyright.markets.polymarket.events(, status=None, event=None, all=False)”

Browse Polymarket events — the top tier of this venue’s hierarchy.

An event groups the markets one question resolves across, and on this venue it is where a browse starts: there is no series above it. The series_ticker column is NULL on every row for exactly that reason — see series(), which says so out loud.

status is not a field Polymarket serves. It is derived from the venue’s own closed / active / acceptingOrders booleans into the same four words the other venue uses, so one filter reads across both (_GAMMA_STATUS_MAP is the whole mapping).

  • Parameters:
    • status (str | None) – One of open / closed / settled / unopened. Rows are matched on the DERIVED status, so the answer never contains a row that reads differently from what was asked for.
    • event (str | None) – An event slug, or a pasted polymarket.com event link, to fetch exactly. The link is parsed offline and never dereferenced.
    • all (bool) – Accept every event the venue lists. Required when no other filter is given — see the error raised in that case.
  • Return type: DataFrame
  • Returns: A schema.markets.events.v1 frame, one row per event, with open_time / close_time as tz-aware UTC instants. A query that matches nothing returns an empty frame with the full column set, never None.
  • Raises:
    • ContractError – No filter and no all=True, an invalid status, or an event that is not a recognisable slug or link.
    • RuntimeError – The keyset walk hit the client’s page ceiling. It is deliberately not caught: a capped walk and a complete one must not look alike.

The polymarket.label namespace singleton (polymarket.label.settlement(...)).

mostlyright.markets.polymarket.market(url_or_slug)

Section titled “mostlyright.markets.polymarket.market(url_or_slug)”

Look a Polymarket market up by slug or by a pasted polymarket.com link.

Paste the link from the post you are reading, or type the slug — both identify the same contract and return the same row.

The pasted link is NEVER fetched. It is parsed offline for host and path shape, the slug is pulled out of it, and the venue request is built from the resolved API address, so a lookalike host cannot steer a request anywhere.

An event-level link returns MORE THAN ONE ROW. Polymarket links come in two shapes, /event/{event}/{market} and the bare /event/{event}, and the second one is what people usually have to hand: it is the link the site shows and the link that gets shared. Refusing it would send the caller back to the site to find a narrower one, which defeats the point of accepting a link at all. So an event link resolves the event and returns every market under it, and this verb’s singular name is a promise about what you ASK for, not about how many rows come back. Read len(frame) if that matters to you, or pass the market-level link to guarantee one row.

The returned row carries outcomes and outcome_token_ids as two positionally aligned comma-joined lists, which is the hand-off to the verbs that want a side: pick the outcome name you mean from the first, and its token id is at the matching position in the second.

An unknown slug raises the venue’s 404 rather than returning an empty frame. “No such market” and “no data” are different answers and this verb will not conflate them.

  • Parameters: url_or_slug (str) – A Polymarket market slug ("new-rhianna-album-before-gta-vi-926"), a market link (/event/{event}/{market} or /market/{market}), or an event link (/event/{event}).
  • Returns: one row for a market reference, one row per market on the event for an event link.
  • Return type: A schema.markets.listing.v1 frame
  • Raises:
    • ContractErrorurl_or_slug is not a recognised slug or a canonical polymarket.com link. Raised before any request exists.
    • httpx.HTTPStatusError – The venue does not serve that slug.

mostlyright.markets.polymarket.markets(, event=None, status=None, all=False)

Section titled “mostlyright.markets.polymarket.markets(, event=None, status=None, all=False)”

List Polymarket markets, narrowed by event or status.

This is the fetch half of find-then-fetch: it returns exactly what the caller names, where mostlyright.discover() searches the catalog fuzzily across domains. (The other discover on this module, discover(), is the venue-local weather-event verb — a third thing again.)

Each row carries outcomes and outcome_token_ids as two comma-joined, POSITIONALLY ALIGNED lists, which is what a caller needs to pick a side before asking for a book or a price history. Token ids stay STRINGS: a CLOB token id is roughly 77 digits, and reading one as a number drops its low-order digits without raising anything.

When those two arrays disagree in length the record cannot be aligned at all, and this verb emits outcomes with outcome_token_ids NULL. A listing is a browse: one malformed market should not poison a whole page, and a null says truthfully that the pairing is unknown. The verbs that RESOLVE a side raise on the same input instead, because there an unnoticed misalignment would put a price on the wrong outcome.

Prices are probabilities in [0, 1] so a frame from this venue and a frame from the other can be concatenated and compared with no unit conversion at the call site. volume_usd here is venue-served — it is Gamma’s own volumeNum, not a figure computed here — unlike the trade-tape column of the same name, which is derived as size times price. The Kalshi-only columns (series_ticker, volume_contracts, open_interest) are NULL: this venue serves no such value, and absent is not zero.

Polymarket’s API answers browser requests directly, which the other venue’s does not — relevant if you are building a dashboard rather than a notebook. See docs/market-data-browser-support.md.

You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.

  • Parameters:
    • event (str | None) – An event slug, or a pasted polymarket.com event link, whose markets to return. The link is parsed offline and never dereferenced.
    • status (str | None) – One of open / closed / settled / unopened, derived from the venue’s booleans (see events()).
    • all (bool) – Accept the full unnarrowed universe. Required when no other filter is given — see the error raised in that case.
  • Return type: DataFrame
  • Returns: A schema.markets.listing.v1 frame, one row per market. A query that matches nothing returns an empty frame with the full column set.
  • Raises:
    • ContractError – No filter and no all=True, an invalid status, or an event that is not a recognisable slug or link.
    • RuntimeError – The keyset walk hit the client’s page ceiling, which is deliberately not caught.
>>> book = markets(event="what-will-happen-before-gta-vi")
>>> book["last_price"].between(0, 1).all()
True

mostlyright.markets.polymarket.orderbook(url_or_slug, , side)

Section titled “mostlyright.markets.polymarket.orderbook(url_or_slug, , side)”

Read one Polymarket outcome’s resting book as it stands right now.

The frame is LONG: one row per price level, with side and level naming where that row sits. That shape is what lets this book and a book from another venue concatenate into one frame and stay unit-honest — a nested bid/ask column pair would have to invent a fill rule for the side with fewer levels, and would silently pair a bid with an unrelated ask. level is 0 at the touch (the highest bid, the lowest ask) and counts outward, assigned here rather than trusted from the wire so the ordering is identical however the venue happened to sort its arrays.

A book belongs to an outcome token, which is why side is required and not optional: asking for “the book” of a market would mean two different books. Note that the side ARGUMENT selects the outcome, while the side COLUMN says bid or ask within that one outcome’s book — the two are different axes that happen to share the venue’s word.

A book is a point-in-time read. There is no historical book tier — a past book cannot be reconstructed from a past price — so captured_at is one instant, identical across the whole frame. It is the venue’s own snapshot stamp when it serves one, and the client clock when it does not.

Prices are probabilities in [0, 1] and price_native equals price: this venue’s native unit already IS probability.

You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.

  • Parameters:
    • url_or_slug (str) – A Polymarket market slug or a polymarket.com market link. The link is parsed offline and never dereferenced.
    • side (str) – The outcome whose book you want, as the venue names it. Case-insensitive.
  • Return type: DataFrame
  • Returns: A schema.markets.orderbook.v2 frame, one row per level. An outcome with no resting orders returns an empty frame carrying the full column set, never None and never [].
  • Raises:
    • ContractErrorurl_or_slug does not identify a single market (an EVENT-level link is refused before any request – an event groups many markets and a price series belongs to one), or side is not one of the market’s outcomes.
    • SchemaValidationError – the market’s outcome and token arrays disagree in length, so no side can be resolved safely.

mostlyright.markets.polymarket.series(*args, **kwargs)

Section titled “mostlyright.markets.polymarket.series(*args, **kwargs)”

Always raises: Polymarket has no series tier.

Kalshi groups its recurring contracts into a series above the event, so markets.kalshi.series() is where a browse of that venue starts. Polymarket has no such tier at all — its hierarchy is Event -> Market, and an event is already the top. Start with events() instead.

This verb exists rather than being omitted so the difference is discoverable. A missing attribute teaches nothing; a shared grammar with a silent hole in it teaches something false.

Every argument is accepted and ignored, so a caller copying a Kalshi call across gets the lesson rather than a complaint about a keyword.

  • Raises: VenueCapabilityError – Always. Carries venue, capability, and remedy, and subclasses ContractError, so it is raised before any I/O and existing contract handlers still catch it.
  • Return type: NoReturn
  • Parameters:

mostlyright.markets.polymarket.settle(event_id, , description=None, event=None, client=None, now=None)

Section titled “mostlyright.markets.polymarket.settle(event_id, , description=None, event=None, client=None, now=None)”

Resolve a Polymarket weather event to its settlement payload.

  • Parameters:
    • event_id (str) – Polymarket event identifier (validated at the boundary).
    • description (str | None) – Optional event description. If passed, used in place of the upstream payload (lets tests skip the HTTP call). Still subject to the 16 KB cap + URL allowlist.
    • event (dict[str, Any] | None) – Optional preloaded event payload (skips the HTTP call entirely). When omitted, fetched from Gamma by event_id.
    • client (Client | None) – Optional httpx.Client for connection reuse.
    • now (datetime | None) – Override wall-clock for tests. Defaults to datetime.now(UTC).
  • Returns:
    • event_id (str), slug (str), title (str)
    • settlement_date (str, YYYY-MM-DD station-local).
    • icao (str), temperature_extreme (str): resolution station + high/low.
    • resolution_source_type (str)
    • observed_value_c (float): the relevant daily low or high from daily_extremes().
    • observation_count (int): hourly observation count backing the value.
    • observed_source (str): provenance of the observed extreme, from the daily_extremes row.
    • country: pass-through from the daily_extremes row.
  • Return type: Settlement payload dict with
  • Raises:
    • PolymarketEventError – invalid event_id format, oversized description, or resolution URL outside the allowlist.
    • ContractError – a Tier-1.5 URL station is denylisted / city-inconsistent / non-registry — refused rather than settling against the wrong station or leaking a bare KeyError.
    • DeferredMarketError – resolves to Taipei / HK-low, whose CWA / HKO settlement source has no client in this SDK.
    • PolymarketSettlementError – settlement date unparseable, or daily_extremes returned no usable row.
    • TooEarlyToSettleError – not enough time has passed since the resolution date for the source to have published.
    • httpx.HTTPStatusError – Gamma API returned non-2xx when no event was provided.

mostlyright.markets.polymarket.settlement_days(entity, from_date, to_date, , station_override=None)

Section titled “mostlyright.markets.polymarket.settlement_days(entity, from_date, to_date, , station_override=None)”

The bare Polymarket settlement-day grid (train == live — the skew guard).

Two positional dates (inclusive ends). entity is the Polymarket event id (a UUID/slug — not a station). station_override= pins the settlement station directly, bypassing event resolution and the network; otherwise the event’s station is resolved via the shipped resolver. The grid is one row per LST settlement day with no y columns.

Every returned row keeps its originating entity (the event id) as the leading column (before station and the date day field), so concatenating several events never collapses provenance — each day stays attributable to the event that minted it.

The caller names the contract; PIT-correct rolling-feature transforms are out of scope (computed inside sources or by users downstream at their own risk).

  • Return type: DataFrame
  • Parameters:
    • entity (str)
    • from_date (str)
    • to_date (str)
    • station_override (str | None)

mostlyright.markets.polymarket.trades(url_or_slug, , from_time, to_time, side=None)

Section titled “mostlyright.markets.polymarket.trades(url_or_slug, , from_time, to_time, side=None)”

Read a Polymarket market’s executed prints over a window.

Where candles() bucketizes, this returns the tape itself: one row per fill, oldest first. The window is half-open — a print exactly at from_time is in, a print exactly at to_time is not — and the bounds are the same tz-aware from_time / to_time grammar every window-scoped verb in the SDK uses.

“side“ is optional here, unlike on the other two verbs. The tape serves every outcome of a market in one stream, so a caller who names no side gets the whole tape with each row’s own outcome in the side column. Naming one filters to it — and an outcome this market does not offer RAISES rather than quietly returning an empty tape, because “no trades” and “no such outcome” are different answers.

The tape endpoint is addressed by “conditionId“, not by a CLOB token id. That is the reverse of the price-history and book endpoints on the same venue, and passing the wrong identifier class returns an empty array rather than an error — so the two are resolved separately and each verb sends the one its endpoint documents.

“volume_usd“ here is DERIVED, not venue-served. The venue’s size is a count of shares/contracts and it publishes no USD notional per fill, so this column is size_contracts * price, computed here. size_contracts and price both travel on the row so the arithmetic is auditable rather than hidden, and the column is NULL whenever either input is missing — a partially-known notional is not a notional. Note that the identically named column on the LISTING frame is the opposite: there it is Gamma’s own lifetime figure, served by the venue.

“side“ carries the OUTCOME, not the taker direction. The venue also publishes a BUY / SELL field; that is a different axis, and the shared cross-venue trade vocabulary does not carry it.

You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.

  • Parameters:
    • url_or_slug (str) – A Polymarket market slug or a polymarket.com market link. The link is parsed offline and never dereferenced.
    • from_time (datetime) – tz-aware UTC bounds; from_time must be strictly earlier than to_time. The filter is applied here rather than by the venue, which accepts no window on this endpoint.
    • to_time (datetime) – tz-aware UTC bounds; from_time must be strictly earlier than to_time. The filter is applied here rather than by the venue, which accepts no window on this endpoint.
    • side (str | None) – An outcome to filter to, as the venue names it. Case-insensitive. Omitted, every outcome’s prints come back.
  • Return type: DataFrame
  • Returns: A schema.markets.trades.v2 frame, one row per fill, ascending by traded_at. A quiet window returns an empty frame carrying the full column set, never None and never [].
  • Raises:
    • ContractErrorurl_or_slug does not identify a single market (an EVENT-level link is refused before any request), or side is not one of the market’s outcomes.
    • SchemaValidationError – the market’s outcome and token arrays disagree in length, so the named side cannot be checked safely.
    • TypeError – either bound is a naive datetime.
    • ValueErrorfrom_time is not earlier than to_time.
    • RuntimeError – The tape ran past the client’s page cap. Narrow the window rather than raising the cap — this verb does not swallow it, because a truncated tape that reads as a complete one is worse than an error.

mostlyright.markets.polymarket.training_table(entity, from_date, to_date, , outcome=False, event=None, features=None)

Section titled “mostlyright.markets.polymarket.training_table(entity, from_date, to_date, , outcome=False, event=None, features=None)”

Polymarket leakage-free supervised table over the label="daily_extremes" target.

A thin delegator with no duplicated join logic. entity is the Polymarket event id. It resolves the event’s settlement station from the Gamma payload, then forwards the whole feature-composition + join to core research.dataset with label="daily_extremes" (Polymarket weather markets resolve on the WU/NOAA-WRH daily extremes, not the NWS CLI product). Two positional dates.

This is the markets analogue of weather.training_table(); the old polymarket.dataset() name is a deprecation shim routing here — dataset is reserved for the catalog noun.

Offline on every path. Station resolution needs the Gamma event payload, but training_table makes no live Gamma round-trip in either outcome mode — the caller supplies the payload via event=, symmetric with Kalshi’s market=. When event= is absent it raises a typed ContractError naming that argument. Fetch the payload yourself with the opt-in markets.polymarket.fetch_event_by_id() and pass it as event=. With outcome=True the per-settlement-date loop reuses that single cached payload for every settle() call — still no network.

  • Parameters:
    • entity (str) – The Polymarket event id (validated at the boundary).
    • from_date (str) – YYYY-MM-DD window bounds (forwarded verbatim).
    • to_date (str) – YYYY-MM-DD window bounds (forwarded verbatim).
    • outcome (bool) – When True, append a binary label_outcome (Int64, 0/1/NA) column — see the comparison rule in _settle_polymarket_strike(). Requires the daily_extremes label frame (the core DataFrame path) and the event’s strike (parsed from the slug/title).
    • event (dict[str, Any] | None) – The preloaded Gamma event payload, required (station resolution and the outcome loop both read it). There is no auto-fetch; when omitted, training_table raises a typed ContractError naming this argument. There are no client / now injection parameters; tests mock the module-level settle / fetch_event_by_id instead.
    • features (list[str] | tuple[str, ...] | None) – Extra core feature names.
  • Return type: DataFrame
  • Returns: The core dataset(label="daily_extremes", ...) frame plus, when outcome=True, the label_outcome column.
  • Raises:
    • ContractErrorevent= is absent (the payload is required; there is no hidden Gamma fetch).
    • PolymarketEventError / DeferredMarketError / PolymarketSettlementError /
    • PolymarketStrikeError – per the settlement + strike-parse contract.