Files
Polymarket Skills BuilderandClaude Opus 4.6 068b2adc75 Add 6 Polymarket trading skills with paper trading engine
Composable Agent Skills (SKILL.md format) for Polymarket prediction market
trading. Includes scanner, analyzer, monitor, paper trader, strategy advisor,
and live executor. All tested against live Polymarket APIs. Security audited
with all HIGH/MEDIUM findings resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 07:25:07 +00:00

143 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Scan and search active Polymarket prediction markets via the Gamma API."""
import argparse
import json
import re
import sys
import requests
GAMMA_API = "https://gamma-api.polymarket.com"
MAX_TEXT_LEN = 200
def sanitize_text(text):
"""Strip control characters and limit length. Market text is user-generated."""
if not text:
return ""
text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
if len(text) > MAX_TEXT_LEN:
text = text[:MAX_TEXT_LEN] + "..."
return text
def fetch_markets(limit=20, category=None, search=None, min_volume=0,
sort_by="volume24hr", ascending=False):
"""Fetch active markets from Gamma API with filtering and sorting."""
params = {
"limit": min(limit, 100),
"active": "true",
"closed": "false",
"order": sort_by,
"ascending": str(ascending).lower(),
}
if category:
params["tag_slug"] = category.lower()
resp = requests.get(f"{GAMMA_API}/markets", params=params, timeout=30)
resp.raise_for_status()
raw_markets = resp.json()
results = []
for m in raw_markets:
vol_24h = float(m.get("volume24hr", 0) or 0)
if vol_24h < min_volume:
continue
# Parse JSON-encoded fields
try:
outcomes = json.loads(m.get("outcomes", "[]"))
except (json.JSONDecodeError, TypeError):
outcomes = []
try:
outcome_prices = json.loads(m.get("outcomePrices", "[]"))
outcome_prices = [float(p) for p in outcome_prices]
except (json.JSONDecodeError, TypeError, ValueError):
outcome_prices = []
try:
token_ids = json.loads(m.get("clobTokenIds", "[]"))
except (json.JSONDecodeError, TypeError):
token_ids = []
# Apply keyword search filter
if search:
question = (m.get("question", "") or "").lower()
description = (m.get("description", "") or "").lower()
search_lower = search.lower()
if search_lower not in question and search_lower not in description:
continue
market = {
"question": sanitize_text(m.get("question", "")),
"slug": m.get("slug", ""),
"url": f"https://polymarket.com/event/{m.get('slug', '')}",
"outcomes": [sanitize_text(o) for o in outcomes],
"outcome_prices": outcome_prices,
"token_ids": token_ids,
"volume_24h": vol_24h,
"volume_total": float(m.get("volumeNum", 0) or 0),
"liquidity": float(m.get("liquidityNum", 0) or 0),
"end_date": m.get("endDate", ""),
"active": m.get("active", False),
"accepting_orders": m.get("acceptingOrders", False),
}
results.append(market)
return results
def main():
parser = argparse.ArgumentParser(
description="Scan active Polymarket prediction markets"
)
parser.add_argument(
"--limit", type=int, default=20,
help="Number of markets to return (max 100, default 20)"
)
parser.add_argument(
"--category", type=str, default=None,
help="Filter by tag/category (e.g. crypto, politics, sports)"
)
parser.add_argument(
"--search", type=str, default=None,
help="Search keyword in market question/description"
)
parser.add_argument(
"--min-volume", type=float, default=0,
help="Minimum 24h volume in USD (default 0)"
)
parser.add_argument(
"--sort-by", type=str, default="volume24hr",
choices=["volume24hr", "liquidity", "endDate", "startDate"],
help="Sort field (default: volume24hr)"
)
parser.add_argument(
"--ascending", action="store_true",
help="Sort ascending instead of descending"
)
args = parser.parse_args()
try:
markets = fetch_markets(
limit=args.limit,
category=args.category,
search=args.search,
min_volume=args.min_volume,
sort_by=args.sort_by,
ascending=args.ascending,
)
print(json.dumps(markets, indent=2))
except requests.RequestException as e:
print(json.dumps({"error": str(e)}), file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()