Why Risk Scoring Matters for Market Makers
Market making in prediction markets is fundamentally different from traditional exchange market making. In equities or futures, settlement is mechanical — you don't worry about whether the exchange will correctly process your trade. In prediction markets, the resolution itself is a risk factor. And that risk is not uniform across markets: a cleanly worded Kalshi contract with a government data source resolves very differently from a Polymarket contract that hinges on a subjective committee vote. If you are quoting both, you need a systematic way to tell them apart.
The Market Maker's Resolution Problem
As a prediction market maker, you're quoting two-sided markets. Your edge comes from the spread. But your risk isn't just directional — it includes:
- Resolution risk — the market might not resolve as expected due to ambiguous rules, subjective language, or oracle failures
- Delay risk — capital locked during disputes can't be redeployed, and the opportunity cost compounds
- Basis risk — if you're hedging across platforms, different resolution criteria create mismatches that can blow up a hedged book
Without systematic risk scoring, you're pricing these risks by feel. That works for a handful of markets. It doesn't scale to hundreds. Our methodology page walks through the full scoring algorithm, but the rest of this post focuses on what it means for your P&L.
The Cost of Ignoring Resolution Risk
To make this concrete, consider two market makers both quoting a Polymarket contract at a $0.65 mid price with $100,000 in notional exposure. The contract has a risk score of 62 (HIGH tier), a dispute probability of 0.24, and a p99 delay of 340 hours.
Maker A: No risk adjustment. They quote a flat 200 bps spread across all markets. Their expected revenue on this position is $2,000 from the spread. But when a dispute is filed, their capital is locked for 14 days. At a 12% annual cost of capital, that lockup costs them roughly $460. The dispute itself resolves against the original oracle reading, and Maker A's YES position is zeroed — a $65,000 loss on the notional. Factoring in the dispute probability, the expected loss from resolution risk alone is roughly $15,600 (0.24 times $65,000), dwarfing their $2,000 spread revenue.
Maker B: Risk-adjusted quoting with SettleRisk. The pricing engine returns a fair_spread_bps of 850 and a resolution_risk_premium_bps of 34. Maker B quotes at 850 bps, earning $8,500 on the position. More importantly, their position limit policy caps HIGH-tier markets at $50,000 notional, so their maximum downside in a dispute scenario is halved. And when the risk score later ticks up to 76 (CRITICAL), a webhook fires, and their system pulls quotes entirely — avoiding the dispute loss altogether.
The difference between Maker A and Maker B is not skill or intuition. It is infrastructure. Maker B has a system that converts resolution risk into numbers and acts on them automatically.
How Risk Scores Improve Quoting
Dynamic Spread Adjustment
Instead of quoting a fixed spread across all markets, use the risk score to dynamically adjust:
import { SettleRiskClient } from "settlerisk";
const client = new SettleRiskClient({
keyId: "vx_...",
secret: "..."
});
const pricing = await client.price({
platform: "polymarket",
platform_market_id: "0xabc",
mid_price: 0.65,
position_side: "YES",
position_notional_usd: 50000,
annual_capital_cost_apr: 0.12
});
// Use fair_spread_bps as your minimum spread
const minSpread = pricing.fair_spread_bps;
// If do_not_quote is true, skip this market entirely
if (pricing.do_not_quote) {
console.log("Resolution risk too high — pulling quotes");
}
Here is the same flow in Python for teams running Python-based trading systems:
from settlerisk import SettleRiskClient
client = SettleRiskClient(key_id="vx_...", secret="...")
pricing = client.price(
platform="polymarket",
platform_market_id="0xabc",
mid_price=0.65,
position_side="YES",
position_notional_usd=50_000,
annual_capital_cost_apr=0.12,
)
min_spread = pricing.fair_spread_bps
if pricing.do_not_quote:
print("Resolution risk too high — pulling quotes")
The fair_spread_bps output tells you the minimum spread that compensates for resolution risk. Quote tighter than this and you're giving away edge. The pricing engine computes this from the dispute probability, expected lockup duration, and your cost of capital — all derived deterministically from the risk score. See our full pricing documentation for the exact formulas.
Position Limits by Risk Tier
Set maximum position sizes based on risk tier:
| Risk Tier | Score Range | Max Position | Rationale | |-----------|-----------|-------------|-----------| | LOW | 0-19 | $500K | Clean resolution, minimal risk | | MEDIUM | 20-49 | $200K | Some ambiguity, moderate risk | | HIGH | 50-74 | $50K | Significant risk, limit exposure | | CRITICAL | 75-100 | $0 | Do not quote |
This prevents concentration in markets where resolution risk could lock up disproportionate capital. The tier boundaries are not arbitrary — they correspond to inflection points in dispute probability. A CRITICAL market (score 75+) has a heuristic dispute probability of at least 0.24 plus a 0.06 CRITICAL surcharge, and on Polymarket that jumps another 0.05 for the on-chain oracle complexity. At those levels, the expected cost of a dispute typically exceeds any realistic spread.
Driver-Level Insights for Risk Management
The 15 risk drivers aren't just a score breakdown — they're actionable intelligence. Each driver carries a strength, confidence, and evidence spans pointing to the exact rule text that triggered it. Our case studies include real examples of each driver in action.
AMBIGUOUS_WORDING
When this driver fires with high strength, expect resolution to require committee review. Budget extra time and wider spreads.
TEMPORAL_AMBIGUITY
This driver fires when time cutoffs or deadlines in the market rules are underspecified — for example, a market that says "by end of Q2" without specifying a timezone or whether that means market close, midnight UTC, or midnight in the issuer's local time. TEMPORAL_AMBIGUITY carries a base weight of 18 points, making it one of the highest-impact drivers. For market makers, temporal ambiguity is particularly dangerous when you are hedging across platforms: if Polymarket and Kalshi interpret "end of Q2" as different timestamps, your hedge can become a naked position. When this driver appears with confidence above 0.7, consider either pulling quotes within 48 hours of the ambiguous deadline or reducing position size to your HIGH-tier limit regardless of the overall score.
SUBJECTIVE_JUDGMENT
This driver detects rule language that requires discretionary interpretation — words like "significant," "material," "substantial," or "in our opinion." It carries a base weight of 24 points, the highest in the entire driver taxonomy. The reason is simple: subjective resolution criteria make the outcome a function of who is on the resolution committee, not just what happened in the world. For a market maker, this means your fair-value model is incomplete by construction — you are implicitly taking a position on committee composition and judgment. When SUBJECTIVE_JUDGMENT fires at high strength, the spread required to compensate for resolution uncertainty is usually wide enough that retail flow dries up, making it hard to earn back even the risk-adjusted spread. Our recommendation: treat high-confidence SUBJECTIVE_JUDGMENT as equivalent to a one-tier upgrade in risk — if the market is MEDIUM, manage it as HIGH.
SINGLE_ORACLE_DEPENDENCY
If the market depends on one data source, check that source's uptime history. A 99.5% uptime API still goes down 1.8 days per year.
RETROACTIVE_CHANGE
This is the worst driver for market makers. If rules can change retroactively, your entire inventory could be repriced overnight. Consider pulling quotes entirely when this driver appears with high confidence.
Automated Risk-Adjusted Quoting Pipeline
A production market-making system should not require human intervention to react to changing risk scores. Here is the architecture we recommend:
-
Fetch scores on a schedule. Use
batchRiskScoresevery 15 minutes to score your entire active universe. The batch endpoint handles up to 1,000 markets per call, so even a large book fits in a single request. -
Adjust spreads. For each market, call the pricing endpoint to get
fair_spread_bpsanddo_not_quote. Feed these into your quoting engine as minimum-spread constraints. -
Set position limits. Map the risk tier to your position limit table. If a market's tier changes, adjust the limit immediately — do not wait for the next rebalance cycle.
-
Monitor via webhooks. Register for
score.tier_changedandrules.changedevents. When a tier change fires, your system should re-price and potentially unwind positions that now exceed the new tier's limit. -
Stream for latency-sensitive paths. If you are quoting within seconds of market events, use the gRPC
StreamAlertsendpoint to get push notifications instead of polling. This is available on Fund tier and above.
import settlerisk
import time
client = settlerisk.SettleRiskClient(key_id="vx_...", secret="...")
# Step 1: Batch score the entire book
markets = [
{"platform": p.platform, "platform_market_id": p.market_id}
for p in active_positions
]
scores = client.batch_risk_scores(markets)
# Step 2 & 3: Adjust spreads and position limits
TIER_LIMITS = {"LOW": 500_000, "MEDIUM": 200_000, "HIGH": 50_000, "CRITICAL": 0}
for score in scores.results:
pricing = client.price(
platform=score.platform,
platform_market_id=score.platform_market_id,
mid_price=get_mid(score.platform_market_id),
position_side="YES",
position_notional_usd=get_notional(score.platform_market_id),
)
update_min_spread(score.platform_market_id, pricing.fair_spread_bps)
update_position_limit(score.platform_market_id, TIER_LIMITS[score.risk_tier])
if pricing.do_not_quote:
pull_quotes(score.platform_market_id)
// Step 4: Register webhooks for real-time tier changes
await client.createWebhook(
"https://your-system.com/webhooks/settlerisk",
["score.tier_changed", "rules.changed"]
);
This pipeline runs autonomously. The only human touchpoint is reviewing the weekly summary of tier changes and pulled-quote events — which you can export from the webhook delivery log.
Backtesting with Historical Risk Scores
One of the less obvious benefits of SettleRisk's architecture is that every risk score snapshot is version-stamped with four identifiers: heuristics_version, stat_model_version, llm_extractor_version, and driver_taxonomy_version. This means that given the same inputs and version stamps, the scoring engine produces identical output — it is fully deterministic.
For backtesting, this property is essential. You can replay historical market conditions through the scoring engine and get the exact same scores that were live at the time, without worrying about model drift or silent retraining. This lets you answer questions like:
- "If I had used a 50 bps minimum spread on all HIGH-tier markets in Q4, what would my P&L have looked like?"
- "How many CRITICAL-tier markets did I quote through, and what was the realized loss?"
- "Did the TEMPORAL_AMBIGUITY driver predict actual resolution delays better than my manual flags?"
To run a backtest, pull historical score snapshots from the API (available on Pro tier and above), join them against your fill data, and compute the counterfactual P&L with risk-adjusted spreads. Teams that do this consistently find that systematic risk scoring eliminates the worst 5-10% of trades by P&L — the ones where a dispute or delay turned a small spread profit into a large capital loss.
Real-World Integration Pattern
Here is the full workflow for a market maker going from zero to production with SettleRisk:
Day 1: Score your existing book. Export your active positions, call batchRiskScores, and tag each position with its risk tier. Most teams discover that 5-15% of their book is HIGH or CRITICAL — markets they were quoting with the same spread as everything else.
Day 2: Set up the pricing engine. For each market, call the pricing endpoint with your actual cost of capital and position size. Compare fair_spread_bps against your current quoted spread. The gap is the resolution risk you have been giving away for free.
Day 3: Integrate webhooks. Register score.tier_changed and rules.changed events. Wire your webhook handler to your quoting engine so that tier changes trigger automatic spread adjustments. Test by using the webhook replay endpoint to simulate a tier change.
Day 4: Automate position limits. Add tier-based position limits to your risk management system. Set CRITICAL to zero. This is the single highest-impact change — it removes the tail risk of quoting markets that are almost certain to face disputes.
Day 5 and beyond: Backtest and tune. Pull historical scores, run your backtest, and calibrate your tier-to-limit mapping and spread multipliers. Revisit monthly as the driver taxonomy evolves.
This workflow is described in more detail in our integration case studies, and you can walk through it interactively in our live demo.
Batch Scoring for Portfolio Monitoring
If you're making markets across 100+ contracts, batch scoring lets you monitor your entire portfolio efficiently:
const markets = activePositions.map(p => ({
platform: p.platform,
platform_market_id: p.marketId
}));
// Score up to 1,000 markets in one call
const results = await client.batchRiskScores(markets);
Set up webhooks to get notified when risk tiers change:
await client.createWebhook(
"https://your-system.com/webhooks/settlerisk",
["score.tier_changed", "rules.changed"]
);
When a market's tier changes from MEDIUM to HIGH, your system can automatically widen spreads or reduce position limits.
Real-Time Monitoring with gRPC
For latency-sensitive trading systems, SettleRisk offers gRPC streaming:
- StreamAlerts delivers real-time notifications when scores change
- Binary protocol minimizes parsing overhead
- Full parity with the REST API
This is available on Fund tier and above.
Measuring the Impact
Market makers who integrate risk scoring typically see:
- Reduced tail losses — avoiding CRITICAL markets prevents the worst capital lockup events
- Improved Sharpe ratio — risk-adjusted spreads mean you're not giving away resolution risk for free
- Better capital utilization — knowing expected delays lets you optimize capital allocation across your book instead of reserving flat buffers
- Faster response to rule changes — webhook-driven automation reacts in seconds, not hours
Our case studies include anonymized before-and-after results from three market-making teams, including one that reduced dispute-related losses by 74% in the first quarter after integration.
Getting Started
Resolution risk is systematic and quantifiable. There is no reason to price it by feel, and the cost of getting it wrong compounds across every market you quote.
- Sign up for a free account — 10 RPM, no credit card required
- Score your active markets with
batchRiskScoresto see where your exposure is - Use
fair_spread_bpsas your minimum spread on every market - Set up webhooks for tier change notifications so your system reacts automatically
- Upgrade to Pro ($249/mo) for webhooks, the pricing engine, and historical score access
If you want a walkthrough tailored to your trading stack, book a demo — we will score your live book and show you exactly where you are underpricing resolution risk.