Initial commit with translated description

This commit is contained in:
2026-03-29 09:38:03 +08:00
commit 3190b1b9ff
3 changed files with 386 additions and 0 deletions

103
SKILL.md Normal file
View 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
View File

@@ -0,0 +1,6 @@
{
"ownerId": "kn73vt6y69bfa21fmmwc7qrrrn7zwjxw",
"slug": "polymarket-odds",
"version": "1.0.0",
"publishedAt": 1769364207598
}

277
polymarket.mjs Normal file
View 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);
}
})();