Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
- name: Example help smoke
run: |
uv run predxt --help
uv run predxt demo --help
uv run predxt explore --help
uv run predxt parse-fixture --help
uv run predxt stream polymarket --help
uv run python examples/polymarket_market_stream.py --help
Expand All @@ -65,6 +67,10 @@ jobs:
/tmp/predxt-smoke/bin/python - <<'PY'
from importlib.metadata import version
from pathlib import Path
import json
import subprocess
import sys
import tempfile
import tomllib

import predxt
Expand All @@ -77,4 +83,13 @@ jobs:

assert version("predxt") == project_version
assert predxt.__version__ == project_version
with tempfile.TemporaryDirectory() as demo_dir:
result = subprocess.run(
[sys.executable, "-m", "predxt.cli", "demo", "--json"],
cwd=demo_dir, check=True, capture_output=True, text=True,
)
demo = json.loads(result.stdout)
assert demo["synthetic"] is True
assert demo["best_bid"] == 0.42
assert demo["best_ask"] == 0.44
PY
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

All notable changes to `predxt` are documented here.

## 0.3.0

- add `predxt demo`, a built-in synthetic orderbook example that works without
network access or repository fixtures
- add `predxt explore polymarket` to search, explicitly select a market/outcome,
read a bounded REST snapshot, and print the corresponding WebSocket command
- fix Polymarket text search to use Gamma public-search and flatten/deduplicate
event markets; add keyword-only `active_only` filtering and reject nonpositive limits
- document installation and first-run errors, and verify the offline demo from
an installed wheel outside the source checkout

## 0.2.2 - 2026-09-11

- fixed graceful websocket stream exhaustion for Polymarket, Kalshi, and
Expand Down
63 changes: 36 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ not a trading, execution, account, or financial-advice library.
## Install

```bash
pip install predxt
pip install "predxt>=0.3.0"
```

For local development:
Expand All @@ -25,39 +25,42 @@ uv sync --group dev
uv run pytest -q -s
```

## 60-second Polymarket demo
## Your first orderbook

Polymarket market websockets are public. Use any valid Polymarket CLOB asset id:
This walkthrough requires Python 3.12 or later and predxt 0.3.0 or later.

Start with a built-in synthetic example. It works from any directory, with no
credentials, files to download, or network connection:

```bash
predxt stream polymarket --asset-id 1234567890 --limit 5 --jsonl
predxt demo
```

Or from Python:

```python
import asyncio

from predxt.polymarket import PolymarketWsClient


async def main() -> None:
client = PolymarketWsClient()
await client.connect()
await client.subscribe(
["market"],
{"assets_ids": ["1234567890"], "initial_dump": True},
)
```text
SYNTHETIC DEMO — no network requests
Market: Example market
Outcome: Yes
BID PRICE SIZE | ASK PRICE SIZE
0.4200 100 | 0.4400 80
0.4100 50 | 0.4500 120
Spread: 0.0200
```

async for message in client.messages():
print(message.event_type, message.asset_id, message.raw_data)
break
Then find a real Polymarket market by name and choose its outcome:

await client.close()
```bash
predxt explore polymarket --query "bitcoin"
```

Choose a market number and an outcome number at the prompts. The CLI reads a
REST snapshot, displays the top five levels on each side, and prints a ready-to-run
WebSocket command for that outcome. Public Polymarket market data needs no API key.
Each API request has a 10-second deadline; empty results and unavailable markets
produce a clear message. The snapshot's fetch time is local receipt time.

asyncio.run(main())
```
See the [first-run guide](docs/first-run.md) for scriptable selection, JSON output,
and troubleshooting. Kalshi and Opinion remain available through the existing
REST and WebSocket clients.

## Venue matrix

Expand Down Expand Up @@ -131,7 +134,13 @@ do not need to access private task attributes.

## CLI

Offline parser demo:
Built-in demo:

```bash
predxt demo --json
```

Parse a fixture from a repository checkout:

```bash
predxt parse-fixture --venue polymarket --jsonl tests/fixtures/polymarket_order_books.json
Expand Down Expand Up @@ -182,5 +191,5 @@ uv run twine check dist/*

## Release

Releases use SemVer and tags like `v0.1.0`. See
Releases use SemVer and tags in the `vX.Y.Z` format. See
[`docs/releasing.md`](docs/releasing.md).
22 changes: 22 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
# CLI

## First run

The first-run commands require predxt 0.3.0 or later:

```bash
pip install "predxt>=0.3.0"
```

```bash
predxt demo
predxt demo --json
predxt explore polymarket --query "bitcoin"
```

`demo` is synthetic and never connects to a venue. `explore` asks you to select
a market and outcome, displays one REST snapshot, and prints a WebSocket command.
Use `--market-id ID --outcome-index N --json` for noninteractive selection.
`--timeout` sets the deadline for each API request (10 seconds by default).
See [Your first orderbook](first-run.md).

## Parse offline fixtures

This command uses a fixture from the repository checkout:

```bash
predxt parse-fixture --venue polymarket --jsonl tests/fixtures/polymarket_order_books.json
```
Expand Down
96 changes: 96 additions & 0 deletions docs/first-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Your first orderbook

The commands below require Python 3.12 or later and predxt 0.3.0 or later:

```bash
pip install "predxt>=0.3.0"
```

## 1. See a result without credentials or network

```bash
predxt demo
```

This displays a **synthetic** two-sided book. Its best bid is 0.42, best ask is
0.44, and spread is 0.02. These are example values, not market quotes. The demo
is included in the installed package and works outside the repository.

To inspect the structured output:

```bash
predxt demo --json
```

The output includes `synthetic: true`, the book, and best bid/ask. No network
client is created, and no source-checkout fixture is required.

## 2. Find a real market

```bash
predxt explore polymarket --query "bitcoin"
```

In an interactive terminal, the command:

1. Searches Polymarket's public Gamma API and lists up to ten open orderbook markets.
2. Asks for the market number you want to inspect.
3. Fetches current details and asks for an outcome number.
4. Uses that outcome's token ID to fetch its CLOB orderbook.
5. Prints the top five bid/ask levels and a command for streaming WebSocket events.

The display is one REST snapshot, not a continuously updating monitor. The fetch
time is measured locally when the response arrives; it is not a guarantee that
the venue's quote is fresh. An empty or one-sided book is shown explicitly.

The printed `predxt stream` command includes the chosen token ID. Copy it to
receive normalized events and raw payloads. It stops after five messages;
an inactive stream may wait, so use Ctrl-C to stop it manually.

## 3. Use the result in a script

The selection menus go to stderr. Pass a Gamma market ID from the search results
and a **1-based** outcome index to skip interactive prompts:

```bash
predxt explore polymarket --market-id "$MARKET_ID" --outcome-index 1 --json
```

Set `MARKET_ID` to the market you selected. The JSON response includes
`synthetic: false`, the market title, outcome label, normalized snapshot,
best bid/ask, and the snapshot's original `raw_data`. It emits one JSON document
on stdout. Inspect outcome labels in the interactive view before selecting by index.

Gamma market IDs identify questions; CLOB token IDs identify the individual
outcomes whose orderbooks you read. The CLI handles that distinction for you.

## Network and selection errors

- Each API request has a wall-clock deadline, defaulting to 10 seconds. Change it
with `--timeout 5`. Human selection time is separate from request timeouts.
- Empty results: try a different query. The command reads the first search page;
it does not crawl the whole catalog or guarantee exhaustive results.
- Closed markets or incomplete outcome identifiers: select a different market.
Details are checked again after selection because market status can change.
- HTTP 403 or other API errors: check venue availability. The command exits with
an error and suggests `predxt demo`; it never substitutes synthetic output for
a live result automatically.
- Without a terminal, the search prints market IDs and explains how to pass
`--market-id` and `--outcome-index`. It does not guess your selections.

Success returns exit code 0, API/selection errors return 1, invalid command-line
arguments return 2, and interrupting the interactive flow returns 130.

## Python search

`PolymarketRestClient.search_markets(query, limit=20, active_only=False)` uses
Gamma's documented `/public-search` endpoint for non-empty queries, flattens
the nested event markets, and removes duplicate market IDs. `active_only=True`
requests active results and filters out closed or unconfirmed-active rows.
An empty query lists markets through `/markets`. `limit` must be positive.

Responses retain the existing `MarketSummary` model and each raw market row.
Use `get_market(market_id)` for outcome labels and token IDs, then
`get_orderbook(token_id)` for that outcome's snapshot.

Source: [Polymarket search API](https://docs.polymarket.com/api-reference/search/search-markets-events-and-profiles).
21 changes: 10 additions & 11 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,23 @@ advice.
## Quick install

```bash
pip install predxt
pip install "predxt>=0.3.0"
```

## Quick stream
## First orderbook

These commands require Python 3.12 or later and predxt 0.3.0 or later.

```bash
predxt stream polymarket --asset-id 1234567890 --limit 5 --jsonl
predxt demo
predxt explore polymarket --query "bitcoin"
```

## Quick REST snapshot

```python
from predxt.polymarket import PolymarketRestClient
`demo` shows a labelled synthetic orderbook with no network access. `explore`
lets you select a real market and outcome, shows a REST snapshot, then prints
a WebSocket command with the selected token ID already filled in.

client = PolymarketRestClient()
book = await client.get_orderbook("CLOB_TOKEN_ID")
await client.close()
```
Read the [first-run guide](first-run.md) for expected output and error handling.

## Core model

Expand Down
39 changes: 30 additions & 9 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

`predxt` uses SemVer. Release tags use the `vX.Y.Z` format.

## First release
## Prepare the release

1. Confirm the version in `pyproject.toml` and `src/predxt/__init__.py`.
2. Update `CHANGELOG.md`.
1. Update the version in `pyproject.toml` and `src/predxt/__init__.py` together.
Run `uv lock --offline` and check that only the local `predxt` package version
changed in `uv.lock`.
2. Add a versioned entry to `CHANGELOG.md`. Update installation requirements in
the README, first-run docs, and LLM guidance when new commands require the release.
3. Run local validation:

```bash
Expand All @@ -15,28 +18,46 @@
uv run pytest -q -s
uv build
uv run twine check dist/*
uv run mkdocs build --strict
```

4. Push `main`.
5. Confirm PyPI Trusted Publishing is configured:
4. Install the built wheel in a fresh environment and run `predxt demo --json`
from outside the repository. Confirm its version matches the release and
its output is marked synthetic. Test `predxt explore polymarket` against the
public API when first-run behavior changes; record any external API failure
separately from the local tests.
5. Open the release PR and verify CI on the final commit. Keep dependency upgrades
separate from a version-only release preparation.

## Publish

After the release PR is merged and CI passes on `main`:

1. Confirm PyPI Trusted Publishing is configured:

- PyPI project name: `predxt`
- Owner: `hzprotocol`
- Repository: `predxt`
- Workflow: `release.yml`
- Environment: `pypi`

6. Create and push a tag:
2. From a clean checkout of the released `main`, create and push the tag matching
the package version. The tag push starts the release workflow:

```bash
git tag v0.1.0
git push origin v0.1.0
release_version=$(uv run python -c "import predxt; print(predxt.__version__)")
git tag "v${release_version}"
git push origin "v${release_version}"
```

7. The release workflow builds distributions first. The publish job waits for
3. The release workflow builds distributions first. The publish job waits for
the GitHub `pypi` environment approval, then creates the GitHub release and
publishes to PyPI with Trusted Publishing.

4. Confirm the GitHub release and exact PyPI version exist. Install that version
in a fresh environment and run the offline demo. Check that the published
documentation shows the matching first-run instructions before sharing them.

## PyPI

Use PyPI Trusted Publishing for GitHub Actions. Configure the PyPI project named
Expand Down
Loading