Skip to content

[Phase 1] CLV Tracking #3

@WFord26

Description

@WFord26

name: "Phase 1: Closing Line Value (CLV) Tracking"
about: Implement CLV tracking to measure betting sharpness
title: "[Phase 1] Closing Line Value (CLV) Tracking"
labels: enhancement, phase-1, analytics
assignees: ''

Overview

Implement Closing Line Value (CLV) tracking - the #1 indicator of long-term betting profitability. CLV measures the difference between odds at bet placement vs odds at game start.

Business Value

  • Sharp Bettor Identification: Users with positive CLV are sharp bettors
  • Long-term ROI Prediction: CLV strongly correlates with profitability
  • Competitive Advantage: Very few betting trackers offer CLV analytics

Technical Requirements

Database Changes

// Add to BetLeg model
model BetLeg {
  // ... existing fields
  closingOdds        Int?     @map("closing_odds")
  clv                Decimal? @db.Decimal(5,2)  // CLV percentage
  clvCategory        String?  @map("clv_category") @db.VarChar(20)  // positive/negative/neutral
}

// New analytics table
model UserCLVStats {
  id                  String   @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  userId              String   @map("user_id") @db.Uuid
  sportKey            String   @map("sport_key") @db.VarChar(50)
  betType             String   @map("bet_type") @db.VarChar(20)
  period              String   @db.VarChar(20)  // week, month, season, all-time
  
  totalBets           Int      @map("total_bets")
  averageCLV          Decimal  @map("average_clv") @db.Decimal(5,2)
  positiveCLVCount    Int      @map("positive_clv_count")
  negativeCLVCount    Int      @map("negative_clv_count")
  
  clvWinRate          Decimal  @map("clv_win_rate") @db.Decimal(5,2)
  expectedROI         Decimal  @map("expected_roi") @db.Decimal(5,2)
  actualROI           Decimal  @map("actual_roi") @db.Decimal(5,2)
  
  calculatedAt        DateTime @default(now()) @map("calculated_at") @db.Timestamptz(6)
  
  user User @relation(fields: [userId], references: [id])
  
  @@unique([userId, sportKey, betType, period])
  @@index([userId])
  @@map("user_clv_stats")
}

Backend Services

File: src/services/clv.service.ts

class CLVService {
  async captureClosingLine(gameId: string): Promise<void>
  async calculateCLV(betLegId: string): Promise<number>
  async generateCLVReport(userId: string, filters): Promise<CLVReport>
  async updateCLVStats(userId: string): Promise<void>
}

Scheduled Job: Capture closing lines 5 minutes before game start

  • Cron: */5 * * * * (every 5 minutes)
  • Query games starting in next 10 minutes
  • Store current odds as closing odds for all related bet legs

API Endpoints

  • GET /api/analytics/clv/summary - User's overall CLV stats
  • GET /api/analytics/clv/by-sport - CLV breakdown by sport
  • GET /api/analytics/clv/by-bookmaker - CLV by bookmaker
  • GET /api/analytics/clv/trends - CLV trends over time
  • GET /api/bets/:betId/clv - CLV for specific bet

Frontend Components

Dashboard Widget: CLVSummaryCard.tsx

  • Display average CLV percentage
  • Positive CLV count vs negative
  • Comparison to typical bettor (if available)
  • Color-coded: Green (positive), Red (negative)

Detailed Page: CLVAnalytics.tsx

  • Charts: CLV trend over time
  • Table: Bets with best/worst CLV
  • Filters: Sport, date range, bet type
  • Export functionality

Calculations

CLV Formula:

CLV% = ((Closing Implied Probability - Opening Implied Probability) / Opening Implied Probability) * 100

Implied Probability:

  • American odds (positive): 100 / (odds + 100)
  • American odds (negative): |odds| / (|odds| + 100)

Acceptance Criteria

  • Database migration completed
  • Closing line capture job running reliably
  • CLV calculated for all settled bets
  • CLV summary widget on dashboard
  • Detailed CLV analytics page
  • API endpoints documented
  • Unit tests for CLV calculations
  • Integration tests for scheduled job

Dependencies

  • Odds sync service must be running
  • Games must have status updates at start time

Estimated Effort

  • Backend: 3 days
  • Frontend: 2 days
  • Testing: 1 day
  • Total: 6 days

Success Metrics

  • CLV data captured for 95%+ of bets
  • Dashboard widget loads in <500ms
  • Users can identify their CLV trends
  • Positive user feedback on feature utility

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