Last updated: September 15, 2025 • Estimated reading time: 12–15 minutes

This guide walks you from zero to a working model you can build in Google Sheets. You’ll choose a sport, gather data, build a simple but honest probability model, price fair odds, and run a light backtest/validation so you don’t fool yourself. No hype—just a clean build you can replicate.

If you’re brand‑new: start with the hub, then come back to build: Sports Betting Models: A Clear, Practical Guide.

What you’ll build

  • A baseline team‑rating model (Elo‑style/logistic) that outputs win probabilities.
  • Fair moneylines from those probabilities.
  • A tiny EV check vs. market odds and a simple stake rule.
  • A rolling backtest with Brier score and log loss so you can tell if it’s any good.

You can later upgrade to sport‑specific approaches (Poisson for low‑scoring sports, player‑level projections, simulations), but a clean team‑rating → probability model is the safest place to start.


Prerequisites (keep it simple)

  • Comfort with percentages/probabilities, basic algebra, and Google Sheets.
  • Core concepts: EV, fair odds, and CLV (covered briefly below).
  • A small historical dataset (we’ll outline columns so you can source it quickly).

Choosing a sport (criteria that matter)

Pick a sport that balances data availability with model tractability:

  • Data: Are box scores and team efficiency stats easy to fetch daily?
  • Scoring structure: Lower scoring (soccer, hockey) → Poisson often fits; higher scoring (basketball) → rating/logistic works well.
  • Sample size: More games = better learning.

Good first choices: Basketball (NBA or a single international league) or Baseball (team‑based Poisson). If you prefer hockey or soccer, the basic pipeline still applies; you’ll swap in a Poisson‑style layer later.


Data you need (columns to collect)

Create a sheet named raw_games with at least these columns (one row per game):

Date | HomeTeam | AwayTeam | HomeScore | AwayScore | HomeCloseOdds | AwayCloseOdds | HomeWin (1/0)

Optional but useful: Home Possessions / Away Possessions, Home Offensive Rating (ORtg), Away ORtg, or a simple point differential.

Sourcing: Use official league sites or reputable aggregators. Keep the schema stable and add a “data_updated” note per import.


Build the baseline model in Google Sheets

We’ll construct a team rating → win probability pipeline using a logistic link. Ratings reflect how many points a team is better than average; probability is a function of rating difference + home‑court advantage (HCA).

1) Prepare team list and parameters

Create a params tab:

B1: HCA_points = 2.0 (basketball example; tune later)

B2: scale_k = 0.12 (logistic steepness; tune later)

Create a teams tab with unique team names in column A. Initialize Rating in column B to 0 for every team.

2) Compute game‑level features

In a features tab, pull from raw_games with these columns:

Date | HomeTeam | AwayTeam | HomeScore | AwayScore | HomeWin

DIF_PTS = HomeScore – AwayScore

For each row, compute rating difference using VLOOKUP/XLOOKUP:

RATING_DIFF = (Rating[HomeTeam] – Rating[AwayTeam]) + HCA_points

In Sheets:
Assume teams!A:B has Team,Rating and params!B1 is HCA

G2 (HomeRating): =XLOOKUP(B2,teams!A:A,teams!B:B)

H2 (AwayRating): =XLOOKUP(C2,teams!A:A,teams!B:B)

I2 (RatingDiff): =G2 – H2 + params!B1

3) Probability from rating difference (logistic)

Use a logistic mapping with scale_k controlling steepness:

J2 (P_home): =1/(1+EXP(- params!B2 * I2))

This outputs a pre‑game win probability for the home team based on ratings + HCA.

4) Update ratings with actual results (simple Elo‑style)

We’ll run one pass through history to learn ratings. Set a learning rate K_rating (e.g., 0.25) in params!B3.

For each game, compute prediction error and adjust:

K2 (Error): = (E2 /*HomeWin*/ – J2)

HomeRating_new = HomeRating + K_rating * Error

AwayRating_new = AwayRating – K_rating * Error

In Sheets you can do this with an iterative approach or by scripting; for a first pass, do a few epochs by copying current ratings to a “working” table, running through games in order, and writing updated ratings back. (If you prefer no iteration, use a rolling point‑diff model instead—see “Alternative v1” below.)

Alternative v1 (no iteration): Compute each team’s Simple Rating = rolling average of point differential per game (optionally per‑possession). Then map RatingDiff to probability with the same logistic function. You lose some elegance but gain simplicity.

5) Fair odds and EV checks

Convert probability to fair decimal odds and compare to market:

L2 (FairOdds): =1/J2

M2 (MarketHome): = HomeCloseOdds (or your available price)

N2 (EV_per_$1): = J2*(M2-1) – (1-J2)

O2 (Bet?): =IF(AND(N2>0, M2>L2),”YES”,”NO”)

Add a stake cell using fractional Kelly (optional):

P2 (Kelly): = ( (J2*M2 – (1-J2)) / (M2-1) )

Q2 (Stake): = MAX(0, MIN( 0.2*P2 , 0.02 )) // 0.2×Kelly capped at 2% bankroll

Interpretation: Only bet when both EV>0 and Market > Fair (for plus‑money) or the equivalent condition for favorites/spreads.

Backtesting and validation (don’t skip)

Create a backtest tab where each historical game has:

Predicted P_home | Actual HomeWin (1/0) | MarketHome

Metrics that matter

  • Brier score (lower is better):

=AVERAGE( (Pred – Actual)^2 )

Log loss (lower is better):

= -AVERAGE( ActualLN(Pred) + (1-Actual)LN(1-Pred) )

  • Calibration: Bin predictions (e.g., 0.40–0.45, 0.45–0.50, …), then compare avg predicted vs actual win rate. A diagonal calibration is good; sloped away from the diagonal means miscalibration.
  • CLV tracking (if you have timestamped bets): compare your price to closing odds; persistent outperformance is a strong edge signal even if short‑term ROI fluctuates.

Rolling evaluation

  • Use a time‑split: train on seasons N‑2 to N‑1, test on season N.
  • Or a rolling window: compute metrics over the most recent 500–1,000 games to monitor drift.

Stop‑loss for models: If your calibration or CLV falls apart, pause bets and investigate (data errors, lineup changes, market shift).


A worked mini‑build you can screenshot

Goal: From ratings to win probability, fair odds, and EV in a compact block.

Inputs (params tab):

B1: HCA_points = 2.0

B2: scale_k = 0.12

B3: K_rating = 0.25

Game row (features tab):

HomeTeam | AwayTeam | HomeScore | AwayScore | HomeWin | HomeCloseOdds

G2: HomeRating =XLOOKUP(HomeTeam,teams!A:A,teams!B:B)

H2: AwayRating =XLOOKUP(AwayTeam,teams!A:A,teams!B:B)

I2: RatingDiff =G2 – H2 + params!B1

J2: P_home =1/(1+EXP(-params!B2*I2))

L2: FairOdds =1/J2

M2: MarketHome =HomeCloseOdds

N2: EV_per_$1 =J2*(M2-1) – (1-J2)

O2: Bet? =IF(AND(N2>0, M2>L2),”YES”,”NO”)

Add a small bar chart for Predicted vs Actual by bins on the backtest tab to make calibration visual.


Data hygiene & versioning

  • Keep a changelog tab (what you changed, why, date).
  • Timestamp imports and freeze the backtest sample so you don’t “peek.”
  • Validate odds conversions and handle voids/OT rules consistently.

Common pitfalls (and easy fixes)

  • Data leakage: Don’t include market numbers or post‑game info in features.
  • Overfitting: Resist adding 50 features; start simple and add only when metrics improve out‑of‑sample.
  • Small samples: Early season models swing—use priors/regularization.
  • No calibration: A sharp model can still be mis‑scaled; fix by Platt scaling or isotonic regression when/if you move beyond Sheets.

Upgrades when you’re ready

  • Sport‑specific math: Poisson for low‑scoring totals; Negative Binomial for overdispersion.
  • Player‑level projections: minutes/usage for basketball; pitcher/batter components for baseball.
  • Simulation: Monte Carlo for game states and correlated markets.
  • Automation: Pull stats nightly via scripts; write projections back to Sheets.

See also: MLB Betting Model: Complete Guide and Google Sheets for Betting Tutorial.


FAQs

What’s a good first sport?
Basketball for rating/logistic or baseball for team‑based Poisson. Pick the league you can follow daily.

How many games do I need for a backtest?
As many as you can cleanly gather—hundreds to a few thousand. Always report performance on unseen data.

Can I do this without coding?
Yes. Sheets is enough for a first model. Move to Python/R when you need automation, scraping, or simulation.

What stake size is sensible?
Many use 0.1×–0.25× Kelly capped at 1–2% per play to control variance.

How do I know if my edge is real?
Monitor CLV and calibration over a few hundred bets. If both deteriorate, re‑examine data and mapping.


A soft next step

If you want templates and video walkthroughs, the Ultimate Modern Bettor’s Blueprint compresses the learning curve with checklists and prebuilt tabs. Concepts here are free; the course simply accelerates the build‑validate loop.

Unlock the secrets of winning bettors—enter your email for proven strategies, expert tips, and smarter betting insights.