Prediction Market Dashboard – Project Submission
About the Project
Despite being incredibly powerful predictive tools, prediction markets aren't very well-understood by the public. They aggregate the collective wisdom of participants who put real money behind their beliefs, making them remarkably accurate at forecasting future events—from elections to sports to economic indicators. Yet accessing this information requires visiting multiple platforms, understanding complex interfaces, and manually correlating data.
Prediction Market Dashboard bridges this gap by using agentic workflows to aggregate, expand, and clarify expected outcomes from major prediction market platforms. We provide a unified interface where users can search across markets, view real-time price movements, and access AI-curated news that contextualizes market movements—all in one place.
Inspiration
The idea came from experiencing the 2024 election cycle firsthand. Prediction markets like Polymarket and Kalshi were generating incredibly accurate signals about election outcomes, but:
- Fragmentation: Data was scattered across multiple platforms with different interfaces
- No context: Raw probabilities without news context left users guessing why prices moved
- Technical barriers: Order books, spreads, and outcome contracts confused casual users
We asked ourselves: What if there was a Bloomberg Terminal for prediction markets: one that was accessible to everyone?
The result is this dashboard: a real-time aggregation platform that combines market data from Polymarket (20,000+ markets) and Kalshi (5,000+ markets) with live news from 4+ sources, all orchestrated by three AI agents that helps users navigate this complexity. Two of the models used within the agent are the GPT-OSS model for speed analysis, and the third is provided by backboard.io for adaptive generation over time.
What We Learned
Building this project taught us several key lessons:
1. API Design Matters
Polymarket uses a dual-API architecture (Gamma for discovery, CLOB for trading), while Kalshi has a unified REST API. Normalizing these into a single Market schema required careful abstraction:
# Our unified schema handles both platforms
class Market(BaseModel):
market_id: str
title: str
source: Literal["polymarket", "kalshi"]
outcomes: List[Outcome]
sector: Optional[str] # Politics, Sports, Economics, etc.
2. Real-Time Data is Hard
WebSocket connections for live market updates required a subscription manager that:
- Spawns pollers only for actively-viewed markets
- Handles reconnection gracefully
- Broadcasts updates to multiple subscribers
3. News Ranking is Nuanced
We built a sophisticated ranking algorithm that balances:
$$\text{Score} = 0.50 \cdot \text{Relevance} + 0.35 \cdot \text{Recency} + 0.15 \cdot \text{Quality}$$
Where recency uses exponential decay with a 48-hour half-life:
$$\text{Recency}(t) = 0.5^{t/48}$$
4. Agentic Workflows Need Structure
Our AI agent follows a Thought-Action-Observation loop:
// Agent Controller processes natural language
events.push(createEvent(`Thought: analyzing "${input}"`));
if (input.includes("news")) {
events.push(createEvent("Action: opening news feed panel"));
executeCommand(COMMANDS.OPEN_PANEL, { panelType: "NEWS_FEED" });
}
5. Managing Model Context is Incredibly Difficult Between User Sessions and Different Business Logic.
This gave us a greater appreciation for services such as backboard.io which pre-tunes the model and handles all memory context out-of-the-box.
How We Built It
Architecture
The project follows a full-stack TypeScript/Python architecture:
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND │
│ React 19 + TypeScript + Zustand + TailwindCSS │
│ ├── Resizable drag-and-drop panel grid │
│ ├── Real-time WebSocket chart updates │
│ ├── Server-Sent Events for streaming news │
│ └── Command palette with AI agent integration │
├─────────────────────────────────────────────────────────────┤
│ BACKEND │
│ FastAPI + Python 3.11+ │
│ ├── Polymarket Connector (Gamma + CLOB APIs) │
│ ├── Kalshi Connector (REST API) │
│ ├── Multi-source News Fetcher (EXA, GDELT, Newsdata) │
│ ├── Intelligent News Ranking (relevance + recency) │
│ └── WebSocket subscription manager │
└─────────────────────────────────────────────────────────────┘
Key Components
1. Market Connectors
We built async connectors for Polymarket and Kalshi that:
- Paginate through 25,000+ markets on startup
- Normalize data into a unified schema
- Poll orderbooks for subscribed markets in real-time
# Polymarket fetches 20,000+ markets on startup
async def fetch_initial_markets(self):
results = await asyncio.gather(
self._fetch_sports_markets(),
self._fetch_event_markets()
)
print(f"[Polymarket] Loaded {sum(results)} markets")
2. News Aggregation
Our news fetcher queries 4 providers in parallel and streams results:
- EXA.ai: AI-curated semantic search
- GDELT 2.0: Global event database
- Newsdata.io: Traditional news API
- CryptoPanic: Crypto-focused aggregator
with ThreadPoolExecutor(max_workers=4) as executor:
for future in as_completed(futures):
provider, articles = future.result()
yield provider, articles # Stream to frontend via SSE
3. Real-Time Updates
The frontend maintains a WebSocket connection that:
- Subscribes to specific markets on-demand
- Receives quote updates (mid/bid/ask prices)
- Updates charts with sub-second latency
// WebSocket subscription pattern
backendInterface.socket.subscribeToMarket(marketId, (point) => {
setPoints(prev => [...prev.slice(-89), point]);
});
4. Command Palette + AI Agent
A keyboard-driven interface (Ctrl+K) lets users:
- Search markets across both platforms
- Open panels with specific configurations
- Interact with the AI agent using natural language
// Natural language → structured commands
if (input.toLowerCase().includes("news")) {
executeCommand(COMMANDS.OPEN_PANEL, {
panelType: "NEWS_FEED",
panelData: { query: input }
});
}
Challenges We Faced
1. Rate Limiting and API Costs
Both Polymarket and Kalshi have rate limits. We mitigated this by:
- Caching market data in memory
- Polling orderbooks only for subscribed markets
- Adding 100ms delays between paginated requests
2. Data Normalization
Polymarket encodes outcome data as JSON strings within JSON:
# Polymarket returns: {"clobTokenIds": "[\"123\", \"456\"]"}
clob_token_ids = json.loads(data.get("clobTokenIds", "[]"))
Kalshi uses a different structure entirely. We wrote normalization functions for each.
3. Streaming News with Ranking
When news streams in from multiple providers:
- First results arrive (e.g., GDELT in 200ms)
- User sees initial ranked results
- More results arrive (EXA in 800ms)
- Challenge: Re-rank without jarring UI changes
Our solution: Re-rank the entire pool on each update and let React handle smooth re-renders.
4. English Language Filtering
GDELT returns articles in many languages. We integrated langdetect to filter:
from langdetect import detect
def is_english(text: str) -> bool:
try:
return detect(text) == "en"
except:
return True # Allow on failure
Built With
Languages
- TypeScript
- Python 3.11+
Frontend
- React 19
- Zustand (state management)
- TailwindCSS 4
- react-grid-layout (resizable panels)
- Recharts (charting)
- cmdk (command palette)
- Radix UI (accessible components)
Backend
- FastAPI
- httpx (async HTTP)
- python-dotenv
- langdetect
APIs & Data Sources
- Polymarket (Gamma API + CLOB API)
- Kalshi (Elections API)
- EXA.ai (AI-powered news search)
- GDELT 2.0 (Global news database)
- Newsdata.io (General news API)
- CryptoPanic (Crypto news aggregator)
Tools
- Bun (frontend runtime/bundler)
- uv (Python package manager)
- Git
"Try It Out" Links
| Type | URL |
|---|---|
| GitHub Repository | https://github.com/[username]/Prediction-Market-Dashboard |
| Live Demo | (Deploy pending) |
Running Locally
Prerequisites
- Python 3.11+
- uv (
pip install uv) - Bun (https://bun.sh/)
Backend
cd backend
uv sync
uv run uvicorn app.main:app --reload
Frontend
cd frontend
bun install
bun dev
Environment Variables
Create a .env file in the project root:
EXA=your_exa_api_key
NDIO=your_newsdata_api_key
CPANIC=your_cryptopanic_api_key
Future Roadmap
- User Authentication: Save workspaces and preferences
- Layout Profiles: Switch between "Sports", "Politics", "Crypto" presets
- Advanced AI Agent: Natural language queries like "Show me markets where Trump is favored"
- Trade Execution: Connect wallets for Polymarket, API keys for Kalshi
- Alerts: Notify users when market prices cross thresholds
Team
Built with ❤️ by Daniel, Matthew, and Varak :)

Log in or sign up for Devpost to join the conversation.