Public
Edited
Apr 18
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
categoryDiscoveryMarkets = fetch(`https://api.data.adj.news/api/markets?${categoryDiscoveryParams.toString()}`, {
headers: {
Authorization: `Bearer ${API_KEY}`
}
})
.then(response => response.json())
.then(json => json.data ?? [])

Insert cell
parsedCategoryLists = categoryDiscoveryMarkets.map(m => {
try {
const parsed = JSON.parse(m.category || "[]");
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
});

Insert cell
uniqueCategorySet = new Set(parsedCategoryLists.flat().map(c => c.trim()).filter(Boolean))
Insert cell
uniqueCategoryList = Array.from(uniqueCategorySet).sort()
Insert cell
uniqueCategoryList
Insert cell
Insert cell
rviCategoryParsed = cleanedMarkets.map(m => {
try {
const parsed = JSON.parse(m.category || "[]");
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
});

Insert cell
Insert cell
rviMainCategory = cleanedMarkets.map((m, i) => {
const parsed = rviCategoryParsed[i];
return parsed.length > 0 ? parsed[0] : inferRviCategory(m.question);
});

Insert cell
rviCategoryMap = ({
"Artificial Intelligence": "Tech Disruption",
"Technology": "Tech Disruption",
"Cryptocurrencies": "Financial Instability",
"Economy & Business": "Financial Instability",
"Elections": "Governance Risk",
"Politics": "Governance Risk",
"Law": "Governance Risk",
"Environment & Climate": "Climate Risk",
"Health & Pandemics": "Health/Bio Risk",
"Geopolitics": "Geopolitics",
"Nuclear Technology & Risks": "Geopolitics",
"Natural Sciences": "Other",
"Social Sciences": "Other",
"Space": "Other",
"Sports & Entertainment": "Info/Culture Chaos",
"Uncategorized": "Other",

// Fallbacks (from inferred category)
"Geopolitics": "Geopolitics",
"Governance Risk": "Governance Risk",
"Tech Disruption": "Tech Disruption",
"Climate Risk": "Climate Risk",
"Health/Bio Risk": "Health/Bio Risk",
"Financial Instability": "Financial Instability",
"Info/Culture Chaos": "Info/Culture Chaos",
"Sports & Entertainment": "Info/Culture Chaos"
});

Insert cell
rviCategoryFinal = rviMainCategory.map(c => rviCategoryMap[c] ?? "Other");
Insert cell
cleanedMarketsWithRvi = cleanedMarkets.map((m, i) => ({
...m,
main_category: rviMainCategory[i],
rvi_category: rviCategoryFinal[i]
}));

Insert cell
RVICategTable = Inputs.table(cleanedMarketsWithRvi, {
columns: [
"platform",
"question",
"probability",
"volume",
"main_category",
"rvi_category"
]
})

Insert cell
Insert cell
impactBaseScore = ({
"Geopolitics": 0.8,
"Governance Risk": 0.7,
"Financial Instability": 0.7,
"Tech Disruption": 0.6,
"Climate Risk": 0.6,
"Health/Bio Risk": 0.6,
"Info/Culture Chaos": 0.4,
"Other": 0.3
})
Insert cell
impactScopeKeywords = ({
"global": 0.15,
"un": 0.15,
"humanity": 0.15,
"us": 0.10,
"u.s.": 0.10,
"usa": 0.10,
"china": 0.10,
"eu": 0.10,
"congress": 0.10,
"fed": 0.10,
"meta": 0.05,
"texas": 0.05,
"california": 0.05,
"google": 0.05
})
Insert cell
impactPhrasing10 = ["collapse", "invade", "nuclear", "emergency", "shutdown", "ban", "break up", "default"];
Insert cell
impactPhrasing05 = ["step down", "resign", "investigate", "fine", "indict", "force", "split"];
Insert cell
Insert cell
rviWithImpact = cleanedMarketsWithRvi.map(row => ({
...row,
impact_score: computeImpactScore(row)
}));

Insert cell
viewof impactTable = Inputs.table(rviWithImpact, {
columns: ["platform", "question", "rvi_category", "impact_score"]
})

Insert cell
Insert cell
scoreTimeHorizon = endDateStr => {
try {
const today = new Date();
const endDate = new Date(endDateStr);
const deltaDays = Math.floor((endDate - today) / (1000 * 60 * 60 * 24)); // ms → days

if (deltaDays <= 30) return 1.0;
if (deltaDays <= 90) return 0.8;
if (deltaDays <= 180) return 0.6;
if (deltaDays <= 365) return 0.4;
return 0.2;
} catch (err) {
return 0.2; // Fallback conservative default
}
}

Insert cell
rviWithTime = rviWithImpact.map(row => ({
...row,
time_horizon_score: scoreTimeHorizon(row.end_date)
}))

Insert cell
viewof timeTable = Inputs.table(rviWithTime, {
columns: ["question", "end_date", "time_horizon_score"]
})

Insert cell
# Probability Volatility
Insert cell
volatilityMarketIds = cleanedMarketsWithRvi.map(m => m.market_id);
Insert cell
fetchVolatilityData = async (marketIds) => {
const baseURL = "https://api.data.adj.news/api/analytics/market-performance";
const start = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
const end = new Date().toISOString().slice(0, 10);

const params = new URLSearchParams({
markets: marketIds.join(","),
metric: "probability",
interval: "day",
start_date: start,
end_date: end
});

const response = await fetch(`${baseURL}?${params}`, {
headers: {
Authorization: `Bearer ${API_KEY}`
}
});

return response.json();
};

Insert cell
volatilityRaw = await fetchVolatilityData(volatilityMarketIds);
Insert cell
computeStdDev = (values) => {
if (values.length < 2) return 0;
const mean = values.reduce((a, b) => a + b, 0) / values.length;
const variance = values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / (values.length - 1);
return Math.sqrt(variance);
}

Insert cell
scoreVolatility = (std) => {
const stdPct = std * 100;
if (stdPct >= 12) return 1.0;
if (stdPct >= 8) return 0.85;
if (stdPct >= 4) return 0.7;
return 0.5;
}

Insert cell
volatilityScores = (() => {
const grouped = {};

for (const entry of volatilityRaw.data?.metrics ?? []) {
const id = entry.market_id;
if (!grouped[id]) grouped[id] = [];
grouped[id].push(entry.value);
}

const result = {};
for (const [id, values] of Object.entries(grouped)) {
const std = computeStdDev(values);
result[id] = scoreVolatility(std);
}

return result;
})();

Insert cell
rviWithVolatility = cleanedMarketsWithRvi.map(row => ({
...row,
volatility_score: volatilityScores[row.market_id] ?? 0.5 // fallback if missing
}));

Insert cell
viewof volatilityTable = Inputs.table(rviWithVolatility, {
columns: [
"platform", "question", "rvi_category", "volatility_score"
]
});

Insert cell
volumes = cleanedMarketsWithRvi.map(m => m.volume ?? 0);
Insert cell
// Pair with market_id
volumeRanked = cleanedMarketsWithRvi.map((m, i) => ({
market_id: m.market_id,
volume: volumes[i]
}));

Insert cell
// Sort by volume
volumeRanked.sort((a, b) => a.volume - b.volume);
Insert cell
volumePercentiles = (() => {
const ranked = [...cleanedMarketsWithRvi]
.map(m => ({ market_id: m.market_id, volume: m.volume ?? 0 }))
.sort((a, b) => a.volume - b.volume);

const percentiles = {};

ranked.forEach((entry, index) => {
percentiles[entry.market_id] = (index + 1) / ranked.length;
});

return percentiles;
})();

Insert cell
scoreLiquidity = (pct) => {
if (pct >= 0.9) return 1.0;
if (pct >= 0.75) return 0.8;
if (pct >= 0.5) return 0.6;
return 0.5;
};

Insert cell
rviWithLiquidity = rviWithVolatility.map(row => ({
...row,
liquidity_score: scoreLiquidity(volumePercentiles[row.market_id] ?? 0)
}));

Insert cell
viewof liquidityTable = Inputs.table(rviWithLiquidity, {
columns: [
"platform",
"question",
"rvi_category",
"volume",
"liquidity_score"
]
})

Insert cell
Insert cell
Insert cell
platformDiversityMap = (() => {
const map = {};

for (const row of cleanedMarketsWithRvi) {
const norm = normalizeQuestion(row.question);
map[norm] ??= new Set();
map[norm].add(row.platform);
}

const result = {};
for (const [norm, platforms] of Object.entries(map)) {
result[norm] = platforms.size;
}

return result;
})();

Insert cell
scorePlatformDiversity = (count) => {
if (count >= 3) return 1.2;
if (count === 2) return 1.1;
return 1.0;
};

Insert cell
rviWithPlatformDiversity = rviWithLiquidity.map(row => {
const norm = normalizeQuestion(row.question);
const count = platformDiversityMap[norm] ?? 1;
return {
...row,
platform_diversity_score: scorePlatformDiversity(count)
};
});

Insert cell
viewof platformDiversityTable = Inputs.table(rviWithPlatformDiversity, {
columns: [
"platform", "question", "rvi_category",
"platform_diversity_score"
]
})

Insert cell
Insert cell
rviScored = rviWithImpact.map(row => {
const matchTime = rviWithTime.find(t => t.market_id === row.market_id);
const matchVol = rviWithVolatility.find(v => v.market_id === row.market_id);
const matchLiq = rviWithLiquidity.find(l => l.market_id === row.market_id);
const matchPlat = rviWithPlatformDiversity.find(p => p.market_id === row.market_id);

return {
...row,
time_horizon_score: matchTime?.time_horizon_score,
volatility_score: matchVol?.volatility_score,
liquidity_score: matchLiq?.liquidity_score,
platform_diversity_score: matchPlat?.platform_diversity_score
};
});

Insert cell
rviWithFinalScore = rviScored.map(row => {
const {
impact_score,
time_horizon_score,
volatility_score,
liquidity_score,
platform_diversity_score,
probability,
rvi_category: existingCategory
} = row;

const scores = [
impact_score,
time_horizon_score,
volatility_score,
liquidity_score,
platform_diversity_score
];

const hasAll = scores.every(x => typeof x === "number");

const composite_weight = hasAll
? Math.pow(scores.reduce((a, b) => a * b, 1), 1 / scores.length)
: null;

const rvi_contribution =
composite_weight !== null && typeof probability === "number"
? composite_weight * probability
: null;

return {
...row,
composite_weight: composite_weight !== null ? Number(composite_weight.toFixed(3)) : null,
rvi_contribution: rvi_contribution !== null ? Number(rvi_contribution.toFixed(2)) : null,
rvi_category: existingCategory // ← don't overwrite if already present
};
});

Insert cell
viewof rviFinalTable = Inputs.table(rviWithFinalScore, {
columns: [
"platform", "question", "rvi_category",
"impact_score", "time_horizon_score", "volatility_score",
"liquidity_score", "platform_diversity_score",
"composite_weight", "probability", "rvi_contribution"
]
});

Insert cell
maxContributionPerMarket = 100;
Insert cell
// Group by category
groupedByCategory = rviWithFinalScore.reduce((acc, row) => {
const cat = row.rvi_category || "Other";
if (!acc[cat]) acc[cat] = [];
acc[cat].push(row);
return acc;
}, {});

Insert cell
// Calculate per-category RVIs
categoryRVIs = Object.fromEntries(
Object.entries(groupedByCategory).map(([category, rows]) => {
const valid = rows.filter(r => typeof r.rvi_contribution === "number");
const sum = valid.reduce((acc, r) => acc + r.rvi_contribution, 0);
const normalized = (sum / (valid.length * maxContributionPerMarket)) * 100;
return [category, Number(normalized.toFixed(2))];
})
);

Insert cell
// Market-weighted total RVI
totalMarkets = rviWithFinalScore.length;
Insert cell

RealityVolatilityIndex = Object.entries(categoryRVIs).reduce(
(sum, [cat, rvi]) => {
const weight = groupedByCategory[cat].length / totalMarkets;
return sum + rvi * weight;
},
0
).toFixed(2);
Insert cell
md`# Reality Volatility Index
## **RVI Score:** ${RealityVolatilityIndex}`
Insert cell

md`### RVI Breakdown by Category

${Object.entries(categoryRVIs).map(([cat, score]) =>
`- **${cat}** → ${score}`
).join("\n")}`

Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more