# Football (Soccer) Monte Carlo Season Predictor (`commodus67/football-soccer-monte-carlo-predictor`) Actor

Soccer betting odds model for 17 leagues: Premier League, LaLiga, Serie A, Bundesliga, Ligue 1, Liga MX, Brasileirao, MLS and more. Monte Carlo replays every remaining fixture for fair title, top-four, playoff and relegation probabilities, plus value bets vs bookmaker odds. No API key.

- **URL**: https://apify.com/commodus67/football-soccer-monte-carlo-predictor.md
- **Developed by:** [ELIO LIBERATORE](https://apify.com/commodus67) (community)
- **Categories:** Agents, AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 team projections

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Football (Soccer) Monte Carlo Season Predictor

Simulates the rest of a football season thousands of times and returns, for every team, the fair probability of finishing first, of taking a continental or promotion place, of reaching the title playoff where the league has one, and of being relegated. If you supply bookmaker implied probabilities, it also reports the gap between the model and the market.

Standings and the remaining calendar come from the public ESPN API. No account, no API key, no configuration.

### What makes it different

Almost every football Actor on the Store is a scraper: it copies a table, a fixture list or a set of odds and hands it back to you. This one is a model. It reads public data, builds a strength rating for every team, plays out the real remaining fixture list match by match and returns probabilities you can price against.

It also handles competition formats properly. A league is not always won by the team on top of the table, and not every league relegates three clubs, so the Actor knows how many continental places, playoff places and relegation places each competition actually has.

### How it works

1. **Current form.** Points per game plus a tenth of goal difference per game, taken from the live ESPN standings.
2. **Historical baseline.** The last three seasons of the same competition, weighted so the most recent counts most. Early in a season a team is mostly its history; by the halfway point it is mostly its current form. Promoted clubs inherit the average of the three weakest teams from the previous campaign.
3. **Absences (optional).** With your own API-Football key, injured and suspended players shave a little strength off the affected squads, capped at 15 percent.
4. **The real calendar.** Every match still to be played is pulled from the ESPN fixture list of each team and de-duplicated, so the model knows exactly who plays whom, how many games each side has left and which of them are at home.
5. **Simulation.** Each iteration draws a slightly different version of every squad from a normal distribution, then plays the whole remaining calendar. Each match becomes a home win, a draw or an away win from the strength gap plus the home advantage. Points are added to the live table and every standings table is ranked separately.
6. **Aggregation.** Across all iterations the Actor counts how often each team finishes first, inside the qualification places, inside the playoff places and inside the relegation places.
7. **Market comparison.** Any team you supply a market probability for gets an edge and a value flag.

Because the real calendar is used, strength of schedule falls out of the model for free: a leader with five away trips to the top six is treated very differently from a leader whose run-in is soft.

### Competition formats

The regular phase does not mean the same thing everywhere, so the output tells you what it means.

| Field | Meaning |
| --- | --- |
| `titleDecidedBy` | `table` when finishing first wins the trophy, `playoff` when the regular phase only seeds a knockout stage |
| `fairTitleProbability` | Probability of finishing first in the team's own table |
| `fairQualifyProbability` | Probability of finishing inside `qualifySpots`, the headline reward of that competition. Null where the competition has no such threshold |
| `fairPlayoffProbability` | Probability of finishing inside `playoffSpots`. Null where there is no playoff |
| `fairRelegationProbability` | Probability of finishing inside `relegationSpots`. Null where there is no relegation |

In the Premier League `qualifySpots` is 4 for the Champions League, in Brazil it is 4 for the Libertadores group stage, in Liga MX it is 6 for a direct Liguilla place and in MLS it is 7 for a direct playoff berth. So in the Premier League `fairTitleProbability` really is the title. In Liga MX, the Argentine Liga Profesional, the Colombian Primera A and MLS it is the probability of topping the regular phase, and `fairPlayoffProbability` is the one that matters for reaching the Liguilla, the cuadrangulares or the postseason.

Leagues split into zones or conferences, such as Argentina and MLS, are ranked table by table rather than merged into one list.

### Injury and suspension data: read this before enabling it

The injury adjustment is off by default and everything else works without it. If you switch it on you must bring your own API-Football key. Their free tier only serves seasons 2022 to 2024, so on a free key the current season returns no absences and the Actor simply carries on without the adjustment. It is one request per league per run.

### Running it once a day

Standings and fixtures move every matchday. Schedule the Actor to run each morning and you get a fresh probability table without touching anything.

### Input

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `leagues` | array of strings | `["eng.1"]` | ESPN league slugs to simulate |
| `iterations` | integer | `2000` | Simulated seasons. More is smoother, and slower |
| `historySeasons` | integer | `3` | Past seasons blended into each strength rating. `0` uses current form only |
| `homeAdvantage` | number | `0.34` | Strength added to the home side of every fixture. `0` ignores venue |
| `edgeThreshold` | number | `0.05` | Minimum edge over the market before `hasValue` turns true |
| `includeInjuries` | boolean | `false` | Turn the absence adjustment on |
| `apiFootballKey` | string | empty | Your own API-Football key, only for absences |
| `apiFootballLeagueIds` | object | `{}` | Manual ESPN slug to API-Football id mapping |
| `marketProbabilities` | array | `[]` | Your own implied probabilities, used to compute the edge |

#### Example input

```json
{
    "leagues": ["bra.1", "mex.1", "col.1"],
    "iterations": 4000,
    "historySeasons": 3,
    "homeAdvantage": 0.34,
    "marketProbabilities": [
        { "team": "Palmeiras", "league": "bra.1", "marketProbability": 0.42 }
    ]
}
```

### Output

One item per team. The dataset ships with four ready-made views: **Season overview**, **Market edge**, **Remaining schedule** and **Baseline, form and absences**.

| Field | What it is |
| --- | --- |
| `league`, `leagueName`, `table`, `team` | Competition, its ESPN name, the standings table and the club |
| `gamesPlayed`, `currentPoints` | Live position in the table |
| `remainingGames`, `homeGamesRemaining` | Fixture load still to come |
| `avgRemainingOpponentStrength` | How hard the run-in is. Higher is harder |
| `scheduleSource` | `espn-fixtures` when the real calendar was used |
| `projectedAvgFinalPoints` | Mean final points across all simulations |
| `titleDecidedBy`, `qualifySpots`, `playoffSpots`, `relegationSpots` | The format of that competition |
| `fairTitleProbability` | Probability of finishing first in its table |
| `fairQualifyProbability`, `fairPlayoffProbability`, `fairRelegationProbability` | The other three outcomes |
| `historicalBaseline`, `currentFormWeight`, `isNewToLeague` | How the strength rating was built |
| `playersInjured`, `playersSuspended`, `injuryPenaltyApplied` | Absence adjustment, when enabled |
| `marketProbability`, `edge`, `hasValue` | Comparison against your own odds |

### Pricing (pay per event)

8.00 USD per 1,000 results. One result is one team, so a 20-team league costs 0.16 USD per run and a daily schedule on a single league is under 5 USD a month.

### Supported leagues

| Slug | Competition |
| --- | --- |
| `eng.1`, `eng.2` | Premier League, Championship |
| `esp.1`, `esp.2` | LaLiga, LaLiga 2 |
| `ita.1`, `ger.1`, `fra.1` | Serie A, Bundesliga, Ligue 1 |
| `ned.1`, `por.1`, `tur.1`, `bel.1`, `sco.1` | Eredivisie, Primeira Liga, Super Lig, Pro League, Premiership |
| `bra.1` | Brasileirao Serie A |
| `mex.1` | Liga MX |
| `arg.1` | Argentine Liga Profesional |
| `col.1` | Colombian Primera A |
| `usa.1` | Major League Soccer |

Any other ESPN soccer slug also runs. Competitions that are not in the table above fall back to four qualification places, three relegation places and no playoff, so check that this matches the real format before trusting those columns.

### Limitations and honest caveats

- The model works from points, goal difference and the calendar. It knows nothing about transfers, managerial changes, weather, fatigue or motivation.
- Draw frequency is estimated from the strength gap rather than modelled from goals, so it is realistic on average but not for a specific fixture.
- Short tournaments such as the Liga MX Apertura or the Colombian Clausura start from a blank table. In the first few rounds the numbers lean heavily on the historical baseline.
- The playoff probability is the probability of reaching the bracket, not of winning it. Knockout rounds are not simulated.
- Relegation by multi-season averages, as used in Argentina and Colombia, is not modelled. Those competitions report no relegation probability at all rather than a wrong one.
- Points deductions, expulsions and mid-season rule changes are not modelled.
- ESPN can be slow to publish fixtures for a competition that has just ended or not yet begun. When no fixture list is available the Actor says so in `scheduleSource` and falls back to an assumed double round robin.
- These are probabilities, not predictions, and the market is often right. Nothing here is betting advice. Never stake money you cannot afford to lose, and if betting stops being fun, stop.

# Actor input Schema

## `leagues` (type: `array`):

ESPN soccer league slugs to analyze. Europe: eng.1 (Premier League), eng.2 (Championship), esp.1 (LaLiga), ita.1 (Serie A), ger.1 (Bundesliga), fra.1 (Ligue 1), ned.1, por.1, tur.1, bel.1, sco.1. Americas: bra.1 (Brasileirao), mex.1 (Liga MX), arg.1 (Liga Profesional), col.1 (Primera A), usa.1 (MLS). Any other ESPN soccer slug also works.

## `iterations` (type: `integer`):

Number of simulated seasons. More iterations are more accurate but slower.

## `historySeasons` (type: `integer`):

How many past seasons to blend into each team strength. This keeps predictions realistic before a season starts, when no matches have been played yet. More recent seasons carry more weight. Set to 0 to use current form only.

## `homeAdvantage` (type: `number`):

Extra strength given to the home side of every remaining fixture, in the same units as team strength (points per game). The default of 0.34 reproduces the usual split of roughly 46 percent home wins, 21 percent draws and 33 percent away wins between evenly matched teams. Set to 0 to ignore venue.

## `edgeThreshold` (type: `number`):

Minimum difference between fair title probability and market probability to mark hasValue as true.

## `includeInjuries` (type: `boolean`):

Reduces the strength of teams that are missing players through injury or suspension. Off by default. Needs your own API-Football key below, on a plan that covers the season you are simulating: their free tier only serves seasons 2022 to 2024, so it will not return absences for the current one.

## `apiFootballKey` (type: `string`):

Your own API-Football key, used only to read injury and suspension data, one request per league per run. Get it from the My Access page of the api-football.com dashboard. Note that their free tier does not cover the current season, so the adjustment only returns real numbers on a plan that does. Leave empty to skip it; every other feature works without a key.

## `apiFootballLeagueIds` (type: `object`):

Only needed for leagues the Actor does not map automatically. Maps an ESPN league slug to an API-Football league id, for example {"eng.1": 39}.

## `marketProbabilities` (type: `array`):

Optional list of your own market odds converted to probabilities, used to compute the edge. Each item: { team, league, marketProbability }.

## Actor input object example

```json
{
  "leagues": [
    "eng.1"
  ],
  "iterations": 2000,
  "historySeasons": 3,
  "homeAdvantage": 0.34,
  "edgeThreshold": 0.05,
  "includeInjuries": false,
  "apiFootballLeagueIds": {},
  "marketProbabilities": []
}
```

# Actor output Schema

## `predictions` (type: `string`):

Full prediction table. Switch between the Season overview, Market edge and Baseline, form and absences views for a narrower set of columns.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("commodus67/football-soccer-monte-carlo-predictor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("commodus67/football-soccer-monte-carlo-predictor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call commodus67/football-soccer-monte-carlo-predictor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,commodus67/football-soccer-monte-carlo-predictor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1LgsW5JhlqZRpH08g/builds/u0uQgWDKIvV0I7Uam/openapi.json
