Skip to content
Back to blog

Team Up Blog

EA FC Leagues in Discord: League Tables vs Elo Ladders

| Team Up | 13 min read

Football communities want a table — fixtures, three points for a win, goal difference. Every ranking bot gives you a ladder. The difference is entirely about your schedule, and it decides which one your league can actually run.

ea-fcleague-managementeloleaderboardsguide

Almost every competitive gaming community on Discord thinks in ladders. You climb, you have a rating, the number goes up and down, and there's no end to it.

Football communities don't think like that at all. An EA FC league, a Pro Clubs season, a football-sim community of any kind thinks in tables: a fixture list, three points for a win and one for a draw, goal difference as a tiebreaker, and a season that ends. That's not a stylistic preference — it's how the sport being simulated actually organises itself, and a league that runs on Elo instead often feels subtly wrong to the people in it.

The two structures are genuinely different objects, and the difference comes down to one thing that almost nobody names: your fixture list. Get that right and the choice makes itself.

A Table Is a Record. A Ladder Is an Estimate.

Start with what each thing is claiming.

A league table is an accounting of what happened. Points are earned and banked, they never go down, and the table makes no claim about who is better — only about who has accumulated most. It is a historical record, and it is complete and correct by construction, because it's just addition.

An Elo ladder is a running estimate of strength. It isn't recording what happened; it's using what happened to update a prediction. Points move between opponents, your rating can fall after a win, and there is no final state — only a current one.

Those answer different questions. "Who won the league?" is a table question. "Who is the best player here?" is a ladder question. A football community usually wants the first, and reaching for a rating system to answer it is a category error that produces a lot of confused complaints about ratings going down.

The Schedule Is the Whole Difference

Here's the part that decides it, and it's more concrete than the philosophy above.

A table is only fair if everyone plays the same fixtures. That's why real football uses a full double round-robin — every club plays every other club home and away. Once the schedule is balanced, points are a fair comparison, because beating the bottom club is worth three to everyone and everyone has to do it.

Elo carries no such requirement. It adjusts for who you played, so it's schedule-independent by design.

When the schedule is balanced, the two agree. Here's an eight-club league playing one complete round-robin with no upsets — the stronger club always wins:

Club rating Points Elo after
1600 21 1635
1500 18 1521
1400 15 1412
1300 12 1304
1200 9 1198
1100 6 1090
1000 3 980
900 0 865

Identical ordering. On a complete, balanced schedule the table and the ladder are two views of the same truth, and the table is the simpler and more readable one. If you can complete a full round-robin, run a table. You don't need a rating system, and the season standings are exactly what your community wants to look at.

Now the case that actually applies to most Discord leagues. Two clubs, both starting at 1300, both finishing a half-season on 6 wins, 0 draws, 2 losses — 18 points each. One played the bottom of the table; one played the top:

Record Points Elo change
Club A — played the bottom half 6-0-2 18 −19
Club B — played the top half 6-0-2 18 +121

Level on points, 140 rating points apart. Club A actually got worse by going 6-2, because beating weak clubs is what a 1300 is supposed to do and losing twice while doing it is a bad sign. The table cannot see any of this, and it isn't malfunctioning — an unbalanced schedule is simply outside what a table is able to measure.

The size of the effect is easy to underrate. Take one club of fixed strength and give it eight fixtures against the bottom of the table, then eight against the top:

  • Against the bottom: expected 6.5 wins → about 19 points
  • Against the top: expected 1.5 wins → about 5 points

Same club, same skill, 14 points of table position decided entirely by who they happened to be scheduled against. In a league where fixtures get arranged ad hoc because two people were online at the same time, that's the dominant effect in your standings.

So Which Does Your League Need?

One question: can you realistically complete a balanced schedule?

Yes — run a table. Fixed roster, everyone committed to playing every opponent, a defined season. You want points, goal difference, and a table nobody has to have explained to them.

No — run a ladder. People drop out mid-season, fixtures go unplayed, someone racks up fourteen games while someone else manages six, and new members join in week five. This describes most Discord leagues. A table with unequal games played is not a slightly degraded table; it's measuring the fixture list.

And be suspicious of the usual patch. Points-per-game makes it worse, not better — it divides out the games-played difference but does nothing about opponent quality, so it takes a small sample and amplifies whatever schedule luck was in it. A club that played six fixtures against the bottom half now tops the table on 2.5 points per game.

The honest middle option: run the table as your season's public standings and keep a ladder underneath for seeding, tiebreaks and cross-season continuity. They're not in competition — one records the season, the other remembers.

Points Have No Opponent Adjustment, By Definition

Worth making explicit, because it's the trade you're accepting when you choose a table.

A 1300-rated club, K=32, beating opponents of varying strength:

Opponent rating League points Elo change
1000 3 +4.8
1150 3 +9.5
1300 3 +16.0
1450 3 +22.5
1600 3 +27.2

Three points every time; between +4.8 and +27.2 on the ladder. Neither column is wrong. Three points for beating the champions and three for beating the bottom club is the definition of a league, and it's exactly why winning one is an achievement — you have to do it against everybody. The rating column is answering a different question.

Draws Are First-Class Here, and They Behave Oddly

Football is the one format on this blog where draws are common rather than an edge case — roughly a quarter of real matches. Most competitive gaming formats either can't draw or treat it as a curiosity.

In a table a draw is simple: one point each, regardless of who you drew with.

On a ladder it isn't, and the difference is worth understanding before your community runs into it. A draw is scored as half a win, so it's judged against expectation like any other result. At K=32:

  • A 1500 club drawing a 1100: −13.1. They were expected to win comfortably; a draw is a bad result and the rating says so.
  • The 1100 club in that same draw: +13.1.
  • Two clubs of equal rating drawing: 0.0 for both.

So a draw can cost the better side more rating than some losses cost the weaker one. That's correct behaviour, and it's also the single most common source of "why did my rating go down, I didn't lose?" — worth explaining once in your server rather than fielding it every week.

Goal Difference Is a Tiebreaker, Not a Rating

Goal difference does one job well: separating clubs level on points, using information the points column threw away.

It is not a quality metric, and it's worth being clear-eyed about what it rewards. GD counts margin, so a club that beats a disconnecting opponent 9–0 banks the same advantage as one that wins three tight matches by three goals total. In a sim league where scorelines can run away, that puts real weight on running up the score against whoever is weakest — which is a fine incentive in a professional sport with pride at stake and a slightly corrosive one in a Discord league where the bottom club is someone's mate who joined last week.

Two options that both work:

  • Keep GD but cap it — count a maximum of, say, five goals of margin per fixture. Preserves the tiebreak, removes the farming incentive.
  • Use head-to-head first, then GD. More faithful to how a lot of real competitions actually break ties, and unfarmable.

Either way, decide before the season starts, not when two clubs finish level.

Running It in Discord

Being straight about what the tooling does and doesn't do here, because a football league is the format that fits a ranking bot least comfortably.

There is no league-table mode and no fixture generator. Round robin sits in the tournament format picker marked coming soon, and nothing anywhere will build, schedule or track a fixture list for you. That part is yours, in a pinned message or a sheet.

But you can build a genuine table out of derived stats, and this is the part most people miss. A derived stat is a formula over a player's or club's career aggregates, with wins, losses, draws, matches and your own custom-stat totals available as variables. So:

  • Points = wins*3 + draws
  • GD = goals_for_sum - goals_against_sum

Both can be displayed as leaderboard columns, and either can be the sort key for the board. Set the columns to Points, record and GD, rank by Points, and what you're looking at is a league table — three points a win, one a draw, goal difference alongside. Derived stats are configured in the web dashboard under Rankings → your ranking → Stats; there's no Discord command for them.

Bake the tiebreak into the formula. The board sorts on one value, so goal difference will not act as an automatic secondary tiebreak the way it does in a real league. Fold it in with a small weight instead:

wins*3 + draws + 0.001*(goals_for_sum - goals_against_sum)

Record draws as equal placements. Put both clubs in the same place option — 1st_place: (@a @b) (@c @d) — and equal places are read as a draw, incrementing the draws counter that Points above depends on. This works but isn't mentioned in the command's help text, so it's worth writing down for your admins. Matches formed by a queue or lobby have an explicit Tie button instead.

Clubs are teams. Create them with /team_admin and record fixtures by club name with /record_match team_alias. Team aliases carry their own ratings, records and public profile pages, so the table becomes a table of clubs rather than of individuals — which is what a Pro Clubs or franchise league actually wants.

Goals for and against are custom stats, defined per fixture with an aggregate:

/settings custom_stats define_number name:goals_for aggregates:sum

Those aggregates can sit on the leaderboard row itself, not only on profiles — which is what makes the GD column possible.

Two traps worth knowing before you build this:

  • Casual matches don't feed stat aggregates by default. If your league marks friendlies casual, their goals silently won't reach GD. Turn aggregation on in the casual policy or keep friendlies off the league board entirely.
  • The queue scoring modes can't express 3-1-0. Queues support a placement_points mode that awards fixed points per finishing place, which sounds like exactly what a football league wants. It isn't: a tie puts both sides in place 1, so both collect the win points. Use the derived-stat route above.

My actual recommendation for most leagues: rank by Elo and show the table columns alongside it, or run the derived-Points board if your schedule really is balanced. The ladder is what survives the incomplete fixture list a Discord league will inevitably have, and the Points and GD columns give your community the view they came for either way.

One Note on Pro Clubs

If your league is 11-a-side Pro Clubs rather than 1v1 Ultimate Team, you have the attribution problem at close to its maximum — one result split across eleven players, most of whom didn't decide it. Rating the club rather than the individuals is by far the cleaner answer when rosters are stable, and it's what the table format assumes anyway. The attribution post covers why individual ratings from large-team results converge so slowly.

Setting It Up

  1. Decide whether you can complete a balanced schedule. Everything else follows from the answer.
  2. Track goals_for and goals_against as number custom stats with a sum aggregate — you need these before anything else works.
  3. Define the derived stats Points = wins*3 + draws and GD = goals_for_sum - goals_against_sum, in the dashboard under Rankings → Stats.
  4. If your schedule is balanced: rank by Points. If it isn't, rank by rating and show Points and GD as columns.
  5. Rate clubs, not players, for team formats with stable rosters — /team_admin plus /record_match team_alias.
  6. Record draws as equal placements, and explain once why a draw can cost the favourite rating.
  7. Pick your tiebreaker before the season — capped GD or head-to-head — and fold it into the Points formula, because it won't tiebreak on its own.

Frequently Asked Questions

Can I run a table and a ladder at the same time?

Yes, and it's the arrangement I'd recommend for most leagues. They answer different questions — the table records the season, the ladder estimates strength and carries across seasons. Record each fixture once into the ladder and maintain the table from the same results.

My league can't finish its fixtures. What do I do?

Switch to a ladder for the ranking and keep the table as a partial record clearly labelled as such. The failure mode to avoid is publishing an unbalanced table as if it were the standings — it will hand the title to whoever drew the easiest fixtures, and everyone will be able to feel that something is wrong without being able to say what.

Should promotion and relegation use the table or the rating?

The table, if the schedule was balanced — promotion should reward the season you actually played, and that's what a table is. If it wasn't balanced, use the rating, because the table isn't measuring what you'd be promoting for. Divisions, promotion and relegation covers the structure in more depth.

How do I stop people farming goal difference?

Cap the margin that counts per fixture, or make head-to-head the first tiebreaker so GD rarely decides anything. Both are better than asking people not to — the incentive is real and it's your rules that created it. If you're using a derived Points stat, a cap has to be applied when you record the fixture rather than in the formula, since the formula only sees the season aggregate.

Why did my rating drop after a draw?

Because your rating expected you to win. A draw is scored as half a win, so drawing against a much weaker opponent is a below-expectation result and costs rating, while the weaker side gains the same amount. On a league table that same draw is one point each — which is exactly the difference between recording a result and estimating strength.


Running a football-sim league on Discord? Team Up records club-vs-club fixtures by name, reads equal placements as draws, tracks goals for and against as custom stats, and lets you define wins*3 + draws as a derived stat and rank the public board by it. Start with the leaderboard setup guide, or read how to run a competitive season for the rollover side.