# NBA Playoff Odds API — Monte Carlo Simulator & Value Bets (`commodus67/nba-playoff-odds-monte-carlo`) Actor

Replays every remaining NBA game thousands of times for playoff, play-in, division, conference and championship probabilities for all 30 teams, priced against live Kalshi contracts.

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

## Pricing

from $2.10 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## NBA Playoff Odds API — Monte Carlo Simulator & Value Bets

Replays every remaining NBA game thousands of times and returns, for all 30 teams, the
probability of making the playoffs, of falling into the play-in tournament, of winning a
division, a conference and the title — then prices each of those against live **Kalshi**
contracts and reports the edge, the expected value net of fees, and a suggested position
size.

Sports data, simulation, statistics, prediction markets, betting odds, basketball.

***

### The one thing to get right about the NBA

In baseball, football and hockey, "make the playoffs" is a single threshold and Kalshi
lists a single market. Basketball is different, and it is the most common way to get this
wrong:

| Finish in your conference | What it means | Kalshi market |
| --- | --- | --- |
| 1st – 6th | In the playoffs, no questions asked | `KXNBAPLAYOFF-27` |
| 7th – 10th | Into the **play-in tournament**, where only two of the four survive | `KXNBAPLAYIN-27EAST` / `KXNBAPLAYIN-27WEST` |
| 11th – 15th | Season over | — |

Kalshi says it in the contract rules: *"Qualifying for the play-in tournament doesn't
constitute playoff qualification."*

So the play-in market is not a weaker version of the playoff market — it is a **band**, and
the two are almost disjoint. The best team in a conference is a near lock for the playoffs
and a near-zero for the play-in. A 45-win team is the reverse. That is why this Actor
simulates the play-in games themselves (7 v 8 for the seventh seed; the loser then hosts
the winner of 9 v 10 for the eighth) instead of guessing, and why it reports
`fairPlayoffProbability` and `fairPlayInProbability` as two separate columns that are
compared against two separate markets.

### What it does

1. Pulls current standings from ESPN, including points scored and allowed.
2. Rates every team from its point differential — Pythagorean expectation with the
   basketball exponent of 13.91 — blended with its actual record and regressed toward a
   prior built from last season.
3. Simulates each remaining game from the ESPN schedule with home court applied in
   log-odds, redrawing every team's true strength once per simulated season so the output
   is a distribution rather than a single confident guess.
4. Seeds each conference, runs the play-in, then runs the full four-round bracket with
   best-of-seven series and the 2-2-1-1-1 home court pattern.
5. Fetches live Kalshi prices, matches every team to its contract, and computes edge,
   expected value net of fees, and a quarter-Kelly stake capped per position and in total.

### Output

One row per team. Highlights:

| Field | Meaning |
| --- | --- |
| `projectedWins` | Mean win total across all simulations |
| `averageSeed` | Mean finishing seed within the conference |
| `fairPlayoffProbability` | Reaches the playoffs — top six, or survives the play-in |
| `fairTopSixProbability` | Avoids the play-in entirely |
| `fairPlayInProbability` | Finishes 7th to 10th |
| `fairDivisionProbability` | Wins its division |
| `fairConferenceProbability` | Reaches the Finals |
| `fairChampionshipProbability` | Wins the title |
| `marketPrice`, `edge`, `expectedValuePerContract` | The contract and what it is worth |
| `call` | `VALUE`, `PASS` or `WATCH` |
| `suggestedContracts`, `suggestedStake` | Quarter-Kelly sizing, if a bankroll is set |

Four dataset views are provided: **Playoff overview**, **Market edge**, **Play-in race**
and **Title odds**.

### Preseason honesty

Before opening night this model knows exactly one thing: how last season ended. It has not
seen free agency, the draft, a trade, or an injury. Its largest disagreements with the
market are therefore not edges — they are the summer.

Two safeguards make that explicit rather than leaving you to discover it:

- **`minGamesPlayedForValue`** (default 10). Until every team has played that many games,
  no row may call itself `VALUE`. The edge is still reported in full; every row is simply
  labelled `WATCH`.
- **`strengthUncertainty`** (default 0.22). Each simulated season redraws every team's
  rating. Set it to zero and the Actor will happily tell you a team makes the playoffs 100%
  of the time, which is never true in September.

Run against real Kalshi prices in September 2026 the model's rank correlation with the
market was about 0.80, with a mean absolute difference of 13 points. The largest gaps were
teams whose entire case rests on the offseason — exactly what the gate is there for.

### Notes on the data

- ESPN names a season by the year it **ends**: 2026-27 is `season=2027`.
- Before opening night ESPN publishes the new division tree with no teams in it. The Actor
  falls back to last season for the club list and the conference map, with records zeroed.
- ESPN lists **80 of the 82** games until the NBA Cup is decided. The missing games are
  simulated against an average opponent so win totals stay on an 82-game scale rather than
  quietly projecting an 80-game season.
- Kalshi's public read API needs no key. Prices come from `yes_bid_dollars` /
  `yes_ask_dollars`; both sides of every contract are priced and the better one is used, so
  an overpriced favourite shows up as a chance to sell rather than as no signal at all.

### Related Actors

Same engine, other leagues: **MLB Playoff Odds**, **NFL Playoff Odds**, **NHL Playoff
Odds**, **Football (Soccer) Monte Carlo Predictor**, and the **Sports Probabilities MCP
Server** that exposes all of them to AI agents.

### Disclaimer

Statistical simulation for research and analysis. Not betting advice, and not affiliated
with the NBA, ESPN or Kalshi.

# Actor input Schema

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

How many full seasons to simulate. More iterations give smoother probabilities and a longer run.

## `season` (type: `integer`):

ESPN names a season by the year it ENDS, so 2026-27 is 2027. Leave empty to pick the current season automatically.

## `archiveToNamedDataset` (type: `string`):

Optional. Name a dataset in your account and every run appends its rows there as well. Run datasets are deleted after 31 days; a named dataset is kept, which is how you build a season-long history of how these probabilities moved.

## `regressionGames` (type: `integer`):

How many games of prior are mixed into each team's rating. Higher values pull teams toward their preseason expectation for longer.

## `pythagoreanWeight` (type: `number`):

How much of a team's rating comes from points scored and allowed rather than from its actual win-loss record. Point differential predicts the rest of the season better than record does.

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

Home edge in log-odds. The default of 0.32 makes an evenly matched home team a 57.9% favourite, which is where the NBA has settled.

## `strengthUncertainty` (type: `number`):

How unsure the model is of each team's true strength, in log-odds. Each simulated season redraws every rating once. Set to 0 to treat the ratings as exact, which makes the probabilities far more confident than they deserve to be.

## `priorCarryover` (type: `number`):

How much of last season's point differential carries into this season's starting rating. At 0 every team opens at .500 and the preseason table is meaningless; at 1 nothing regresses toward the mean.

## `seasonLength` (type: `integer`):

Games per team. ESPN publishes 80 of the 82 before the season starts because two depend on the NBA Cup; the gap is simulated against an average opponent so win totals stay on an 82-game scale.

## `minGamesPlayedForValue` (type: `integer`):

Until each team has played this many games, no row is allowed to call itself VALUE. In October the model only knows how last season ended, so its biggest edges are really the offseason it cannot see. Edges are still reported in full; every row is simply labelled WATCH.

## `includeMarketComparison` (type: `boolean`):

Fetch live prices from the Kalshi playoff-qualifier market and compute edge, expected value and position sizing. Turn off for projections only.

## `includePlayInMarkets` (type: `boolean`):

Also price the two per-conference play-in markets. Careful: these settle on finishing 7th to 10th, which is NOT making the playoffs, so they are compared against a different column. They are also far less liquid.

## `includeChampionshipMarket` (type: `boolean`):

Also price the outright title market by simulating the full bracket, including home court and the play-in.

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

How far the model has to be from the market before a row is called VALUE.

## `feeRate` (type: `number`):

Kalshi's taker fee coefficient. The fee per contract is rate x price x (1 - price). Assuming taker is deliberate and conservative; a maker pays roughly a quarter of it.

## `bankroll` (type: `integer`):

Optional. With a bankroll set, each VALUE row gets a quarter-Kelly position size, capped per position and in total. Leave at 0 for no sizing.

## `maxPerPositionPct` (type: `integer`):

Cap on any single position as a percentage of bankroll.

## `maxTotalExposurePct` (type: `integer`):

Cap on the sum of all suggested positions as a percentage of bankroll.

## Actor input object example

```json
{
  "iterations": 20000,
  "archiveToNamedDataset": "",
  "regressionGames": 20,
  "pythagoreanWeight": 0.65,
  "homeAdvantage": 0.32,
  "strengthUncertainty": 0.22,
  "priorCarryover": 0.6,
  "seasonLength": 82,
  "minGamesPlayedForValue": 10,
  "includeMarketComparison": true,
  "includePlayInMarkets": false,
  "includeChampionshipMarket": false,
  "edgeThreshold": 0.05,
  "feeRate": 0.07,
  "bankroll": 0,
  "maxPerPositionPct": 5,
  "maxTotalExposurePct": 25
}
```

# Actor output Schema

## `teamProjections` (type: `string`):

All 30 team rows: playoff, play-in, division, conference and title probabilities, projected record, and the market comparison.

# 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/nba-playoff-odds-monte-carlo").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/nba-playoff-odds-monte-carlo").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/nba-playoff-odds-monte-carlo --silent --output-dataset

```

## MCP server setup

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

```

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/42QwqlTfLRbOZrDYp/builds/SGtpp4ZLXfIBIJk2F/openapi.json
