Markets
Prices
Two numbers, and the whole product is organised around not confusing them. The reference probability is where the market is. The execution price is what a trade costs.
referenceProbability and executionPrice
| referenceProbability | executionPrice | |
|---|---|---|
| What it is | Predicta’s normalised view of where the market sits. Usually the midpoint of the book. | A side of a real book. What the trade actually crosses. |
| Who has offered it | Nobody. A midpoint is a statistic, not an offer. | Somebody. A resting order sits there. |
| Where it appears | probability, yesCents, noCents on the catalogue | execution.buyYes / execution.buyNo on the catalogue, executionPrice on a quote |
| Use it for | Showing a player “63% chance”. | Charging a player, and computing a payout. |
They differ enough to matter
Measured across 22,586 open contracts in this catalogue, the ask sits a median 1.5¢ above the reference, 31¢ at the 90th percentile and 59¢ at the 99th. Roughly one contract in four differs by more than 10¢. The worst observed case displays 0.5¢ and executes at 99¢.
A ticket that renders the reference shows a number the player will not be charged, and a payout computed from it is wrong in the player's favour every time.
priceBasis
Every quote and every catalogue row says which of the two you are holding. Read it: a reference-priced quote is an estimate wearing a price's clothes, and you are entitled to know which one you have.
| Value | Where | Meaning |
|---|---|---|
book | Quote | A real side of a real order book. A buy crossed the ask. |
reference | Quote | No usable two-way price upstream, so this is the normalised probability. An estimate. |
midpoint | Catalogue | Reference derived from bid and ask. |
last | Catalogue | Reference derived from the last trade. |
source | Catalogue | Reference taken from a probability the source published directly. |
none | Catalogue | No price could be derived at all. |
How a side is priced
- Buying YES crosses the YES ask. Selling YES hits the YES bid.
- Where a source publishes a NO book directly, that book is used. Where it does not, NO is mirrored from YES: a NO ask is
1 − (YES bid), which is arithmetically exact for a binary contract. - A crossed book, bid at or above ask, is discarded on both sides and the quote falls back to the reference. Bad data that looks like a gift is exactly what a router would otherwise pick every time.
- A spread wider than the configured maximum (0.2 by default) is treated as no usable two-way price: an illiquid book's midpoint is noise, not a probability.
- 0 and 1 are settled, not tradeable. Neither is ever published as a price.
When there is no executable price
On a catalogue row, execution.buyYes and execution.buyNo are null whenever the book publishes no usable side. That null is a value, not a gap in the response.
"price": { "yesCents": 63.4, "noCents": 37.2, ... }, // reference — a midpoint
"execution": { "buyYes": 0.651, "buyNo": null, "basis": "book" }Never fall back to the reference
A null means show no price and disable the control. It does not mean “use yesCents instead”. The reference is a midpoint nobody has offered; substituting it renders a number the player cannot trade at, and the substitution is invisible to them.
One side may be executable while the other is not. Price and enable each side independently: a tradeable YES does not make NO tradeable.
execution.basisisbookwhen at least one side came off a real two-way price, andreferencewhen neither did. Read the per-side value for what to display, and the basis for how much to trust the row.- A quote is the authority, not the catalogue. The catalogue tells you whether to offer a control; the quote tells you what the trade costs. Never charge from a catalogue price.
- An outcome with no executable side can still be shown as a market with a probability. What it cannot be shown with is a price or a buy button.
Precision, and why sub-cent prices are real
Catalogue prices are decimals between 0 and 1. The cent figures, yesCents and noCents, are rounded to the tenth of a cent, which is the finest tick any upstream actually uses. 63.4 is a legitimate value and so is 0.3.
Do not round to whole cents
Thousands of open contracts in this catalogue trade below one cent. Rounding a price of 0.4¢ to zero turns a long-shot contract into a free one, and a payout computed from a zero price is a division by zero or an infinite position, depending on which line runs first.
- Carry prices at the precision you receive them, all the way to display. Round for the player's eye only, at the last step, and never before a calculation.
- Contract counts are returned rounded to four decimal places for transport. The stored quote keeps full precision and is what the fill is checked against: so do not recompute contracts from a rounded figure and expect a match.
- Money amounts are cents-exact: the fee rounds up to the cent and the payout rounds down. Prices are not money, and rounding them the same way is the error this section exists to prevent.
- Never store a price as an integer number of cents. It is the same bug as rounding, held for longer.
Freshness
Prices carry an age, and the age decides what may be traded. Thresholds are per feed, because a streamed price 60 seconds old means the socket broke while a polled price 60 seconds old is simply normal.
| Level | Streamed | Polled | Effect |
|---|---|---|---|
| fresh | ≤ 30s | ≤ 90s | Trades at any size. |
| aging | ≤ 90s | ≤ 300s | Trades at any size. |
| stale | ≤ 300s | ≤ 900s | Stake capped ($25 by default). Over the cap is 422 stake_exceeds_stale_limit. |
| suspended | > 300s | > 900s | No quote at any size: 409 price_stale. |
- A missing timestamp is treated as
suspended, not fresh. An unknown age is precisely the case where the price could be hours old. - The gate runs on the server, at quote time and again at order time. A quote that was fresh when issued can go stale inside its own 30-second window.
- Every quote returns its own verdict in
freshness. Render that rather than recomputing your own: the two disagreeing is the bug the field exists to prevent.
"freshness": { "level": "fresh", "ageSeconds": 5, "feed": "websocket" }Note
Most of the catalogue is polled rather than streamed: the live socket budget is finite and goes to the contracts with demand behind them. A cold contract is legitimately minutes behind for most of every cycle, which is why the polled bands are wider rather than the streamed bands being loose.
Fees and edge
Two independent levers, deliberately not folded together. An edge is hidden in the price; a fee is an explicit charge a player can see.
| Lever | Default | How it works |
|---|---|---|
| Platform fee | 120 bps (1.2%) | Deducted from the stake before contracts are bought. A $50 stake wagers $49.40. |
| House edge | 0 bps | Applied on top of the reference probability, widening YES and NO. Zero by default: Predicta’s model is the transaction layer, not taking the other side. |
stake 50.00
− fee 0.60 (120 bps, rounded up to the cent)
= wagered 49.40
÷ price 0.72 (executionPrice)
= contracts 68.6111
× $1.00 each
= payout 68.61 (rounded down to the cent)
− stake 50.00
= profit 18.61 (measured against the FULL stake)- The fee rounds up to the cent; the payout rounds down. Neither direction accrues a fractional cent to the player.
- Profit is measured against the full stake, because that is what left the player's balance.
venueFeeisnull, not0. No upstream publishes a readable taker fee and writing zero would assert a fact Predicta does not have.

