Skip to main content

Scoring and salary calculation for GridRival fantasy F1

Project description

gr_analytics

Tests

Python package for scoring and salary calculation in GridRival fantasy F1.

Installation

pip install -e .

Quick Start

import pandas as pd
from gr_analytics import score_event, score_my_team, optimal_lineup

# Load your race scenario
scenario = pd.read_csv("my_race.csv")

# Score the event (defaults to the latest round in driver_data)
result = score_event(scenario)

# Or score a specific round
result = score_event(scenario, round=1)

# Score your specific team selection
points, salary_change = score_my_team(
    scenario,
    drivers=["RUS", "ANT", "LEC", "BEA", "LIN"],
    team="MER",
    star_driver="BEA",
    round=1,
)

# Find the optimal lineup (maximise points, £100M budget)
lineup = optimal_lineup(result)

# With locked-in drivers (already under contract, cost nothing)
# and a budget for the remaining open spots
lineup = optimal_lineup(
    result,
    locked_in=["HAM", "LEC"],   # driver_abbr or team code
    optimize_for="points",       # or "salary_change"
    budget=60.0,                 # £M available for non-locked picks
)

Scenario Format

The scenario DataFrame must have one row per driver with these columns:

Column Type Description
driver_abbr str Driver abbreviation (e.g. "RUS", "VER")
qualifying_position int Official qualifying position (1–22)
completed_qualifying int 1 if driver completed qualifying, 0 if DNQ
finishing_position int Race finishing position (1–22)
completed_pct float or "DNS" Fraction of race completed (0.0–1.0), or "DNS" if driver did not start

DNQ drivers get 0 qualifying points but their qualifying_position is still used to calculate overtake points.

DNS drivers (completed_pct="DNS") get 0 for all race-related points (race, overtake, improvement, completion, teammate).

DNF drivers (e.g. completed_pct=0.3) receive partial completion bonus points and their finishing position is used normally.

Qualifying and race positions must each form a complete sequence 1..n with no duplicates or gaps.

Output

score_event returns a DataFrame with all drivers and constructors, with scoring columns appended:

Drivers:

  • pts_qualifying, pts_race, pts_overtake, pts_improvement, pts_completion, pts_teammate
  • points_earned — total fantasy points
  • salary_after_event, salary_change

Constructors:

  • pts_qualifying, pts_race (sum across both drivers, using constructor-specific tables)
  • points_earned, salary_after_event, salary_change

Scoring Rules

All scoring follows GridRival's rules for Grand Prix events (no sprint races).

Drivers

Bonus Rule
Qualifying P1=50, P2=48, … P22=8 (step −2)
Race finish P1=100, P2=97, … P22=37 (step −3)
Overtake (qualifying pos − finishing pos) × 3, min 0
Improvement Points for finishing ahead of 8-race average (2 pos=2 pts, 3=4, 4=6, 5=9, 6=12, 7=16, 8=20, 9=25, 10+=30)
Completion 3 pts each at 25%, 50%, 75%, 90% of race distance (max 12)
Teammate Points for beating teammate by margin: ≥1 pos=2 pts, ≥4=5, ≥8=8, ≥13=12

Constructors

Constructor qualifying and race points use separate tables (P1=30/60, step −1/−2 per driver) summed across both drivers. No overtake, improvement, completion, or teammate bonuses.

Salary Adjustment

After each race, salaries adjust based on the gap between a driver's actual starting salary and the default salary for their points-ranking position:

adjustment = truncate(variation / 4, to nearest £100K)

Capped at ±£2M for drivers, ±£3M for constructors.

Driver Data

Bundled driver data (gr_analytics/data/driver_data.csv) contains starting salaries and 8-race averages by round:

  • round=0 — pre-season (before Australia 2026)
  • round=1 — post-Australia 2026

Eight-Race Average

GridRival's "8 race average" can be computed instead of entered by hand. GridRival seeds the season with 8 slots holding a hard-coded initial average (the round=0 values in driver_data); each race replaces one slot with the driver's classified finishing position, and the displayed value is the ceiling of the slot mean. Race finishing positions live in gr_analytics/data/race_results.csv.

from gr_analytics import calculate_eight_race_averages, eight_race_average

# All drivers, after the latest round in race_results.csv
calculate_eight_race_averages()

# All drivers, after round 2
calculate_eight_race_averages(through_round=2)

# Single driver from scratch: seed 1, finished P6 then P16
eight_race_average(1, [6, 16])

This reproduces GridRival's displayed values exactly for all rounds so far (verified in tests/test_eight_race_average.py).

Lineup Optimisation

optimal_lineup uses mixed-integer linear programming (via scipy.optimize.milp) to find the best 5-driver + 1-constructor lineup within a salary budget.

lineup = optimal_lineup(
    scored,                  # DataFrame from score_event()
    locked_in=None,          # list of driver_abbr / team codes already on your team
    optimize_for="points",   # "points" or "salary_change"
    budget=100.0,            # £M for non-locked picks
)
  • locked_in picks are included free (already under contract) and don't count against the budget.
  • optimize_for="points" selects the optimal star driver (who earns double points) across all candidates.
  • optimize_for="salary_change" maximises total salary gain for the next race's team valuation.

The returned DataFrame has a star column (1 = starred driver, points mode only).

Running Tests

python -m pytest tests/test_scoring.py -v

Tests include hand-calculated unit tests for all scoring components and a full integration test against real GridRival results from Australia 2026 (22 drivers + 3 constructors).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gr_analytics-0.3.2.tar.gz (24.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gr_analytics-0.3.2-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

Details for the file gr_analytics-0.3.2.tar.gz.

File metadata

  • Download URL: gr_analytics-0.3.2.tar.gz
  • Upload date:
  • Size: 24.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for gr_analytics-0.3.2.tar.gz
Algorithm Hash digest
SHA256 b5c883b71704505a24d2c2abc150019ce356fb4fe9694b2198fdf0132733a197
MD5 e56a8ac80fb05ec419ebd7e9d90f8c7d
BLAKE2b-256 6240a0c34c1962e2f96db1ddf4527e8dee1e898484739d9c2360de0a06ba93f2

See more details on using hashes here.

File details

Details for the file gr_analytics-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: gr_analytics-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 22.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for gr_analytics-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9eafb3b82915ba972fc73ad53fb857bb5884ac5e424b2bffce9ea49bde26501d
MD5 a50f76b5745579d75618c2a6c9cc1ab0
BLAKE2b-256 4c7f982ed38af1584e5f6fb71f865a774105dbfe7122abf86f31a28c68c78b0c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page