Parlay Calculator Example - JavaScript

Build a multi (parlay) calculator that combines multiple legs and calculates total odds and payout from live Australian prices.

What you'll build

A script that:

  • Fetches live odds from multiple games
  • Allows selecting multiple legs
  • Calculates combined multi odds
  • Shows potential payout
  • Prevents legs from the same game

Perfect for: Multi calculators, bet-slip builders

Prerequisites

  • Node.js 18+
  • SockOdds API key (free)
  • Basic JavaScript

Complete code

Step 1: Setup project

mkdir multi-calc && cd multi-calc && npm init -y

Step 2: Create calculator.js

// calculator.js
const API_KEY = process.env.SOCKODDS_KEY, BASE = "https://api.sockodds.com/v2";

async function events(league) {
  const url = new URL(BASE + "/events");
  url.search = new URLSearchParams({ leagueID: league, oddsAvailable: "true", oddID: "points-home-game-ml-home", includeOpposingOdds: "true", limit: "20" });
  return (await (await fetch(url, { headers: { "x-api-key": API_KEY } })).json()).data;
}

// a leg: the best available decimal for one side of one market on one event
function bestLeg(event, oddID) {
  const odd = event.odds[oddID]; if (!odd) return null;
  const [book, q] = Object.entries(odd.byBookmaker).filter(([, q]) => q.available).sort((a, b) => b[1].decimal - a[1].decimal)[0] ?? [];
  return q ? { eventID: event.eventID, label: `${odd.marketName} @ ${book}`, decimal: q.decimal, book } : null;
}

function multi(legs, stake) {
  const eventIDs = new Set(legs.map((l) => l.eventID));
  if (eventIDs.size !== legs.length) throw new Error("Cannot multi two legs from the same game — use the SGM lanes for that");
  const decimal = legs.reduce((p, l) => p * l.decimal, 1);
  const american = decimal >= 2 ? `+${Math.round((decimal - 1) * 100)}` : `${Math.round(-100 / (decimal - 1))}`;
  return { decimal: +decimal.toFixed(2), american, payout: +(stake * decimal).toFixed(2), profit: +(stake * (decimal - 1)).toFixed(2), impliedProbability: +((1 / decimal) * 100).toFixed(1) };
}

const stake = Number(process.argv[2] || 10);
const legs = [];
for (const league of ["AFL", "NRL"]) for (const e of await events(league)) { const leg = bestLeg(e, "points-home-game-ml-home"); if (leg && legs.length < 3) legs.push(leg); }
legs.forEach((l) => console.log(`leg  ${l.decimal.toFixed(2)}  ${l.label}`));
console.log(multi(legs, stake));

Step 3: Run it

SOCKODDS_KEY=so_live_… node calculator.js 20

Expected output

leg  1.87  Head to Head — Fremantle @ sportsbet
leg  2.10  Head to Head — Canterbury Bulldogs @ tab
leg  1.65  Head to Head — Collingwood @ pointsbet
{ decimal: 6.48, american: '+548', payout: 129.6, profit: 109.6, impliedProbability: 15.4 }

How it works

1. Calculate combined odds

Multiply the legs' decimal prices.

2. Calculate payout

stake × decimal.

3. Prevent correlated legs

One leg per eventID; same-game legs are priced by the SGM lanes (betfocus__sgm_only, …).

4. Show implied probability

1 / decimal.

Enhancements

Same game multis

// use bookmakerID=betfocus__sgm_only,mintbet__sgm_only and take that lane's prices for correlated legs

Calculate true odds

// on Base: multiply legs' fair decimals (from fairOdds) to see the vig in the multi

Round robin

function combos(arr, k) { return k === 0 ? [[]] : arr.flatMap((v, i) => combos(arr.slice(i + 1), k - 1).map((c) => [v, ...c])); }

Troubleshooting

"Cannot multi two legs from the same game"

By design; use an SGM lane.

Calculated odds don't match the bookmaker

Books cap multi payouts and price SGMs on correlation.

Multi odds seem too good

A leg with available: false slipped in — the example filters them; make sure yours does.

Next steps

Combine with other examples

Learn more

Need help?FAQ · Email · Contact