Initial commit with translated description
This commit is contained in:
103
SKILL.md
Normal file
103
SKILL.md
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
name: Polymarket
|
||||
description: "通过CLI查询Polymarket预测市场赔率和事件。搜索市场、获取当前价格、按类别列出事件。支持体育博彩(NFL、NBA、足球/英超、欧冠)、政治、加密货币、选举、地缘政治。真钱市场比民意调查更准确。无需API密钥。当被问及赔率、概率、预测或"X的可能性有多大"时使用。"
|
||||
---
|
||||
|
||||
# Polymarket Prediction Markets
|
||||
|
||||
Query real-time odds from Polymarket, the world's largest prediction market.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Search for markets (instant via /public-search API)
|
||||
polymarket search "Arsenal FC"
|
||||
polymarket search "Super Bowl"
|
||||
polymarket search "Bitcoin"
|
||||
polymarket search "Trump"
|
||||
|
||||
# Browse by category
|
||||
polymarket events --tag=sports
|
||||
polymarket events --tag=crypto
|
||||
polymarket events --tag=politics
|
||||
|
||||
# Get specific market details
|
||||
polymarket market will-bitcoin-reach-100k
|
||||
```
|
||||
|
||||
The CLI is at `polymarket.mjs` in this skill folder. Run with:
|
||||
```bash
|
||||
node /path/to/skill/polymarket.mjs <command>
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `search <query>` | Search markets by keyword (recommended) |
|
||||
| `events [options]` | List active events |
|
||||
| `market <slug>` | Get market details by slug |
|
||||
| `tags` | List available categories |
|
||||
| `price <token_id>` | Get current price for a token |
|
||||
| `book <token_id>` | Get orderbook depth |
|
||||
|
||||
## Event Options
|
||||
|
||||
- `--tag=<slug>` - Filter by category (crypto, politics, sports, etc.)
|
||||
- `--limit=<n>` - Maximum results (default: 20)
|
||||
|
||||
## Understanding Odds
|
||||
|
||||
Prices = Probabilities:
|
||||
- 0.65 (65¢) = 65% chance of "Yes"
|
||||
- Volume = total $ traded
|
||||
- Liquidity = available $ in orderbook
|
||||
|
||||
## Individual Match Betting
|
||||
|
||||
Polymarket has individual match markets for soccer, NFL, NBA, and more.
|
||||
|
||||
```bash
|
||||
# Soccer - use "FC" suffix for team names
|
||||
polymarket search "Arsenal FC"
|
||||
polymarket search "Manchester United FC"
|
||||
polymarket search "Liverpool FC"
|
||||
|
||||
# NFL/NBA - team name works
|
||||
polymarket search "Patriots"
|
||||
polymarket search "Chiefs"
|
||||
polymarket search "Lakers"
|
||||
```
|
||||
|
||||
**Market types available:**
|
||||
- **Moneyline**: Win/Draw/Lose percentages
|
||||
- **Spreads**: e.g., Arsenal -1.5
|
||||
- **Totals**: Over/Under 2.5 goals
|
||||
- **BTTS**: Both Teams to Score
|
||||
|
||||
## Common Categories
|
||||
|
||||
| Tag | Markets |
|
||||
|-----|---------|
|
||||
| `sports` | NFL, NBA, soccer, tennis, etc. |
|
||||
| `politics` | Elections, legislation, appointments |
|
||||
| `crypto` | Price targets, ETFs, regulations |
|
||||
| `business` | IPOs, acquisitions, earnings |
|
||||
| `tech` | Product launches, AI developments |
|
||||
|
||||
## API Reference
|
||||
|
||||
The CLI uses these public endpoints (no auth required):
|
||||
|
||||
- **Search**: `GET /public-search?q=<query>` - keyword search
|
||||
- **Events**: `GET /events?active=true&closed=false` - list events
|
||||
- **Markets**: `GET /markets?slug=<slug>` - market details
|
||||
- **Tags**: `GET /tags` - available categories
|
||||
|
||||
Base URL: `https://gamma-api.polymarket.com`
|
||||
|
||||
## Notes
|
||||
|
||||
- Real money markets tend to be more accurate than polls/pundits
|
||||
- Odds update in real-time as people trade
|
||||
- Markets resolve to $1.00 (correct) or $0.00 (incorrect)
|
||||
6
_meta.json
Normal file
6
_meta.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn73vt6y69bfa21fmmwc7qrrrn7zwjxw",
|
||||
"slug": "polymarket-odds",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1769364207598
|
||||
}
|
||||
277
polymarket.mjs
Normal file
277
polymarket.mjs
Normal file
@@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Polymarket CLI - Query prediction market odds
|
||||
*
|
||||
* Usage:
|
||||
* polymarket search <query> - Search for markets by keyword
|
||||
* polymarket events [options] - List events with filters
|
||||
* polymarket market <slug> - Get market details and current odds
|
||||
* polymarket sports - List sports leagues/series
|
||||
* polymarket tags - List available categories
|
||||
* polymarket price <token_id> - Get current price for a token
|
||||
*/
|
||||
|
||||
const GAMMA_API = 'https://gamma-api.polymarket.com';
|
||||
const CLOB_API = 'https://clob.polymarket.com';
|
||||
|
||||
async function fetchJSON(url) {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function parsePrice(pricesStr) {
|
||||
try {
|
||||
const prices = JSON.parse(pricesStr);
|
||||
return prices.map(p => (parseFloat(p) * 100).toFixed(1) + '%');
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function parseOutcomes(outcomesStr) {
|
||||
try {
|
||||
return JSON.parse(outcomesStr);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function formatMarket(market, verbose = false) {
|
||||
const outcomes = parseOutcomes(market.outcomes);
|
||||
const prices = parsePrice(market.outcomePrices);
|
||||
const odds = outcomes.map((o, i) => `${o}: ${prices[i] || '?'}`).join(' | ');
|
||||
|
||||
let out = `📊 ${market.question}\n`;
|
||||
out += ` ${odds}\n`;
|
||||
out += ` Volume: $${(market.volumeNum || 0).toLocaleString()}`;
|
||||
if (market.liquidity) out += ` | Liquidity: $${parseFloat(market.liquidity).toLocaleString()}`;
|
||||
if (verbose) {
|
||||
out += `\n Slug: ${market.slug}`;
|
||||
if (market.endDate) out += `\n Ends: ${market.endDate.split('T')[0]}`;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function formatEvent(event, verbose = false) {
|
||||
let out = `\n🎯 ${event.title}\n`;
|
||||
if (event.description && verbose) {
|
||||
out += ` ${event.description.slice(0, 200)}${event.description.length > 200 ? '...' : ''}\n`;
|
||||
}
|
||||
out += ` Volume: $${(event.volume || 0).toLocaleString()}`;
|
||||
if (event.liquidity) out += ` | Liquidity: $${parseFloat(event.liquidity).toLocaleString()}`;
|
||||
out += '\n';
|
||||
|
||||
if (event.markets && event.markets.length > 0) {
|
||||
for (const m of event.markets.slice(0, 5)) {
|
||||
if (m.active && !m.closed) {
|
||||
out += formatMarket(m, verbose) + '\n';
|
||||
}
|
||||
}
|
||||
if (event.markets.length > 5) {
|
||||
out += ` ... and ${event.markets.length - 5} more markets\n`;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
async function search(query, limit = 10) {
|
||||
// Use the public-search endpoint for efficient keyword search
|
||||
const url = `${GAMMA_API}/public-search?q=${encodeURIComponent(query)}&limit=50`;
|
||||
const data = await fetchJSON(url);
|
||||
|
||||
if (!data.events || data.events.length === 0) {
|
||||
console.log(`No markets found for "${query}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter to only active, non-closed events
|
||||
const matches = data.events.filter(e => e.active && !e.closed).slice(0, limit);
|
||||
|
||||
if (matches.length === 0) {
|
||||
console.log(`No active markets found for "${query}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Found ${matches.length} active events matching "${query}":\n`);
|
||||
for (const event of matches) {
|
||||
console.log(formatEvent(event, true));
|
||||
}
|
||||
}
|
||||
|
||||
async function listEvents(options = {}) {
|
||||
const params = new URLSearchParams();
|
||||
params.set('active', 'true');
|
||||
params.set('closed', 'false');
|
||||
params.set('limit', options.limit || '20');
|
||||
|
||||
if (options.tag) params.set('tag_slug', options.tag);
|
||||
if (options.series) params.set('series_id', options.series);
|
||||
if (options.order) params.set('order', options.order);
|
||||
|
||||
const url = `${GAMMA_API}/events?${params}`;
|
||||
const events = await fetchJSON(url);
|
||||
|
||||
console.log(`Active events (${events.length}):\n`);
|
||||
for (const event of events) {
|
||||
console.log(formatEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
async function getMarket(slugOrId) {
|
||||
const url = `${GAMMA_API}/markets?slug=${encodeURIComponent(slugOrId)}`;
|
||||
const markets = await fetchJSON(url);
|
||||
|
||||
if (!markets || markets.length === 0) {
|
||||
// Try by ID
|
||||
const byIdUrl = `${GAMMA_API}/markets/${slugOrId}`;
|
||||
try {
|
||||
const market = await fetchJSON(byIdUrl);
|
||||
console.log(formatMarket(market, true));
|
||||
return;
|
||||
} catch {
|
||||
console.log(`Market not found: ${slugOrId}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const market of markets) {
|
||||
console.log(formatMarket(market, true));
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
|
||||
async function listSports() {
|
||||
const url = `${GAMMA_API}/sports`;
|
||||
try {
|
||||
const sports = await fetchJSON(url);
|
||||
console.log('Sports leagues:\n');
|
||||
for (const sport of sports.slice(0, 30)) {
|
||||
console.log(` ${sport.label || sport.title} (series_id: ${sport.id})`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Sports endpoint not available or empty');
|
||||
}
|
||||
}
|
||||
|
||||
async function listTags(limit = 50) {
|
||||
const url = `${GAMMA_API}/tags?limit=${limit}`;
|
||||
const tags = await fetchJSON(url);
|
||||
|
||||
console.log('Available categories:\n');
|
||||
for (const tag of tags) {
|
||||
console.log(` ${tag.label} (slug: ${tag.slug})`);
|
||||
}
|
||||
}
|
||||
|
||||
async function getPrice(tokenId, side = 'buy') {
|
||||
const url = `${CLOB_API}/price?token_id=${tokenId}&side=${side}`;
|
||||
try {
|
||||
const data = await fetchJSON(url);
|
||||
console.log(`Price (${side}): ${(parseFloat(data.price) * 100).toFixed(1)}%`);
|
||||
} catch (e) {
|
||||
console.log(`Error fetching price: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function getOrderbook(tokenId) {
|
||||
const url = `${CLOB_API}/book?token_id=${tokenId}`;
|
||||
try {
|
||||
const data = await fetchJSON(url);
|
||||
console.log('Orderbook:');
|
||||
console.log(' Bids:', data.bids?.slice(0, 5).map(b => `${(parseFloat(b.price)*100).toFixed(1)}% x $${b.size}`).join(', ') || 'none');
|
||||
console.log(' Asks:', data.asks?.slice(0, 5).map(a => `${(parseFloat(a.price)*100).toFixed(1)}% x $${a.size}`).join(', ') || 'none');
|
||||
} catch (e) {
|
||||
console.log(`Error fetching orderbook: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Main
|
||||
const [,, cmd, ...args] = process.argv;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
switch (cmd) {
|
||||
case 'search':
|
||||
case 's':
|
||||
if (!args[0]) {
|
||||
console.log('Usage: polymarket search <query>');
|
||||
process.exit(1);
|
||||
}
|
||||
await search(args.join(' '), parseInt(args.find(a => a.startsWith('--limit='))?.split('=')[1]) || 10);
|
||||
break;
|
||||
|
||||
case 'events':
|
||||
case 'e':
|
||||
const evtOpts = {};
|
||||
for (const arg of args) {
|
||||
if (arg.startsWith('--tag=')) evtOpts.tag = arg.split('=')[1];
|
||||
if (arg.startsWith('--series=')) evtOpts.series = arg.split('=')[1];
|
||||
if (arg.startsWith('--limit=')) evtOpts.limit = arg.split('=')[1];
|
||||
if (arg.startsWith('--order=')) evtOpts.order = arg.split('=')[1];
|
||||
}
|
||||
await listEvents(evtOpts);
|
||||
break;
|
||||
|
||||
case 'market':
|
||||
case 'm':
|
||||
if (!args[0]) {
|
||||
console.log('Usage: polymarket market <slug>');
|
||||
process.exit(1);
|
||||
}
|
||||
await getMarket(args[0]);
|
||||
break;
|
||||
|
||||
case 'sports':
|
||||
await listSports();
|
||||
break;
|
||||
|
||||
case 'tags':
|
||||
case 't':
|
||||
await listTags(parseInt(args[0]) || 50);
|
||||
break;
|
||||
|
||||
case 'price':
|
||||
case 'p':
|
||||
if (!args[0]) {
|
||||
console.log('Usage: polymarket price <token_id> [buy|sell]');
|
||||
process.exit(1);
|
||||
}
|
||||
await getPrice(args[0], args[1] || 'buy');
|
||||
break;
|
||||
|
||||
case 'book':
|
||||
case 'b':
|
||||
if (!args[0]) {
|
||||
console.log('Usage: polymarket book <token_id>');
|
||||
process.exit(1);
|
||||
}
|
||||
await getOrderbook(args[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`Polymarket CLI - Query prediction market odds
|
||||
|
||||
Commands:
|
||||
search <query> Search markets by keyword
|
||||
events [options] List active events
|
||||
--tag=<slug> Filter by category (crypto, politics, sports, etc.)
|
||||
--limit=<n> Max results (default: 20)
|
||||
market <slug> Get market details and current odds
|
||||
sports List sports leagues
|
||||
tags List available categories
|
||||
price <token_id> Get current price for a token
|
||||
book <token_id> Get orderbook for a token
|
||||
|
||||
Examples:
|
||||
polymarket search "super bowl"
|
||||
polymarket search "bitcoin 100k"
|
||||
polymarket events --tag=crypto --limit=10
|
||||
polymarket market will-bitcoin-reach-100k
|
||||
`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user