Building fair real-time odds for CS2 stream predictions

Published: (March 19, 2026 at 03:46 PM EDT)
5 min read
Source: Dev.to

Source: Dev.to

Stream Delay & Odds – A Recap

In my last post I wrote about stream delay and why realtime on Twitch is secretly a timeline problem.

This time: odds.

number of kills prediction

I am building elo.market, a live‑prediction system for CS2 streams. Viewers bet virtual elo on things like round winners, bomb plants, and clutches.


The Naïve Idea

Votes come in → odds move.

Sounds simple, but:

  • If odds move too slowly, the market feels fake.
  • If odds move too fast, a smart whale can make the whole thing feel rigged.

The Problem In One Line

small early vote → juicy odd appears → whale grabs it → market feels broken

Visually:

+------------------+     +--------------------+     +------------------+     +------------------+
| Small early vote | --> | Big price appears  | --> | Whale takes it   | --> | Everyone else    |
| from normal user|     | on the other side  |     | before it settles|     | thinks: "lol ok" |
+------------------+     +--------------------+     +------------------+     +------------------+

That is technically a dynamic market, but it’s terrible product design.


The First Version Was Too Naïve

My initial approach:

  1. Start from a base probability.
  2. Add a seed so the first bet doesn’t nuke the market.
  3. Recalculate odds from the current pool.

Conceptual formula

adjustedProb = (amountOnOutcome + baseProb * seed) / (totalPool + seed)

What Went Wrong

  1. Not all markets start 50/50.
    A round_winner market isn’t even if one side is broke and the other has rifles.
    → I began feeding real‑game context into the base probabilities (loss streaks, score momentum, streamer economy). This made the opening price feel smarter, but the whale problem persisted.

The Whale Problem

The obvious model is amount‑based: more money on one side → odds shift harder.
That works until a single large bet overpowers the market.

First Attempt to Fix It

Blend two signals:

  • How much money was bet.
  • How many people bet on that side.

I used average bet size in the formula, which unintentionally gave whales double influence (both amount and “crowd consensus”).


The Fix That Actually Mattered

I stopped using average bet size for voter influence and switched to a fixed vote unit.

New logic

effectiveAmount = (1 - voterWeight) * rawAmount \
                 + voterWeight * voterCount * FIXED_VOTE_UNIT

Result:

  • Whales can still move odds because size matters.
  • They can’t masquerade as “the crowd” simply by betting huge amounts.

The market feels far less abusable.


The Next Problem: Scaling the Seed

Fixed seeds break at different economy sizes.
Streamer A averages 50 elo bets, Streamer B averages 1 000 elo bets → the same seed behaves very differently.

Solution: make the seed dynamic

dynamicMinSeed = seasonAvgBet * 50
effectiveSeed   = max(dynamicMinSeed, totalPool * seedMultiplier)

Now early odds are hard to snipe on both small and large channels.


Not Every Market Should Behave the Same

A bomb‑plant prediction and a map‑wide prediction need different personalities.
I introduced templates:

TemplateUse case
dynamicMarkets that can move a lot
balancedStandard round predictions
stableShort live windows
anchoredLonger markets that should respect the opening line

One size does not fit all, and the templates give each market the right feel.


Delay Came Back Again

Twitch’s stream delay re‑appeared here.

If I delayed both PREDICTION_CREATED and ODDS_UPDATE equally, viewers saw stale odds.

Final model

  1. Delay the prediction event.
  2. Send odds updates immediately.
  3. Buffer them on the client until the prediction card becomes visible.

When the card appears, viewers see current odds instead of ancient history.


Fairness Needed One More Layer

Edge case: a user clicks at price X, but by the time the vote reaches the backend, odds have moved against them.

Slippage protection – if the odds move too far, reject the vote and let the UI ask the user to accept the new number.

This turned out to matter almost as much as the formula itself. Fair pricing isn’t just math; it’s also about users feeling they aren’t being tricked.


Where I Landed

The current system is essentially:

game state priors
      +
adaptive seed
      +
voter consensus
      +
slippage protection

All together they give a live‑prediction market that feels responsive, fair, and resilient to whales and Twitch’s inherent delay.

Protection + Delay‑aware delivery = Dynamic odds that still feel fair

Enter fullscreen mode

Exit fullscreen mode
  • Smarter base probabilities from real game state
  • Adaptive seed so early votes do not create nonsense
  • Voter weighting so one whale does not dominate instantly
  • Fixed vote units so big bets do not fake consensus
  • Different templates for different market types
  • Slippage protection for bad fills
  • Delay‑aware delivery so live odds still look live

The funny part is that dynamic odds sounded like a tiny feature when I started.

In reality, it turned into a product‑trust problem.

  • If the odds feel fake, people stop caring.
  • If the odds feel exploitable, people stop trusting.

The goal was not “perfect market making.”

The goal was simpler:

Make odds move enough to feel alive, but not enough to become a farming strategy for whales.

If you have built low‑liquidity markets, game economies, or live pricing systems, I would love to hear what trade‑offs you made.

0 views
Back to Blog

Related posts

Read more »