# +EV & Arbitrage Betting Finder: 18 Sportsbooks + Exchanges (`artsiom_k/betting-ev-arbitrage-finder`) Actor

Finds +EV bets and arbitrage across 18 US and international sportsbooks plus the Kalshi, Polymarket and Smarkets exchanges: fair (no-vig) price, edge %, best book and stake split for NFL, NBA, MLB, NHL, college, soccer, UFC and tennis.

- **URL**: https://apify.com/artsiom_k/betting-ev-arbitrage-finder.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 results

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## +EV & Arbitrage Betting Finder: 18 Sportsbooks + Exchanges

Finds **positive expected value (+EV) bets** and **arbitrage (sure bets)** across **18 sportsbooks**
(DraftKings, FanDuel, BetMGM, Caesars, Fanatics, bet365, BetRivers, theScore Bet, Hard Rock Bet,
Bally Bet, Unibet, BetVictor, Betfred, Parx, Bet99, Sports Interaction, TonyBet, LeoVegas) and three
**betting exchanges** (Kalshi, Polymarket, Smarkets). For every bet it gives the **fair (no-vig)
price**, the **edge %**, the **best book** and every other book's price; for every arbitrage, the
books, odds and **stake split**.

NFL, NCAA Football, NBA, NCAA Basketball, WNBA, MLB, NHL, 8 soccer leagues (Premier League, La Liga,
Bundesliga, Serie A, Ligue 1, Champions League, Europa League, MLS), UFC and ATP/WTA tennis.
Moneyline, spread and total, main and alternate lines. A run takes seconds.

### Contents

- [Why this finder](#-why-this-finder)
- [How the fair price and edge are worked out](#-how-the-fair-price-and-edge-are-worked-out)
- [Output](#-output)
- [Input](#️-input)
- [Input examples](#-input-examples)
- [Use it from an AI assistant](#-use-it-from-an-ai-assistant)
- [Good to know](#-good-to-know)
- [FAQ](#-faq)

### ✅ Why this finder

- **21 price sources in one run.** Most +EV tools compare 3–4 books. More books means a sharper fair
  price and more chances that one book is behind the market.
- **Exchanges included.** Kalshi and Polymarket prices (prediction markets) and the Smarkets order
  book go into the fair price; Kalshi and Smarkets are also offered as places to bet, with their fees
  taken off.
- **Each sportsbook counts once.** DraftKings in 15 states is still one opinion, not 15.
- **Bad prices filtered out.** A price far from every other book (a swapped or stale line) is dropped
  instead of showing up as a 400% "edge".
- **Your books only.** Pick the sportsbooks legal where you are; the finder only suggests bets there.
- **Best first.** Arbitrage first (highest profit), then +EV bets (highest edge): a capped run returns
  the best opportunities.

### 🧮 How the fair price and edge are worked out

1. For every line (the moneyline, the spread at -3.5, the total at 221.5...), each book's prices for
   all outcomes are turned into probabilities and its margin (the "vig") is removed.
2. The **fair probability** of each outcome is the median across books, so one odd book can't move it.
3. **Edge (EV %)** = fair probability × decimal odds − 1. An edge of 3% means 3 units of expected
   profit per 100 staked, over many bets.
4. **Arbitrage**: when the best prices for every outcome add up to less than 100% implied
   probability, staking in the shown proportions wins the same amount whatever happens.

Spreads and totals are only compared at the same number: a -3.5 price is never compared with -4.

### 📋 Output

Rows are either `bet` (one outcome) or `arbitrage` (one set of bets). See the **Output** tab's
**Opportunities** view for a table.

**+EV bet:**

```json
{
  "row_type": "bet",
  "league": "nfl",
  "start_time": "2026-11-01T18:00:00.000Z",
  "away_team": "Miami Dolphins",
  "home_team": "Buffalo Bills",
  "market": "moneyline",
  "selection": "Miami Dolphins",
  "fair_probability_pct": 25.16,
  "fair_odds_american": 297,
  "fair_price_books": ["BetMGM", "Caesars", "DraftKings", "FanDuel", "Kalshi", "Polymarket", "Smarkets", "..."],
  "best_book": "DraftKings",
  "best_odds_american": 310,
  "best_odds_decimal": 4.1,
  "ev_pct": 3.17,
  "books_at_best_price": ["DraftKings"],
  "books_quoting": 16,
  "prices": [
    {"book": "DraftKings", "odds_american": 310, "odds_decimal": 4.1, "ev_pct": 3.17},
    {"book": "FanDuel", "odds_american": 290, "odds_decimal": 3.9, "ev_pct": -1.87}
  ],
  "scanned_at": "2026-10-27T18:05:12Z"
}
```

**Arbitrage:**

```json
{
  "row_type": "arbitrage",
  "league": "nhl",
  "market": "total",
  "line": 6.5,
  "arbitrage_profit_pct": 3.0,
  "legs": [
    {"selection": "Over 6.5", "book": "Unibet", "odds_american": 105, "stake_pct": 50.24},
    {"selection": "Under 6.5", "book": "BetRivers", "odds_american": 107, "stake_pct": 49.76}
  ]
}
```

Every row also has the game id, start time (UTC), teams and the game's Action Network page, plus the
Smarkets event link when the game was matched there. Download as JSON, CSV or Excel, or read it
through the Apify API.

### ⚙️ Input

| Parameter | Default | Description |
|---|---|---|
| `leagues` | US leagues | Which leagues to scan (soccer, UFC and tennis are opt-in). |
| `opportunities` | both | `positiveEv` and/or `arbitrage`. |
| `markets` | all | `moneyline`, `spread`, `total`. |
| `books` | all | Only suggest bets at these books, e.g. `["DraftKings", "FanDuel"]`. |
| `minEvPct` | `1` | Smallest edge to return, in %. |
| `maxEdgePct` | `20` | Hide edges and arbitrage above this % (nearly always a stale price). `null` = show all. |
| `daysAhead` | `1` | Daily leagues: also scan this many days after today. NFL/NCAAF always scan this week. |
| `startsWithinHours` | none | Only games starting within this many hours. |
| `allOutcomes` | `false` | Every outcome of every line (a full odds screen with fair prices), not just edges. |
| `minBooks` | `3` | Books needed before a line gets a fair price. |
| `devigMethod` | `multiplicative` | Or `power`, which takes more margin off long shots. |
| `includeSmarkets` | `true` | Add the Smarkets exchange. |
| `maxItems` | `50` | Max rows, best first. `null` = all. |

### 🧪 Input examples

**Tonight's +EV bets at DraftKings and FanDuel, NBA and NHL:**

```json
{ "leagues": ["nba", "nhl"], "books": ["DraftKings", "FanDuel"], "daysAhead": 0, "maxItems": null }
```

**Arbitrage only, every league, next 3 days:**

```json
{ "leagues": ["nfl", "ncaaf", "nba", "ncaab", "nhl", "mlb", "soccer", "ufc"], "opportunities": ["arbitrage"], "daysAhead": 3, "maxItems": null }
```

**A full NFL odds screen with fair prices (every outcome, edge or not):**

```json
{ "leagues": ["nfl"], "allOutcomes": true, "maxItems": null }
```

**Run it every 10 minutes** with an Apify Schedule and a webhook or integration (Slack, email,
Google Sheets) to get alerts while the edge is still there.

### 🤖 Use it from an AI assistant

Connect Claude, ChatGPT, Cursor or any MCP client to Apify's MCP server and this Actor becomes a tool
it can call. Questions that map straight onto the input:

- "Any +EV NBA bets at FanDuel tonight?" → `leagues: ["nba"]`, `books: ["FanDuel"]`, `daysAhead: 0`
- "Is there an arbitrage on Sunday's NFL games?" → `leagues: ["nfl"]`, `opportunities: ["arbitrage"]`
- "What's the fair price of the Bills moneyline?" → `leagues: ["nfl"]`, `allOutcomes: true`, `markets: ["moneyline"]`

The status message of every run sums it up ("97 games, 358 lines scanned: 8 arbitrage, 24 +EV of
1%+"), and rows come back best first.

### ℹ️ Good to know

- **Prices move fast.** Rows carry `scanned_at`; check the price at the book before betting. Big
  edges are often a book that hasn't moved its line yet and will within minutes.
- **Games that have started are skipped.** In-play prices lag and would show false edges.
- **Exchange fees are included:** Kalshi's trading fee and Smarkets' 2% commission are taken off
  before the edge is calculated. Polymarket prices are midpoints, so they shape the fair price but are
  never suggested as a bet.
- **Smarkets** covers US leagues and soccer; NHL spreads and totals and UFC/tennis use the
  sportsbooks only. Smarkets prices are in the order book, so stakes may be limited
  (`stake_available_gbp`).
- **Asian quarter lines** (-0.25, 1.75) are skipped.
- **Pinnacle isn't included.** The fair price is the consensus of all the other books and exchanges.
- This is data, not betting advice. Bet only where it's legal for you.

### ❓ FAQ

**What's the difference between +EV and arbitrage?** Arbitrage wins on every outcome, but is rare
and small (0.5–3%). A +EV bet can lose; it's a price better than the fair odds, so over many bets it
should win more than it loses.

**Why didn't a bet I expected show up?** It needs `minBooks` books pricing the same line, an edge
above `minEvPct` and below `maxEdgePct`, and (with `books`) a price at one of your books.

**How often should I run it?** Lines move most in the last hours before a game. Every 5–15 minutes
with `startsWithinHours` set is a good start.

**Can I see the raw odds of every sportsbook too?** Yes: `allOutcomes: true` returns every outcome
with all books' prices in `prices`. For public betting splits, line movement and props, see the
[Action Network Odds Scraper](https://apify.com/artsiom_k/actionnetwork-scraper).

### 🔗 You might also like

- [Action Network Odds, Betting Splits & Line Movement Scraper](https://apify.com/artsiom_k/actionnetwork-scraper)
- [Sports Odds History: Opening & Closing Lines](https://apify.com/artsiom_k/sports-odds-history-scraper)
- [Kalshi & Polymarket Prediction Markets Scraper](https://apify.com/artsiom_k/prediction-markets-scraper)
- [Smarkets Betting Exchange Scraper](https://apify.com/artsiom_k/smarkets-scraper)

# Actor input Schema

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

Leagues to scan. Leave all selected for every league; out-of-season leagues return nothing. NFL and NCAA Football scan this week's games; the other leagues scan today (US Eastern), plus more days with "Days ahead".

## `opportunities` (type: `array`):

"positiveEv": bets priced better than the fair price (the consensus of every book with its margin removed). "arbitrage": a set of bets at different books that wins whatever happens.

## `markets` (type: `array`):

Full-game moneyline, spread (point spread, puck line, run line, handicap) and total (over/under). Main and alternate lines are both scanned.

## `books` (type: `array`):

Only suggest bets at these sportsbooks and exchanges (for example the ones legal in your state). Leave empty for all. The fair price always uses every book.

## `minEvPct` (type: `number`):

Only return +EV bets whose expected profit is at least this percent of the stake.

## `maxEdgePct` (type: `number`):

Edges and arbitrage profits above this are almost always a stale or wrong price, so they're left out. Clear it to see everything.

## `daysAhead` (type: `integer`):

For daily leagues (all but NFL and NCAA Football): also scan this many days after today. 0 = today only. Soccer leagues usually need 2-4 to reach the weekend.

## `startsWithinHours` (type: `number`):

Ignore games that start later than this. Lines close to kickoff are the sharpest. Empty = no limit.

## `allOutcomes` (type: `boolean`):

Return a row for every outcome of every line, with the best price, the fair price and every book's odds, edge or not. Many more rows.

## `minBooks` (type: `integer`):

A line gets a fair price only when at least this many books price all of its outcomes.

## `devigMethod` (type: `string`):

"multiplicative" scales each book's probabilities down to 100%. "power" takes more of the margin off long shots.

## `includeSmarkets` (type: `boolean`):

Add Smarkets back prices (after its 2% commission) and order-book midpoints for NFL, NCAA, NBA, WNBA, MLB, NHL and soccer games.

## `maxItems` (type: `integer`):

Return at most this many rows, best first (arbitrage, then the highest edges). Set to null for all.

## `proxyConfiguration` (type: `object`):

Not needed: the odds sources answer Apify's servers directly.

## Actor input object example

```json
{
  "leagues": [
    "nfl",
    "ncaaf",
    "nba",
    "ncaab",
    "wnba",
    "mlb",
    "nhl"
  ],
  "opportunities": [
    "positiveEv",
    "arbitrage"
  ],
  "markets": [
    "moneyline",
    "spread",
    "total"
  ],
  "minEvPct": 1,
  "maxEdgePct": 20,
  "daysAhead": 1,
  "allOutcomes": false,
  "minBooks": 3,
  "devigMethod": "multiplicative",
  "includeSmarkets": true,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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("artsiom_k/betting-ev-arbitrage-finder").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("artsiom_k/betting-ev-arbitrage-finder").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 artsiom_k/betting-ev-arbitrage-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,artsiom_k/betting-ev-arbitrage-finder"
        }
    }
}
```

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/dWcUU5qVsfgnBesxq/builds/fVvD6DLCQOhwKme8l/openapi.json
