Panel: Opus (judge) + Sonnet + Grok 4.2 Reasoning + Gemini Pro 3.1 Judge: Opus (this document) Date: 2026-03-28 Overall Grade: A
Strong consensus across all 3 panelists on the core architecture. DraftKings DFS data is a legitimate signal source for Kalshi player props — the DFS crowd is large, partially informed, and prices player performance differently than prediction markets. The cross-platform divergence is tradeable.
Two separate value streams confirmed:
All 3 proposed variants of the same core idea. Opus's OLR (Ownership Leverage Rating) is the most complete:
OLR = (edge / salary) / sqrt(projected_ownership)
Where edge = our_projection - DK_implied_projection.
Sonnet's OAV (Ownership-Adjusted Value) is simpler and also good:
OAV = (our_projection - consensus_projection) / projected_ownership
RULING: Use OAV for quick screening, OLR for final lineup optimization. Both capture the same insight: low-ownership players with projection edge are GPP gold.
Thresholds:
All 3 agreed: single-point projections are insufficient. You need distributions.
RULING: Use Sonnet's gamma distribution approach (most rigorous):
Score ~ Gamma(k, theta) + shift
Floor(P10) = gamma.ppf(0.10, k, theta) + shift
Ceiling(P90) = gamma.ppf(0.90, k, theta) + shift
Fit from player's last 30-game score distribution. Gamma is appropriate because DFS scores are non-negative and right-skewed.
Contest-specific optimization targets (Sonnet's formulas, approved):
CashScore = 0.7 * Projection + 0.3 * Floor(P10)
GPPScore = 0.5 * Projection + 0.5 * Ceiling(P90) - 0.3 * (ProjectedOwnership * 100)
H2HScore = 0.6 * Projection + 0.25 * Floor(P10) + 0.15 * Ceiling(P90)
Cash threshold: Floor > 3x Salary/1000 GPP threshold: Ceiling > 5x Salary/1000
All 3 agreed: correlated lineups maximize GPP upside. Build pairwise correlation matrices from historical data.
RULING: Stack rules by sport (consensus across all 3):
NBA:
Game_Attractiveness = implied_total * (1 / (1 + abs(spread)))NHL:
MLB:
MLB_Stack_Score = implied_team_total * (1 - pitcher_quality_pct) * handedness_factorCorrelation thresholds:
All 3 identified this as the single largest underexploited edge. Most casual players set-and-forget.
RULING: Build automated late-swap pipeline with these triggers:
NBA usage boost rule (Sonnet):
Alert priority:
Alert_Priority = abs(news_impact) * (time_remaining_before_lock / 60)
NBA:
Pace_Adjusted_Projection = base * (matchup_pace / league_avg_pace) (Opus)Usage_Boost = base * (1 + teammate_absence_usage_increase) (Opus)UAP = (Usage_Rate * Minutes * 0.4) + Opponent_Defensive_Adjustment (Grok)NHL:
PP_TOI_Share is the ceiling driver (Opus)LSV = (Line_Shots * Line_GPG * 0.3) + PP_Bonus (Grok)MLB:
BvPE = (wOBA_vs_Handedness * 0.5) + (Park_Factor * 0.2) - xFIP_Adj (Grok)All 3 agreed: DK salary is a lagged but unbiased estimator of expected statistical output.
RULING: Build salary-to-stat regression (Opus's approach, most complete):
Step 1: Fit regression from historical (salary, actual_fantasy_points):
DK_Implied_FP = a * salary + b
NBA example: DK_Implied_FP ≈ 0.0057 * salary - 2.5
Step 2: Decompose FP to individual stats using player's historical stat distribution:
Implied_Points = DK_Implied_FP * (historical_pts_share / pts_FP_weight)
Step 3: Convert to probability at Kalshi threshold:
P(over T) = 1 - NormalCDF((T - implied_stat) / historical_std_dev)
Use Normal for volume stats (points, rebounds). Use Poisson for count stats (blocks, steals).
Step 4: Compare to Kalshi price:
edge = DK_implied_prob - kalshi_implied_prob
Trade threshold: edge >= 5 cents with FanDuel confirmation.
Salary_Momentum = (today_salary - avg_salary_last_5_slates) / avg_salary_last_5_slates
RULING: This is the highest-alpha signal because DK salary changes are proprietary information embedded in pricing that Kalshi may not reflect.
All 3 agreed: DFS ownership represents aggregated opinion of millions of players. Compare to Kalshi's smaller, sharper crowd.
When DFS crowd is RIGHT (Sonnet's analysis, approved):
When Kalshi is RIGHT:
RULING: When DFS ownership AND FanDuel sharp model both disagree with Kalshi, high-confidence trade. Single signal = half size or monitor only.
All 3 flagged this as the most time-sensitive and highest-edge signal.
Detection (Sonnet):
OwnershipDelta = OwnershipAt(lock - 5min) - OwnershipAt(lock - 60min)
If delta > +8% in final hour → mass late-swap toward player (positive news). If delta < -8% → mass exodus (negative news).
Cross-platform execution window: 5-15 minutes.
RULING: This signal requires automation. Manual execution is too slow. Build automated trigger: detect swap pattern → check Kalshi price → execute if edge > 5 cents.
| Signal Combination | Confidence | Position Size |
|---|---|---|
| DK-implied + FanDuel sharp + Ownership agree | STRONG | Full size |
| DK-implied + FanDuel sharp agree, ownership neutral | MODERATE | 60% |
| DK-implied + Ownership agree, sharp neutral | MODERATE | 50% |
| DK-implied only | WEAK | No trade |
| Late-swap detected, Kalshi hasn't moved | TIME-SENSITIVE | Full size, execute within 5 min |
-- DK salary + ownership per slate
CREATE TABLE dfs_dk_players (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
slate_date TEXT NOT NULL,
player_name TEXT NOT NULL,
team TEXT NOT NULL,
position TEXT NOT NULL,
dk_salary INTEGER NOT NULL,
dk_implied_fp REAL,
projected_ownership REAL,
actual_ownership REAL,
actual_fp REAL,
actual_pts INTEGER,
actual_reb INTEGER,
actual_ast INTEGER,
fetched_at TEXT DEFAULT (datetime('now')),
UNIQUE(sport, slate_date, player_name)
);
-- Ownership snapshots for late-swap detection
CREATE TABLE dfs_ownership_snapshots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
slate_date TEXT NOT NULL,
player_name TEXT NOT NULL,
snapshot_time TEXT NOT NULL,
minutes_before_lock REAL,
ownership_pct REAL NOT NULL,
UNIQUE(sport, slate_date, player_name, snapshot_time)
);
-- Salary history for momentum tracking
CREATE TABLE dfs_salary_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
player_name TEXT NOT NULL,
slate_date TEXT NOT NULL,
dk_salary INTEGER NOT NULL,
salary_5slate_avg REAL,
salary_momentum REAL,
UNIQUE(sport, player_name, slate_date)
);
-- Player stat distributions for probability conversion
CREATE TABLE dfs_player_distributions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
player_name TEXT NOT NULL,
stat_type TEXT NOT NULL,
sample_size INTEGER,
mean REAL NOT NULL,
std_dev REAL NOT NULL,
p10 REAL,
p50 REAL,
p90 REAL,
gamma_k REAL,
gamma_theta REAL,
gamma_shift REAL,
updated_at TEXT NOT NULL,
UNIQUE(sport, player_name, stat_type)
);
-- Stack correlations
CREATE TABLE dfs_correlations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
player_a TEXT NOT NULL,
player_b TEXT NOT NULL,
correlation REAL NOT NULL,
sample_size INTEGER,
stack_type TEXT,
updated_at TEXT DEFAULT (datetime('now')),
UNIQUE(sport, player_a, player_b)
);
-- Cross-platform signals: DK vs Kalshi
CREATE TABLE dfs_kalshi_signals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
game_date TEXT NOT NULL,
player_name TEXT NOT NULL,
signal_type TEXT NOT NULL,
dk_salary INTEGER,
dk_implied_prob REAL,
kalshi_ticker TEXT,
kalshi_prop_type TEXT,
kalshi_threshold REAL,
kalshi_price REAL,
kalshi_implied_prob REAL,
fanduel_implied_prob REAL,
edge_estimate REAL,
signal_strength TEXT,
direction TEXT,
acted_on INTEGER DEFAULT 0,
actual_result TEXT,
pnl REAL,
created_at TEXT DEFAULT (datetime('now')),
UNIQUE(sport, game_date, player_name, kalshi_prop_type, kalshi_threshold)
);
-- Contest results for backtesting
CREATE TABLE dfs_contest_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sport TEXT NOT NULL,
slate_date TEXT NOT NULL,
platform TEXT DEFAULT 'draftkings',
contest_type TEXT NOT NULL,
entry_fee REAL,
payout REAL,
placement INTEGER,
percentile REAL,
lineup_json TEXT,
total_score REAL,
created_at TEXT DEFAULT (datetime('now'))
);
-- Indexes
CREATE INDEX idx_dfs_players_date ON dfs_dk_players(sport, slate_date);
CREATE INDEX idx_dfs_ownership_snap ON dfs_ownership_snapshots(sport, slate_date, player_name);
CREATE INDEX idx_dfs_signals_date ON dfs_kalshi_signals(sport, game_date);
CREATE INDEX idx_dfs_salary_hist ON dfs_salary_history(sport, player_name);
| Panelist | Grade | Strengths | Weaknesses |
|---|---|---|---|
| Opus | A | Most complete DK-to-Kalshi pipeline. Salary decomposition to individual stats is novel. Signal combination framework is immediately actionable. | Verbose |
| Sonnet | A | Gamma distribution for floor/ceiling is the most rigorous projection approach. Late-swap cross-platform window analysis is practical. Crowd bias analysis (when DFS is right vs Kalshi) is the most useful insight. | Could have been more sport-specific on correlation |
| Grok | A- | Sport-specific formulas (UAP, LSV, BvPE) are immediately implementable. Practical thresholds for all contest types. | Salary-to-probability conversion was less rigorous than Opus/Sonnet. Schema was simpler. |
| Gemini | A | Critical correction: DFS crowd is generally INefficient — sportsbooks are almost certainly correct when they disagree. Late-swap dynamic programming (trailing/leading strategy) is novel. Sum-of-Ownership cap (120%) is actionable. NBA negative correlations (PG/PF same team) is important. | Schema was lighter than Opus/Sonnet. |
"DraftKings ownership and DFS crowd behavior are generally inefficient and should NOT be treated as smart money."
When FanDuel (sharp anchor) or Kalshi prices a prop conservatively but DFS crowd heavily owns the player, the sportsbook is almost certainly correct. This overrides Sonnet/Opus's more bullish view on DFS crowd wisdom.
RULING: DFS ownership is a SECONDARY signal, never primary. FanDuel remains the sharp anchor. DK ownership only becomes actionable when it AGREES with FanDuel AND diverges from Kalshi.
Lineup_Own_sum = sum(Own_i for all players)
Keep GPP lineup sum ownership below 120% for large-field tournaments.
High-usage PG and PF on the same team negatively correlate — they steal rebounds/assists from each other. Stack cautiously. Other sports have stronger positive stacking dynamics.