> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sx.bet/llms.txt
> Use this file to discover all available pages before exploring further.

# Odds Rounding

> How to validate and round odds to the SX Bet odds ladder.

## The odds ladder

SX Bet enforces an **odds ladder** to prevent diming (posting odds in tiny increments to gain an unfair edge). Your `percentageOdds` value must land exactly on one of the allowed steps, or your order will be rejected.

The ladder works in intervals of the implied probability. The current step size is **0.125%**, meaning valid implied odds are:

```
50.000%, 50.125%, 50.250%, 50.375%, 50.500%, ...
```

An offer of **50.25%** is valid. An offer of **50.20%** is not.

<Warning>Orders with odds not on the ladder will be rejected and will not be posted.</Warning>

## Getting the current step size

The step size is available from [`GET /metadata`](/api-reference/get-metadata). It returns a number from 0 to 1000:

| Metadata value | Step size |
| -------------- | --------- |
| 10             | 0.010%    |
| 25             | 0.025%    |
| 125            | 0.125%    |

The step size in raw `percentageOdds` units is:

```
stepInRaw = metadataValue * 10^15
```

For the current default of 125: `125 * 10^15 = 1.25 * 10^17`

## Checking if your odds are valid

To check if a `percentageOdds` value falls on the ladder, take the modulus with the step size and check if it equals 0:

<CodeGroup>
  ```python Python theme={null}
  ODDS_PRECISION = 10 ** 20
  ODDS_LADDER_STEP_SIZE = 125  # from GET /metadata

  def is_odds_valid(percentage_odds: int) -> bool:
      step = ODDS_LADDER_STEP_SIZE * (10 ** 15)
      return percentage_odds % step == 0

  # Valid: 50.250% implied = 50250000000000000000
  print(is_odds_valid(50250000000000000000))  # True

  # Invalid: 50.200% implied = 50200000000000000000
  print(is_odds_valid(50200000000000000000))  # False
  ```

  ```javascript JavaScript theme={null}
  const ODDS_PRECISION = 10n ** 20n;
  const ODDS_LADDER_STEP_SIZE = 125n; // from GET /metadata

  function isOddsValid(percentageOdds) {
    const step = ODDS_LADDER_STEP_SIZE * 10n ** 15n;
    return BigInt(percentageOdds) % step === 0n;
  }

  // Valid: 50.250% implied
  console.log(isOddsValid("50250000000000000000")); // true

  // Invalid: 50.200% implied
  console.log(isOddsValid("50200000000000000000")); // false
  ```
</CodeGroup>

## Rounding to the nearest valid step

If your calculated odds don't land on the ladder, round down to the nearest valid step before submitting:

<CodeGroup>
  ```python Python theme={null}
  def round_odds_down(percentage_odds: int) -> int:
      """Round odds down to the nearest valid step on the ladder."""
      step = ODDS_LADDER_STEP_SIZE * (10 ** 15)
      return (percentage_odds // step) * step

  # 50.200% → 50.125%
  raw = 50200000000000000000
  rounded = round_odds_down(raw)
  print(f"{raw / ODDS_PRECISION:.3%} → {rounded / ODDS_PRECISION:.3%}")
  # 50.200% → 50.125%

  # 67.800% → 67.750%
  raw = 67800000000000000000
  rounded = round_odds_down(raw)
  print(f"{raw / ODDS_PRECISION:.3%} → {rounded / ODDS_PRECISION:.3%}")
  # 67.800% → 67.750%
  ```

  ```javascript JavaScript theme={null}
  function roundOddsDown(percentageOdds) {
    const step = ODDS_LADDER_STEP_SIZE * 10n ** 15n;
    const odds = BigInt(percentageOdds);
    return (odds / step) * step;
  }

  // 50.200% → 50.125%
  console.log(roundOddsDown("50200000000000000000").toString());
  // "50125000000000000000"

  // 67.800% → 67.750%
  console.log(roundOddsDown("67800000000000000000").toString());
  // "67750000000000000000"
  ```
</CodeGroup>

## Full example: implied probability to valid `percentageOdds`

A common workflow: you have a fair probability (e.g., from your model), add margin, and need to convert it to a valid `percentageOdds` value.

<CodeGroup>
  ```python Python theme={null}
  def implied_to_valid_odds(implied: float) -> int:
      """Convert an implied probability to the nearest valid percentageOdds (rounded down)."""
      raw = int(implied * ODDS_PRECISION)
      return round_odds_down(raw)

  # Your model says 54.3% implied, you want to post at that price
  odds = implied_to_valid_odds(0.543)
  print(f"percentageOdds: {odds}")
  # 54250000000000000000 (54.250%)

  print(f"Implied: {odds / ODDS_PRECISION:.3%}")
  # 54.250%

  print(f"Valid: {is_odds_valid(odds)}")
  # True
  ```

  ```javascript JavaScript theme={null}
  function impliedToValidOdds(implied) {
    const raw = BigInt(Math.round(implied * 1e20));
    return roundOddsDown(raw);
  }

  // Your model says 54.3% implied, you want to post at that price
  const odds = impliedToValidOdds(0.543);
  console.log(`percentageOdds: ${odds}`);
  // 54250000000000000000 (54.250%)

  console.log(`Valid: ${isOddsValid(odds)}`);
  // true
  ```
</CodeGroup>

<Tip>Always round **down** when posting maker orders. Rounding up would give worse odds for you. If you need to round to the nearest step in either direction, compare the distance to the step above and below.</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Odds Formats →" icon="calculator" href="/developers/odds-formats">
    Converting between implied, American, and decimal odds.
  </Card>

  <Card title="Unit Conversions →" icon="arrows-rotate" href="/developers/unit-conversions">
    Full reference for odds and token conversions.
  </Card>

  <Card title="Post New Order →" icon="paper-plane" href="/api-reference/post-new-order">
    API reference for submitting orders.
  </Card>

  <Card title="GET /metadata →" icon="circle-info" href="/api-reference/get-metadata">
    Retrieve the current odds ladder step size.
  </Card>
</CardGroup>
