Skip to content

[Phase 2] Bookmaker Analytics #8

@WFord26

Description

@WFord26

name: "Phase 2: Bookmaker Performance Analytics"
about: Track and rank bookmakers by value offered, market-making behavior, and reliability
title: "[Phase 2] Bookmaker Performance Analytics"
labels: enhancement, phase-2, analytics
assignees: ''

Overview

Comprehensive analytics on bookmaker performance: which books offer best value, move lines first (sharp), have best limits, and provide most reliable odds.

Business Value

  • Bookmaker Selection: Help users choose which books to use
  • Sharp Book Identification: Know which books set the market
  • Value Optimization: Always get best available odds
  • Market Intelligence: Understand bookmaker strategies

Technical Requirements

Database Changes

model BookmakerAnalytics {
  id                    String   @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  bookmaker             String   @unique @db.VarChar(50)
  
  // Odds quality metrics
  averageCLVOffered     Decimal  @map("average_clv_offered") @db.Decimal(5,2)
  bestOddsFrequency     Decimal  @map("best_odds_frequency") @db.Decimal(5,2)
  marginVsConsensus     Decimal  @map("margin_vs_consensus") @db.Decimal(5,2)
  outlierFrequency      Decimal  @map("outlier_frequency") @db.Decimal(5,2)
  
  // Market making behavior
  firstMoverFrequency   Decimal  @map("first_mover_frequency") @db.Decimal(5,2)
  lineMovementLag       Int      @map("line_movement_lag")  // Average seconds behind market
  sharpBookRating       Int      @map("sharp_book_rating")  // 1-10
  marketEfficiency      Decimal  @map("market_efficiency") @db.Decimal(5,2)
  
  // Coverage & reliability
  sportsCovered         String[] @map("sports_covered")
  marketsCovered        String[] @map("markets_covered")
  uptimePercentage      Decimal  @map("uptime_percentage") @db.Decimal(5,2)
  oddsUpdateFrequency   Int      @map("odds_update_frequency")  // Seconds
  averageOddsAge        Int      @map("average_odds_age")  // Seconds since last update
  
  // Limits & accessibility
  limitProfile          String   @map("limit_profile") @db.VarChar(20)  // high/medium/low
  estimatedMaxBet       Decimal? @map("estimated_max_bet") @db.Decimal(10,2)
  accountLimitReports   Int      @map("account_limit_reports")  // User reports of being limited
  
  // Historical performance
  totalGamesOffered     Int      @map("total_games_offered")
  totalMarketsOffered   Int      @map("total_markets_offered")
  averageMargin         Decimal  @map("average_margin") @db.Decimal(5,2)
  
  // Reputation
  userRating            Decimal? @map("user_rating") @db.Decimal(3,2)
  userReviewCount       Int      @default(0) @map("user_review_count")
  recommendationScore   Int      @map("recommendation_score")  // 1-100
  
  // Metadata
  calculatedAt          DateTime @default(now()) @map("calculated_at") @db.Timestamptz(6)
  updatedAt             DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6)
  
  @@index([bestOddsFrequency])
  @@index([sharpBookRating])
  @@map("bookmaker_analytics")
}

// Bookmaker movement events (track who moves first)
model BookmakerMovementEvent {
  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)
  detectedAt        DateTime @default(now()) @map("detected_at") @db.Timestamptz(6)
  
  firstMover        String   @map("first_mover") @db.VarChar(50)
  firstMoveTime     DateTime @map("first_move_time") @db.Timestamptz(6)
  followers         Json     // [{bookmaker, lagSeconds}]
  movementSize      Decimal  @map("movement_size") @db.Decimal(5,2)
  
  game Game @relation(fields: [gameId], references: [id])
  
  @@index([firstMover])
  @@index([detectedAt])
  @@map("bookmaker_movement_events")
}

Backend Services

File: src/services/bookmaker-analytics.service.ts

class BookmakerAnalyticsService {
  async calculateBookmakerMetrics(bookmaker: string): Promise<Analytics>
  async rankBookmakers(criteria: string): Promise<Ranking[]>
  async identifySharpBooks(): Promise<string[]>
  async trackLineMovement(bookmaker: string): Promise<MovementStats>
  async generateBookmakerReport(): Promise<Report>
}

Metrics Calculations

Best Odds Frequency:

// % of time bookmaker has best odds vs all others
function calculateBestOddsFrequency(bookmaker: string, period: string): number {
  const totalGames = getGamesWithOdds(bookmaker, period);
  const bestOddsCount = totalGames.filter(game => 
    hasBestOdds(game, bookmaker)
  ).length;
  
  return (bestOddsCount / totalGames.length) * 100;
}

Sharp Book Rating:

function calculateSharpBookRating(bookmaker: string): number {
  const metrics = {
    firstMoverFrequency: getFirstMoverFrequency(bookmaker),  // Weight: 35%
    marginVsConsensus: getMarginVsConsensus(bookmaker),      // Weight: 25%
    limits: getLimitProfile(bookmaker),                       // Weight: 20%
    efficiency: getMarketEfficiency(bookmaker),              // Weight: 20%
  };
  
  const score = 
    (metrics.firstMoverFrequency * 0.35) +
    ((100 - metrics.marginVsConsensus) * 0.25) +
    (metrics.limits * 0.20) +
    (metrics.efficiency * 0.20);
  
  return Math.round(score / 10);  // Scale to 1-10
}

Average CLV Offered:

// Average CLV users get when betting at this bookmaker
function calculateAverageCLVOffered(bookmaker: string): number {
  const bets = getBetsPlacedAt(bookmaker);
  const clvValues = bets.map(bet => bet.clv);
  
  return mean(clvValues);
}

Scheduled Jobs

Daily Analytics Update: Runs at 2 AM

  • Calculate all metrics for each bookmaker
  • Update bookmaker_analytics table
  • Generate rankings
  • Send alerts for significant changes

Real-time Movement Tracking: Runs every 5 minutes

  • Identify line movements
  • Track who moved first
  • Update movement event records
  • Increment first-mover counts

API Endpoints

  • GET /api/bookmakers - List all bookmakers with basic stats
  • GET /api/bookmakers/:bookmaker - Detailed analytics for one bookmaker
  • GET /api/bookmakers/rankings/:criteria - Rankings by specific metric
  • GET /api/bookmakers/sharp - List of sharp books
  • GET /api/bookmakers/best-value/:sport - Best value bookmakers by sport
  • GET /api/bookmakers/movement/:bookmaker - Line movement stats
  • GET /api/bookmakers/compare - Compare multiple bookmakers side-by-side

Frontend Components

Bookmaker Leaderboard: BookmakerLeaderboard.tsx

┌────────────────────────────────────────────────┐
│ 🏆 Bookmaker Rankings                         │
├────────────────────────────────────────────────┤
│ 1. Pinnacle        Sharp: 9/10  Value: 92%   │
│ 2. Circa Sports    Sharp: 8/10  Value: 88%   │
│ 3. BetCRIS         Sharp: 7/10  Value: 85%   │
│ 4. DraftKings      Sharp: 5/10  Value: 76%   │
│ 5. FanDuel         Sharp: 5/10  Value: 74%   │
└────────────────────────────────────────────────┘

Bookmaker Profile: BookmakerProfile.tsx

  • Full analytics dashboard for single bookmaker
  • Radar chart: Sharp rating, value, coverage, reliability
  • Line chart: Metrics over time
  • Best sports/markets for this book
  • User reviews and ratings

Comparison Tool: BookmakerComparison.tsx

  • Side-by-side comparison of 2-4 bookmakers
  • Highlight advantages/disadvantages
  • Sport-specific comparisons
  • Recommendation engine

Sharp Book Identifier: SharpBookBadge.tsx

  • Visual badge on game cards
  • Shows which books are sharp for that game/market
  • Quick reference for users
  • Click to see detailed analysis

Visualizations

Sharp Book Network Graph:

  • Nodes = Bookmakers
  • Edges = Line movement following
  • Size = Influence
  • Color = Sharp rating

Value Heatmap:

  • Rows = Bookmakers
  • Columns = Sports
  • Color = Best odds frequency
  • Helps identify which book for which sport

Acceptance Criteria

  • Database migration completed
  • Metrics calculation service implemented
  • Daily analytics update job
  • Real-time movement tracking
  • Bookmaker leaderboard page
  • Detailed bookmaker profiles
  • Comparison tool
  • API endpoints documented
  • Unit tests for all calculations
  • Historical data validation (manual review)

Dependencies

  • Odds sync with multiple bookmakers
  • Line movement tracking (Phase 1)
  • Market consensus (Phase 2)
  • Historical game results

Estimated Effort

  • Backend: 7 days
  • Frontend: 5 days
  • Testing & Validation: 3 days
  • Total: 15 days

Success Metrics

  • Analytics calculated for 100% of active bookmakers
  • Sharp book identification accuracy >85% (expert validation)
  • Users consult rankings when choosing books
  • Positive correlation between bookmaker rating and user satisfaction

Future Enhancements

  • User-submitted limit reports
  • Bookmaker account health scoring
  • Payout speed tracking
  • Customer service ratings
  • Promo/bonus value analysis
  • Machine learning for sharp book prediction

Metadata

Metadata

Assignees

No one assigned

    Labels

    analyticsAdvanced analytics featuresenhancementNew feature or requestphase-2Phase 2: Market Intelligence

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions