From 7f2bad27e7aef92456eeff5d5cd25c63c945df67 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:42:11 -0500 Subject: [PATCH 1/8] build(examples): lint and type-check the examples package Add `examples` to ruff `src` and pyright `include` so the example scripts are linted and strictly type-checked alongside `src`/`tests`. --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e860d9f..aaf8c66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,7 @@ markers = [ [tool.ruff] line-length = 100 target-version = "py311" -src = ["src", "tests"] +src = ["src", "tests", "examples"] [tool.ruff.lint] select = [ @@ -109,7 +109,7 @@ quote-style = "double" indent-style = "space" [tool.pyright] -include = ["src", "tests"] +include = ["src", "tests", "examples"] pythonVersion = "3.11" typeCheckingMode = "strict" venvPath = "." From 06b10b693f682d1bee3e1eff1dabe37b0bbd7c0c Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:09:37 -0500 Subject: [PATCH 2/8] feat(examples): add shared env, market, and table helpers Helpers shared across the example scripts: `require_env` for required env vars, `find_order_example_market` to locate a live order-book market, and Node `console.table`-style printers for output parity with the ts-sdk examples. --- examples/__init__.py | 0 examples/lib/__init__.py | 0 examples/lib/env.py | 17 +++++++++++ examples/lib/markets.py | 51 ++++++++++++++++++++++++++++++++ examples/lib/tables.py | 63 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 examples/__init__.py create mode 100644 examples/lib/__init__.py create mode 100644 examples/lib/env.py create mode 100644 examples/lib/markets.py create mode 100644 examples/lib/tables.py diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/lib/__init__.py b/examples/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/lib/env.py b/examples/lib/env.py new file mode 100644 index 0000000..e409d95 --- /dev/null +++ b/examples/lib/env.py @@ -0,0 +1,17 @@ +"""Environment helpers for the examples. + +The SDK does not load `.env` at runtime, so examples read credentials straight +from the environment. Export them in your shell (or `source` a `.env`). +""" + +from __future__ import annotations + +import os + + +def require_env(name: str) -> str: + """Return the environment variable, or exit with a clear message if unset.""" + value = os.environ.get(name, "").strip() + if not value: + raise SystemExit(f"{name} is required — set it in your environment to run this example.") + return value diff --git a/examples/lib/markets.py b/examples/lib/markets.py new file mode 100644 index 0000000..5de5065 --- /dev/null +++ b/examples/lib/markets.py @@ -0,0 +1,51 @@ +"""Find a live, tradable market for the order examples. + +Port of the ts-sdk `findOrderExampleMarket` helper: scan liquid markets and +return the first binary market that has an order book, is accepting orders, has +a usable price band, and a non-empty book. +""" + +from __future__ import annotations + +from polymarket import Market, PolymarketError, PublicClient, SecureClient + +# Either client exposes the read methods this helper needs. +MarketLookupClient = PublicClient | SecureClient + + +def find_order_example_market(client: MarketLookupClient) -> Market: + """Return a liquid, order-book-enabled binary market suitable for order examples.""" + paginator = client.list_markets( + closed=False, + liquidity_num_min=1000, + page_size=1000, + order="liquidityNum", + ascending=False, + sports_market_types=["moneyline", "spreads", "totals"], + ) + for candidate in paginator.iter_items(): + if _is_order_example_candidate(client, candidate): + return candidate + raise SystemExit("Could not find a live market for the order example.") + + +def _is_order_example_candidate(client: MarketLookupClient, market: Market) -> bool: + token_id = market.outcomes.yes.token_id + if ( + market.state.enable_order_book is not True + or market.state.accepting_orders is False + or market.trading.minimum_order_size is None + or market.trading.minimum_tick_size is None + or token_id is None + or market.prices.best_ask is None + or market.prices.best_ask >= 1 + or market.prices.best_bid is None + or market.prices.best_bid <= 0 + ): + return False + + try: + book = client.get_order_book(token_id=token_id) + except PolymarketError: + return False + return len(book.asks) > 0 and len(book.bids) > 0 diff --git a/examples/lib/tables.py b/examples/lib/tables.py new file mode 100644 index 0000000..7c8215f --- /dev/null +++ b/examples/lib/tables.py @@ -0,0 +1,63 @@ +"""Boxed console tables for the examples. + +Mirrors Node's `console.table` so the Python example output matches the +TypeScript reference: an `(index)` column, single-quoted strings, lowercase +booleans, and box-drawing borders. Pure stdlib — no third-party dependency. +""" + +from __future__ import annotations + +from collections.abc import Mapping, Sequence + + +def _cell(value: object) -> str: + """Render one value the way `console.table` does (quote strings, lowercase bools).""" + if isinstance(value, str): + return f"'{value}'" + if isinstance(value, bool): + return "true" if value else "false" + if value is None: + return "" + return str(value) + + +def _draw(headers: list[str], rows: list[list[str]]) -> None: + widths = [len(h) for h in headers] + for row in rows: + for i, cell in enumerate(row): + widths[i] = max(widths[i], len(cell)) + + def border(left: str, mid: str, right: str) -> str: + return left + mid.join("─" * (w + 2) for w in widths) + right + + def row_line(cells: list[str]) -> str: + padded = (cell.ljust(width) for cell, width in zip(cells, widths, strict=True)) + return "│ " + " │ ".join(padded) + " │" + + print(border("┌", "┬", "┐")) + print(row_line(headers)) + print(border("├", "┼", "┤")) + for row in rows: + print(row_line(row)) + print(border("└", "┴", "┘")) + + +def print_rows_table(rows: Sequence[Mapping[str, object]]) -> None: + """Print a list of records, like `console.table([{...}, {...}])`. + + Columns are taken from the first record; each row is numbered in an + `(index)` column. + """ + if not rows: + print("(no rows)") + return + columns = list(rows[0].keys()) + headers = ["(index)", *columns] + body = [[str(i), *[_cell(row.get(col)) for col in columns]] for i, row in enumerate(rows)] + _draw(headers, body) + + +def print_values_table(obj: Mapping[str, object]) -> None: + """Print a single record as a key/`Values` table, like `console.table({...})`.""" + body = [[key, _cell(value)] for key, value in obj.items()] + _draw(["(index)", "Values"], body) From 8b41b8138aa5af71270bc29127d45b58aaaf7310 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:31:05 -0500 Subject: [PATCH 3/8] feat(examples): add market discovery read examples List markets, fetch a single market by url/slug/id, and walk pages of a list endpoint. Run via `uv run python -m examples.`; no credentials required. --- examples/fetch_market.py | 35 +++++++++++++++++++++++++++++++++++ examples/list_markets.py | 22 ++++++++++++++++++++++ examples/pagination.py | 27 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 examples/fetch_market.py create mode 100644 examples/list_markets.py create mode 100644 examples/pagination.py diff --git a/examples/fetch_market.py b/examples/fetch_market.py new file mode 100644 index 0000000..6198159 --- /dev/null +++ b/examples/fetch_market.py @@ -0,0 +1,35 @@ +"""Fetch a single market by url, slug, and id. + + uv run python -m examples.fetch_market + +No credentials required. Discovers a few live markets, then re-fetches them +three ways. +""" + +from __future__ import annotations + +from polymarket import PublicClient + + +def main() -> None: + with PublicClient() as client: + items = client.list_markets(page_size=3).first_page().items + if len(items) < 3: + raise SystemExit("Not enough live markets to demo all three lookups.") + + slug0 = items[0].slug + slug1 = items[1].slug + if slug0 is None or slug1 is None: + raise SystemExit("Discovered markets are missing slugs; try again.") + + by_url = client.get_market(url=f"https://polymarket.com/market/{slug0}") + by_slug = client.get_market(slug=slug1) + by_id = client.get_market(id=str(items[2].id)) + + print(f"URL lookup: {by_url.question or by_url.id}") + print(f"Slug lookup: {by_slug.question or by_slug.id}") + print(f"ID lookup: {by_id.question or by_id.id}") + + +if __name__ == "__main__": + main() diff --git a/examples/list_markets.py b/examples/list_markets.py new file mode 100644 index 0000000..713da52 --- /dev/null +++ b/examples/list_markets.py @@ -0,0 +1,22 @@ +"""List the first page of markets. + + uv run python -m examples.list_markets + +No credentials required. +""" + +from __future__ import annotations + +from polymarket import PublicClient + + +def main() -> None: + with PublicClient() as client: + # List methods return a Paginator; `.first_page()` fetches just the first page. + page = client.list_markets(page_size=5).first_page() + for market in page.items: + print(f"{market.id}: {market.question or market.slug or 'Untitled market'}") + + +if __name__ == "__main__": + main() diff --git a/examples/pagination.py b/examples/pagination.py new file mode 100644 index 0000000..42649f0 --- /dev/null +++ b/examples/pagination.py @@ -0,0 +1,27 @@ +"""Walk multiple pages of a list endpoint. + + uv run python -m examples.pagination + +No credentials required. Iterating a Paginator yields whole pages; iterating +`.iter_items()` would yield individual items across pages. +""" + +from __future__ import annotations + +from polymarket import PublicClient + + +def main() -> None: + with PublicClient() as client: + markets = client.list_markets(page_size=5) + + for page_count, page in enumerate(markets, start=1): # iterating yields pages + print(f"Page {page_count}") + for market in page.items: + print(f" {market.id}: {market.question or 'Untitled market'}") + if page_count == 3: + break + + +if __name__ == "__main__": + main() From 16ca82baf94497a08bd8f1449d9a93a6242fedcd Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:52:48 -0500 Subject: [PATCH 4/8] feat(examples): add market-data and search read examples Read CLOB order book/prices for a token and search events/tags/profiles. Output mirrors the ts-sdk `console.table` shape for side-by-side parity. --- examples/market_prices.py | 47 ++++++++++++++++++++++++++++++++ examples/search.py | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 examples/market_prices.py create mode 100644 examples/search.py diff --git a/examples/market_prices.py b/examples/market_prices.py new file mode 100644 index 0000000..3c4cfdb --- /dev/null +++ b/examples/market_prices.py @@ -0,0 +1,47 @@ +"""Read CLOB market data — order book, price, midpoint, spread, last trade. + + uv run python -m examples.market_prices + +No credentials required. Discovers a token id from a live market, then queries +its prices and book. +""" + +from __future__ import annotations + +from examples.lib.tables import print_values_table +from polymarket import PublicClient + + +def main() -> None: + with PublicClient() as client: + items = client.list_markets(page_size=1).first_page().items + if not items: + raise SystemExit("No live markets found.") + market = items[0] + token_id = market.outcomes.yes.token_id + if token_id is None: + raise SystemExit("Discovered market has no tradable YES token; try again.") + + order_book = client.get_order_book(token_id=token_id) + buy_price = client.get_price(token_id=token_id, side="BUY") + midpoint = client.get_midpoint(token_id=token_id) + spread = client.get_spread(token_id=token_id) + last_trade = client.get_last_trade_price(token_id=token_id) + + print_values_table( + { + "market": market.question or market.slug or market.id, + "tokenId": token_id, + "bids": len(order_book.bids), + "asks": len(order_book.asks), + "buyPrice": buy_price, + "midpoint": midpoint, + "spread": spread, + "lastTradePrice": last_trade.price, + "lastTradeSide": last_trade.side, + } + ) + + +if __name__ == "__main__": + main() diff --git a/examples/search.py b/examples/search.py new file mode 100644 index 0000000..895d728 --- /dev/null +++ b/examples/search.py @@ -0,0 +1,56 @@ +"""Search events, tags, and profiles. + + uv run python -m examples.search + +No credentials required. +""" + +from __future__ import annotations + +from examples.lib.tables import print_rows_table +from polymarket import PublicClient + + +def main() -> None: + with PublicClient() as client: + page = client.search( + q="ethereum", + search_tags=True, + search_profiles=True, + page_size=3, + ).first_page() + # Search returns a single results payload (events/tags/profiles) per page. + if not page.items: + raise SystemExit("No search results returned.") + results = page.items[0] + + print("Events") + print_rows_table( + [ + {"id": event.id, "title": event.title or event.slug or "Untitled event"} + for event in results.events + ] + ) + + print("\nTags") + print_rows_table( + [ + {"id": tag.id, "label": tag.label or tag.slug or "Untitled tag"} + for tag in results.tags + ] + ) + + print("\nProfiles") + print_rows_table( + [ + { + "id": profile.id or "profile", + "name": profile.name or profile.wallet or "Unnamed profile", + } + for profile in results.profiles + ] + ) + + +if __name__ == "__main__": + main() From 8c90018b273834b04bec5e3c61948342c26c29bd Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:14:22 -0500 Subject: [PATCH 5/8] feat(examples): add account positions read example List a wallet's open positions. Needs only `POLYMARKET_DEPOSIT_WALLET` (a public address to inspect), no signing key. --- examples/list_positions.py | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 examples/list_positions.py diff --git a/examples/list_positions.py b/examples/list_positions.py new file mode 100644 index 0000000..af4bfe7 --- /dev/null +++ b/examples/list_positions.py @@ -0,0 +1,42 @@ +"""List a wallet's open positions. + + POLYMARKET_DEPOSIT_WALLET=0x... uv run python -m examples.list_positions + +Reads only — no signing key required, just a wallet address to inspect. +""" + +from __future__ import annotations + +from examples.lib.env import require_env +from examples.lib.tables import print_rows_table +from polymarket import PublicClient + + +def main() -> None: + wallet = require_env("POLYMARKET_DEPOSIT_WALLET") + with PublicClient() as client: + positions = list(client.list_positions(user=wallet, page_size=100).iter_items()) + + print(f"Found {len(positions)} open positions for {wallet}") + print_rows_table( + [ + { + "title": position.title or position.slug or position.condition_id, + "outcome": position.outcome or "", + "size": position.size if position.size is not None else "0", + "currentValue": ( + position.current_value if position.current_value is not None else "0" + ), + "avgPrice": position.avg_price if position.avg_price is not None else "", + "curPrice": position.cur_price if position.cur_price is not None else "", + "redeemable": position.redeemable if position.redeemable is not None else False, + "mergeable": position.mergeable if position.mergeable is not None else False, + "tokenId": position.token_id or "", + } + for position in positions + ] + ) + + +if __name__ == "__main__": + main() From 2d2547c1a729626fd57eb76a193d036604bc0812 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:39:50 -0500 Subject: [PATCH 6/8] feat(examples): add build-only order examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build and sign market and limit orders locally and print the `SignedOrder`. They never call `post_order`/`place_*` — nothing is submitted to the exchange. --- examples/create_limit_order.py | 59 +++++++++++++++++++++++++++++++ examples/create_market_order.py | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 examples/create_limit_order.py create mode 100644 examples/create_market_order.py diff --git a/examples/create_limit_order.py b/examples/create_limit_order.py new file mode 100644 index 0000000..9fb3b1c --- /dev/null +++ b/examples/create_limit_order.py @@ -0,0 +1,59 @@ +"""Build and sign a limit order — without posting it. + + POLYMARKET_PRIVATE_KEY=0x... POLYMARKET_DEPOSIT_WALLET=0x... \ + uv run python -m examples.create_limit_order + +`create_limit_order` signs the order locally and returns it; it does NOT submit +to the exchange. Use `place_limit_order` (or `post_order`) to actually trade. +""" + +from __future__ import annotations + +from examples.lib.env import require_env +from examples.lib.markets import find_order_example_market +from examples.lib.tables import print_values_table +from polymarket import SecureClient + + +def main() -> None: + client = SecureClient.create( + private_key=require_env("POLYMARKET_PRIVATE_KEY"), + wallet=require_env("POLYMARKET_DEPOSIT_WALLET"), + ) + with client: + market = find_order_example_market(client) + token_id = market.outcomes.yes.token_id + if token_id is None: + raise SystemExit("Selected market has no tradable YES token.") + + # `find_order_example_market` guarantees these are set. Bid one tick above + # zero and one minimum lot — a passive price that will rest on the book. + price = market.trading.minimum_tick_size + size = market.trading.minimum_order_size + if price is None or size is None: + raise SystemExit("Selected market is missing tick size or order size.") + order = client.create_limit_order( + token_id=token_id, + price=price, + size=size, + side="BUY", + ) + + print("Signed limit order (built locally, not submitted):") + print_values_table( + { + "market": market.question or market.slug or market.id, + "minimumTickSize": price, + "minimumOrderSize": size, + "tokenId": order.token_id, + "side": order.side, + "orderType": order.order_type, + "maker": order.maker, + "makerAmount": order.maker_amount, + "takerAmount": order.taker_amount, + } + ) + + +if __name__ == "__main__": + main() diff --git a/examples/create_market_order.py b/examples/create_market_order.py new file mode 100644 index 0000000..9eee4f8 --- /dev/null +++ b/examples/create_market_order.py @@ -0,0 +1,61 @@ +"""Build and sign a market order — without posting it. + + POLYMARKET_PRIVATE_KEY=0x... POLYMARKET_DEPOSIT_WALLET=0x... \ + uv run python -m examples.create_market_order + +`create_market_order` signs the order locally and returns it; it does NOT submit +to the exchange. Use `place_market_order` (or `post_order`) to actually trade. +""" + +from __future__ import annotations + +from examples.lib.env import require_env +from examples.lib.markets import find_order_example_market +from examples.lib.tables import print_values_table +from polymarket import SecureClient + + +def main() -> None: + client = SecureClient.create( + private_key=require_env("POLYMARKET_PRIVATE_KEY"), + wallet=require_env("POLYMARKET_DEPOSIT_WALLET"), + ) + with client: + market = find_order_example_market(client) + token_id = market.outcomes.yes.token_id + if token_id is None: + raise SystemExit("Selected market has no tradable YES token.") + + # `find_order_example_market` guarantees minimum_order_size is set. + amount = market.trading.minimum_order_size + if amount is None: + raise SystemExit("Selected market has no minimum order size.") + + estimated_price = client.estimate_market_price( + token_id=token_id, side="BUY", amount=amount, order_type="FAK" + ) + order = client.create_market_order( + token_id=token_id, + side="BUY", + amount=amount, + order_type="FAK", + ) + + print("Signed market order (built locally, not submitted):") + print_values_table( + { + "market": market.question or market.slug or market.id, + "minimumOrderSize": amount, + "tokenId": order.token_id, + "side": order.side, + "orderType": order.order_type, + "estimatedPrice": estimated_price, + "maker": order.maker, + "makerAmount": order.maker_amount, + "takerAmount": order.taker_amount, + } + ) + + +if __name__ == "__main__": + main() From 27e18914e82bf87e280610e1bd34872eb7d4399e Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:03:17 -0500 Subject: [PATCH 7/8] docs(examples): document running the examples Run commands, credential setup (export or `source .env`), and a note on the shared `lib/` helpers. --- examples/README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/README.md diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..6918e24 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,44 @@ +# Python Examples + +Runnable scripts that demonstrate common SDK workflows. Each is a module under +the `examples` package; run one from the repository root with `uv`: + +```bash +uv run python -m examples.list_markets +uv run python -m examples.fetch_market +uv run python -m examples.pagination +uv run python -m examples.market_prices +uv run python -m examples.search +uv run python -m examples.list_positions +uv run python -m examples.create_limit_order +uv run python -m examples.create_market_order +``` + +## Credentials + +The read examples (`list_markets`, `fetch_market`, `pagination`, +`market_prices`, `search`) need no credentials. + +The remaining examples read environment variables — the same ones the +integration tests use — straight from your shell. Nothing auto-loads a `.env` +here, so either export the variables, or copy the root `.env.example` to `.env` +and load it yourself before running: + +```bash +set -a && source .env && set +a +``` + +Or pass them inline on the command (as shown in each script's header): + +- `list_positions` needs `POLYMARKET_DEPOSIT_WALLET` (the wallet to inspect). +- `create_limit_order` / `create_market_order` need `POLYMARKET_PRIVATE_KEY` + and `POLYMARKET_DEPOSIT_WALLET`. + +The order examples **build and sign** an order locally and print it; they do +**not** submit anything to the exchange. + +## Shared helpers + +`examples/lib/` holds small helpers shared across scripts: `require_env` for +required environment variables and `find_order_example_market` for locating a +live, order-book-enabled market for the order examples. From fab230c27e9dd9c9e191991f32a49703bce9be0a Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:13:29 -0500 Subject: [PATCH 8/8] fix(examples): require accepting_orders to be explicitly true The order-example market filter rejected `accepting_orders` only when explicitly `False`, letting markets with it unset (`None`) through. Match the strict `enable_order_book is not True` check in the same guard so only markets confirmed to be accepting orders are selected. --- examples/lib/markets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lib/markets.py b/examples/lib/markets.py index 5de5065..db559f6 100644 --- a/examples/lib/markets.py +++ b/examples/lib/markets.py @@ -33,7 +33,7 @@ def _is_order_example_candidate(client: MarketLookupClient, market: Market) -> b token_id = market.outcomes.yes.token_id if ( market.state.enable_order_book is not True - or market.state.accepting_orders is False + or market.state.accepting_orders is not True or market.trading.minimum_order_size is None or market.trading.minimum_tick_size is None or token_id is None