Skip to content

[Phase 1] Bookmaker Disagreement Detection #4

@WFord26

Description

@WFord26

name: "Phase 1: Bookmaker Disagreement Detection"
about: Find value by identifying games where bookmakers strongly disagree
title: "[Phase 1] Bookmaker Disagreement Detection"
labels: enhancement, phase-1, analytics
assignees: ''

Overview

Detect and highlight games where bookmakers have significantly different odds, indicating market uncertainty and potential value opportunities.

Business Value

  • Value Detection: High disagreement = uncertainty = potential value
  • Arbitrage Opportunities: Extreme disagreement can create arbs
  • Market Inefficiency: Shows where the market hasn't reached consensus
  • User Education: Teaches users to spot value

Technical Requirements

Database Changes

model MarketConsensus {
  id                  String   @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  gameId              String   @map("game_id") @db.Uuid
  marketType          String   @map("market_type") @db.VarChar(20)
  calculatedAt        DateTime @default(now()) @map("calculated_at") @db.Timestamptz(6)
  
  // Consensus metrics
  consensusLine       Decimal  @map("consensus_line") @db.Decimal(5,1)
  standardDeviation   Decimal  @map("standard_deviation") @db.Decimal(5,2)
  outlierBookmakers   Json     @map("outlier_bookmakers")
  
  // Value indicators
  disagreementScore   Int      @map("disagreement_score")  // 1-100
  bestValue           Json     @map("best_value")  // Which side has best odds
  
  game Game @relation(fields: [gameId], references: [id])
  
  @@index([gameId])
  @@index([disagreementScore])
  @@index([calculatedAt])
  @@map("market_consensus")
}

Backend Services

File: src/services/market-consensus.service.ts

class MarketConsensusService {
  async calculateConsensus(gameId: string, marketType: string): Promise<Consensus>
  async findHighDisagreement(threshold: number): Promise<Game[]>
  async identifyOutliers(gameId: string): Promise<Bookmaker[]>
  async calculateDisagreementScore(gameId: string): Promise<number>
}

Scheduled Job: Calculate consensus every 15 minutes for upcoming games

  • Cron: */15 * * * *
  • Query games in next 48 hours with odds
  • Calculate consensus for each market type
  • Store results and disagreement scores

Algorithm

Consensus Line Calculation:

// For spreads/totals
consensus = median(allBookmakerLines)

// For moneylines
impliedProbs = lines.map(line => toImpliedProbability(line))
consensusProb = median(impliedProbs)
consensusLine = toAmericanOdds(consensusProb)

// Standard Deviation
stdDev = calculateStdDev(allLines)

// Disagreement Score (1-100)
score = min(100, (stdDev / consensus) * 100 * 10)

Outlier Detection:

  • Lines > 2 standard deviations from consensus
  • Store bookmaker name and how far off

API Endpoints

  • GET /api/analytics/disagreement/live - Current high disagreement games
  • GET /api/analytics/disagreement/game/:gameId - Disagreement for specific game
  • GET /api/analytics/disagreement/trends - Historical disagreement patterns
  • GET /api/analytics/disagreement/bookmaker/:bookmaker - How often a bookmaker is an outlier

Frontend Components

Dashboard Widget: HighDisagreementGames.tsx

  • List of top 5 games with highest disagreement
  • Show disagreement score (1-100)
  • Click to see full consensus breakdown
  • Real-time updates every 60 seconds

Detailed Modal: DisagreementBreakdown.tsx

  • All bookmaker lines for the game
  • Visual representation of spread/distribution
  • Highlight outliers in red
  • Show which side has best value
  • Historical disagreement for this matchup

Filters Page: ValueOpportunities.tsx

  • Filter by disagreement score
  • Filter by sport
  • Filter by time until game starts
  • Sort by score, time, sport

Calculations & Thresholds

Disagreement Categories:

  • Low (0-30): Normal market efficiency
  • Medium (31-60): Some uncertainty
  • High (61-80): Significant disagreement
  • Extreme (81-100): Major market inefficiency

Alert Thresholds:

  • Score > 70: Push notification to users
  • Score > 85: Email alert for major opportunities

Acceptance Criteria

  • Database migration completed
  • Consensus calculation service implemented
  • Scheduled job running reliably (15-min intervals)
  • Dashboard widget showing high disagreement games
  • Detailed breakdown modal with visual distribution
  • API endpoints documented
  • Unit tests for consensus calculations
  • Historical data showing disagreement accuracy

Dependencies

  • Odds sync service must have multiple bookmakers
  • Minimum 5 bookmakers per game for reliable consensus

Estimated Effort

  • Backend: 4 days
  • Frontend: 3 days
  • Testing & Tuning: 2 days
  • Total: 9 days

Success Metrics

  • Detect 10+ high disagreement games per day
  • Alert notifications sent within 1 minute of detection
  • Users click through on 20%+ of alerts
  • 5+ bookmakers per consensus calculation (average)

Future Enhancements

  • Machine learning to predict which side wins when disagreement is high
  • Historical win rates by disagreement level
  • Bookmaker accuracy tracking (who's right when they're outliers)

Metadata

Metadata

Assignees

No one assigned

    Labels

    analyticsAdvanced analytics featuresenhancementNew feature or requestphase-1Phase 1: Core Analytics

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions