Correlated Markets
Find markets connected to another market by generated real-world outcome signals
Correlated Markets starts from one prediction market and returns events that may become more relevant if that market resolves a certain way. Use it for related-market rails, portfolio ideas, hedge discovery, and thematic search that goes beyond title matching.
All endpoints are app-tier: send x-app-id, no user token. Your app's venue and category
exclusions still apply. Closed and resolved markets are left out unless you pass
includeResolved: true. Free-text matching (q on resolve, and the title fallback of a text
query) always searches open markets only; resolve a closed or resolved market by venue +
externalId, slug or conditionId instead.
Endpoint map
| Endpoint | Use when | SDK method |
|---|---|---|
POST /correlated-markets/resolve | You have a venue id, external id, slug, condition id, or text and want candidates in one call. | resolveCorrelatedMarkets |
GET /correlated-markets/cascade/{venueMarketId} | You already have an sufwan-local-test venueMarketId and want expand or hedge candidates. | getCorrelatedMarketCascade |
GET /correlated-markets/connections/{venueMarketId} | You want related events for a market, without choosing a side or mode. | none, use REST |
GET /correlated-markets/{venueMarketId} | You want the generated Yes/No signals for a market. | getMarketCorrelatedSignals |
POST /correlated-markets/query | You want free-text search across generated signals. | queryCorrelatedMarkets |
Expand vs hedge
mode: "expand"returns Yes-side events that become more attractive if your thesis is right.mode: "hedge"returns Yes-side events that become more attractive if your thesis is wrong. Hedge results leave out the expand results for the same market and side.
Resolve a market
Use resolve when your app stores venue-native identifiers. It resolves the market, checks
whether signals exist, and returns a paginated cascade.
import { createAggClient } from "@agg-build/sdk";
const client = createAggClient({ baseUrl: "https://api.t.sufwankhalid.com", appId: "your-app-id" });
const result = await client.resolveCorrelatedMarkets({
venue: "polymarket",
externalId: "123456",
side: "yes",
mode: "expand",
limit: 10,
});
if ("status" in result && result.status === "processing") {
// Signals are still being generated. Send the same request again later.
} else {
console.table(result.data);
}externalId on resolve is not externalIdentifier and not the webhook partner id. 202 means still generating ({ status: "processing" }).
If signals do not exist yet, generation starts and the response says so:
{
"market": { "id": "vm_abc123", "question": "Will oil close above $100 this year?" },
"status": "processing",
"message": "Correlated market generation queued"
}Send the same request again after generation finishes.
Use an sufwan-local-test market id directly
If you already have a venueMarket.id from GET /venue-events or GET /venue-markets, call the
cascade endpoint. This path does not resolve identifiers.
const cascade = await client.getCorrelatedMarketCascade({
venueMarketId: "vm_abc123",
side: "yes",
mode: "hedge",
limit: 20,
});
if (cascade.nextCursor) {
const nextPage = await client.getCorrelatedMarketCascade({
venueMarketId: "vm_abc123",
side: "yes",
mode: "hedge",
limit: 20,
cursor: cascade.nextCursor,
});
}limit is capped at 100. Page with the returned nextCursor.
Result shape
Each result is an event-level candidate. Use venueEventId to fetch the event or link to it.
{
"venueEventId": "ve_oil_supply",
"eventTitle": "OPEC production cut",
"eventStatus": "open",
"eventStartDate": "2026-06-18T00:00:00.000Z",
"eventEndDate": "2026-07-01T00:00:00.000Z",
"score": 0.72,
"action": "BUY YES",
"reason": "Energy markets tighten as supply risk rises",
"reasonDomain": "energy"
}Inspect generated signals
Each market has a set of generated Yes/No signals: short statements about which real-world states become more or less likely if the market resolves a given way. They drive the cascade and connection endpoints. Fetch them to render "why this is related" copy.
const batch = await client.getMarketCorrelatedSignals("vm_abc123");
for (const signal of batch.signals) {
console.log(signal.side, signal.direction, signal.domain, signal.text);
}Connections without side or mode
connections returns related events for a market without a side or mode. Use it for a single
"Related markets" rail on an event page.
curl -H "x-app-id: YOUR_APP_ID" \
"https://api.t.sufwankhalid.com/correlated-markets/connections/vm_abc123?limit=10"Page with nextCursor. Pass includeResolved=true to include resolved and closed markets.
Search by theme
Use query search when the user starts from a theme instead of a market. Results carry market and
event status and dates, so you can keep resolved markets out of tradeable recommendations. Set
direction to more_likely or less_likely to filter, or balanced: true to mix both in one
page.
const { results } = await client.queryCorrelatedMarkets({
text: "oil supply shock raises inflation risk",
limit: 10,
balanced: true,
});
for (const match of results) {
console.log(match.marketQuestion, match.marketStatus, match.eventEndDate, match.score);
console.log(match.matchSource, match.matchedSignal.direction, match.matchedSignal.text);
}