Skip to content
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- Name request/path construction helpers with `build_*`.
- Do not rename existing variables, functions, or classes unless the operator explicitly asks for it in the prompt. Keep PRs lean; if a name looks wrong, propose the rename as a separate change instead of bundling it.
- Avoid reuse that does not carry semantic or domain-specific value. Do not add boolean mode flags or generic helpers that hide distinct behavior behind one function; prefer separate explicit helpers whose names describe the behavior they implement.
- Narrow exception: retain the existing `full_history` keyword on `list_trades`, `list_activity`, `list_positions`, and `get_user_volume`, together with their request construction support. It complements the existing `start`/`end` keywords without introducing a second time-window input shape. Keep endpoint-specific semantics explicit; this exception does not authorize new boolean mode flags. See `docs/sdk-direction.md`.

## Public Model Types

Expand Down
16 changes: 14 additions & 2 deletions docs/sdk-direction.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ async with AsyncPublicClient() as client:

Clients should also expose explicit `close()` methods. Async clients should expose `await client.close()` so callers that do not use `async with` can still release async HTTP sessions, sockets, or other transport resources deterministically.

## Full-history requests

The existing `full_history=True` keyword on `list_trades`, `list_activity`, `list_positions`, and `get_user_volume` is an intentional, narrow exception to the rule against boolean mode flags. It complements the existing `start` and `end` keywords without requiring a separate time-window object or union. It cannot be combined with either explicit bound.

Positions have no time bounds by default. For `list_positions`, `full_history=True` preserves that behavior, including holdings without an activity timestamp. Explicit bounds filter positions by their last activity and exclude holdings without one. Other methods retain their own full-history request behavior; request construction must preserve these distinctions.

This exception preserves the current public signature and does not establish a convention for new boolean mode flags.

## Domain Types

The SDK uses lightweight marked types for important domain values where a plain primitive would hide useful meaning in IDEs and type hints.
Expand All @@ -80,7 +88,11 @@ We intentionally do not mark every primitive value. Marked types should be reser

The SDK uses two patterns for string-set enums depending on the direction:

- **Inputs** use `typing.Literal`. Users pass plain strings (`time_period="DAY"`). The type drives autocomplete and static checking without forcing users to import an enum class. The type alias is exported (e.g., `BuilderVolumeTimePeriod`) so callers can annotate their own variables when they want to.
- **Outputs** use `enum.StrEnum`. Returned model fields surface the enum so users can compare against named members (`if status is UmaResolutionStatus.DISPUTED`) without typo risk on the right-hand side.
- **Inputs** use `typing.Literal`. Users pass plain strings (`window="day"`). The type drives autocomplete and static checking without forcing users to import an enum class. The type alias is exported (e.g., `LeaderboardWindow`) so callers can annotate their own variables when they want to.
- **Outputs** use `enum.StrEnum`. Returned model fields surface the enum so users can compare against named members (`if status is ResolutionStatus.DISPUTED`) without typo risk on the right-hand side.

The split is principled: inputs are write-once at the call site and benefit from string ergonomics; outputs are read-many in user logic and benefit from named members.

Some vocabularies travel in both directions, such as `PositionStatus`, which filters `list_positions` and is also a field on every returned `Position`. Those keep the `StrEnum` name for the output type and expose an input alias that accepts either the plain string literals or the enum members, for example `PositionStatusFilter` and `UserPnlIntervalInput`. The `Filter` suffix marks parameters that select rows and the `Input` suffix marks other request parameters. Callers can pass `"CLOSED"` or `PositionStatus.CLOSED`, and can feed a returned value straight back into a request.

Arrow, pandas, and Polars exports use the enum's value. SDK fields that mix `StrEnum` members and plain strings export together as a string column, such as trade and tip sides or known and unknown activity types. The original SDK objects retain their enum members after export.
2 changes: 2 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ 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).
It shows `current_size` in shares, `current_price` in USDC, and `asset_id`.
Use `client.list_positions(status="CLOSED", user=wallet)` for closed positions.
- `create_limit_order` / `create_market_order` need `POLYMARKET_PRIVATE_KEY`
and `POLYMARKET_DEPOSIT_WALLET`.

Expand Down
16 changes: 7 additions & 9 deletions examples/list_positions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ def main() -> None:
{
"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,
"assetId": position.asset_id or "",
"current_size": position.current_size,
"current_value": position.current_value,
"avg_price": position.avg_price,
"current_price": position.current_price,
"redeemable": position.redeemable,
"mergeable": position.mergeable,
"asset_id": position.asset_id,
}
for position in positions
]
Expand Down
Loading
Loading