sifting/io
Forex & Crypto
5 min readSiftingIO Team

Detecting a stale or manipulated quote with a cross-venue consensus price

How to use a robust cross-venue fair price as a validation layer to flag when one venue is printing a stale, thin, or manipulated quote.

Detecting a stale or manipulated quote with a cross-venue consensus price

How do you know the price your execution venue is showing you is real? On a deep, liquid instrument the answer is usually yes. On a thin pair, an off-hours print, or an on-chain pool with shallow reserves, a single venue's number can drift, freeze, or get pushed around without anyone flagging it. The quote still arrives. It just isn't trustworthy.

The practical fix is to stop treating any one venue as ground truth and instead compare its print against a reference value aggregated from many venues. SiftingIO publishes exactly one fair price per instrument, formed as a volume-and-reputation-weighted robust median across multiple independent venues. Because a median has a 50% breakdown point, a majority of those venues would have to err in the same direction before the consensus itself is wrong. That makes it a useful second opinion: a reference of record you can hold your own execution feed up against.

What the fair price actually is#

It helps to be precise about what you're getting, because the bounds matter. The fair price is a synthetic reference value, not an official exchange-of-record print and not executable depth. You don't route orders against it. You use it to research, to model, to power dashboards and alerts, and to sanity-check the number a venue is quoting you.

Under the hood the value comes out of a four-stage pipeline. Incoming ticks are validated (stale feeds and hard outliers are dropped), scored for deviation using Median Absolute Deviation and modified z-scores, weighted by a per-venue reputation that decays over time, and then aggregated into a single robust median weighted by real traded volume times that reputation. One useful consequence: a feed that keeps sending messages but never changes its price while the market moves gets caught as a frozen feed and quarantined, rather than silently dragging the consensus.

The part that makes this usable for validation is that quality is exposed on every tick, not hidden. Each value carries three timestamps (source, ingest, publish), a cross-venue consensus value, and an explicit quality flag that reads either Normal or Degraded. Degraded means the pipeline fell back to the safest available source because it couldn't form a confident consensus. That flag is the signal you build your check around.

Pulling the reference value#

Start with a live snapshot. The /v1/last/quote/{venue}/{symbol} endpoint returns the best bid and ask for a symbol, authenticated with the X-API-Key header.

curl -H "X-API-Key: $SIFTING_KEY" \
     "https://api.sifting.io/v1/last/quote/crypto/BTCUSD"

The response carries the quote plus the quality metadata. A simple Python check compares a venue's mid against the consensus and decides whether to trust it:

import os, requests

HEADERS = {"X-API-Key": os.environ["SIFTING_KEY"]}
BASE = "https://api.sifting.io/v1"

def reference_quote(symbol, venue="crypto"):
    r = requests.get(f"{BASE}/last/quote/{venue}/{symbol}", headers=HEADERS)
    r.raise_for_status()
    return r.json()

def trust_check(symbol, venue_mid, tol_bps=25):
    q = reference_quote(symbol)
    consensus = q["consensus"]
    flag = q["quality"]
    drift_bps = abs(venue_mid - consensus) / consensus * 10_000
    ok = flag == "Normal" and drift_bps <= tol_bps
    return {"trust": ok, "drift_bps": round(drift_bps, 1), "quality": flag}

print(trust_check("BTCUSD", venue_mid=64_010.0))

If the consensus quality flag is Degraded, you don't have a strong reference for that instant, so you widen tolerance or hold off rather than acting on a noisy comparison. If the flag is Normal and your venue's mid sits 80 basis points off the consensus, that gap is worth investigating before you treat the venue's print as fact.

For a continuously updating check, subscribe over the WebSocket stream instead of polling. Connect with the key as a query parameter, then subscribe to the product you care about:

wss://stream.sifting.io/ws/v1?key=$SIFTING_KEY
{"op":"subscribe","product":"cex","symbols":["BTCUSD","ETHUSD"]}

The server emits the last cached value first, then live tick frames. Each tick carries the price, bid and ask fields, and a millisecond timestamp in t, so a long-running monitor can keep a rolling consensus in memory and alarm the moment a watched venue diverges past your threshold. The fair-price update cadence is tier-dependent (1 Hz on the free tier up to 10 Hz on the higher tier), so size your alert windows to the cadence you're actually subscribed to. That cadence is a refresh rate for the reference value, not an execution latency figure.

Common pitfalls#

The error you're most likely to hit on a live snapshot is a 503 with stale_snapshot. This is not a transport failure. It means the freshest value the pipeline has is older than the freshness threshold, and the body hands you last_t and server_now so you can compute exactly how stale. Treat it as a real signal: during a thin window or a venue outage, a stale reference is the system telling you it won't vouch for the number, which is the honest answer. Retry with backoff rather than hammering it.

Don't confuse quality: "Degraded" with an error. The request succeeded and you got a value. Degraded simply tells you the consensus fell back to the safest source because venues disagreed or too many were quarantined. A validation layer that ignores the flag and trusts a Degraded value as if it were Normal defeats the entire point of the cross-check.

Finally, watch the boundary on what robustness buys you. The median survives a minority of bad feeds, not a majority. No median- or mean-based estimator survives a coordinated error across most venues, so don't write your monitor as if the consensus is guaranteed correct. It's a strong second opinion, not an oracle. And remember the 99.9% figure on the higher tiers is an uptime SLA, not an accuracy claim; the data's trustworthiness comes from the filtering and consensus described above, not from a percentage.

Used this way, the fair price becomes a reference of record sitting above your execution feeds: a normalized, multi-venue number you can cross-check any single venue's print against, across equities, FX, crypto, commodities, and on-chain pools, all under one credential and one schema.

Read the docs

Tagsfair-priceconsensusmarket-datawebsocketdata-qualityvalidationcryptoapi
All postsLast updated June 13, 2026
Keep reading

Related posts