No prediction market platform has a complete bot tutorial. Polymarket has a GitHub agents repo with no walkthrough. Kalshi has SDKs with no strategy docs. Every platform says "build a bot" and then gives you a raw API reference.
Here is the tutorial that should have existed years ago. By the end, you will have a working bot that reads market data, computes signals, encodes bets as bitmaps, submits them on-chain through commit-reveal, and tracks performance on the live leaderboard. Ten minutes, real code, no hand-waving.
Prerequisites
Before you start, make sure you have:
- A wallet — MetaMask or any EVM-compatible wallet with a private key you can export
- USDC on Arbitrum — bridge from mainnet if needed, or use a faucet for testnet
- Node.js 18+ or Python 3.10+ — the tutorial shows both
- Optional: Claude Code or any AI agent framework — useful for strategy iteration, not required
Minimum capital to start: $0.10 per tick. You can test a full strategy for under a dollar.
Step 1: Scaffold Your Bot
One command sets up the entire project:
npx generalmarket init
This scaffolds:
my-bot/
├── config.json # RPC endpoint, wallet address, batch preferences
├── strategy.ts # Your strategy logic — the only file you edit
├── lib/
│ ├── data.ts # Fetches market data from the data node
│ ├── bitmap.ts # Encodes your bets into packed binary
│ ├── submit.ts # Commit-reveal submission pipeline
│ └── monitor.ts # Balance and P&L tracking
├── package.json
└── .env.example # PRIVATE_KEY goes here
Copy .env.example to .env and add your private key. The config file comes pre-filled with the production RPC and API endpoints. You do not need to hunt for URLs.
cd my-bot
npm install
cp .env.example .env
# Add your private key to .env
If you prefer Python, pass the --python flag:
npx generalmarket init --python
Same structure, same logic, different language. Both are first-class.
Step 2: Understand the Data Sources
Vision runs 25,000+ prediction markets across 79 data feeds. Each market is a simple binary question: will this value go UP or DOWN in the next tick?
Browse all available sources at /sources. Or hit the data node API directly:
curl https://www.generalmarket.io/api/vision/markets/active
The response contains every active market:
[
{
"id": 42,
"source": "weather_tokyo_temp",
"name": "Tokyo Temperature",
"value": 18.4,
"change24h": 2.1
},
{
"id": 107,
"source": "crypto_btc_usd",
"name": "BTC/USD",
"value": 84521.30,
"change24h": -1.8
},
{
"id": 213,
"source": "earthquake_global_mag5",
"name": "Global Earthquakes Mag 5+",
"value": 3,
"change24h": 0
}
]
Each market has an id (used in bitmap encoding), a source name, the current value, and a change24h percentage. Your strategy reads these fields and decides UP or DOWN for each market.
Picking your niche matters. Crypto prices are crowded — hundreds of bots compete on BTC and ETH. But earthquake frequency, weather patterns, tech infrastructure metrics? Almost no competition. The fewer bots trading a market, the more edge you have. This is the core thesis: niche data sources are where alpha lives.
Step 3: Write a Simple Strategy
Here is a complete momentum strategy in TypeScript. If the 24h change is positive, bet UP. If negative, bet DOWN. Simple, but it illustrates the full pipeline.
// strategy.ts
import { fetchActiveMarkets, Market } from "./lib/data";
export type Bet = "UP" | "DOWN";
export async function computeBets(): Promise<{ bets: Bet[]; marketCount: number }> {
const markets: Market[] = await fetchActiveMarkets();
const bets: Bet[] = markets.map((market) => {
// Momentum: positive 24h change → UP, negative → DOWN
return market.change24h > 0 ? "UP" : "DOWN";
});
return { bets, marketCount: markets.length };
}
That is a toy strategy. Here is a slightly smarter one — mean reversion on weather data, momentum on everything else:
export async function computeBets(): Promise<{ bets: Bet[]; marketCount: number }> {
const markets: Market[] = await fetchActiveMarkets();
const bets: Bet[] = markets.map((market) => {
if (market.source.startsWith("weather_")) {
// Mean reversion: if temperature spiked, bet it comes back down
return market.change24h > 3.0 ? "DOWN" : "UP";
}
// Default: momentum
return market.change24h > 0 ? "UP" : "DOWN";
});
return { bets, marketCount: markets.length };
}
The key insight: you can use different logic for different data sources within the same bitmap. Weather reverts. Crypto trends. Earthquakes are random. Your strategy should reflect this.
Building a Claude Code Trading Bot
If you are using Claude Code or another AI agent framework, you can go further. Feed Claude the market data and ask it to reason about each source:
import Anthropic from "@anthropic-ai/sdk";
async function getAIBets(markets: Market[]): Promise<Bet[]> {
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [
{
role: "user",
content: `You are a prediction market trader. For each market below, predict UP or DOWN for the next tick. Return ONLY a JSON array of "UP" or "DOWN" strings, one per market, in order.
Markets:
${markets.map((m) => `${m.id}: ${m.name} — current: ${m.value}, 24h change: ${m.change24h}%`).join("\n")}`,
},
],
});
return JSON.parse(response.content[0].text);
}
This is not hypothetical. Multiple bots on Vision use LLM-based strategies. The sealed-bet mechanism means nobody can see your reasoning — only your results on the leaderboard.
Step 4: Encode the Bitmap
Vision uses packed binary bitmaps for bets. One bit per market. 1 means UP, 0 means DOWN. Big-endian byte order.
If you are betting on 25 markets, you need ceil(25/8) = 4 bytes (32 bits, with the last 7 bits unused).
TypeScript
// lib/bitmap.ts
export function encodeBitmap(bets: string[], marketCount: number): Uint8Array {
const byteCount = Math.ceil(marketCount / 8);
const bitmap = new Uint8Array(byteCount);
for (let i = 0; i < marketCount; i++) {
if (i < bets.length && bets[i] === "UP") {
const byteIdx = Math.floor(i / 8);
const bitIdx = 7 - (i % 8); // big-endian
bitmap[byteIdx] |= 1 << bitIdx;
}
}
return bitmap;
}
Python
def encode_bitmap(bets: list[str], market_count: int) -> bytes:
byte_count = (market_count + 7) // 8
bitmap = bytearray(byte_count)
for i in range(market_count):
if i < len(bets) and bets[i] == "UP":
byte_idx = i // 8
bit_idx = 7 - (i % 8) # big-endian
bitmap[byte_idx] |= 1 << bit_idx
return bytes(bitmap)
Example: 8 markets, bets = [UP, DOWN, UP, UP, DOWN, DOWN, UP, DOWN]
Bit layout: 1 0 1 1 0 0 1 0
Byte value: 0xB2 (178 decimal)
One byte encodes 8 markets. A bitmap for all 25,000+ markets fits in about 3.2 KB. The encoding is compact by design.
Step 5: Submit Your Bets (Commit-Reveal)
Vision uses commit-reveal to prevent front-running. You commit a hash first, then reveal the actual bitmap. Nobody can see your bets until after the commitment window closes.
Step 5a: Hash the Bitmap
import { keccak256 } from "ethers";
const bitmap = encodeBitmap(bets, marketCount);
const bitmapHash = keccak256(bitmap);
Step 5b: Commit On-Chain
Call joinBatch on the Vision contract. This locks in your commitment and deposits your stake.
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const vision = new ethers.Contract(VISION_ADDRESS, VISION_ABI, wallet);
const tx = await vision.joinBatch(
batchId, // which batch to join
ethers.parseUnits("1.0", 6), // deposit amount (USDC, 6 decimals)
ethers.parseUnits("0.10", 6), // stake per tick ($0.10 minimum)
bitmapHash // keccak256 of your bitmap
);
await tx.wait();
console.log("Committed:", tx.hash);
Step 5c: Reveal to Issuer Nodes
After committing on-chain, POST the actual bitmap bytes to the issuer network. They verify it matches your hash.
const response = await fetch("https://www.generalmarket.io/api/vision/bitmap", {
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
body: bitmap,
});
if (!response.ok) throw new Error(`Reveal failed: ${response.status}`);
console.log("Revealed bitmap to issuer nodes");
The sequence matters: commit first, then reveal. If you reveal before committing, your bets are visible and you lose the sealed-bet advantage. The scaffolded project handles this ordering automatically.
Step 6: Monitor Performance
Once your bot is live, it appears on the leaderboard at generalmarket.io. Track three numbers:
- P&L per tick — are you net positive over the last 100 ticks?
- Win rate — what percentage of individual market bets are correct?
- Portfolio breadth — how many markets are you betting on per tick?
Check your balance programmatically:
curl https://www.generalmarket.io/api/vision/balance/{batchId}/{yourAddress}
const balanceRes = await fetch(
`https://www.generalmarket.io/api/vision/balance/${batchId}/${wallet.address}`
);
const balance = await balanceRes.json();
console.log(`Current balance: $${balance.amount}`);
console.log(`Win rate: ${balance.winRate}%`);
When you are ready to withdraw, claim winnings via a BLS balance proof. The claim is verified on-chain — no trust required.
Step 7: Register On-Chain (Optional)
If you want your bot to have a public profile on the leaderboard:
const tx = await vision.registerBot(
"https://your-bot-endpoint.com", // public endpoint (optional, can be empty)
pubkeyHash // keccak256 of your bot's public key
);
await tx.wait();
Registration is free. No collateral required. Your bot gets a profile showing its performance stats — win rate, P&L history, markets traded. Other traders can see how you perform, but they can never see your strategy. Bets are sealed until resolution.
Tips for Better Performance
Diversify across data sources. The biggest mistake new bot builders make is trading only crypto. BTC and ETH have hundreds of competitors. Weather data, earthquake monitors, and tech metrics have almost none. Fewer competitors means more edge per correct prediction.
Bigger portfolio = more edge. Betting on 50+ markets per tick averages out noise. If your strategy has a 55% accuracy rate, that is barely distinguishable from random on 5 markets but statistically significant across 200. Top bots on the leaderboard trade 100+ markets simultaneously.
Match tick duration to strategy type. Five-minute ticks suit momentum and mean reversion on volatile data. One-hour or one-day ticks suit fundamental analysis — weather forecasts, economic indicators, slower-moving feeds. The config.json from npx generalmarket init lets you set your preferred tick duration.
Start with $0.10 stakes. The minimum stake per tick is ten cents. Run your bot for a week at minimum stake before committing real capital. A week of data gives you roughly 2,000 ticks on 5-minute intervals — enough to measure whether your strategy has real edge or got lucky.
Iterate with AI. If you are building a Claude Code trading bot, use the feedback loop: run the strategy, collect results, feed the win/loss data back into the prompt, and ask Claude to refine the logic. This is where AI agent frameworks shine — not in raw prediction accuracy, but in rapid iteration over strategy parameters.
Never overfit to recent data. A strategy that perfectly predicts yesterday's markets will underperform tomorrow. Keep your logic simple. The best-performing bots on Vision use 3-5 signals at most. Complexity is the enemy of robustness.
The Full Loop
Here is the complete flow in one script:
import { computeBets } from "./strategy";
import { encodeBitmap } from "./lib/bitmap";
import { keccak256, ethers } from "ethers";
async function main() {
// 1. Compute signals
const { bets, marketCount } = await computeBets();
console.log(`Generated ${bets.length} bets across ${marketCount} markets`);
// 2. Encode bitmap
const bitmap = encodeBitmap(bets, marketCount);
// 3. Hash for commitment
const bitmapHash = keccak256(bitmap);
// 4. Commit on-chain
const tx = await vision.joinBatch(batchId, deposit, stakePerTick, bitmapHash);
await tx.wait();
// 5. Reveal to issuer nodes
await fetch("https://www.generalmarket.io/api/vision/bitmap", {
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
body: bitmap,
});
console.log("Bets submitted. Check leaderboard at generalmarket.io");
}
main().catch(console.error);
Five steps. Fetch data, compute signals, encode bitmap, commit hash, reveal bitmap. Every bot on Vision follows this exact pipeline. The only variable is what happens inside computeBets() — that is where your edge lives.
Fee Structure
Vision charges 0.3% on profit only. If you lose a tick, you pay nothing in fees. If you win $10 on a tick, you pay $0.03. There is no entry fee, no subscription, no platform cut on losses. This makes it viable to run strategies at very small scale while testing.
Further Reading
- AI Prediction Markets — Why Vision is built for AI agents
- Prediction Market Bots — How bots are beating human traders
- Browse Data Sources — Explore all 79 data feeds
- What Are ITPs? — Index Tracking Products on General Market