5.9 KiB
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_adminboolean field
API Endpoints
Admin Routes (/api/v1/admin)
Settings:
GET /settings- Get current admin settingsPATCH /settings- Update settings (commission %, bet limits, etc.)
Event Management:
POST /events- Create new sport eventGET /events- List all events (with filters)GET /events/{id}- Get specific eventPATCH /events/{id}- Update event detailsDELETE /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 eventsGET /{id}- Get event with spread grid
Spread Bets (/api/v1/spread-bets):
POST /- Create spread betPOST /{id}/take- Take an open betGET /my-active- Get user's active betsDELETE /{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
- First Come, First Serve: Only ONE bet allowed per spread per team
- Equal Stakes: Both users must bet the same amount
- Opposite Sides: Taker automatically gets opposite spread
- House Commission: Default 10%, adjustable per bet
- Escrow: Funds locked when bet is matched
- 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 $10default_max_bet_amount- Default $1000default_min_spread- Default -10default_max_spread- Default +10spread_increment- Default 0.5maintenance_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_eventsspread_betsadmin_settings
User table needs migration:
- Add
is_adminboolean column (default false)
Next Steps
- ✅ Database models created
- ✅ API routes implemented
- ⏳ Initialize database with new tables
- ⏳ Create seed script for admin user and sample event
- ⏳ Build frontend grid view
- ⏳ Test complete flow
Files Created
Backend:
backend/app/models/sport_event.py- SportEvent modelbackend/app/models/spread_bet.py- SpreadBet modelbackend/app/models/admin_settings.py- AdminSettings modelbackend/app/schemas/sport_event.py- SportEvent schemasbackend/app/schemas/spread_bet.py- SpreadBet schemasbackend/app/routers/admin.py- Admin routesbackend/app/routers/sport_events.py- Sport event routesbackend/app/routers/spread_bets.py- Spread bet routes
Modified:
backend/app/models/user.py- Added is_admin fieldbackend/app/models/__init__.py- Exported new modelsbackend/app/main.py- Registered new routers