An interactive, browser-only risk management dashboard for a sample Nifty 50 equity portfolio (₹, INR) — dark, finance-terminal aesthetic, built with vanilla HTML/CSS/JS and Chart.js. No backend, no build step, no dependencies beyond the Chart.js CDN — it's designed to run as-is on GitHub Pages.
Live demo: https://nnd1106.github.io/risk-command-center/
Value-at-Risk computed two ways from ~2 years of simulated daily portfolio returns:
- Historical simulation — empirical percentile of realized returns, scaled by √horizon.
- Parametric (variance-covariance) — normal-distribution assumption using sample mean/σ and the inverse normal CDF.
- Expected Shortfall (CVaR) — mean loss beyond the VaR cutoff.
Confidence level (90–99.5%), time horizon (1–60 trading days), and portfolio size (₹50L–₹5Cr) are all adjustable sliders, with a live histogram of the return distribution and marker lines showing where each method's cutoff falls.
Forward-simulates the portfolio using correlated Geometric Brownian Motion across all six positions (same correlation matrix as the historical data), with adjustable path count (200–3,000), horizon (21–252 trading days), and a volatility multiplier. Renders the full spaghetti plot of simulated paths plus 5th/median/95th percentile bands and a terminal-value distribution histogram.
Three scenario sliders — market crash (equity shock), interest-rate shock (bps), and volatility spike (multiplier) — reprice the portfolio instantaneously using illustrative per-stock sensitivities (crash beta, rate sensitivity). Includes one-click presets (2008-style GFC, rate shock, vol spike).
The sample book itself: six NSE (Nifty 50) large-caps — Reliance Industries, TCS, HDFC Bank, Infosys, ICICI Bank, ITC — spanning energy/conglomerate, IT, banking, and FMCG, their weights/returns/vols, a correlation matrix heatmap, a trailing 2-year value chart, and an optional live price panel (see below).
All historical returns driving the VaR / Monte Carlo / stress-test math are synthetic: a seeded pseudo-random generator (mulberry32 + Box-Muller + Cholesky-decomposed correlation) produces reproducible, correlated daily returns entirely in the browser. Nothing here is real market history, and nothing here is investment advice.
The Positions table can show real, delayed last-traded prices for the six stocks via Twelve Data's free tier — free email signup, no credit card, no billing anywhere in this flow. This is opt-in: paste a free API key into the "Live market data" card on the Portfolio tab, and it activates.
Why this is opt-in rather than on by default: there's no way to get real Indian stock quotes into a pure-static, no-backend page with zero setup. I verified this directly before building anything:
- Yahoo Finance's public (no-signup) endpoint sends no CORS headers, so browsers block it outright, and it's already aggressively rate-limited for shared/cloud IPs (it returned
429 Too Many Requestson the very first test). - Public CORS proxies that some projects use to route around that (
corsproxy.io,allorigins.win) are not dependable — one now requires a paid plan for this kind of use, the other was returning522(origin unreachable) when tested. - Twelve Data's free tier is the one option that actually supports being called directly from a browser (
Access-Control-Allow-Origin: *) with no card required — but, like effectively every legitimate quote API, it does require a free account to get a key.
Rate-limit safety: one API call fetches all 6 symbols at once. A fetch only happens on page load or an explicit "Refresh now" click, and even then only if the cached data is more than 5 minutes old — there is no background polling timer. Worst-case realistic usage stays roughly two orders of magnitude under the free tier's 800 requests/day, 8/minute caps. The key is stored only in your browser's local storage.
Scope note: live prices are purely an informational overlay on the Positions table. They never feed into the VaR / Monte Carlo / stress-test calculations, which stay on the synthetic history by design — blending a handful of live quotes into a model calibrated on synthetic returns would look more "real" without actually being more correct.
No build step — just serve the directory statically, e.g.:
python -m http.server 8080
# then open http://localhost:8080Pure HTML/CSS/JS + Chart.js (via CDN). No frameworks, no bundler, no backend.