Skip to main content

Overview

The Mapping API provides normalization services for league names and market result mapping, ensuring consistent data across different data sources.

LeagueNormalizer

Normalize League Names

from PROPPR.SharedServices.mapping.league_normalizer import LeagueNormalizer

normalized = LeagueNormalizer.normalize("LaLiga")
# Returns: "La Liga"

normalized = LeagueNormalizer.normalize("Primera Division")
# Returns: "La Liga"
league_name
string
required
League name to normalize
normalized_name
string
Canonical league name, or original if no mapping exists

League Normalization Map

The normalization map resolves data source inconsistencies:
LEAGUE_NORMALIZATION_MAP = {
    # Spain
    "LaLiga": "La Liga",
    "LaLiga 2": "La Liga 2",
    
    # Portugal
    "Liga Portugal": "Primeira Liga",
    
    # England
    "Enterprise National League": "National League",
    
    # Europe
    "UEFA Conference League": "Europa Conference League",
    
    # Australia
    "A-League Men": "A-League",
    
    # Japan
    "J.League": "J-League",
    
    # Greece
    "Super League Greece": "Super League",
    
    # Austria
    "Admiral Bundesliga": "Bundesliga",
    
    # Argentina
    "Liga Profesional de Futbol": "Liga Profesional",
    
    # Brazil
    "Brasileiro Serie A": "Serie A",
    
    # Bolivia
    "Division Profesional": "Liga De Futbol Prof",
    "División Profesional": "Liga De Futbol Prof"
}

MarketResultMapper

Get Market Mapping

from PROPPR.SharedServices.mapping.market_result_mapper import MarketResultMapper

mapping = MarketResultMapper.get_mapping_for_market("Team Total Away")
# Returns: {'type_id': 52, 'location': 'away', 'stat_type': 'goals'}
market_name
string
required
Market name (e.g., “Team Total Away”, “Corners Totals”)
type_id
integer
API type ID for statistic
location
string
Location: “home”, “away”, “total”, or “team_based”
stat_type
string
Stat type: “goals”, “corners”, “cards”, “shots”, etc.

Supported Markets

{
    "Team Total Home": {"type_id": 52, "location": "home", "stat_type": "goals"},
    "Team Total Away": {"type_id": 52, "location": "away", "stat_type": "goals"},
    "Match Goals": {"type_id": 52, "location": "total", "stat_type": "goals"}
}
{
    "Corners Totals": {"type_id": 34, "location": "total", "stat_type": "corners"},
    "Match Corners": {"type_id": 34, "location": "total", "stat_type": "corners"},
    "Team Corners Home": {"type_id": 34, "location": "home", "stat_type": "corners"},
    "Team Corners Away": {"type_id": 34, "location": "away", "stat_type": "corners"}
}
{
    "Bookings Totals": {"type_id": 84, "location": "total", "stat_type": "cards"},
    "Total Cards": {"type_id": 84, "location": "total", "stat_type": "cards"},
    "Match Cards": {"type_id": 84, "location": "total", "stat_type": "cards"}
}
{
    "Total Shots": {"type_id": 42, "location": "total", "stat_type": "shots"},
    "Team Shots On Target Home": {"type_id": 86, "location": "home", "stat_type": "shots_on_target"},
    "Match Shots On Target": {"type_id": 86, "location": "total", "stat_type": "shots_on_target"}
}

Extract Statistics

Extract Stat Value

actual_value = MarketResultMapper.extract_stat_value(
    statistics=fixture_statistics,
    type_id=52,
    location="away",
    team_id=55,
    suppress_warnings=False
)
statistics
array
required
List of statistics from API response
type_id
integer
required
API type ID for statistic
location
string
required
“home”, “away”, or “total”
team_id
integer
Team ID for team-specific stats
suppress_warnings
boolean
default:"false"
Suppress warning logs (useful for live grading)
value
float
Actual statistic value, or None if not found

Stat Extraction Logic

  1. Location Priority: Match by location (“home”/“away”) first
  2. Participant ID Fallback: Match by participant_id if location fails
  3. Total Calculation: Sum home + away for total markets
  4. Zero Default: Return 0.0 for missing stats in common types

Calculate Results

Calculate Bet Result

result = MarketResultMapper.calculate_bet_result(
    actual_value=3.0,
    threshold=2.5,
    direction="over",
    market_name="Totals"
)
# Returns: "won"
actual_value
float
required
Actual match statistic
threshold
float
required
Bet threshold
direction
string
required
“over” or “under”
market_name
string
Market name to determine handicap type
result
string
“won”, “lost”, “refund”, “half_win”, or “half_loss”

Result Logic

Standard Handicaps (0.5, 1.5, 2.5):
  • Over: actual > threshold → Won, actual <= threshold → Lost
  • Under: actual < threshold → Won, actual >= threshold → Lost
Whole Number Handicaps (1.0, 2.0, 3.0):
  • Over: actual > threshold → Won, actual == threshold → Refund, actual < threshold → Lost
  • Under: actual < threshold → Won, actual == threshold → Refund, actual > threshold → Lost
Quarter Handicaps (1.25, 1.75, 2.25, 2.75): Split into two half bets:
  • 1.75 = Half on 1.5 + Half on 2.0
  • 2.25 = Half on 2.0 + Half on 2.5
Results:
  • Both halves win → Won
  • Both halves lose → Lost
  • One wins, one refunds → Half Win
  • One loses, one refunds → Half Loss
  • Both refund → Refund

Prepare for Tracking

Add Result Tracking

alert_doc = MarketResultMapper.prepare_alert_for_tracking(alert_doc)
alert_doc
object
required
Original alert document
result_tracking
object
Result tracking metadata
{
    'api_type_id': 52,
    'api_location': 'away',
    'stat_type': 'goals',
    'expected_threshold': 1.5,
    'market_direction': 'over',
    'result_status': 'pending',
    'actual_value': None,
    'calculated_at': None,
    'api_response_id': None
}

Early Grading

Check Early Grade

can_grade = MarketResultMapper.can_grade_early(
    alert_doc=alert_doc,
    actual_value=3.0
)
alert_doc
object
required
Alert document with result tracking
actual_value
float
required
Current actual value
can_grade
boolean
True if over bet exceeded threshold (can grade as won early)
Early Grading Rules:
  • Only “over” bets can be graded early
  • Only when actual_value > threshold
  • “Under” bets must wait until match ends

Helper Functions

Get Market Mapping

from PROPPR.SharedServices.mapping.market_result_mapper import get_market_mapping

mapping = get_market_mapping("Team Total Away")

Calculate Result

from PROPPR.SharedServices.mapping.market_result_mapper import calculate_result

result = calculate_result(
    actual_value=3.0,
    threshold=2.5,
    direction="over",
    market_name="Totals"
)

Check Supported Market

from PROPPR.SharedServices.mapping.market_result_mapper import is_supported_market

supported = is_supported_market("Team Total Away")
# Returns: True

Example Usage

Complete Mapping Flow

# Normalize league name
league = LeagueNormalizer.normalize("LaLiga")
# "La Liga"

# Get market mapping
mapping = MarketResultMapper.get_mapping_for_market("Team Total Away")
# {'type_id': 52, 'location': 'away', 'stat_type': 'goals'}

# Extract actual value
actual_value = MarketResultMapper.extract_stat_value(
    statistics=fixture_statistics,
    type_id=mapping['type_id'],
    location=mapping['location']
)
# 2.0

# Calculate result
result = MarketResultMapper.calculate_bet_result(
    actual_value=actual_value,
    threshold=1.5,
    direction="over"
)
# "won"

References

  • Source: SharedServices/mapping/league_normalizer.py
  • Source: SharedServices/mapping/market_result_mapper.py
  • Related: Grading API
  • Related: Fixture Model

Build docs developers (and LLMs) love