Files
h2h-prototype/SPREAD_BETTING_IMPLEMENTATION.md

5.9 KiB

Spread Betting Implementation

Overview

Complete reimplementation of H2H as a sports spread betting platform where:

  • Admins create sporting events with official spreads
  • Users create bets at specific spreads (first come, first serve)
  • Users take bets and get automatically assigned the opposite side
  • House takes 10% commission (adjustable by admin)

Database Schema

New Models Created:

1. SportEvent (sport_events table)

  • Admin-created sporting events
  • Teams, official spread, game time, venue, league
  • Configurable spread range (default -10 to +10)
  • Bet limits (min/max amounts)
  • Status tracking: upcoming, live, completed, cancelled

2. SpreadBet (spread_bets table)

  • Bets on specific spreads for events
  • Links to creator and taker
  • Spread value and team side (home/away)
  • Stake amount (equal for both sides)
  • House commission percentage
  • Status: open, matched, completed, cancelled, disputed
  • Payout tracking

3. AdminSettings (admin_settings table)

  • Global platform settings (single row)
  • Default house commission (10%)
  • Default bet limits
  • Default spread range
  • Spread increment (0.5 for half-point spreads)
  • Platform name, maintenance mode

4. User Model Update

  • Added is_admin boolean field

API Endpoints

Admin Routes (/api/v1/admin)

Settings:

  • GET /settings - Get current admin settings
  • PATCH /settings - Update settings (commission %, bet limits, etc.)

Event Management:

  • POST /events - Create new sport event
  • GET /events - List all events (with filters)
  • GET /events/{id} - Get specific event
  • PATCH /events/{id} - Update event details
  • DELETE /events/{id} - Delete event (only if no active bets)
  • POST /events/{id}/complete - Mark complete with final scores

User Routes

Sport Events (/api/v1/sport-events):

  • GET / - List upcoming events
  • GET /{id} - Get event with spread grid

Spread Bets (/api/v1/spread-bets):

  • POST / - Create spread bet
  • POST /{id}/take - Take an open bet
  • GET /my-active - Get user's active bets
  • DELETE /{id} - Cancel open bet (creator only)

How It Works

Example Flow:

1. Admin Creates Event:

{
  "sport": "football",
  "home_team": "Wake Forest",
  "away_team": "MS State",
  "official_spread": 3.0,
  "game_time": "2024-01-15T19:00:00",
  "league": "NCAA",
  "min_spread": -10.0,
  "max_spread": 10.0,
  "min_bet_amount": 10.0,
  "max_bet_amount": 1000.0
}

2. User Views Spread Grid:

Wake Forest vs MS State
Official Line: WF +3 / MS -3

Spread Grid:
-10  -9.5  -9  -8.5  -8  -7.5  -7  ... -3  ... 0 ... +3 ... +10
                                    [Alice $100]

- Empty slots = can create bet
- Occupied slots = can take bet
- Official spread highlighted

3. Alice Creates Bet:

{
  "event_id": 1,
  "spread": -3.0,
  "team": "home",  // Wake Forest
  "stake_amount": 100.00
}

Meaning: Alice bets Wake Forest will win by MORE than 3 points

4. Charlie Takes Bet:

POST /api/v1/spread-bets/5/take
  • Charlie automatically gets: MS State +3 (opposite side)
  • Both $100 stakes locked in escrow
  • Bet status: MATCHED

5. Game Ends:

Final Score: Wake Forest 24, MS State 20
Wake Forest wins by 4 points

Result: Alice wins (-3 spread covered)

Payout:
- Total pot: $200
- House commission (10%): $20
- Alice receives: $180

Spread Grid Display Logic

GET /api/v1/sport-events/{id} returns:

{
  "id": 1,
  "home_team": "Wake Forest",
  "away_team": "MS State",
  "official_spread": 3.0,
  "spread_grid": {
    "-10.0": null,
    "-9.5": null,
    ...
    "-3.0": {
      "bet_id": 5,
      "creator_id": 1,
      "creator_username": "alice",
      "stake": 100.00,
      "status": "open",
      "team": "home",
      "can_take": true
    },
    "-2.5": null,
    ...
    "3.0": null,
    ...
  }
}

Key Business Rules

  1. First Come, First Serve: Only ONE bet allowed per spread per team
  2. Equal Stakes: Both users must bet the same amount
  3. Opposite Sides: Taker automatically gets opposite spread
  4. House Commission: Default 10%, adjustable per bet
  5. Escrow: Funds locked when bet is matched
  6. Spread Increments: 0.5 points (e.g., -3, -2.5, -2, -1.5, etc.)

Admin Settings

Adjustable via /api/v1/admin/settings:

  • default_house_commission_percent - Default 10%
  • default_min_bet_amount - Default $10
  • default_max_bet_amount - Default $1000
  • default_min_spread - Default -10
  • default_max_spread - Default +10
  • spread_increment - Default 0.5
  • maintenance_mode - Enable/disable betting

Payout Calculation

total_pot = creator_stake + taker_stake
house_fee = total_pot * (house_commission_percent / 100)
payout_to_winner = total_pot - house_fee

Example:
- Alice stakes: $100
- Charlie stakes: $100
- Total pot: $200
- House commission (10%): $20
- Winner gets: $180

Database Migration Notes

New tables need to be created:

  • sport_events
  • spread_bets
  • admin_settings

User table needs migration:

  • Add is_admin boolean column (default false)

Next Steps

  1. Database models created
  2. API routes implemented
  3. Initialize database with new tables
  4. Create seed script for admin user and sample event
  5. Build frontend grid view
  6. Test complete flow

Files Created

Backend:

  • backend/app/models/sport_event.py - SportEvent model
  • backend/app/models/spread_bet.py - SpreadBet model
  • backend/app/models/admin_settings.py - AdminSettings model
  • backend/app/schemas/sport_event.py - SportEvent schemas
  • backend/app/schemas/spread_bet.py - SpreadBet schemas
  • backend/app/routers/admin.py - Admin routes
  • backend/app/routers/sport_events.py - Sport event routes
  • backend/app/routers/spread_bets.py - Spread bet routes

Modified:

  • backend/app/models/user.py - Added is_admin field
  • backend/app/models/__init__.py - Exported new models
  • backend/app/main.py - Registered new routers