Project Info
Inspiration
Prediction markets are powerful tools for forecasting, but they can be overwhelming. While traditional finance offers ETFs (Exchange-Traded Funds) to let investors bet on sectors or trends without picking individual stocks, prediction markets like Kalshi require users to find and trade specific, granular contracts (e.g., "Fed rates in March" vs "Fed rates in April"). So, our project explores ETFs for prediction markets. Our inspiration came from the desire to bridge the gap between high-level intuition ("I think AI is going to boom this year") and the specific, complex instruments available on exchanges. We wanted to build a tool that lets anyone trade on a theme in a single click.
What it does
Kalshi ETF Baskets allows users to: Select a Theme: Choose from curated baskets like "Tech Growth", "Climate Change", or "Inflation". Generate with AI: Describe a trend in natural language (e.g., "Crypto will crash in late 2025"), and our LLM agent dynamically constructs a portfolio of relevant Kalshi markets. One-Click Execution: Instantly execute a batched order to buy "Yes" or "No" positions across multiple markets, weighted by confidence or strategy.
How we built it
Stack Backend: Python & FastAPI Frontend: Streamlit Model: We used GPT-4 to interpret natural language trends and map them to live Kalshi market tickers Key Algorithms To allocate capital across different markets in a basket, we implement a weighted allocation strategy. The total budget B is distributed among n selected markets based on a relevance score R_i and a confidence factor C_i. Allocation for market i is computed as: This ensures that capital is distributed proportionally to the strength of each market’s signal, so the ETF emphasizes the contracts most aligned with the chosen theme.
Challenges we ran into
Market Ephemerality: Unlike stocks, prediction markets expire. A "Climate" basket today must have different contracts than one next month. Our dynamic sourcing engin constantly updates the available components of a basket. Latency & Atomicity: Executing a basket trade implies placing multiple orders simultaneously. We had to handle partial fills and ensure that either the whole basket executes or we handle failures gracefully (using batch orders where possible).
Accomplishments we're proud of
End-to-End Trading: We successfully placed real (demo) trades on Kalshi from a single button click in our custom UI Smart Curation: The "Generate from Trend" feature lets you type a sentence and see a list of financial contracts pop up is a glimpse into the future of trading interfaces.
BetBasket
Trade prediction-market baskets like ETFs — one click, multiple markets.
Built at TreeHacks 2026.
The Idea
Prediction markets (like Kalshi) let you bet on real-world outcomes — elections, Fed policy, AI milestones, sports. But placing individual bets across many markets is tedious. What if you could:
- Pick a theme — e.g., "AI stagnation in 2026"
- Build a basket — 5–10 related markets with one click
- Trade the whole basket — set a budget, preview cost, execute
Think of it as an ETF for prediction markets: diversify across a thesis instead of one-off contracts.
What We Built
Three Ways to Build a Basket
| Source | How it works |
|---|---|
| Pre-defined theme | Curated trend baskets: AI Stagnation, Trump Economic Agenda, Climate Goals, Cannabis Policy |
| Generate from trend | Describe a belief in plain English → GPT-4o-mini picks markets and directions |
| Search events | Browse top events by volume, search by keyword, use any event as a basket |
UX Features
- For / Against toggle — Flip the whole basket from betting on the trend to betting against it
- Yes / No per leg — Simple labels instead of BUY_YES/BUY_NO/SELL_YES/SELL_NO
- Preview before execute — See estimated cost, contracts, and orderbook before placing orders
- Weighted legs — Adjust allocation per market (default: equal weight)
Tech Highlights
- SQLite events DB — Searchable index of 50k+ Kalshi events by volume
- Keyword expansion — "AI" → OpenAI, xAI, ChatGPT, Anthropic for smarter search
- Structured output — LLM returns JSON with market tickers, directions, weights (validated against candidate set)
Tech Stack
| Layer | Tech |
|---|---|
| Backend | FastAPI, Pydantic |
| Frontend | Streamlit |
| Database | SQLite (events index) |
| LLM | OpenAI GPT-4o-mini (structured output) |
| API | Kalshi demo (RSA-signed requests) |
Technical Challenges & How We Solved Them
1. Matching natural language to markets
Problem: User says "AI progress will stall" — how do we find relevant markets among 50k+ events?
Solution: Keyword extraction + expansion. Short terms like "ai" expand to ["OpenAI", "xAI", "ChatGPT", "Anthropic"] so we search the events DB for each. We batch-fetch full market data from Kalshi and pass ~80 candidates to the LLM with tickers, titles, and rules.
2. LLM hallucinating tickers
Problem: The model might invent tickers that don't exist or are closed.
Solution: Strict schema + validation. We use response_format with a JSON schema so the model returns only market_ticker, direction, weight. We filter each leg: if the ticker isn't in our candidate set, we drop it. No hallucinated contracts reach the basket.
3. Unified direction UX (For/Against vs Yes/No)
Problem: BUY_YES, BUY_NO, SELL_YES, SELL_NO are confusing. Users think in terms of "I bet on this" or "I bet against this."
Solution: Two-level abstraction. A global For / Against toggle flips all legs (BUY_YES ↔ BUY_NO, SELL_YES ↔ SELL_NO). Per-leg we display Yes / No — betting the outcome happens or doesn't. Internally we still send Kalshi’s 4-direction enum.
4. Events DB vs live API
Problem: Kalshi’s API returns events with nested markets, but searching by keyword isn’t supported. We need volume-ordered, searchable events.
Solution: One-time init script fetches all open events, parses market tickers, stores in SQLite with title, volume, markets_json. Search uses SQL LIKE on title/series/category. Generate-from-trend and Search share the same event pool.
5. Batch orders and pricing
Problem: Each leg needs a price (ask for buy, bid for sell). Orders are GTC resting orders.
Solution: basket_service fetches markets in batches, applies overrides (direction, weight, enabled), computes per-leg budget and contract counts, builds Kalshi batch order payload. Preview shows est. cost before execute.
How to Run
Prerequisites
- Python 3.9+
- Kalshi demo account (no real money)
- Optional: OpenAI API key for "Generate from trend"
1. Clone & install
git clone <your-repo-url>
cd treehacks
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r backend/requirements.txt
pip install -r frontend/requirements.txt
2. Configure
cp backend/.env.example backend/.env
Edit backend/.env:
| Variable | Required for | Where to get |
|---|---|---|
KALSHI_API_KEY_ID | All | Kalshi demo → Account & security → API Keys |
KALSHI_PRIVATE_KEY_PATH | All | Same page — download PEM, save as backend/kalshi_private.key |
OPENAI_API_KEY | Generate from trend | platform.openai.com |
3. Initialize events DB (required for search & generate)
cd backend
python scripts/init_events_db.py
Creates events.db with open events indexed by volume. Run once after clone; re-run if markets change.
4. Start the app
Terminal 1 — API
cd backend
uvicorn app.main:app --reload
Terminal 2 — UI
cd frontend
streamlit run streamlit_app.py
Open http://localhost:8501.
Project Structure
treehacks/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI routes
│ │ ├── basket_service.py # Preview & execute
│ │ ├── llm_basket_service.py # Generate from trend (LLM)
│ │ ├── events_db.py # SQLite search
│ │ ├── kalshi_client.py # RSA auth, markets, orders
│ │ └── models.py
│ ├── scripts/
│ │ ├── init_events_db.py # Populate events DB
│ │ └── build_themes_from_events.py
│ ├── themes.json # Pre-defined trend baskets
│ └── requirements.txt
├── frontend/
│ ├── streamlit_app.py
│ └── requirements.txt
└── README.md
License
MIT.
Uses Kalshi demo — no real money. Trade at your own risk.
Analysis
View
Metric
- 4
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- FastAPIIn code
- OpenAIIn code
- PythonIn code
- StreamlitIn code
4 of 4 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
80 KB
Source files
17
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
mirabor/treehacks
24 files · 2.2 MB · @ e91133f
Structure
Interface
9 files · 38%Screens, components and styles rendered to the user.
Application logic
4 files · 17%Domain rules, services and shared utilities.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python90%
- Markdown10%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
backend/requirements.txt
pypi · 8- cryptography
- fastapi
- httpx
- openai
- pydantic
- python-dotenv
- streamlit
- uvicorn[standard]
frontend/requirements.txt
pypi · 2- httpx
- streamlit
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.