Skip to main content

mts1b-sports

Sports betting: DFS lineup optimization, sportsbook arb, esports, consensus aggregation, Bradley-Terry rating models.

Repo: github.com/MTS1B/mts1b-sports Layer: 6 Wave: 3 (months 8-12) Depends on: foundation, platform, llm, operations, httpx, pulp Audience: sports bettors + DFS players

What it is

A treasury-allocated sleeve focused on sports. Treats sports markets as another asset class: ingests odds + outcomes, builds rating models, finds inefficiencies, sizes positions.

Sub-areaWhat
DFS optimizerLineup construction under salary + constraint rules
Sportsbook arbCross-book arb detection (FanDuel, DraftKings, BetMGM, ...)
EsportsLeague of Legends, CS, Dota, Valorant odds + outcomes
ConsensusMedian odds across N books
RatingsBradley-Terry + Elo + bespoke per-league

⚠️ The Odds API key is dead — we use FreeOddsAggregator (FanDuel public + ESPN pickcenter) instead. Documented constraint.

Module layout

mts1b_sports/
├── odds/
│ ├── free_aggregator.py # FanDuel public + ESPN pickcenter
│ ├── normalizer.py
│ └── parser.py
├── dfs/
│ ├── optimizer.py # PuLP MILP
│ ├── projections.py
│ └── correlation.py
├── arb/
│ ├── detector.py
│ └── sizer.py
├── ratings/
│ ├── bradley_terry.py
│ ├── elo.py
│ └── per_league/
│ ├── nfl.py
│ ├── nba.py
│ └── ...
├── markets/
│ ├── nfl.py
│ ├── nba.py
│ ├── mlb.py
│ ├── nhl.py
│ ├── soccer.py
│ └── esports.py
└── api/
└── rest.py

DFS lineup optimizer

from mts1b_sports.dfs import optimize_lineup

lineup = await optimize_lineup(
sport="nba",
site="draftkings",
slate_date=date(2026, 5, 25),
salary_cap=50_000,
projections=projections_df, # custom proj
correlations=correlation_matrix, # stack/anti-stack
n_lineups=20, # GPP entries
exposure_caps={"LeBron": 0.30, ...}, # max % of lineups using each player
)
# [Lineup(players=[...], projected_points=295.4, salary_used=49_900, ...), ...]

Backed by pulp (mixed-integer linear programming). Solving 20 lineups under typical constraints: ~10s on a workstation.

Sportsbook arb

from mts1b_sports.arb import find_arbs

arbs = await find_arbs(
sport="nfl",
books=["fanduel", "draftkings", "betmgm", "caesars", "pointsbet"],
min_edge_pct=2.0, # net edge after juice
)
# [Arb(event="KC @ DEN", market="ml",
# legs=[(book="fanduel", side="KC -3", odds=1.91),
# (book="betmgm", side="DEN +3", odds=2.00)],
# net_edge_pct=2.3, stake_per_$100=0.49)]

Quirk: FanDuel inPlay=True games must NOT cross ESPN non-pre-state games (causes spurious 30%+ arbs from state mismatch). Adapter handles this.

Bradley-Terry ratings

from mts1b_sports.ratings import bradley_terry

ratings = bradley_terry(
games=historical_games_df, # winner, loser, weight columns
prior_strength=10.0,
iterations=100,
)
# pd.Series indexed by team, sorted by rating

Used to:

  • Predict head-to-head probabilities
  • Identify mispriced moneylines
  • Build power rankings for narrative content

Per-league custom models layer on top (NBA: tempo + ORtg/DRtg adjustments; NFL: EPA-based; NHL: Corsi-adjusted).

Esports

Esports has weaker data infrastructure but higher inefficiency. Markets covered:

  • League of Legends (LCS, LEC, LCK, LPL)
  • CS2 (premier ESL leagues)
  • Dota 2 (DPC majors)
  • Valorant (VCT)

Custom scrapers since major odds aggregators undercover these.

Treasury integration

mts mts1b-treasury fund create --fund-id sports-dfs --nav 10000 --type sports

Sports funds use the same treasury + reporting + risk infrastructure as trading funds. P/L flows into the firm-level NAV.

Build + test

pip install -e ".[dev]"
pytest -m unit
pytest -m live --sport=nba # live data fetch

Roadmap

VersionItems
0.1 (Wave 3)Free odds aggregator, DFS optimizer, arb detector, Bradley-Terry, 6 sports
0.2 (Wave 3)Esports expansion, live in-game models
0.3Player-prop markets (PrizePicks, Underdog)
1.0 (LTS)Stable interface

See also