How to calculate qualifying loss and ratings
A matched bet's rating is the share of the stake a back-and-lay pair gives back, and the qualifying loss formula turns that share into money: the stake times the rating over 100, minus the stake.
Both come from four numbers: the back price, the lay price, your stake and your exchange commission.
const qualifyingLoss = S * ((B * (1 - c)) / (L - c) - 1);
The feed supplies the two prices. Each matched outcome arrives with bookmaker back offers and exchange lay offers from Betfair, Smarkets and Matchbook, and each lay offer states in available how much money waits at its price. The plain one-line rating is in oddsmatcher data, explained. This post puts commission inside it and covers free bets.
Why the feed leaves the numbers out
A qualifying loss changes with the stake and the commission rate. Your users pick the stake, and each of them pays their own rate on each exchange they use, so store the rate per user and per exchange. A figure worked out before the data reached you would be right for one imaginary user and wrong for everyone else.
The bet type changes the formula too. A qualifying bet and a free bet whose stake is not returned need different lay stakes from the same two prices. Sending the prices and leaving the sums to you means one board serves both, at any rate your users set. An oddsmatcher that bakes one commission rate into its numbers shows the wrong figure to every user on a different rate.
The pair you start from
Here is one outcome from a standard board, trimmed to a single market. It carries two back offers, best price first, and two lay offers, lowest price first. available is the money waiting at that lay price.
{
"event_id": "or_evt_917dd44bce05",
"commence_time": "2026-09-20T14:00:00Z",
"home_team": "Arsenal",
"away_team": "Chelsea",
"markets": [{
"key": "h2h",
"outcomes": [{
"name": "Arsenal",
"back": [
{ "bookmaker": "william_hill", "price": 2.9, "link": null },
{ "bookmaker": "paddy_power", "price": 2.8, "link": null }
],
"lay": [
{ "exchange": "smarkets", "price": 2.96, "available": 6, "link": null },
{ "exchange": "matchbook", "price": 3.0, "available": 175, "link": null }
]
}]
}]
}Nothing in it scores the pair. Every back offer can be crossed with every lay offer, so this outcome alone gives four candidate matches. The rest of this post takes the best back price, 2.9, against the 3.0 lay, then shows why the lower lay listed first is the wrong pick at this stake.
Rating with commission inside it
The plain rating is back over lay, times 100. It ignores commission, so it overstates what you keep, and it can rank pairs at very different prices in the wrong order. Put the commission rate c into it and the rating becomes the exact percentage of your stake the qualifying bet returns:
const plainRating = (B / L) * 100; const rating = ((B * (1 - c)) / (L - c)) * 100; // 2.9 back, 3.0 lay, 2% commission // plainRating = 96.7 // rating = 95.4
At zero commission the two formulas agree. At 2% the gap between them is 1.3 points, and it grows with the rate. When two tools show different ratings for the same prices, check commission first.
Qualifying loss from the rating
The lay stake that balances both outcomes is the back stake times the back price, divided by the lay price minus the commission. At that lay stake the loss is the same whether the bookmaker bet wins or the lay wins, and it falls straight out of the rating:
const layStake = (S * B) / (L - c); const qualifyingLoss = S * (rating / 100 - 1); // S = 10, B = 2.9, L = 3.0, c = 0.02 // layStake = 9.73 // liability = layStake * (L - 1) = 19.46 // qualifyingLoss = -0.46 either way
Check it both ways. If Arsenal win, the bookmaker pays 19.00 profit and the lay loses its 19.46 liability, which nets -0.46. If they don't, the back stake of 10 is lost and the lay wins 9.73 less 2% commission, or 9.54, which nets -0.46 again. The liability is the figure your user needs in their exchange balance, so show it beside the loss.
Is a qualifying loss of 2 to 5% normal?
Yes. On a back price around 2.5 to 3 at about 2% commission, a lay price a few hundredths to a tenth above the back gives a qualifying loss of roughly 2 to 5% of the stake. The loss share is 100 minus the rating, so at a given back price it depends on only two things: how far the lay price sits above it, and the commission.
| Lay price against a 2.9 back | 0% commission | 2% commission | 5% commission |
|---|---|---|---|
| 2.9 | 0% | 1.3% | 3.3% |
| 2.96 | 2.0% | 3.3% | 5.3% |
| 3.0 | 3.3% | 4.6% | 6.6% |
| 3.1 | 6.5% | 7.7% | 9.7% |
Qualifying loss as a share of the stake, from the rating formula above
Even with the back and lay prices level on a 2.9 price, commission alone costs 1.3% of the stake at 2%. The stake changes none of these shares: it only scales the money figure, so a share column reads the same for every user, whatever their stake.
A better price you cannot fill
The first lay offer, 2.96, comes out higher: 96.7 at 2% commission, against 95.4 for the 3.0 lay. It also needs a lay stake of 9.86, and only 6 is waiting at that price. The rest would go unmatched or fill at a worse price, and the rating you sorted by would no longer be true.
So filter before you sort. Drop any pair whose available is below the lay stake the user's own stake needs, then rank what is left. Why lay liquidity matters covers the depth side in more detail.
Free bets change the lay stake
A free bet where the stake is not returned only pays the winnings, so the back side is worth B - 1 per unit instead of B. Replace B with B - 1 in the lay stake and the rating, and the rating becomes the conversion, the share of the free bet's face value you keep:
const layStake = (S * (B - 1)) / (L - c); const retained = layStake * (1 - c); const conversion = (retained / S) * 100; // S = 10 free bet, B = 2.9, L = 3.0, c = 0.02 // layStake = 6.38 // retained = 6.25 either way // conversion = 62.5%
Because the stake is gone, the - 1 matters less at longer prices, which is why free-bet conversion usually favours longer odds than a qualifying bet does. A free bet that returns its stake uses the qualifying formula unchanged, and what you keep is the lay stake times one minus the commission.
The oddsmatcher widget does this for you
If you would rather show the numbers than build the screen, the oddsmatcher widget takes the same paired prices and displays a plain rating and the money result for each pair. To build your own board, how to build an oddsmatcher walks through crossing offers and sorting them, and the matched board filters guide shows how to narrow a reply to the bookmakers and exchanges your users hold accounts with. The pairs themselves come from the matched feed.
Showing those numbers to your users, through the widget or a board of your own, runs on Enterprise. Work the sums on your own Free key first.
Related posts
- What is an oddsmatcher?An oddsmatcher ranks back prices against exchange lay prices. The data it needs, and the sums it runs.
- How to build an oddsmatcherAn oddsmatcher is paired price data plus the product on top. Which half deserves your engineering time.
- Why lay liquidity matters in a matched odds feedA lay price with no money behind it cannot be taken. How to check a pair against your stake.
18+ · OddsRelay supplies odds data only and takes no bets. Please gamble responsibly.