• Introduction

    In this article I am going to consider the topic of adjusting team ratings for schedule strength.  All fans will know that teams will on average perform better against opposition that is ranked lower in the table and worse against opposition ranked higher.  This blog is all about the predictive and we don’t want our measure of a team’s performance to be skewed by their opposition. 

    My team ratings are nearly always in the style of a performance delta for each game (as opposed to a percentage/ratio).  E.g. if the home team has 10 shots in a game and the away team has 5, the home teams rating for that game is +5.  If a team has 6.25 xG for and 10.1 xG against over 5 games then the team’s rating for that sample of games is the xG difference (6.25 – 10.1 = -3.85) divided by the number of games (5) to give -0.77 (xG) per game.

    How to apply a fixture adjustment

    Let’s make a mock 10 team league and assign the ability of each team as follows:

    Table 1

    Let’s consider how I would make 2 different schedule adjustments.

    Example a):

    If Team D (a league average team1) plays teams A and C (one home and one away so it balances out) – we’d expect their performance for those 2 games to average -2.4 xG, or -1.2xG per game.

    Table 1 (team ratings based on a large sample of games) tells us team D is an average team.  We want their rating to show as 0 for whatever sample of games they play.  This means our fixture adjustment for team D for these 2 games is going to be +1.2 (-1.2xG (rating)+ 1.2xG (fixture adjustment) = 0

    Example b):

    Team B plays teams F and I, one home and one away.  Again we consider the performance of an average team against teams F and I and conclude the fixture adjustment for Team B will be -0.6 (sum the strength of the two opponents and divide by 2). 

    Seems simple enough but I believe the 2nd example is missing something.  Do you know what it is?

    Special Adjustment

    In order to explain what extra adjustment is missing here, let’s play out a season in this mock league where each teams plays each team once (or more, it doesn’t matter too much but we assume home/away ties aren’t a factor).  The schedule adjustment I calculate for each team is as follows.

    Table 2

    Even though every team has played every team, it appears as though Team A has had an easy schedule (their opponents had an average performance of -0.24 xG per game) and team J a hard one. This comes about because if we average our performance rating for every team in a league will get 0 (it’s a zero sum situation, every xG produced is an xG conceded). Now when we consider all opponents team A have had, we are effectively removing team A and averaging the rating of every other team. This will not equal zero (and only would if we were considering the league average side, team D).

    This all means we need an extra adjustment. No one would say a league is unfair because the better teams played an easier schedule than the lowly ranked teams did.  The opponents of the highly ranked teams only appear ‘bad’ as a function of the highly ranked teams own performance. We don’t want the schedule adjustment for each team to be a function of the teams own performance!

    The adjustment we require for calculating the scheduled adjustment for a team is then:

    Special adjustment = (Team rating) / (total teams in the league – 1)

    where Team Rating is the rating of the team we are calculating the schedule adjustment for.

    In example a) above the factor is zero as team rating is 0 in that case (0/11 = 0).  Using the formula for example b) we calculate 1.4 / 9 = 0.16.  This means we add a factor of 0.16 to the team rating of all the teams that Team B plays.  This means the fixture adjustment for team B would be -0.44 after playing team F and team I (-0.6 + 0.16).

    The fixture adjustment of each team once the league is finished would now be zero – exactly what we want. The formula above is equal to the values in table 2 but with the opposite sign. When I recalculate table 2 with the special adjustment each value equals zero. This is what we want – in a completed league the schedule adjustment for every team is zero.

    I would define a fixture adjustment for any Team ‘X’ as ‘the performance of a league average side against Team X’s opponents in an otherwise similar league without Team X’.

    Summary

    We now have a complete adjustment to add to the rating of a team.  For Team A this is

    Fixture adjusted rating  =

    Raw rating + Average level of Team A’s opponents + (rating of Team A / (total league teams – 1))

    Remember the rating should be in the format of +3 shots per game or +0.5 xG per game or +1 goal per game e.t.c.

    Quiz

    Calculate the fixture adjusted rating for the following team.

    The team in question have a rating of +0.3 xG after 5 games and they have played teams we estimate are of levels -0.1 xG, -0.05 xG, +0.2 xG, +0.5 xG, and +1.0 xG in a 20 team league. 

    Circular Issues

    In order to calculate the fixture adjustment we need the true performance level of the opponents.  The method is somewhat counterintuitive because we are trying to calculate the true performance level of every team but we need the performance levels of the teams as an input to adjust for schedule.  With smaller samples I recommend estimating the level of each opponent rather than inputting their raw performance.  If the adjusted ratings significantly change your estimated ratings it would be reasonable to recalculate the schedule adjustment with the new ratings.

    Edit: Back from the future, I did a little study on how many iterations are optimal for a fixture here: https://syzygyanalytics.co.uk/2025/10/25/grab-bag-25th-october-2025/

    If you would like to get in touch about anything or tweet me blow at https://x.com/SamH112358.

    Also you could consider subscribing using the white box on my home page!

    Glossary

    1 It’s interesting to note there could be different definitions of ‘league average’.  In this case average to us means total attacking output is equal to the total attacking output of their opponents (i.e. their goal difference equals 0).  However it’s also not unreasonable to argue that the average side is the middle team of the league, e.g. 10th in a 20-team league.  If a league is skewed towards either having some very dominant teams or very weak teams then the middle team (10th in a 20 team league) would not be expected to have a goal difference of zero.  For all analytical purposes our ‘league average’ team is going to be the one with a goal difference of zero, an xG difference of zero, a shot ratio of 0.5 e.t.c.    

  • Since I started working on my soccer team ratings around 9 years ago, my goal has been to make my rating system as predictive as possible. 

    xG models are popular because they contain useful descriptive information as well as being more predictive than simpler metrics such as goal difference/points/shot ratio.

    For a rating to be predictive we need to make as many adjustments as required such that a league average team always rates as league average.  A team that plays while losing scoreline may appear to perform better in a metric, a team that’s played lower ranked opposition may appear to be better than they are, a team with a player advantage will appear better than their true level e.t.c.  Another consideration is to lower the variance such that our rating system needs fewer games for the same level of predictive accuracy than other ratings.

    In this article I am going to give a basic summary of the ideas I have that improve on the predictive performance starting from a baseline of xG.

    All these have been the basis for the ideas and adjustments that are used in my team ratings today.  I am going to cover these topics in a lot more depth in the future of this site.

    • A team gets no credit for dangerous passes.  It’s a good sign if a team is making more successful passes into a dangerous area than another if everything else was equal.
    • Red card adjustment – If teams play minutes up or down a player that will make them look better/worse than they actually are (as red cards happen fairly randomly)
    • Scoring goals gets no credit.  Even though finishing is fairly random it is not completely random hence we may want to give a team *some* amount of credit for finishing ability or goalkeeping/defending ability.
    • Unassisted shots – Are unassisted shots created through a more random process?  Are they less repeatable and should hence be given less credit.
    • Shots with very large xG give the team too much credit.  I don’t think this is too debatable if we are talking about an unassisted shot that bounces off a players thigh on the goal-line during a scramble following a corner but I still believe this even if we talk about a great open-play intricate team goal that results in an unmissable pass into the goal.
    • Team style – Can teams overperform raw xG because of the way they play?  Consider maybe Juventus or Atletico Madrid.  How could we predict this over/under performance.
    • Sample size – If we have to rate a team’s performance to the best of our ability over 3 games should we use different parameters than say, for a 25 game sample? When do we start putting more weight on big chances? When does awarding credit for successful passes stop adding predictive value?

    If you would like to get in touch about anything you can e-mail syzygy112358@proton.me or tweet me at https://x.com/SamH112358