Arbitrage Better is a full-stack web application that automates the discovery and analysis of arbitrage betting opportunities in MMA bouts—enabling users to identify risk-free profit scenarios by exploiting odds discrepancies across major sportsbooks in real-time.
The application continuously monitors and analyzes betting odds from 6 major sportsbooks (DraftKings, BetMGM, Caesars, BetRivers, FanDuel, and BetWay) to find situations where you can bet on both fighters in a match and guarantee a profit regardless of the outcome.
Frontend:
- Angular 18 (Standalone Components)
- TypeScript 5.5
- RxJS (Reactive Programming)
- Angular HttpClient (REST API Integration)
Backend:
- Spring Boot 3.3.2
- Java 17
- Maven (Build & Dependency Management)
- Spring Mail (SMTP Email Service)
- Spring Scheduler (Automated Tasks)
Web Scraping:
- Selenium WebDriver 4.23
- WebDriverManager 5.9 (ChromeDriver Management)
- Headless Chrome Browser
Architecture:
- RESTful API Design
- Client-Server Architecture
- CORS-Enabled Cross-Origin Communication
1. Live Odds Aggregation
- Real-time web scraping of odds from multiple bookmakers
- Comprehensive coverage of all upcoming UFC and MMA events
- Data refreshed hourly to capture market movements
2. Automated Arbitrage Detection
- Sophisticated algorithm calculates implied probability across all bookmaker combinations
- Instantly identifies arbitrage opportunities when combined odds create a profit margin
- Displays exact profit percentages and optimal bookmaker pairings
3. Scheduled Monitoring
- Automated scraping runs every hour without manual intervention
- Tracks odds from weeks in advance up to fight day
- Captures fleeting opportunities that may only exist for narrow time windows
4. Email Alert System
- Subscribers receive instant notifications when arbitrage opportunities are detected
- Includes fight details, bookmaker combinations, and expected profit margins
- Ensures you never miss a profitable betting window
5. Interactive Bet Calculator
- Visual highlighting of profitable bets directly in the odds table
- Real-time calculation of optimal bet distribution
- Clear display of guaranteed returns on investment
Arbitrage opportunities in sports betting are rare and typically disappear within hours as bookmakers adjust their lines. This application automates the tedious process of:
- Manually checking odds across multiple platforms
- Performing complex probability calculations
- Monitoring for market inefficiencies 24/7
By leveraging automated scraping and algorithmic analysis, Arbitrage Better turns sporadic manual monitoring into a systematic, efficient process for identifying risk-free profit opportunities.
The MMA Arbitrage Betting App follows a client-server architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ Angular Frontend (Port 4200) │
│ • Displays fights & odds in real-time │
│ • Calculates and highlights arbitrage opportunities │
│ • Provides interactive UI for bet calculations │
└────────────────────┬────────────────────────────────────────┘
│ HTTP REST API
│
┌────────────────────▼────────────────────────────────────────┐
│ Spring Boot Backend (Port 8080) │
│ • RESTful API endpoints │
│ • Scheduled scraping service │
│ • Email notification service │
│ • CORS configuration │
└────────────────────┬────────────────────────────────────────┘
│
│
┌────────────────────▼────────────────────────────────────────┐
│ Selenium Web Scraper │
│ • Headless Chrome browser automation │
│ • Scrapes live odds from BestFightOdds.com │
│ • Extracts data for 6 major bookmakers │
└──────────────────────────────────────────────────────────────┘
When the Spring Boot application starts:
- The
@EnableSchedulingannotation activates the scheduling framework - An
ApplicationReadyEventlistener triggers an immediate scrape of current fight odds - The scheduled task is configured to run every hour (3,600,000 milliseconds)
The scraping engine uses Selenium WebDriver to extract live betting odds:
Step 1: Browser Setup
- Initializes a headless Chrome browser with optimized configurations
- Sets user-agent to avoid detection
- Navigates to BestFightOdds.com
Step 2: Data Extraction
- Waits for the odds table to load dynamically (up to 30 seconds)
- Identifies event tables on the page (e.g., "UFC 310", "UFC Fight Night")
- Iterates through each event until reaching "FUTURE EVENTS"
Step 3: Fight Parsing For each event:
- Reads fighter pairs (two rows = one fight)
- Extracts fighter names from table headers
- Scrapes odds from 6 major bookmakers:
- DraftKings
- BetMGM
- Caesars
- BetRivers
- FanDuel
- BetWay
Step 4: Data Structure
Each fight is stored as a Fight object containing:
{
"eventTitle": "UFC 310 - Alexandre Pantoja vs Kai Asakura",
"fighterOne": "Alexandre Pantoja",
"fighterTwo": "Kai Asakura",
"odds": {
"Alexandre Pantoja": {
"DraftKings": "-175",
"BetMGM": "-180",
"Caesars": "-170",
...
},
"Kai Asakura": {
"DraftKings": "+145",
"BetMGM": "+150",
"Caesars": "+140",
...
}
}
}Step 1: Data Fetching
- On component initialization, Angular sends HTTP GET request to
/scrape-fights - Backend returns the complete list of scraped fights with odds
Step 2: Arbitrage Calculation The frontend calculates arbitrage opportunities for every fight:
For each fight:
For each bookmaker combination (e.g., DraftKings vs BetMGM):
1. Get odds for Fighter A from Bookmaker 1
2. Get odds for Fighter B from Bookmaker 2
3. Convert American odds to decimal odds
4. Calculate: impliedProbability = (1/decimal1) + (1/decimal2)
5. If impliedProbability < 1:
- Arbitrage opportunity found!
- Calculate profit percentage
- Store bookmaker combinationConversion Formula:
- Positive odds (+150):
decimal = (150 / 100) + 1 = 2.50 - Negative odds (-166):
decimal = (100 / 166) + 1 ≈ 1.60
Step 3: Visual Display
- Groups fights by event title
- Highlights rows with arbitrage opportunities in green
- Displays profit percentage and optimal bookmaker combination
- Organizes data in an interactive, responsive table
- Spring's
@Scheduledannotation runs scraping task hourly - Ensures odds data is continuously updated
- Prepares system for email notifications when arbitrage is detected
Configured to send alerts when arbitrage opportunities are found:
- Uses Spring Mail with SMTP configuration
- Notifies subscribers of profitable betting opportunities
- Includes fight details, bookmakers, and expected profit
1. ArbitragerApplication.java
- Main Spring Boot application entry point
- Enables scheduling with
@EnableScheduling - Triggers initial scrape on application startup
2. Fight.java (Data Model)
- POJO representing a single MMA bout
- Stores event title, fighter names, and nested odds map
- Structure:
Map<FighterName, Map<Bookmaker, Odds>>
3. FightOddsScraper.java (Service Layer)
- Core scraping logic using Selenium WebDriver
- Headless Chrome configuration for server deployment
- Parses DOM structure to extract odds from multiple bookmakers
- Returns list of
Fightobjects
4. FightOddsController.java (REST Controller)
- Exposes
/scrape-fightsendpoint - Triggers scraping and returns JSON response
- Called by Angular frontend to fetch current odds
5. ScheduledScrape.java (Scheduled Task)
- Executes scraping automatically every hour
- Ensures data freshness without manual intervention
6. ScrapeController.java (Manual Trigger)
- Provides
/scrapeendpoint for manual scraping - Useful for testing or on-demand updates
7. EmailService.java (Notification Service)
- Sends email alerts to subscribers
- Configured via
application.properties
8. WebConfig.java (CORS Configuration)
- Enables Cross-Origin Resource Sharing
- Allows Angular frontend (localhost:4200) to communicate with backend (localhost:8080)
- Permits GET, POST, PUT, DELETE methods
1. app.component.ts (Main Component)
- Data Fetching: HTTP client calls backend API
- Business Logic: Arbitrage calculation algorithms
- Data Transformation: Groups fights by event, converts odds formats
- State Management: Manages fights array and event groups
2. app.component.html (Template)
- Displays odds in tabular format
- Dynamically highlights arbitrage opportunities
- Responsive design for various screen sizes
3. app.component.css (Styling)
- Modern, clean UI design
- Color-coded arbitrage indicators
- Professional table styling
| Endpoint | Method | Description | Response |
|---|---|---|---|
/scrape-fights |
GET | Scrapes current odds and returns all fights | List<Fight> (JSON) |
/scrape |
GET | Manually triggers scraping process | Status message |
/api/test |
GET | Health check endpoint | "API is working!" |
User Opens App
│
▼
Angular Frontend Loads
│
▼
HTTP GET /scrape-fights
│
▼
Backend Triggers Scraper
│
▼
Selenium Opens Headless Chrome
│
▼
Navigates to BestFightOdds.com
│
▼
Waits for Dynamic Content
│
▼
Extracts Event Tables
│
▼
Parses Fighter Names & Odds
│
▼
Constructs Fight Objects
│
▼
Returns JSON to Frontend
│
▼
Frontend Calculates Arbitrage
│
▼
Displays Results with Highlighting
│
▼
User Views Profitable Opportunities
- Why Selenium? BestFightOdds.com uses dynamic JavaScript rendering. Traditional HTTP scraping (JSoup, HTTP clients) cannot access content loaded after page initialization.
- Headless Mode: Reduces resource consumption and enables deployment on servers without GUI.
- Why Frontend? Reduces backend load and provides instant visual feedback.
- Real-time Updates: Users see arbitrage opportunities immediately without additional API calls.
- Why Hourly? Balances data freshness with server resource usage and avoids rate limiting.
- Startup Scrape: Ensures data availability immediately after deployment.
- Efficient Lookups: Quickly access odds for any fighter/bookmaker combination:
fight.getOdds().get(fighterName).get(bookmaker) - Maintainable: Easy to add new bookmakers or fighters
- Development Setup: Allows local frontend (port 4200) to communicate with backend (port 8080)
- Production Ready: Can be configured for deployed frontend domain
# Navigate to project root
cd /Users/ridwan/Arbitrage-Better
# Run Spring Boot application
./mvnw spring-boot:run
# Application starts on http://localhost:8080# Navigate to frontend directory
cd frontend
# Install dependencies
npm install
# Start Angular development server
ng serve
# Application accessible at http://localhost:4200Edit src/main/resources/application.properties for email notifications:
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username[email protected]
spring.mail.password=your-app-password(+140) Odds:
• if you bet $100, you will win $140 -> Total Return: $240
• The (+) indicates the fighter is the Underdog.
(-166) Odds:
• you need to bet $166 to win $100 -> Total Return: $266
• The (-) indicates the fighter is the Favorite.
By placing bets on both fighters on different bookmakers:
[Ilia] at DraftKings
Decimal Odds: 1 + (100/166) ≈ 1.60
Reciprocal: (1/1.60) ≈ 0.625
[Max] at Caesars
Decimal Odds: 1 + (170/100) = 2.70
Reciprocal: (1/2.70) ≈ 0.370
______________________________________
0.625 + 0.370 = 0.995
To find an arbitrage opportunity, we must look for a combination of odds on both fighters where the sum of the reciprocals of the decimal odds is less than 1:
• [< 1] Indicates an arbitrage opportunity. The total implied probability is under 100%, suggesting that the market has underpriced the combined probability of all possible outcomes - offering a guaranteed profit scenario regardless of the outcome of the fight.
• [= 1] Implies that the market is perfectly balanced, i.e Payout = Risk.
• [> 1] Implies no arbitrage bet is possible and the bookmakers may be overpricing the combined probability of the outcomes.
However, this arbitrage opportunity disappears within hours, as DraftKings' odds for [Ilia] rise to -175 to close this gap. Bookmakers collaborate to resolve wide discrepencies in odds, yielding only small windows of time to capitalize. Consequently, the closer the date to the actual bout, the less likely an arbitrage bet exists. To combat this, scraping live odds is scheduled for every 15 minutes, priming the app to alert subscribers via email when a current arbitrage opportunity exists, from up to weeks in advance.
[Jose Perez] at BetMGM
Decimal Odds: 1 + (100 / 165) ≈ 1.60
Reciprocal: (1 / 1.60) ≈ 0.625
[Jesse Stirn] at DraftKings
Decimal Odds: 1 + (265/100) ≈ 3.65
Reciprocal: (1/3.65) ≈ 0.274
______________________________________
0.625 + 0.317 = 0.942
Bet $305.56 on Fighter [Jesse Stirn] at Draftkings:
• Expected Payout: $1,115.28
Bet $694.44 on Fighter [Jose Perez] at BetMGM:
• Expected Payout: $1,115.28
Total Investment: $305.56 + $694.44 = $1,000
Total Payout in Either Case: $1,115.28
_____________________________________________________
Total Guaranteed Profit: $1,115.28 - $1,000 = $115.28
Use at your own risk. Arbitrage betting is NOT illegal; however, bookmakers will likely ban you from their betting platform if detected.



