178 lines
5.4 KiB
Python
178 lines
5.4 KiB
Python
"""
|
|
Polymarket Gamma API Client
|
|
|
|
Provides market discovery, metadata, and event data.
|
|
API Documentation: https://docs.polymarket.com/developers/gamma-markets-api/overview
|
|
"""
|
|
|
|
import requests
|
|
from typing import List, Dict, Optional, Any
|
|
from datetime import datetime
|
|
import time
|
|
|
|
|
|
class GammaClient:
|
|
"""Client for Polymarket Gamma API - Market discovery and metadata"""
|
|
|
|
BASE_URL = "https://gamma-api.polymarket.com"
|
|
|
|
def __init__(self, timeout: int = 30):
|
|
"""
|
|
Initialize Gamma API client.
|
|
|
|
Args:
|
|
timeout: Request timeout in seconds
|
|
"""
|
|
self.timeout = timeout
|
|
self.session = requests.Session()
|
|
self.session.headers.update({
|
|
'Accept': 'application/json',
|
|
'User-Agent': 'Polymarket-Trading-Framework/1.0'
|
|
})
|
|
|
|
def _get(self, endpoint: str, params: Optional[Dict] = None) -> Dict:
|
|
"""Make GET request with error handling"""
|
|
url = f"{self.BASE_URL}{endpoint}"
|
|
try:
|
|
response = self.session.get(url, params=params, timeout=self.timeout)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
# According to docs, /events returns an array directly
|
|
# But handle both array and dict responses
|
|
return data
|
|
except requests.exceptions.RequestException as e:
|
|
raise Exception(f"Gamma API error: {e}")
|
|
|
|
def get_events(self,
|
|
active: bool = True,
|
|
closed: bool = False,
|
|
limit: int = 100,
|
|
tag_id: Optional[int] = None,
|
|
series_id: Optional[int] = None,
|
|
order: Optional[str] = None,
|
|
ascending: bool = True) -> List[Dict]:
|
|
"""
|
|
Fetch active events/markets.
|
|
|
|
Args:
|
|
active: Filter for active events
|
|
closed: Filter for closed events
|
|
limit: Maximum number of results
|
|
tag_id: Filter by tag/category ID
|
|
series_id: Filter by series ID (for sports)
|
|
order: Sort order (e.g., 'startTime')
|
|
ascending: Sort ascending or descending
|
|
|
|
Returns:
|
|
List of event dictionaries
|
|
"""
|
|
params = {
|
|
'active': str(active).lower(),
|
|
'closed': str(closed).lower(),
|
|
'limit': limit
|
|
}
|
|
|
|
if tag_id:
|
|
params['tag_id'] = tag_id
|
|
if series_id:
|
|
params['series_id'] = series_id
|
|
if order:
|
|
params['order'] = order
|
|
params['ascending'] = str(ascending).lower()
|
|
|
|
return self._get('/events', params=params)
|
|
|
|
def get_event_by_slug(self, slug: str) -> Optional[Dict]:
|
|
"""
|
|
Get event details by slug.
|
|
|
|
Args:
|
|
slug: Event slug (e.g., 'will-bitcoin-reach-100k-by-2025')
|
|
|
|
Returns:
|
|
Event dictionary or None if not found
|
|
"""
|
|
events = self.get_events(limit=1)
|
|
for event in events:
|
|
if event.get('slug') == slug:
|
|
return event
|
|
return None
|
|
|
|
def get_market_by_slug(self, slug: str) -> Optional[Dict]:
|
|
"""
|
|
Get market details by slug.
|
|
|
|
Args:
|
|
slug: Market slug
|
|
|
|
Returns:
|
|
Market dictionary with clobTokenIds, outcomes, prices
|
|
"""
|
|
params = {'slug': slug}
|
|
markets = self._get('/markets', params=params)
|
|
return markets[0] if markets else None
|
|
|
|
def get_tags(self, limit: int = 100) -> List[Dict]:
|
|
"""
|
|
Get all available tags/categories.
|
|
|
|
Args:
|
|
limit: Maximum number of tags to return
|
|
|
|
Returns:
|
|
List of tag dictionaries
|
|
"""
|
|
params = {'limit': limit}
|
|
return self._get('/tags', params=params)
|
|
|
|
def get_sports(self) -> List[Dict]:
|
|
"""
|
|
Get all supported sports leagues.
|
|
|
|
Returns:
|
|
List of sports league dictionaries
|
|
"""
|
|
return self._get('/sports')
|
|
|
|
def get_market_prices(self, market: Dict) -> Dict[str, float]:
|
|
"""
|
|
Extract current prices from market data.
|
|
|
|
Args:
|
|
market: Market dictionary with outcomes and outcomePrices
|
|
|
|
Returns:
|
|
Dictionary mapping outcome to price (probability)
|
|
"""
|
|
import json
|
|
|
|
outcomes = json.loads(market.get('outcomes', '[]'))
|
|
prices = json.loads(market.get('outcomePrices', '[]'))
|
|
|
|
return {outcome: float(price) for outcome, price in zip(outcomes, prices)}
|
|
|
|
def search_events(self, query: str, limit: int = 20) -> List[Dict]:
|
|
"""
|
|
Search events by title/keywords.
|
|
|
|
Args:
|
|
query: Search query
|
|
limit: Maximum results
|
|
|
|
Returns:
|
|
List of matching events
|
|
"""
|
|
# Note: This is a simplified search - actual API may have different endpoint
|
|
all_events = self.get_events(limit=1000)
|
|
query_lower = query.lower()
|
|
|
|
matches = []
|
|
for event in all_events:
|
|
title = event.get('title', '').lower()
|
|
if query_lower in title:
|
|
matches.append(event)
|
|
if len(matches) >= limit:
|
|
break
|
|
|
|
return matches
|