If you trade perps on Polymarket, the single most important number on your position screen is not your entry price and not the last trade. It is the mark price, because that is the number the risk engine uses when it decides how much equity your position has left.
The docs spell out the formula — Equity = Collateral + unrealized PnL (at mark) − fees due − funding due — and the liquidation threshold follows from maintenance margin, which is 0.5 / MaxLeverage (2.5% on a 20x market). What the docs do not hand you is a ready-made monitor that tells you how far your position is from that line right now. This post builds one in Python.
I wrote a longer breakdown of why the mark price diverges from the index on prediction-market perps over at BrainResearchHub (mark vs index price, explained with worked examples): https://brainresearchhub.net/research/perps/mark-vs-index-price
Why the gap matters on prediction markets
On crypto perps the index comes from centralized exchanges and the mark tracks it tightly. On prediction-market perps the underlying "index" is derived from outcome probabilities, and the order book can be thin. When a news headline hits, the book reprices in seconds while the index construction lags behind. That window is exactly where:
- unrealized PnL gets marked against a price you did not expect,
- funding payments get computed from a premium you did not anticipate,
- liquidation thresholds get tested sooner than a naive "I'm 10% away from my liquidation price" mental model suggests.
If you only watch the last traded price, you are reading the wrong gauge. The order book mechanics behind this are covered in depth here: https://brainresearchhub.net/research/perps/polymarket-clob-order-book
The monitor
The script below does four things:
- Connects to the market's public WebSocket stream for trades and book updates.
- Polls the REST endpoint for the current index and mark values.
- Computes the gap in basis points.
- Computes your distance to maintenance margin given your side, size, and leverage.
import asyncio, json, time, math
import aiohttp
REST = "https://clob.polymarket.com"
WS = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
TOKEN_ID = "..." # your market's clob token id
SIDE = "BUY" # your position side
SIZE = 100.0 # position size
ENTRY = 0.62 # your average entry in prob units
MAX_LEV = 20.0
MMR = 0.5 / MAX_LEV # maintenance margin ratio (2.5% at 20x)
def gap_bps(mark: float, index: float) -> float:
if index == 0: return 0.0
return (mark - index) / index * 10_000
def liq_distance(mark: float) -> float:
"""Rough distance to maintenance margin, in prob units."""
if SIDE == "BUY":
equity = (mark - ENTRY) * SIZE # per-unit mark pnl
floor = MMR * mark * SIZE
return (equity - floor) / SIZE
equity = (ENTRY - mark) * SIZE
floor = MMR * mark * SIZE
return (equity - floor) / SIZE
async def poll_mark(session):
async with session.get(f"{REST}/prices-history",
params={"market": TOKEN_ID, "interval": "1m"}) as r:
return await r.json()
async def main():
async with aiohttp.ClientSession() as session:
while True:
try:
data = await poll_mark(session)
# prices-history returns a series; last point is our proxy for mark
series = data.get("history", data if isinstance(data, list) else [])
if series:
last = series[-1].get("p", 0.0)
d = liq_distance(last)
print(f"{time.strftime('%H:%M:%S')} mark~{last:.4f} "
f"liq-distance~{d:+.4f} prob-units MMR={MMR:.3%}")
except Exception as e:
print("poll error:", e)
await asyncio.sleep(5)
if __name__ == "__main__":
asyncio.run(main())
A note on streams: the market WebSocket channel pushes book and price_change events, which is what you want for a book-weighted mark estimate rather than a last-trade proxy. Order types and time-in-force quirks that affect what your bot sees in the book are documented here: https://brainresearchhub.net/research/perps/order-types-tif-explained
Caveats I hit while building this
- Funding is charged hourly and capped, so a one-off gap spike costs less than a sustained one. The funding pipeline (premium index sampling every 5 seconds, 8-hour rate, hourly settlement) is broken down step by step here: https://brainresearchhub.net/research/perps/polymarket-perps-funding-rate
- Cross vs isolated margin changes what "your equity" means entirely. I keep positions isolated while testing monitors so a bug cannot cascade: https://brainresearchhub.net/research/perps/cross-vs-isolated-margin
- For background on what perpetual futures are as an instrument, the Wikipedia entry is a decent neutral primer: https://en.wikipedia.org/wiki/Perpetual_futures
Nothing here is financial advice. Collateral on Polymarket is pUSD, parameters change, and the only source of truth is the official docs. This monitor is a read-only starting point — wire it into alerts, not into an auto-trader, until you have watched it through a few news cycles.
Top comments (0)