Thesis System (Explanation)
The thesis system is the core differentiator of this research platform. Instead of making one-off predictions and forgetting them, you create structured theses that track your reasoning, predictions, and outcomes over time.
Why Track Theses?
Most prediction market participants:
- Look at a market
- Form an opinion ("I think this is underpriced")
- Maybe bet on it
- Forget about it
- Never learn if they were right
This makes it impossible to improve. You can't fix what you don't measure.
The thesis system forces you to:
- Commit to a probability before you see the outcome
- Document your reasoning (bull case, bear case, key assumptions)
- Define invalidation criteria (what would prove you wrong?)
- Track resolution (did you get it right?)
- Measure calibration (are your 70% predictions hitting 70% of the time?)
Thesis Lifecycle
DRAFT ──► ACTIVE ──► RESOLVED
│
└──► ABANDONED (with reason)
- Draft: Initial creation, still refining
- Active: You've committed to this prediction
- Resolved: Market settled, outcome recorded
- Abandoned: You changed your mind (and documented why)
Thesis Data Model
Each thesis captures:
@dataclass(frozen=True)
class ThesisEvidence:
url: str
title: str
source_domain: str
published_date: datetime | None
snippet: str
supports: str # bull, bear, neutral
relevance_score: float
added_at: datetime = field(default_factory=lambda: datetime.now(UTC))
@dataclass
class Thesis:
id: str # Unique identifier
title: str # Human-readable name
market_tickers: list[str] # Which Kalshi markets this covers
# Your predictions
your_probability: float # 0-1, YOUR estimate
market_probability: float # 0-1, what Kalshi said at creation time
confidence: float # 0-1, how sure are you?
# Reasoning (the important part!)
bull_case: str # Why it might be YES
bear_case: str # Why it might be NO
key_assumptions: list[str] # What must be true for your thesis?
invalidation_criteria: list[str] # What would prove you wrong?
# Tracking
status: ThesisStatus = ThesisStatus.DRAFT
created_at: datetime = field(default_factory=lambda: datetime.now(UTC))
resolved_at: datetime | None = None
actual_outcome: str | None = None # "yes", "no", or "void"
updates: list[dict[str, Any]] = field(default_factory=list) # Timestamped notes
# Optional: attached Exa research
evidence: list[ThesisEvidence] = field(default_factory=list)
research_summary: str | None = None
last_research_at: datetime | None = None
Edge Detection
The edge_size property tells you how much you disagree with the market:
edge_size = your_probability - market_probability
- Positive edge: You think YES is more likely than the market
- Negative edge: You think NO is more likely than the market
- Large absolute edge: Potential opportunity (if you're right)
Performance Metrics
After resolution, you can compute:
Brier Score
brier_score = (your_probability - outcome)²
Where outcome is 1.0 for YES, 0.0 for NO.
-
If
actual_outcomeis"void"(or any non-yes/novalue),brier_scoreisNoneand excluded from averages. -
0.0 = perfect prediction
- 0.25 = equivalent to random guessing
- 1.0 = perfectly wrong
Was Correct
Simple binary: did your probability correctly predict the direction?
was_correct = (your_probability > 0.5 and outcome == "yes") or
(your_probability < 0.5 and outcome == "no")
If the thesis is unresolved, or resolves as "void", was_correct is None.
Storage
Theses are persisted to data/theses.json in this format:
{
"theses": [
{
"id": "abc123",
"title": "Trump wins 2024",
"market_tickers": ["PRES-2024-TRUMP"],
"your_probability": 0.65,
"market_probability": 0.45,
...
}
]
}
The ThesisTracker class handles atomic saves (write to temp file, then rename) to prevent corruption.
CLI Usage
# Create a thesis
uv run kalshi research thesis create "My prediction" \
--markets TICK1,TICK2 \
--your-prob 0.65 \
--market-prob 0.55 \
--confidence 0.8
# Create + attach Exa research evidence (requires EXA_API_KEY)
uv run kalshi research thesis create "My prediction" \
--markets TICK1 \
--your-prob 0.65 \
--market-prob 0.55 \
--confidence 0.8 \
--with-research \
--yes
# List all theses
uv run kalshi research thesis list --full
# Edit an existing thesis
uv run kalshi research thesis edit <ID_PREFIX> --title "New title"
uv run kalshi research thesis edit <ID_PREFIX> --bull "Updated bull case"
# View details
uv run kalshi research thesis show <ID_PREFIX>
# View details + linked positions (reads from your local DB)
uv run kalshi research thesis show <ID_PREFIX> --with-positions --db data/kalshi.db
# Resolve when market settles
uv run kalshi research thesis resolve <ID_PREFIX> --outcome yes
Integration with Backtesting
Resolved theses feed into the backtesting system (see docs/research/backtesting.md), which calculates:
- What your P&L would have been
- Your win rate
- Aggregate Brier score
- Sharpe ratio
Key Code
- Thesis model:
src/kalshi_research/research/thesis.py - CLI commands:
src/kalshi_research/cli/research.py - Storage path:
src/kalshi_research/paths.py(DEFAULT_THESES_PATH)
See Also
- Backtesting - Simulate P&L from resolved theses
- Calibration Analysis - Measure prediction accuracy
- Usage: Research - CLI commands