Skip to main content
Use matching to find cross-venue clusters, then use price helpers or venue exchanges to inspect executable bid/ask data.

compareMarketPrices

Side-by-side bid/ask for identity matches in the hosted catalog. This returns a flat side-by-side view for one anchored market. For cluster-first discovery across the whole catalog, use fetchMatchedMarketClusters.
import pmxt

router = pmxt.Router(pmxt_api_key="pmxt_live_...")

prices = router.compare_market_prices(market_id="d35bc8c6-...")

for p in prices:
    print(f"{p.venue:12s}  bid {p.best_bid:.2f}  ask {p.best_ask:.2f}")
polymarket    bid 0.60  ask 0.65
kalshi        bid 0.58  ask 0.63
limitless     bid 0.61  ask 0.66

Response shape

{
  "market": { "marketId": "...", "title": "..." },
  "relation": "identity",
  "confidence": 0.95,
  "reasoning": "Same resolution condition.",
  "bestBid": 0.60,
  "bestAsk": 0.65,
  "venue": "kalshi"
}

fetchRelatedMarkets

Find related markets across venues — markets whose resolution condition is a subset or superset of the target market.
# Positional dict, camelCase keys. Returns a list of plain dicts
# (not typed dataclasses like compare_market_prices).
related = router.fetch_related_markets({"marketId": "d35bc8c6-..."})

for r in related:
    print(f"{r['relation']:10s} {r['venue']:12s}  {r['market']['title']}")
    print(f"           confidence {r['confidence']:.0%}  bid {r['bestBid']}  ask {r['bestAsk']}")
    print(f"           {r['reasoning']}")
subset     kalshi        Will the nominee be from California?
           confidence 85%  bid 0.40  ask 0.45
           Narrower market — California origin implies Democratic candidacy.
superset   polymarket    Will a Democrat win the popular vote?
           confidence 72%  bid 0.70  ask 0.73
           Broader — popular vote does not guarantee election win.
Subset means A=YES implies B=YES but not vice versa. Superset is the reverse. See relation types for the full taxonomy.
fetchRelatedMarkets filters to subset and superset relations. If you want all relation types, use fetchMatchedMarketClusters with relation or relations filters.

fetchMatchedMarketClusters

Returns matched market clusters across venues. Use this when you want the full group of markets first, then inspect prices and outcomes inside each venue market.
clusters = router.fetch_matched_market_clusters(
    relation="identity",
    sort="volume",
    min_venues=2,
    limit=20,
)

for cluster in clusters:
    print(cluster.canonical_title)
    for market in cluster.markets:
        price = market.yes.price if market.yes else None
        print(f"  {market.source_exchange:12s} @ {price}")
Will BTC hit $100k by Dec 31?
  polymarket   @ 0.58
  kalshi       @ 0.63

Parameters

ParameterTypeDefaultNotes
relationstringFilter to a relation type such as identity.
minVenuesintegerRequire at least this many venues in a cluster.
sortstringvolumeSort by volume or confidence.
limitinteger50Maximum number of clusters to return.
Results are cluster-first. PMXT does not pick a best opportunity for you; inspect the returned markets, outcomes, and order books before deciding how to trade.

Response shape

{
  "clusterId": "mcl_...",
  "canonicalTitle": "Will BTC hit $100k by Dec 31?",
  "relations": ["identity"],
  "confidence": 0.98,
  "markets": [
    { "marketId": "pm_...", "sourceExchange": "polymarket", "title": "Will BTC hit $100k by Dec 31?" },
    { "marketId": "kalshi_...", "sourceExchange": "kalshi", "title": "Bitcoin above $100,000 on Dec 31" }
  ]
}

Composing with venue exchanges

The Router is read-only. To trade, use venue-specific exchange classes with the local SDK. A typical workflow:
import pmxt

router = pmxt.Router(pmxt_api_key="pmxt_live_...")
poly   = pmxt.Polymarket(private_key="0x...")

# 1. Browse matched market clusters across venues
clusters = router.fetch_matched_market_clusters(relation="identity", limit=20)

# 2. Direct self-hosted calls need IDs returned by the venue client.
# Re-fetch or reverse-resolve the matched venue market, then verify the outcome.
polymarket_match = next(m for m in clusters[0].markets if m.source_exchange == "polymarket")
venue_markets = poly.fetch_markets({"query": polymarket_match.title, "limit": 1})
venue_outcome = venue_markets[0].outcomes[0]  # verify label/slug before trading

# 3. Inspect the order book on that venue with its native outcome ID
book = poly.fetch_order_book(outcome_id=venue_outcome.outcome_id)

# 4. Place an order locally (never proxied through PMXT)
# poly.create_order(...)
Router returns the same unified schema as every other exchange, but identifiers keep their address space. Catalog IDs work for Router and hosted flows; direct self-hosted venue calls need venue-native IDs returned by that venue client.