Skip to content

[Bug]: list_markets(order="volume") orders non-numerically; accepted values undocumented #288

Description

@joeychan-hk

SDK package and version

polymarket (py-sdk) — source inspected at main, not installed. Reproduction below is against the Gamma API directly, so it does not depend on the SDK version.

Runtime

Python 3.13, macOS

What happened?

list_markets() accepts order: str | None with no documented values. The natural guess is the model attribute name — order="volume" — but the Gamma API does not order that field numerically.

Every value on the order=volume page starts with the digit 9, the largest being 999.94, against a true maximum of about 83,453,020 in the same filter set. order=liquidity behaves the same way: top value 999.96 against a true maximum of about 2,902,308.

volume and liquidity come back as JSON strings; volumeNum and liquidityNum as numbers. That appears to explain it. I can't tell the mechanism from outside — I only know the returned order isn't numeric, and the numeric twins order correctly.

Why this is easy to hit from the SDK

The filter parameters already distinguish the numeric fields — volume_num_min, volume_num_max, liquidity_num_min, liquidity_num_max — so the SDK treats volumeNum as the numeric field for filtering. There is no equivalent signal for ordering: order is an unvalidated string, and the visible model attribute is volume. In models/gamma/market.py both are declared Decimal | None, so the distinction isn't apparent there either.

A reasonable call therefore returns the wrong markets silently rather than raising.

What else I checked

I verified the surrounding invariants before concluding the ordering was the outlier. Across samples of 800–1000 live markets:

  • volume and volumeNum agree numerically — no mismatches
  • liquidity and liquidityNum agree — no mismatches
  • len(outcomes) == len(clobTokenIds) holds
  • offset pagination returns no duplicate or missing ids, under both order=volume and order=volumeNum
  • volumeNumMin filtering agrees with the returned values
  • closed and archived markets showed no malformed records
  • Paginator terminates on the server's has_more flag, so omitted markets cannot truncate iteration early

All of those held. The ordering is the only thing that didn't.

One related note

About 5% of low-volume active markets in my sample returned no clobTokenIds. Per the list_markets docstring these are omitted from results. Pagination stays correct, but the caller gets no signal that anything was skipped — worth a line in the docstring for anyone reconciling counts.

Suggested fix

Document the accepted order values in the list_markets docstring, and note that volumeNum/liquidityNum order numerically while volume/liquidity do not. A short comment on the metrics model would help too. This would also fit naturally into #219.

Happy to open a PR for the docstring if that's useful.

Minimal reproduction

Q="active=true&closed=false"

# 1. field types
curl -s "https://gamma-api.polymarket.com/markets?$Q&limit=1" | python3 -c "
import sys,json; m=json.load(sys.stdin)[0]
print({k: type(m[k]).__name__ for k in ('volume','volumeNum','liquidity','liquidityNum')})"
# -> {'volume': 'str', 'volumeNum': 'float', 'liquidity': 'str', 'liquidityNum': 'float'}

# 2. order by "volume"
curl -s "https://gamma-api.polymarket.com/markets?$Q&limit=10&order=volume&ascending=false" \
  | python3 -c "import sys,json;print([m['volume'] for m in json.load(sys.stdin)])"
# -> ['99.995453','999.942321','99.99405','999.935914','99.99','999.8','9.996466', ...]

# 3. order by "volumeNum", same filters
curl -s "https://gamma-api.polymarket.com/markets?$Q&limit=1&order=volumeNum&ascending=false" \
  | python3 -c "import sys,json;print(json.load(sys.stdin)[0]['volumeNum'])"
# -> 83453020.65649901

# 4. same pattern for liquidity
curl -s "https://gamma-api.polymarket.com/markets?$Q&limit=10&order=liquidity&ascending=false" \
  | python3 -c "import sys,json;print([m['liquidity'] for m in json.load(sys.stdin)])"
curl -s "https://gamma-api.polymarket.com/markets?$Q&limit=1&order=liquidityNum&ascending=false" \
  | python3 -c "import sys,json;print(json.load(sys.stdin)[0]['liquidityNum'])"
# -> top value 999.9617 vs true maximum 2902308.31206

Expected behavior, actual behavior, or logs

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions