list_markets
Browse and filter active prediction markets from Kalshi, Polymarket, and Metaculus across 7 categories including sports, crypto, and politics. Sort by trading volume, probability, or closing date to discover betting opportunities.
Instructions
Browse and discover prediction markets across 7 categories with filtering and sorting.
Lists active betting markets from Kalshi, Polymarket, and Metaculus. Filter by category, sort by trading volume, probability, or closing date. 500+ markets available. Categories: sports, crypto, politics, economics, pop_culture, weather, other. Use when exploring what predictions are available, finding trending markets, or discovering betting opportunities.
Example queries:
"Show me crypto prediction markets" → Bitcoin, Ethereum, altcoin forecasts
"What sports markets are trending?" → NFL, NBA, soccer odds
"List political predictions" → elections, legislation, geopolitics
"What economic forecasts are available?" → GDP, inflation, interest rates
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Filter by category (default: all) | |
| sort_by | No | Sort order (default: volume) | |
| limit | No | Maximum markets to return (default: 10, max: 50) | |
| source | No | Filter by data source (default: all) | |
| jurisdiction | No | Filter by regulatory jurisdiction. US-regulated = Kalshi (CFTC-regulated), international = Polymarket, forecasting = Metaculus (not gambling). Default: all. |
Implementation Reference
- worker/src/tools.ts:331-403 (handler)The implementation of the `list_markets` tool handler.
async function listMarkets( supabase: SupabaseClient, args: { category?: string; sort_by?: string; limit?: number; source?: string; jurisdiction?: string; }, ): Promise<ToolResult> { const { category = "all", sort_by = "volume", limit = 10, source = "all", jurisdiction = "all", } = args; let effectiveSource = source; if (jurisdiction !== "all" && source === "all") { const jSources = JURISDICTION_SOURCES[jurisdiction]; if (jSources?.length === 1) effectiveSource = jSources[0]; } const effectiveLimit = Math.min(Math.max(1, limit), 50); let query = supabase .from("telekash_markets") .select( "id, external_id, title, category, source, external_odds, raw_data, status, closes_at", ) .eq("status", "active") .limit(effectiveLimit); if (category !== "all") query = query.eq("category", category); if (effectiveSource !== "all") query = query.eq("source", effectiveSource); switch (sort_by) { case "probability": query = query.order("external_odds->yes", { ascending: false }); break; case "closing_date": query = query.order("closes_at", { ascending: true }); break; default: query = query.order("raw_data->volume", { ascending: false, nullsFirst: false, }); } const { data, error } = await query; if (error) throw new Error(`Database error: ${error.message}`); // eslint-disable-next-line @typescript-eslint/no-explicit-any const markets = (data || []).map((m: any) => { const ji = SOURCE_JURISDICTION[m.source] || SOURCE_JURISDICTION.demo; return { id: m.id, title: m.title, category: m.category, source: m.source, jurisdiction: ji.jurisdiction, yes_probability: Math.round((m.external_odds?.yes || 0.5) * 100), volume_24h: m.raw_data?.volume_24h || m.raw_data?.volume || 0, closes_at: m.closes_at, status: m.status, }; }); return json({ markets, total: markets.length, filters: { category, sort_by, source: effectiveSource, jurisdiction }, }); }