About & ELO Calculation

How player ELO is computed on HLL Stats (detailed but concise).

Overview

ELO is updated per match. For each eligible round we compute a game score (gamepunkte) from your in-game stats, then adjust your ELO toward that score. The change is capped and scaled by opponent strength so that beating weaker teams gives less gain and losing to stronger teams gives less loss.

When is a match / player counted?

  • Match: Only rounds marked usable (min duration, KPM, max duration) and with at least 40 players.
  • Player: At least 15 minutes playtime; minimum activity (offense + defense) / time ≥ 0.08; at least 2 kills or deaths combined.

1. Game score (gamepunkte)

We normalize playtime to a reference length (5340 seconds ≈ 89 min) via time_factor = 5340 / your_time_seconds.

Weapon-adjusted kills

Every weapon belongs to a category. Each kill is multiplied by that category's factor. When a weapon covers multiple categories, the smallest factor is used (conservative policy).

Category Factor Examples
Infantry1.0M1 Garand, STG44, Thompson, …
Machinegun0.95MG42, Browning M1919, MG34
Sniper0.72M1903 Springfield, K98 x8, FG42 x4
SPA0.62StuG, SU-76, M8 Greyhound, …
Explosive0.60Grenades, satchels, Panzerschreck/Bazooka, mines
Tank0.50Panther, Tiger, Sherman, T-34, Puma, …
Commander0.40Bombing Run, Strafing Run, Precision Strike
Artillery0.30Howitzer

adjusted_kills = Σ weapon_kills × category_factor. Unknown weapons default to factor 1.0.

Victim-ELO factor (how strong were the players you killed?)

adjusted_kills is then multiplied by a victim-ELO factor: factor = clamp(1 + 0.1 × (avg_victim_elo − your_elo) / 1000, 0.8, 1.2). avg_victim_elo is the kill-weighted ELO of the players you killed (using most_killed, only real SteamIDs, their ELO taken from a pre-match snapshot). Killing much stronger opponents gives up to +20 %, killing much weaker up to −20 %. No matching victim data → factor 1.0 (neutral).

Active part

  • Kills: adjusted_kills × time_factor × 7.
  • Combat: Your combat score is weighted by a combat factor = combat / adjusted_kills (same basis as the kill line). If adjusted_kills = 0, combat points = 0.
    • If factor ≤ 15: full weight (1.0).
    • From factor 15 → 35: linear drop to weight 0.2.
    • From 35 → 40: linear drop to 0.1.
    • Above 40: constant 0.1 (hard floor – never zero, so tank-only / commander-heavy rounds still keep a small share of combat points).
  • Active points = time_factor × (weighted_combat + adjusted_kills × 7).

Commander boost

As soon as your commander-ability kills (Bombing / Strafing / Precision Strike) are more than 2, you are treated as a commander — even if you also used other weapons. Your support contribution is then doubled: support_effective = support × 2. Below the threshold: unchanged (multiplier 1.0).

Passive part (support / defense / offense)

  • If (offense + defense) > 22 pts/min × your time, offense and defense are set to 0 (unrealistic values).
  • Smoothed support factor (no hard thresholds anymore): f(x) = 0.05 + 0.05 / (1 + (x/4000)^3.42), with x = support_effective × time_factor. That gives ~0.10 at x=0, ~0.075 at 4000, ~0.06 at 6000 and approaches 0.05 for large x.
  • Passive = time_factor × (support_effective × f(x) + defense × 0.15 + offense × 0.3).

Game score = active + passive.

2. ELO change (before opponent adjustment)

Raw change = (gamepunkte − current_elo) × base_multiplier. base_multiplier: 0.5 for your first 4 counted games (history rows with a non-null ELO), then 0.1.

Caps (so one match never swings too much)

  • If |raw_change| ≤ 600: use raw change.
  • If |raw_change| ≤ 1200: first 600 at 100%, rest at 50%.
  • If |raw_change| > 1200: first 600 at 100%, next 600 at 50%, remainder at 25%.

3. Opponent strength factor

Opponent strength per side uses the same formula as match-page team averages: 0.30×top5 + 0.30×top10 + 0.40×top20, only players with ≥ 15 min in that match, unknown players treated as 1000. Your opponents are the other side (Axis vs Allies). For the strength factor, ELO is taken before anyone in that match is updated (pre-match snapshot).

Strength factor (between 0.2 and 1.2)

  • Win vs stronger or equal opponents: factor = 1.0 (full gain).
  • Win vs weaker opponents: factor = 1000 / (1000 + (your_elo − opponent_avg)) (reduced gain).
  • Loss vs stronger opponents: factor = 1000 / (1000 + (opponent_avg − your_elo)) (reduced loss).
  • Loss vs weaker opponents: factor = 1.0 (no extra penalty). If your ELO ≥ 1500, factor is capped at 1.0.

ELO change so far = capped_change × strength_factor.

4. Team-underdog protection (loss dampening)

If your team is clearly weaker than the enemy team, an ELO loss is dampened so you are not punished for being drafted into an underdog side. "Loss" here means your performance was below your own ELO (elo_change < 0) — the match outcome itself is not used, which keeps the rule robust against corrupt/missing scores.

Let team_diff = opponent_team_avg − own_team_avg (positive = your team is weaker).

  • team_diff ≤ 100: factor 1.0 (no effect).
  • team_diff > 100: factor = clamp(1 − (team_diff − 100) / 1500, 0.7, 1.0).
  • Hard floor at 0.7 (max 30 % dampening).
  • On a win (elo_change ≥ 0) the factor is always 1.0 — no exploit for strong players drafted into weak teams.
  • Unknown side (missing team assignment) also gives factor 1.0.
team_diff underdog_factor
≤ 1001.00
2000.93
3000.87
4000.80
5000.73
≥ 5500.70 (floor)

Final ELO change = capped_change × strength_factor × underdog_factor. New ELO = current_elo + final_change (rounded).

Match ELO (axis_avg / allies_avg)

On match and match-list pages we show axis_avg and allies_avg from the stored map_match_elo row: same weighted top-5/10/20 mix as above, but computed with each player’s ELO after that match has been applied (post-match snapshot). Tiers (e.g. Very Low, Normal, High, Super High) and imbalanced / highly imbalanced labels use these stored values and their difference (>100 / >200).

In short: strength factor for your ELO change uses pre-match side averages; match page team ELO bars use post-match averages.

Summary

ELO is a smoothed estimate of your performance. Your game score reflects weapon-adjusted kills (per-category factors), scaled by a victim-ELO factor (it matters who you actually kill), plus weighted combat and support / defense / offense with a smoothed support curve and a commander boost (support × 2 once commander-ability kills > 2). The ELO update is damped by caps and by opponent strength (pre-match side ELO). Match team ELO bars on match pages use post-match values. Everything is processed chronologically.

Full specification (same rules): backend/docs/ELO_AND_GAMEPUNKTE_CALCULATION.md