Elo — the rating system invented for chess and borrowed by every sport since — is the friendliest way to build your own power ranking. There's no matrix algebra, no optimizer, just one update rule applied after every game: the winner takes points from the loser, and the size of the transfer depends on how surprising the result was. In about 30 lines of Python we'll rate every FBS team from real results, then check how often it would have called the winner. Full code is in scripts/cfb-elo-rating-python.py.

The one formula you need

Before a game, each team has a rating (everyone starts at 1500). The favorite's expected win probability is:

def expected(a, b):
    return 1 / (1 + 10 ** ((b - a) / 400))
A 400-point edge means ~91% expected; equal ratings mean 50%.

After the game, you nudge each rating toward what actually happened:

new_rating = old_rating + K * (actual - expected)

actual is 1 for a win, 0 for a loss. K is the step size — bigger K means ratings move faster. We use K = 40 and give the home team a +65 Elo bump for home-field before computing the expectation.

Run it over a season

Pull the season's games in order (we use the shared _cfb_season helper over ESPN's public results), then loop:

elo = {}
for g in games:                       # games sorted by week
    rh = elo.get(g["home"], 1500)
    ra = elo.get(g["away"], 1500)
    eh = expected(rh + 65, ra)        # home-field in the expectation
    home_won = 1 if g["hs"] > g["as"] else 0
    elo[g["home"]] = rh + 40 * (home_won - eh)
    elo[g["away"]] = ra + 40 * ((1 - home_won) - (1 - eh))
That's the entire engine. Everything else is sorting and printing.

The result, and a back-test

While we loop, we can also check the rating's predictive value: did the higher pre-game rating (plus home-field) win? On the 2024 season:

Back-test: predicted the winner in 604/873 = 69.2% of games.

Top 15 by Elo:
 1  ORE    1698     6  IU     1639     11  CLEM  1619
 2  BOIS   1669     7  SMU    1633     12  OSU   1618
 3  ND     1664     8  PSU    1631     13  ARMY  1617
 4  ASU    1649     9  TEX    1630     14  SC    1617
 5  UGA    1645    10  MRSH   1629     15  OHIO  1616
Actual output, 2024 season (ESPN results), retrieved June 2026.
Horizontal bar chart of end-of-2024 college football Elo ratings, led by Oregon near 1700.
Your from-scratch Elo, end of 2024. Data: ESPN public API; Elo by the code above. Retrieved June 2026.

Predicting ~69% of games from one number is genuinely good — and it exposes Elo's nature. Notice Ohio State sits 12th, even though the Buckeyes won the national championship. Pure Elo only knows results, and Ohio State lost two regular-season games (to Oregon and Michigan) before getting hot in the playoff. Elo doesn't reward "peaking at the right time"; it rewards a body of work. That's a feature for prediction and a quirk for crowning champions — exactly the tension we explore in choosing a champion.

Make it better

  • Margin of victory. Multiply K by a function of the score margin (with diminishing returns) so blowouts move ratings more than one-point wins — but cap it to avoid rewarding running up the score.
  • Preseason priors. Instead of starting everyone at 1500, carry over a fraction of last year's rating. Early-season predictions improve a lot.
  • Tune K and home-field. Re-run the back-test with different values and keep what predicts best. That's a one-line experiment now.
  • Regress to the mean between seasons so a great team doesn't start the next year overrated.

Elo is the gateway drug of sports analytics: simple enough to understand fully, powerful enough to beat the polls at prediction. Once it's working, the logistic-regression tutorial shows how to turn that Elo edge into a calibrated win probability.

Sources & further reading

The CollegeAthleteInsider Analyst

I'm an independent analyst covering college football and basketball through public data. Every number here traces to a script in /scripts. More about the methodology →