Polymarket betting analysis tool. Fetches market data from Polymarket, analyzes it using AI (Perplexity), and produces bet recommendations with position sizing.
- .NET 10 SDK (install)
Install via script (no sudo):
curl -sSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 10.0 --install-dir ~/.dotnet
export PATH="$HOME/.dotnet:$PATH"- Clone the repo
- Copy
config.local.jsonand add your API keys:# config.local.json is git-ignored and holds your secrets # Edit it and add your Perplexity API key:
Get a key at perplexity.ai/settings/api{ "analysisProviders": { "perplexity": { "apiKey": "pplx-your-key-here" } } } - Adjust
capitalManagement.maxCapitalUsdinconfig.jsonto your desired max capital - (Optional) Add your Polymarket wallet address to track positions:
{ "user": { "walletAddress": "0x..." } }
# Fetch current market data from Polymarket (no API key needed)
dotnet run --project src/Polybate -- fetch
# Analyze latest snapshot with Perplexity (requires API key)
dotnet run --project src/Polybate -- analyze
# Analyze with a specific provider
dotnet run --project src/Polybate -- analyze --provider=perplexity
# Run all providers and combine into master recommendations
dotnet run --project src/Polybate -- master-analysis
# Fetch your current Polymarket positions (requires wallet address in config)
dotnet run --project src/Polybate -- currentThe tool operates in two stages:
- Fetch - Retrieves events, markets, and price data from Polymarket's Gamma and CLOB APIs. Also fetches 7-day price history for the top 20 markets. Saves a JSON snapshot to
data/snapshots/. - Analyze - Loads the latest snapshot, sends market data (including historical trends) to an AI analysis provider (Perplexity), and produces recommendations saved to
data/recommendations/as both JSON and Markdown.
Stages are independent. You can fetch once and run analysis multiple times on the same snapshot.
The fetch command retrieves 7 days of price history for the top 20 markets (by volume, filtered for meaningful uncertainty). This data is included in analysis prompts to help detect:
- Momentum: Sustained price movement may indicate emerging consensus or new information
- Reversals: Recent direction change may indicate market overreaction or correction
- Stability: Stable prices with sudden movement warrant investigation
Historical data is summarized per-outcome in the prompt (not raw data points) to keep prompt size manageable. Example trend line: 7d Trend: +0.082 (+8.2%), strongly rising
The analyze command does not send the entire snapshot to Perplexity. A snapshot typically contains 10,000+ markets; the algorithm narrows that down to 20 before making the API call, then post-processes the response into sized recommendations. The steps:
Three filters are applied in sequence, then the result is sorted and truncated:
| Step | Filter | Purpose |
|---|---|---|
| 1 | Active && !Closed |
Drop resolved or inactive markets |
| 2 | Volume > $1,000 |
Drop illiquid markets where you can't get meaningful fill |
| 3 | At least one outcome price in the 5%–95% range | Key filter. The highest-volume Polymarket markets are overwhelmingly near-certainties (99%+ or <1%) — long-tail questions like "will celebrity X win nomination." These have no edge. This filter keeps only markets with genuine uncertainty. |
| 4 | Sort by volume descending, take top 20 | Among the uncertain markets, prefer the most liquid. 20 is the practical limit for a single prompt. |
Each of the 20 markets is included with: numeric ID, question text, each outcome with its current price and implied probability, total volume, liquidity, and end date.
The prompt frames the task as pure probability estimation: estimate the true probability of each outcome and flag where the market price is wrong by more than 3 percentage points. Capital and bet-size constraints are deliberately excluded — telling the LLM about a $2 max bet causes it to self-censor and dismiss all opportunities. Position sizing is handled after parsing by the Kelly criterion.
Perplexity's built-in web search provides current news and data relevant to each market question.
The response is split on the literal keyword RECOMMENDATION. Each fragment is scanned line-by-line for structured fields: market_id, outcome, estimated_probability, confidence, timeframe, explanation. A recommendation is kept only if the market ID matches one of the 20 markets sent and the outcome matches a valid outcome name on that market. The confidence text (low/medium/high) maps to a numeric score (0.35 / 0.60 / 0.85).
Each recommendation is sized independently:
b = (1 / currentPrice) - 1 // decimal odds
kellyFraction = (b×p - q) / b // full Kelly, where p = estimated prob, q = 1-p
f = kellyFraction × kellyConfig × confidenceScore
f is clamped to [0, maxSingleBetFraction]. If the total dollar allocation across all recommendations exceeds maxCapitalUsd, all amounts are scaled down proportionally.
Configuration is split into two files:
config.json- versioned in git, contains all non-sensitive settingsconfig.local.json- git-ignored, contains secrets (API keys)
config.local.json is deep-merged on top of config.json at startup. You only need to put the keys you want to override in the local file.
| Section | Default | Description |
|---|---|---|
capitalManagement.maxCapitalUsd |
1000.00 |
Maximum total capital for recommendations |
capitalManagement.kellyFraction |
0.25 |
Fractional Kelly multiplier (0.25 = quarter-Kelly) |
capitalManagement.maxSingleBetFraction |
0.10 |
Max fraction of capital per single bet |
polymarket.historyDays |
7 |
Days of historical price data to fetch |
polymarket.historyInterval |
"6h" |
Price history resolution (1m, 1h, 6h, 1d, 1w) |
polymarket.historyMarketsLimit |
20 |
Number of markets to fetch history for |
analysisProviders.perplexity.model |
"sonar-pro" |
Perplexity model for analysis |
masterAnalysis.model |
"sonar-reasoning" |
Model used for combining multi-provider results |
| Section | Description |
|---|---|
analysisProviders.perplexity.apiKey |
Perplexity API key |
user.walletAddress |
Your Polymarket wallet address (for current command) |
Recommendations are saved to data/recommendations/ with both JSON and Markdown formats:
perplexity_20260203_143000.json- machine-readable recommendationsperplexity_20260203_143000.md- human-readable report with summary table and detailed analysis
The raw AI response from the most recent analyze run is always saved to data/last_raw_response_perplexity.txt (overwritten each run) for debugging.
Each recommendation includes:
- Market link, question, outcomes, current prices
- Estimated probability and edge over market price
- Confidence score
- Recommended amount (Kelly criterion-based)
- Timeframe rationale
- Detailed explanation with sources
src/Polybate/
├── Program.cs # Entry point, config loading, command routing
├── Commands/ # CLI command implementations
│ ├── ICommand.cs
│ ├── FetchCommand.cs
│ ├── AnalyzeCommand.cs
│ ├── MasterAnalysisCommand.cs
│ └── CurrentCommand.cs
├── Models/ # Data models (config, domain, analysis)
├── Services/ # Business logic
│ ├── PolymarketService.cs # Polymarket API integration
│ ├── IAnalysisProvider.cs # Extensible analysis interface
│ ├── PerplexityAnalysisProvider.cs
│ └── RecommendationEngine.cs # Master analysis combiner
└── Storage/
└── FileStorageService.cs # JSON + Markdown persistence
- Implement
IAnalysisProvider(seePerplexityAnalysisProvider.csas reference) - Add provider config section to
config.jsonunderanalysisProviders - Register in
Program.csalongside the Perplexity provider - Use via
dotnet run --project src/Polybate -- analyze --provider=yourprovider
- Polymarket Gamma API (
gamma-api.polymarket.com) - market discovery, no auth needed - Polymarket CLOB API (
clob.polymarket.com) - pricing data, no auth needed - Polymarket Data API (
data-api.polymarket.com) - user positions, no auth needed (just wallet address) - Perplexity API (
api.perplexity.ai) - AI analysis with web search and citations
Zero external NuGet packages. Uses only built-in .NET libraries (System.Text.Json, HttpClient).