Action valuation for handball: H-xT (Expected Threat) and H-VAEP (Valuing Actions by Estimating Probabilities), adapted from the soccer library socceraction to handball geometry, event types and game flow. If you use this code, please cite the paper.
Paper: H-VAEP and H-xT: Valuing Offensive On-the-Ball Actions in Handball by Estimating Probabilities. To appear at MLSA 2026 @ ECML/PKDD. Preprint: arXiv:2608.12926.
Every on-ball action (a pass, a dribble, a shot) changes how likely a team is to score next, and how likely it is to concede next. Both models put a number on that change, so that the players who create value without ever touching the scoresheet become visible.
- H-xT divides the court into zones and iterates a move/shoot transition matrix until the scoring probability of each zone converges. An action is worth the difference in threat between where it ended and where it started.
- H-VAEP uses gradient-boosted trees to learn the two probabilities directly from the game state: the last k actions with their positions, timing and outcome. An action is worth how much it raised the scoring probability minus how much it raised the conceding one.
- Player ratings aggregate action values over a season and are validated against external metrics with the meta-metric framework of Franks et al. (2016): discrimination, stability and independence.
- Data connectors for the SportApp (Kinexon), Sportradar Datacore and HBL Statistics Center APIs feed tracking-derived event data into the pipeline without custom integration work.
Actions are represented in OHADL (On-ball Handball Action Data Language), handball's counterpart to SPADL: a Pandera-validated table with one row per action.
Requires Python 3.11+.
uv syncWithout uv, or with GPU / development extras
# pip
python -m venv .venv && source .venv/bin/activate
pip install .
# GPU-accelerated random forest via cuML (needs CUDA 12)
uv sync --extra gpu
# development: linting, formatting and notebook tooling
uv sync --extra dev
uv run pre-commit installThe pipeline runs as a sequence of CLI scripts, each taking --help. Data comes from the HBL
APIs, so downloading needs credentials: copy .env.example to .env and fill
it in. Getting a season into OHADL takes four scripts, listed with their arguments in
scripts/README.md.
With datafiles/hbl_ohadl/ populated, an H-VAEP model is tuned on one season and evaluated on
the next:
# Tune the scoring and the conceding classifier
uv run python scripts/tune_vaep_model.py --target=scores --ml_model_type=catboost --season=2023
uv run python scripts/tune_vaep_model.py --target=concedes --ml_model_type=catboost --season=2023
# Retrain with the best hyperparameters and evaluate on the held-out season
uv run python scripts/train_eval_vaep_model.py --eval_season=2024 \
--tuning_results_path=datafiles/tuning_results/scores_catboost_2023_results.jsonsrc/handballaction/
data/ OHADL schema and converter, API clients, extraction helpers
valuation/ H-xT and H-VAEP models, feature generators, label strategies, tuning
player_rating/ Aggregation of action values into player ratings
evaluation/ Meta-metrics, held-out predictions, game-clustered bootstrap
visualization/ Handball court and action-sequence plots
scripts/ CLI entry point per pipeline stage (see scripts/README.md)
notebooks/ Analyses behind the paper's figures and tables
datafiles/ Local data store, gitignored
If you use this code, please cite the preprint:
@misc{broermann2026hvaephxt,
title={H-VAEP and H-xT: Valuing Offensive On-the-Ball Actions in Handball by Estimating Probabilities},
author={Julius Broermann and Oliver Müller and Michael Döring and Jochen Baumeister},
year={2026},
eprint={2608.12926},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2608.12926},
}MIT, see LICENSE.