{# avoid-ai-design-ignore-file: K7 (reason follows) :focus-visible is styled for the whole site in pmlab.css #} {#- The home page. Every number on it comes from docs/assets/data/sample-run.json (see scripts/make_site_data.py), read by scripts/mkdocs_hooks.py; the quickstart is the code block of docs/index.md, which is the README's, which CI runs. Nothing here is typed in by hand. -#} {% extends "main.html" %} {% set s = config.extra.sample %} {% set h = config.extra.home %} {% set gate = s.gate %} {% block site_nav %}{% endblock %} {% block container %}

pmlab {{ config.extra.pmlab_version }}stable API · MIT · Python 3.12+

{# avoid-ai-design-ignore: SD5 (reason follows) two whole lines, solid then outlined, the hiddenterps.si headline pattern; no single word is accented #}

Prediction markets, without lookahead.

pmlab is a plugin-based ML framework for Polymarket. Write four methods for a market family; pmlab does the rest: edge and cost arithmetic, walk-forward backtests, a hard GO / NO_GO gate before anything is promoted, paper trading, and settlement that waits until the truth is final.

pip install pmlab
rolling origin · bundled sample {{ s.backtest.folds }} folds
    {% for r in h.rows %}
  1. fold {{ r.n }} {{ '%.3f' | format(r.brier) }}
  2. {% endfor %}

traintest daynot seen


brier by fold, lower is better ({{ '%.3f' | format(h.spark_range[0]) }} to {{ '%.3f' | format(h.spark_range[1]) }})

folds
{{ s.backtest.folds }}
trades
{{ s.backtest.trades }}
brier
{{ '%.4f' | format(s.backtest.brier) }}
gate
{{ gate.decision }}

Synthetic sample: {{ s.sample.markets }} markets, {{ s.sample.cities }} cities, {{ s.sample.days }} days, no network. It says nothing about real markets.

signals
    {% for copy in range(2) %}{% for g in s.signals %}

It will not look ahead, or ship a loser.

Enforced in code and checked by the test suite, not left to convention. Each claim below links to the page that shows how.

  1. No lookahead.

    rolling_origin_eval trains only on rows from before the day it predicts. build_panel refuses a price seen at or after the decision it informs, and check_no_leakage raises when a feature gives the outcome away.

    fold  1  train {{ s.backtest.train_start }} → {{ h.first_fold.train_end }}  test {{ h.first_fold.test }}
    fold {{ s.backtest.folds }}  train {{ s.backtest.train_start }} → {{ h.last_fold.train_end }}  test {{ h.last_fold.test }}  ({{ h.last_fold.train_rows }} rows)
    How the checks work
  2. A failed gate cannot ship.

    ChampionManifest.publish raises unless the gate says GO, and that is not configurable. On the sample the gate reads every city, one of them loses money, and publishing is refused. Scope the champion to the cities that pass and it publishes, with that scope recorded in champion.json.

      {% for c in h.cities %}
    • {{ c.segment }} {{ '%+.2f' | format(c.pnl) }} {{ 'ok' if c.passes else c.reason }}
    • {% endfor %}
    ValueError: {{ gate.publish_refused }}
    The champion registry
  3. Reproducible.

    Every backtest records its seeds, library versions, resolved config and a fingerprint of the data. pmlab reproduce re-runs it and verifies that the metrics come back.

    reproduce → {{ s.reproduce.status }}  data match: {{ 'yes' if s.reproduce.data_match else 'no' }}  metrics compared: {{ s.reproduce.metrics_compared }}
    Reproducibility
  4. Frozen API.

    From 1.0 pmlab follows semantic versioning. What is public is compared with a checked-in snapshot on every change, and nothing public is removed before 2.0 without a deprecation warning that names the replacement.

    {{ s.api.names }} public names in {{ s.api.modules }} modules · {{ s.api.commands }} CLI commands · tests/api/public_api.json
    What is public
  5. Five rules, in code.

    A champion is never published with a NO_GO gate. Canonical training data is never overwritten without an explicit flag. Workspaces are never mixed: live forward evidence and training data stay apart. The champion's segment gate is always read from champion.json, the record made at promotion. A trade is never settled before MarketPlugin.is_truth_final says the truth is final.

    Architecture

Run it in a minute.

Offline, on a small synthetic sample that ships in the package: no network, no account, no order placed. The code is the README's, and CI runs it.

{{ page.content }}
{% endblock %}