Training-load metrics and Strava archive parsing for endurance sport — with zero runtime dependencies.
trainingload is a small, typed Python toolkit for the math behind endurance
training analytics: Training Stress Score (TSS) for swim/bike/run/strength, the
Performance Management Chart (CTL / ATL / TSB), and a parser for Strava's bulk
data export. It's the load engine extracted from the production codebase of
Motus — an AI triathlon coach — and packaged so you
can drop it into a notebook, a script, or your own app.
No NumPy, no pandas, no web framework. Just the standard library.
pip install trainingloadRequires Python 3.10+.
from datetime import date
from trainingload import calculate_pmc
# Daily Training Stress Score -> fitness (CTL), fatigue (ATL), form (TSB)
series = calculate_pmc({
date(2026, 1, 1): 80.0,
date(2026, 1, 2): 120.0,
date(2026, 1, 3): 0.0, # rest day
})
today = series[-1]
print(today.ctl, today.atl, today.tsb)Three independent modules — use one or all three.
Sport-aware TSS from whatever data you have (power, pace, heart rate, or just duration), with sensible fallbacks.
from trainingload import TSSCalculator, TrainingZones
zones = TrainingZones(bike_ftp=250, run_threshold_pace=300, swim_css=95)
# Cycling from normalized power:
TSSCalculator.calculate_bike_tss(duration_seconds=3600, normalized_power=200, ftp=250) # 64.0
# Or let it pick the best method for the sport and data available:
TSSCalculator.estimate_tss(sport_type="run", duration_seconds=3600,
distance_meters=10000, zones=zones) # 69.4
# Show your work — which method, inputs and formula were used:
TSSCalculator.explain_tss_calculation(sport_type="bike", duration_seconds=3600,
tss=64.0, normalized_power=200, zones=zones)CTL/ATL/TSB time series and a current-fitness snapshot from a map of daily TSS.
from datetime import date
from trainingload import fitness_summary, interpret_tsb, recommend_training
summary = fitness_summary(daily_tss) # {date: tss} -> ctl/atl/tsb + ramp rate
print(interpret_tsb(summary.tsb)) # e.g. "fresh"
print(recommend_training(summary.tsb, target_event_days=7))- CTL (Chronic Training Load) — 42-day EMA of TSS → fitness
- ATL (Acute Training Load) — 7-day EMA of TSS → fatigue
- TSB (Training Stress Balance) — CTL − ATL → form
Turn the activities.csv from a Strava data export into typed records. Accepts
a file path or an in-memory stream (e.g. an upload), so it works server-side
or in a worker without touching disk.
from trainingload import StravaArchiveParser
parser = StravaArchiveParser()
activities = parser.parse_zip_activities("strava_export.zip")
meta = parser.parse_zip("strava_export.zip") # totals, date range, sport breakdownSee examples/strava_to_pmc.py for the full flow —
parse the archive, score every activity, and print your current CTL/ATL/TSB:
python examples/strava_to_pmc.py path/to/strava_export.zipTSS, NP/IF, and the CTL/ATL/TSB model come from the endurance-training literature popularised by Hunter Allen & Andrew Coggan (Training and Racing with a Power Meter) and the TrainingPeaks Performance Management Chart. The implementations here are independent and intentionally transparent — every formula is documented in the source and covered by tests.
Trademark note. "TSS", "CTL", "ATL", "TSB", "NP" and "IF" are used in this project descriptively to refer to widely-documented training-load concepts. They are trademarks of Peaksware, LLC (TrainingPeaks). This project is not affiliated with, sponsored by, or endorsed by TrainingPeaks or Strava.
trainingload powers the analytics inside Motus,
an AI coach for runners and triathletes. If you want the metrics in this library
turned into adaptive training plans, race predictions and a coach in your pocket,
give Motus a try
— and read the training-science guides on the Motus blog.
Issues and pull requests are welcome — see CONTRIBUTING.md.
MIT © Motus