Async Clients & Disk Cache¶
pmlab.markets provides both synchronous and asynchronous API clients, plus a TTL disk cache to avoid redundant network calls.
Sync Clients (Default)¶
GammaClient¶
from pmlab import GammaClient
with GammaClient() as client:
markets = client.fetch_markets(tag="temperature", keyword="highest", limit=100)
for m in markets:
print(m["question"], m["conditionId"])
ClobClient¶
from pmlab import ClobClient
with ClobClient() as client:
prices = client.fetch_prices(token_ids=["0xabc...", "0xdef..."])
for token_id, price in prices.items():
print(f"{token_id}: {price:.3f}")
Async Clients¶
Use async clients when scanning many markets or tokens in parallel.
AsyncGammaClient¶
import asyncio
from pmlab import AsyncGammaClient
async def main():
async with AsyncGammaClient() as client:
markets = await client.fetch_markets(tag="temperature", keyword="highest")
return markets
markets = asyncio.run(main())
AsyncClobClient¶
import asyncio
from pmlab import AsyncClobClient
async def fetch_all_prices(token_ids: list[str]) -> dict[str, float]:
async with AsyncClobClient(concurrency=20) as client:
return await client.fetch_prices(token_ids)
prices = asyncio.run(fetch_all_prices(["0xabc...", "0xdef...", ...]))
The concurrency parameter controls the asyncio.Semaphore — how many tokens are fetched simultaneously. Default is 10. Failed tokens are silently skipped (not in the result dict).
Parallel scan pattern¶
import asyncio
from pmlab import AsyncGammaClient, AsyncClobClient
async def full_scan(tag: str):
async with AsyncGammaClient() as gamma:
markets = await gamma.fetch_markets(tag=tag)
token_ids = [m["conditionId"] for m in markets if "conditionId" in m]
async with AsyncClobClient(concurrency=15) as clob:
prices = await clob.fetch_prices(token_ids)
return [
{**m, "current_price": prices.get(m.get("conditionId", ""))}
for m in markets
]
results = asyncio.run(full_scan("temperature"))
DiskCache¶
Avoid hitting the API on every scan by caching responses to disk.
Basic usage¶
from pmlab import DiskCache, GammaClient
cache = DiskCache(cache_dir=".pmlab_cache", ttl_seconds=3600) # 1-hour TTL
client = GammaClient(cache=cache)
markets = client.fetch_markets(tag="temperature") # API call
markets = client.fetch_markets(tag="temperature") # served from disk cache
Manual cache operations¶
from pmlab import DiskCache
cache = DiskCache(".pmlab_cache", ttl_seconds=1800)
# Set a value
cache.set("my_key", {"data": [1, 2, 3]})
# Get a value (returns None if missing or expired)
value = cache.get("my_key")
value = cache.get("missing", default=[]) # custom default
# Check membership
if "my_key" in cache:
print("cached!")
# Delete one entry
cache.delete("my_key")
# Remove all entries
cache.clear()
# Remove only expired entries
purged = cache.purge_expired()
print(f"Purged {purged} expired entries")
Cache key design¶
The cache uses MD5 hashes of the key string. Keys can be any string — use descriptive prefixes:
cache.set(f"gamma:markets:{tag}:{limit}", markets)
cache.set(f"clob:price:{token_id}", price)
cache.set(f"weather:forecast:{city}:{date}", forecast)
TTL recommendations¶
| Data type | Recommended TTL |
|---|---|
| Polymarket market list | 1–4 hours (3600–14400) |
| CLOB prices | 5–15 minutes (300–900) |
| Weather forecasts | 3–6 hours (10800–21600) |
| Resolved outcomes | 24 hours+ (86400) |
Choosing Sync vs Async¶
| Use sync when | Use async when |
|---|---|
| Fetching a single tag/set of markets | Fetching 50+ token prices |
| Running in a cron script | Building a real-time scanner |
| Simplicity matters | Latency matters |
| < 10 tokens | 10+ tokens |