commit 03e94e780903d7eadebc10ff38766eda903077fe Author: zlei9 Date: Sun Mar 29 09:37:51 2026 +0800 Initial commit with translated description diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..8f44687 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,44 @@ +--- +name: polymarket +description: "查询Polymarket预测市场。用于关于预测市场、投注赔率、市场价格、事件概率的问题,或当用户询问Polymarket数据时使用。" +--- + +# Polymarket + +Query prediction market data from Polymarket's public API (no auth required). + +## Quick Start + +```bash +# Top markets by 24h volume +python3 scripts/polymarket.py --top + +# Search markets +python3 scripts/polymarket.py --search "trump" + +# Get specific market by slug +python3 scripts/polymarket.py --slug "will-trump-win-the-2024-election" + +# List events (grouped markets) +python3 scripts/polymarket.py --events +``` + +## Script Location + +`skills/polymarket/scripts/polymarket.py` + +## API Endpoints + +The script uses `gamma-api.polymarket.com`: +- `/markets` - Individual markets with prices, volumes +- `/events` - Event groups containing related markets + +## Output Format + +Markets show: question, Yes/No prices (as percentages), 24h volume, total volume. + +## Interpreting Prices + +- `outcomePrices` are 0-1 representing probability +- Price of 0.65 for "Yes" = market thinks 65% chance of Yes +- Higher volume = more liquid, more reliable signal diff --git a/_meta.json b/_meta.json new file mode 100644 index 0000000..3f0d216 --- /dev/null +++ b/_meta.json @@ -0,0 +1,6 @@ +{ + "ownerId": "kn7caxjvqk9fengp67p290smnn800sv9", + "slug": "polymarket-api", + "version": "1.0.0", + "publishedAt": 1769515386284 +} \ No newline at end of file diff --git a/scripts/polymarket.py b/scripts/polymarket.py new file mode 100644 index 0000000..91ac9e4 --- /dev/null +++ b/scripts/polymarket.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Query Polymarket prediction markets via public API.""" + +import argparse +import json +import urllib.request +import urllib.parse +from typing import Optional + +BASE_URL = "https://gamma-api.polymarket.com" + +def fetch(endpoint: str, params: dict = None) -> list | dict: + """Fetch from Polymarket API.""" + url = f"{BASE_URL}{endpoint}" + if params: + url += "?" + urllib.parse.urlencode(params) + req = urllib.request.Request(url, headers={ + "User-Agent": "Mozilla/5.0 (compatible; polymarket-skill/1.0)", + "Accept": "application/json" + }) + with urllib.request.urlopen(req, timeout=15) as resp: + return json.loads(resp.read()) + +def format_market(m: dict) -> str: + """Format a single market for display.""" + q = m.get("question", "Unknown")[:80] + prices = json.loads(m.get("outcomePrices", '["0","0"]')) + yes_pct = float(prices[0]) * 100 if prices else 0 + no_pct = float(prices[1]) * 100 if len(prices) > 1 else 0 + vol24h = m.get("volume24hr", 0) or 0 + vol_total = m.get("volumeNum", 0) or 0 + closed = "🔒" if m.get("closed") else "" + return f"{closed}{q}\n Yes: {yes_pct:.1f}% | No: {no_pct:.1f}% | 24h: ${vol24h:,.0f} | Total: ${vol_total:,.0f}" + +def top_markets(limit: int = 10) -> None: + """Show top markets by 24h volume.""" + markets = fetch("/markets", { + "active": "true", + "closed": "false", + "limit": limit, + "order": "volume24hr", + "ascending": "false" + }) + print(f"📈 Top {len(markets)} Markets by 24h Volume\n") + for m in markets: + print(format_market(m)) + print() + +def search_markets(query: str, limit: int = 10) -> None: + """Search markets by text.""" + # The API doesn't have a search param, so we fetch more and filter + markets = fetch("/markets", { + "active": "true", + "closed": "false", + "limit": 100, + "order": "volume24hr", + "ascending": "false" + }) + query_lower = query.lower() + matches = [m for m in markets if query_lower in m.get("question", "").lower() + or query_lower in m.get("description", "").lower()][:limit] + + if not matches: + print(f"No markets found matching '{query}'") + return + + print(f"🔍 Markets matching '{query}'\n") + for m in matches: + print(format_market(m)) + print() + +def get_market(slug: str) -> None: + """Get a specific market by slug.""" + markets = fetch("/markets", {"slug": slug}) + if not markets: + print(f"No market found with slug: {slug}") + return + + m = markets[0] + print(f"📊 {m.get('question', 'Unknown')}\n") + prices = json.loads(m.get("outcomePrices", '["0","0"]')) + outcomes = json.loads(m.get("outcomes", '["Yes","No"]')) + + for i, (outcome, price) in enumerate(zip(outcomes, prices)): + pct = float(price) * 100 + print(f" {outcome}: {pct:.1f}%") + + print(f"\n 24h Volume: ${m.get('volume24hr', 0):,.0f}") + print(f" Total Volume: ${m.get('volumeNum', 0):,.0f}") + print(f" Liquidity: ${m.get('liquidityNum', 0):,.0f}") + print(f" Status: {'Closed' if m.get('closed') else 'Open'}") + if m.get("endDate"): + print(f" End Date: {m.get('endDate')[:10]}") + if m.get("description"): + desc = m.get("description", "")[:500] + print(f"\n {desc}{'...' if len(m.get('description', '')) > 500 else ''}") + +def list_events(limit: int = 10) -> None: + """List top events (grouped markets).""" + events = fetch("/events", { + "active": "true", + "closed": "false", + "limit": limit, + "order": "volume24hr", + "ascending": "false" + }) + print(f"📅 Top {len(events)} Events\n") + for e in events: + title = e.get("title", "Unknown")[:70] + vol = e.get("volume", 0) or 0 + markets_count = len(e.get("markets", [])) + print(f"• {title}") + print(f" Volume: ${vol:,.0f} | Markets: {markets_count}") + print() + +def main(): + parser = argparse.ArgumentParser(description="Query Polymarket prediction markets") + parser.add_argument("--top", action="store_true", help="Show top markets by 24h volume") + parser.add_argument("--search", "-s", type=str, help="Search markets by text") + parser.add_argument("--slug", type=str, help="Get market by slug") + parser.add_argument("--events", "-e", action="store_true", help="List top events") + parser.add_argument("--limit", "-n", type=int, default=10, help="Number of results") + parser.add_argument("--json", action="store_true", help="Output raw JSON") + + args = parser.parse_args() + + if args.json: + if args.search: + data = fetch("/markets", {"active": "true", "closed": "false", "limit": 100}) + data = [m for m in data if args.search.lower() in m.get("question", "").lower()][:args.limit] + elif args.slug: + data = fetch("/markets", {"slug": args.slug}) + elif args.events: + data = fetch("/events", {"active": "true", "closed": "false", "limit": args.limit}) + else: + data = fetch("/markets", {"active": "true", "closed": "false", "limit": args.limit, "order": "volume24hr", "ascending": "false"}) + print(json.dumps(data, indent=2)) + return + + if args.search: + search_markets(args.search, args.limit) + elif args.slug: + get_market(args.slug) + elif args.events: + list_events(args.limit) + else: + top_markets(args.limit) + +if __name__ == "__main__": + main()