Skip to content
Open
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
44 changes: 44 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -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.
Empty file added examples/__init__.py
Empty file.
59 changes: 59 additions & 0 deletions examples/create_limit_order.py
Original file line number Diff line number Diff line change
@@ -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()
61 changes: 61 additions & 0 deletions examples/create_market_order.py
Original file line number Diff line number Diff line change
@@ -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()
35 changes: 35 additions & 0 deletions examples/fetch_market.py
Original file line number Diff line number Diff line change
@@ -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()
Empty file added examples/lib/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions examples/lib/env.py
Original file line number Diff line number Diff line change
@@ -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
51 changes: 51 additions & 0 deletions examples/lib/markets.py
Original file line number Diff line number Diff line change
@@ -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 not True
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
63 changes: 63 additions & 0 deletions examples/lib/tables.py
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 22 additions & 0 deletions examples/list_markets.py
Original file line number Diff line number Diff line change
@@ -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()
Loading
Loading