maxkru92 commited on
Commit
a5af339
Β·
verified Β·
1 Parent(s): fe34879

feat: SPX crash risk monitor

Browse files
Files changed (1) hide show
  1. spx-crash-risk-monitor.html +901 -0
spx-crash-risk-monitor.html ADDED
@@ -0,0 +1,901 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SPX Directional Index β€” Crash Risk Monitor | Krupp Capital</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
8
+ <style>
9
+ :root {
10
+ --bg: #07090f; --bg2: #0d1117; --border: #1e2a38;
11
+ --blue: #3b7bff; --red: #ef4444; --green: #22c55e;
12
+ --amber: #f59e0b; --text: #e2e8f0; --muted: #64748b; --subtle: #334155;
13
+ }
14
+ * { box-sizing: border-box; margin: 0; padding: 0; }
15
+ body { background: var(--bg); color: var(--text); font-family: 'SF Mono','Fira Code',monospace; font-size: 12px; min-height: 100vh; }
16
+
17
+ .header { display:flex; align-items:center; justify-content:space-between; padding:10px 18px; background:var(--bg2); border-bottom:1px solid var(--border); }
18
+ .header-left { display:flex; align-items:center; gap:14px; }
19
+ .logo-badge { background:var(--blue); color:#fff; font-size:9px; font-weight:700; letter-spacing:.08em; padding:3px 7px; border-radius:3px; }
20
+ .header-title { font-size:14px; font-weight:600; letter-spacing:.05em; }
21
+ .header-sub { font-size:10px; color:var(--muted); }
22
+ .live-badge { display:flex; align-items:center; gap:5px; font-size:10px; color:var(--green); }
23
+ .live-dot { width:6px; height:6px; border-radius:50%; background:var(--green); animation:pulse 2s infinite; }
24
+ @keyframes pulse { 0%,100%{opacity:1}50%{opacity:.4} }
25
+
26
+ .metric-strip { display:flex; border-bottom:1px solid var(--border); background:var(--bg2); overflow-x:auto; }
27
+ .metric-item { flex:1; min-width:110px; padding:8px 14px; border-right:1px solid var(--border); }
28
+ .metric-item:last-child { border-right:none; }
29
+ .metric-label { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; margin-bottom:3px; }
30
+ .metric-val { font-size:14px; font-weight:700; }
31
+ .metric-sub { font-size:9px; color:var(--muted); margin-top:1px; }
32
+ .pos { color:var(--blue); } .neg { color:var(--red); } .warn { color:var(--amber); }
33
+
34
+ .tab-bar { display:flex; border-bottom:1px solid var(--border); background:var(--bg2); padding:0 18px; }
35
+ .tab-btn { padding:10px 20px; font-size:11px; font-weight:600; letter-spacing:.06em; color:var(--muted); cursor:pointer; border-bottom:2px solid transparent; background:none; border-top:none; border-left:none; border-right:none; transition:all .2s; }
36
+ .tab-btn:hover { color:var(--text); }
37
+ .tab-btn.active { color:var(--blue); border-bottom-color:var(--blue); }
38
+ .tab-content { display:none; padding:16px 18px; }
39
+ .tab-content.active { display:block; }
40
+
41
+ .two-col { display:grid; grid-template-columns:1fr 320px; gap:14px; }
42
+ .three-col { display:grid; grid-template-columns:1fr 1fr 1fr; gap:14px; }
43
+ .panel { background:var(--bg2); border:1px solid var(--border); border-radius:4px; padding:14px; }
44
+ .panel-title { font-size:10px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.1em; margin-bottom:10px; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:4px; }
45
+ .pbadge { font-size:9px; padding:2px 6px; border-radius:3px; }
46
+ .b-blue { background:rgba(59,123,255,.15); color:var(--blue); }
47
+ .b-amber { background:rgba(245,158,11,.15); color:var(--amber); }
48
+
49
+ #heatmapCanvas { display:block; }
50
+ #overlayCanvas { position:absolute; top:0; left:0; cursor:crosshair; }
51
+ .hm-wrap { position:relative; }
52
+ .hm-outer { padding-left:44px; position:relative; }
53
+ .x-axis { display:flex; justify-content:space-between; padding:4px 0 0; font-size:9px; color:var(--muted); }
54
+ .y-axis { position:absolute; left:-42px; top:0; height:100%; display:flex; flex-direction:column; justify-content:space-between; font-size:9px; color:var(--muted); text-align:right; pointer-events:none; }
55
+ .legend-bar { height:10px; border-radius:2px; margin:6px 0 2px; background:linear-gradient(to right,#7f1d1d,#ef4444,#f97316,#fbbf24,#f1f5f9,#93c5fd,#3b7bff,#1e3a6e,#0a1628); }
56
+ .legend-labels { display:flex; justify-content:space-between; font-size:9px; color:var(--muted); }
57
+
58
+ table { width:100%; border-collapse:collapse; font-size:11px; }
59
+ th { text-align:left; color:var(--muted); font-size:9px; text-transform:uppercase; letter-spacing:.08em; padding:3px 6px; border-bottom:1px solid var(--border); }
60
+ td { padding:5px 6px; border-bottom:1px solid rgba(30,42,56,.6); }
61
+ tr:last-child td { border-bottom:none; }
62
+ tr:hover td { background:rgba(59,123,255,.04); }
63
+
64
+ .chart-box { height:200px; position:relative; }
65
+ .chart-box-lg { height:260px; position:relative; }
66
+
67
+ .risk-meter { height:8px; border-radius:4px; background:linear-gradient(to right,var(--green),#84cc16,var(--amber),#f97316,var(--red)); position:relative; margin:8px 0 4px; }
68
+ .risk-needle { position:absolute; top:-4px; width:2px; height:16px; background:#fff; border-radius:1px; transform:translateX(-50%); box-shadow:0 0 4px rgba(255,255,255,.6); }
69
+ .risk-labels { display:flex; justify-content:space-between; font-size:9px; color:var(--muted); }
70
+
71
+ .row { display:flex; gap:14px; margin-bottom:14px; }
72
+ .col-half { flex:1; min-width:0; }
73
+ .mb { margin-bottom:14px; }
74
+
75
+ .fc-grid { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:14px; }
76
+ .sc-card { padding:12px; border-radius:4px; }
77
+ .sc-row { display:flex; justify-content:space-between; padding:3px 0; border-bottom:1px solid rgba(255,255,255,.04); font-size:11px; }
78
+ .sc-row:last-child { border-bottom:none; }
79
+ .sc-title { font-size:11px; font-weight:700; margin-bottom:7px; }
80
+
81
+ #hmTooltip { position:fixed; background:rgba(7,9,15,.97); border:1px solid var(--border); border-radius:4px; padding:8px 12px; font-size:11px; pointer-events:none; display:none; z-index:9999; line-height:1.8; min-width:180px; }
82
+ .tip-hdr { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; margin-bottom:4px; }
83
+
84
+ ::-webkit-scrollbar { width:5px; height:5px; }
85
+ ::-webkit-scrollbar-track { background:var(--bg); }
86
+ ::-webkit-scrollbar-thumb { background:var(--subtle); border-radius:3px; }
87
+ </style>
88
+ </head>
89
+ <body>
90
+
91
+ <!-- Header -->
92
+ <div class="header">
93
+ <div class="header-left">
94
+ <div class="logo-badge">KRUPP CAPITAL</div>
95
+ <div>
96
+ <div class="header-title">SPX DIRECTIONAL INDEX β€” CRASH RISK MONITOR</div>
97
+ <div class="header-sub">Quantitative Research Β· GEX+ Risk Surface Β· Options Flow Intelligence</div>
98
+ </div>
99
+ </div>
100
+ <div class="live-badge"><div class="live-dot"></div><span>CBOE DATA Β· Apr 19 2026 Β· SPX 7,126</span></div>
101
+ </div>
102
+
103
+ <!-- Metric Strip -->
104
+ <div class="metric-strip">
105
+ <div class="metric-item"><div class="metric-label">SPX Spot</div><div class="metric-val pos">7,126</div><div class="metric-sub">βˆ’0.85% session</div></div>
106
+ <div class="metric-item"><div class="metric-label">Net GEX</div><div class="metric-val pos">+$1.195B</div><div class="metric-sub">Dealer Long Ξ“</div></div>
107
+ <div class="metric-item"><div class="metric-label">Zero-Gamma</div><div class="metric-val warn">6,184</div><div class="metric-sub">βˆ’13.2% from spot</div></div>
108
+ <div class="metric-item"><div class="metric-label">HVL</div><div class="metric-val">6,860</div><div class="metric-sub">Regime transition</div></div>
109
+ <div class="metric-item"><div class="metric-label">Call Wall</div><div class="metric-val pos">7,100</div><div class="metric-sub">$1.178B gamma</div></div>
110
+ <div class="metric-item"><div class="metric-label">Put Wall</div><div class="metric-val neg">6,900</div><div class="metric-sub">Gamma support</div></div>
111
+ <div class="metric-item"><div class="metric-label">VGR</div><div class="metric-val warn">1,086Γ—</div><div class="metric-sub">Vanna dominance</div></div>
112
+ <div class="metric-item"><div class="metric-label">Crash Risk</div><div class="metric-val neg">42</div><div class="metric-sub">Moderate–High</div></div>
113
+ </div>
114
+
115
+ <!-- Tab Bar -->
116
+ <div class="tab-bar">
117
+ <button class="tab-btn active" onclick="switchTab('heatmap',this)">HEATMAP</button>
118
+ <button class="tab-btn" onclick="switchTab('risk',this)">RISK ANALYSIS</button>
119
+ <button class="tab-btn" onclick="switchTab('crash',this)">CRASH RISK</button>
120
+ <button class="tab-btn" onclick="switchTab('forecast',this)">FORECAST</button>
121
+ </div>
122
+
123
+ <!-- ═══ TAB 1: HEATMAP ═══ -->
124
+ <div id="tab-heatmap" class="tab-content active">
125
+ <div class="two-col">
126
+ <div class="panel">
127
+ <div class="panel-title">
128
+ <span>GEX+ RISK SURFACE β€” Spot Move Γ— IV Shock</span>
129
+ <div style="display:flex;gap:6px">
130
+ <span class="pbadge b-blue">CBOE OI</span>
131
+ <span class="pbadge b-amber">BS Gamma</span>
132
+ </div>
133
+ </div>
134
+ <div class="hm-outer" id="hmOuter">
135
+ <div class="y-axis">
136
+ <span>+60%</span><span>+45%</span><span>+30%</span><span>+15%</span><span>0%</span>
137
+ </div>
138
+ <div class="hm-wrap" id="hmWrap">
139
+ <canvas id="heatmapCanvas"></canvas>
140
+ <canvas id="overlayCanvas"></canvas>
141
+ </div>
142
+ <div class="x-axis">
143
+ <span>βˆ’20%</span><span>βˆ’15%</span><span>βˆ’10%</span><span>βˆ’5%</span><span>0%</span><span>+5%</span><span>+10%</span>
144
+ </div>
145
+ </div>
146
+ <div class="legend-bar"></div>
147
+ <div class="legend-labels">
148
+ <span>Amplifying (Cascade)</span>
149
+ <span>Neutral</span>
150
+ <span>Dampening (Safe)</span>
151
+ </div>
152
+ <div style="font-size:10px;color:var(--muted);margin-top:6px">
153
+ ↕ IV Shock (0β†’+60%) &nbsp;Β·&nbsp; ↔ Spot Move (βˆ’20%β†’+10%) &nbsp;Β·&nbsp; Hover for live values
154
+ </div>
155
+ </div>
156
+
157
+ <div style="display:flex;flex-direction:column;gap:12px">
158
+ <div class="panel">
159
+ <div class="panel-title">CURRENT POSITION</div>
160
+ <table>
161
+ <tbody>
162
+ <tr><td style="color:var(--muted)">Spot</td><td class="pos">7,126</td></tr>
163
+ <tr><td style="color:var(--muted)">Spot Move</td><td>0.00%</td></tr>
164
+ <tr><td style="color:var(--muted)">IV Shock</td><td>+0%</td></tr>
165
+ <tr><td style="color:var(--muted)">Net GEX+</td><td class="pos">+$1.195B</td></tr>
166
+ <tr><td style="color:var(--muted)">Regime</td><td class="pos">Dampening</td></tr>
167
+ <tr><td style="color:var(--muted)">Zero-Ξ“ Level</td><td class="warn">6,184</td></tr>
168
+ </tbody>
169
+ </table>
170
+ </div>
171
+ <div class="panel">
172
+ <div class="panel-title">GEX+ AT DRAWDOWN LEVELS</div>
173
+ <table>
174
+ <thead><tr><th>Drawdown</th><th>Spot</th><th>GEX+</th><th>Regime</th></tr></thead>
175
+ <tbody id="drawdownTable"></tbody>
176
+ </table>
177
+ </div>
178
+ <div class="panel">
179
+ <div class="panel-title">IV SKEW (CBOE)</div>
180
+ <table>
181
+ <thead><tr><th>Expiry</th><th>Call</th><th>Put</th><th>Skew</th></tr></thead>
182
+ <tbody id="skewTable"></tbody>
183
+ </table>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <!-- ═══ TAB 2: RISK ANALYSIS ═══ -->
190
+ <div id="tab-risk" class="tab-content">
191
+ <div class="row mb">
192
+ <div class="col-half panel">
193
+ <div class="panel-title">DEALER GAMMA EXPOSURE BY STRIKE</div>
194
+ <div class="chart-box"><canvas id="gexChart"></canvas></div>
195
+ </div>
196
+ <div class="col-half panel">
197
+ <div class="panel-title">IV SKEW TERM STRUCTURE</div>
198
+ <div class="chart-box"><canvas id="skewChart"></canvas></div>
199
+ </div>
200
+ </div>
201
+ <div class="row mb">
202
+ <div class="col-half panel">
203
+ <div class="panel-title">NET GEX SENSITIVITY vs SPOT</div>
204
+ <div class="chart-box"><canvas id="sensitivityChart"></canvas></div>
205
+ </div>
206
+ <div class="col-half panel">
207
+ <div class="panel-title">VANNA EXPOSURE (IV-DRIVEN DELTA)</div>
208
+ <div class="chart-box"><canvas id="vannaChart"></canvas></div>
209
+ </div>
210
+ </div>
211
+ <div class="three-col">
212
+ <div class="panel">
213
+ <div class="panel-title">KEY LEVELS</div>
214
+ <table>
215
+ <thead><tr><th>Level</th><th>Price</th><th>Note</th></tr></thead>
216
+ <tbody id="keyLevelsTable"></tbody>
217
+ </table>
218
+ </div>
219
+ <div class="panel">
220
+ <div class="panel-title">FLOW METRICS</div>
221
+ <table>
222
+ <thead><tr><th>Metric</th><th>Value</th><th>Pctile</th></tr></thead>
223
+ <tbody id="flowMetricsTable"></tbody>
224
+ </table>
225
+ </div>
226
+ <div class="panel">
227
+ <div class="panel-title">REGIME SIGNALS</div>
228
+ <table>
229
+ <thead><tr><th>Signal</th><th>Status</th></tr></thead>
230
+ <tbody id="regimeTable"></tbody>
231
+ </table>
232
+ </div>
233
+ </div>
234
+ </div>
235
+
236
+ <!-- ═══ TAB 3: CRASH RISK ═══ -->
237
+ <div id="tab-crash" class="tab-content">
238
+ <div class="two-col">
239
+ <div>
240
+ <div class="panel mb">
241
+ <div class="panel-title">COMPOSITE CRASH RISK INDEX</div>
242
+ <div style="display:flex;align-items:center;gap:16px;margin-bottom:8px">
243
+ <div style="font-size:48px;font-weight:800;color:var(--amber);line-height:1">42</div>
244
+ <div>
245
+ <div style="font-size:13px;font-weight:700;color:var(--amber)">MODERATE–HIGH RISK</div>
246
+ <div style="font-size:10px;color:var(--muted);margin-top:2px">Elevated put skew Β· VIX 28 Β· Below HVL zone</div>
247
+ </div>
248
+ </div>
249
+ <div class="risk-meter"><div class="risk-needle" style="left:42%"></div></div>
250
+ <div class="risk-labels">
251
+ <span>LOW (0)</span><span>MODERATE (40)</span><span>HIGH (70)</span><span>EXTREME (100)</span>
252
+ </div>
253
+ </div>
254
+ <div class="panel mb">
255
+ <div class="panel-title">IMPLIED PROBABILITY DISTRIBUTION (Breeden-Litzenberger)</div>
256
+ <div class="chart-box-lg"><canvas id="probChart"></canvas></div>
257
+ </div>
258
+ <div class="panel">
259
+ <div class="panel-title">CRASH SCENARIO ANALYSIS</div>
260
+ <table>
261
+ <thead><tr><th>Scenario</th><th>Target</th><th>Move</th><th>GEX Regime</th><th>Prob</th></tr></thead>
262
+ <tbody id="scenarioTable"></tbody>
263
+ </table>
264
+ </div>
265
+ </div>
266
+ <div style="display:flex;flex-direction:column;gap:12px">
267
+ <div class="panel">
268
+ <div class="panel-title">RISK FACTOR DECOMPOSITION</div>
269
+ <table>
270
+ <thead><tr><th>Factor</th><th>Score</th><th>Wt</th><th>Contrib</th></tr></thead>
271
+ <tbody id="riskFactors"></tbody>
272
+ </table>
273
+ </div>
274
+ <div class="panel">
275
+ <div class="panel-title">GAMMA CLIFF</div>
276
+ <div class="chart-box"><canvas id="cliffChart"></canvas></div>
277
+ </div>
278
+ <div class="panel">
279
+ <div class="panel-title">GEX+ vs SPOT MOVE</div>
280
+ <table>
281
+ <thead><tr><th>Spot</th><th>Move</th><th>GEX+</th><th>Status</th></tr></thead>
282
+ <tbody id="gexLevelsTable"></tbody>
283
+ </table>
284
+ </div>
285
+ </div>
286
+ </div>
287
+ </div>
288
+
289
+ <!-- ═══ TAB 4: FORECAST ═══ -->
290
+ <div id="tab-forecast" class="tab-content">
291
+ <div class="row mb">
292
+ <div class="col-half panel">
293
+ <div class="panel-title">SPX 5-DAY SCENARIO FAN</div>
294
+ <div class="chart-box-lg"><canvas id="forecastChart"></canvas></div>
295
+ </div>
296
+ <div class="col-half panel">
297
+ <div class="panel-title">5-DAY EXPECTED MOVE DISTRIBUTION</div>
298
+ <div class="chart-box-lg"><canvas id="emChart"></canvas></div>
299
+ </div>
300
+ </div>
301
+ <div class="fc-grid" id="scenarioCards"></div>
302
+ <div class="row">
303
+ <div class="col-half panel">
304
+ <div class="panel-title">PROBABILITY FORECAST TABLE</div>
305
+ <table>
306
+ <thead><tr><th>Horizon</th><th>Bull Target</th><th>Bear Target</th><th>P(Up)</th><th>P(Down)</th></tr></thead>
307
+ <tbody id="probForecastTable"></tbody>
308
+ </table>
309
+ </div>
310
+ <div class="col-half panel">
311
+ <div class="panel-title">EXPECTED MOVE SUMMARY</div>
312
+ <table>
313
+ <thead><tr><th>Window</th><th>+1Οƒ</th><th>βˆ’1Οƒ</th><th>Range</th><th>IV</th></tr></thead>
314
+ <tbody id="emTable"></tbody>
315
+ </table>
316
+ </div>
317
+ </div>
318
+ </div>
319
+
320
+ <div id="hmTooltip">
321
+ <div class="tip-hdr" id="tipHdr">GEX+ Surface</div>
322
+ <div id="tipSpot"></div>
323
+ <div id="tipIV"></div>
324
+ <div id="tipGex"></div>
325
+ <div id="tipRegime"></div>
326
+ </div>
327
+
328
+ <script>
329
+ // ─── Tab switching ───────────────────────────────────────
330
+ function switchTab(id, btn) {
331
+ document.querySelectorAll('.tab-content').forEach(function(t){ t.classList.remove('active'); });
332
+ document.querySelectorAll('.tab-btn').forEach(function(b){ b.classList.remove('active'); });
333
+ document.getElementById('tab-' + id).classList.add('active');
334
+ btn.classList.add('active');
335
+ if (id === 'risk') initRiskCharts();
336
+ if (id === 'crash') initCrashCharts();
337
+ if (id === 'forecast') initForecastCharts();
338
+ }
339
+
340
+ // ─── Real CBOE OI data (Apr 19 2026) ────────────────────
341
+ var SPOT = 7126;
342
+ var CALLS_OI = {
343
+ 6850:1053, 6900:1123, 6950:2635, 7000:3197, 7010:1779,
344
+ 7025:746, 7030:1342, 7045:1166, 7050:4243, 7070:687,
345
+ 7075:1255, 7100:4071, 7110:2185, 7120:607, 7125:1406,
346
+ 7140:799, 7150:1663, 7175:1011, 7200:1707, 7240:842, 7250:1263
347
+ };
348
+ var PUTS_OI = {
349
+ 6800:2170, 6825:660, 6850:4165, 6875:1355, 6890:765,
350
+ 6900:4306, 6915:726, 6925:1302, 6935:714, 6950:1634,
351
+ 7000:1344, 7050:834
352
+ };
353
+
354
+ // ─── Black-Scholes helpers ───────────────────────────────
355
+ function normalPDF(x) { return Math.exp(-0.5*x*x) / Math.sqrt(2*Math.PI); }
356
+ function bsGamma(S, K, sigma, T) {
357
+ if (T <= 0 || sigma <= 0 || S <= 0) return 0;
358
+ var sqrtT = Math.sqrt(T);
359
+ var d1 = (Math.log(S/K) + 0.5*sigma*sigma*T) / (sigma*sqrtT);
360
+ return normalPDF(d1) / (S * sigma * sqrtT);
361
+ }
362
+ // Returns net GEX in $B
363
+ function computeNetGex(spotPct, ivMult) {
364
+ var S = SPOT * (1 + spotPct);
365
+ var sigma = 0.158 * (1 + ivMult);
366
+ var T = 7 / 365;
367
+ var callGex = 0, putGex = 0;
368
+ var k, oi;
369
+ for (k in CALLS_OI) {
370
+ oi = CALLS_OI[k];
371
+ callGex += oi * bsGamma(S, +k, sigma, T) * S * S * 100;
372
+ }
373
+ for (k in PUTS_OI) {
374
+ oi = PUTS_OI[k];
375
+ putGex += oi * bsGamma(S, +k, sigma, T) * S * S * 100;
376
+ }
377
+ return (callGex - putGex) / 1e9;
378
+ }
379
+
380
+ // ─── Heatmap setup ───────────────────────────────────────
381
+ var SPOT_STEPS = 140, IV_STEPS = 90;
382
+ var SPOT_MIN = -0.20, SPOT_MAX = 0.10;
383
+ var IV_MIN = 0.00, IV_MAX = 0.60;
384
+
385
+ var gexGrid = new Float32Array(IV_STEPS * SPOT_STEPS);
386
+ var gexMin = 1e9, gexMax = -1e9;
387
+ (function buildGrid() {
388
+ for (var j = 0; j < IV_STEPS; j++) {
389
+ var ivMult = IV_MIN + (j / (IV_STEPS - 1)) * (IV_MAX - IV_MIN);
390
+ for (var i = 0; i < SPOT_STEPS; i++) {
391
+ var sPct = SPOT_MIN + (i / (SPOT_STEPS - 1)) * (SPOT_MAX - SPOT_MIN);
392
+ var v = computeNetGex(sPct, ivMult);
393
+ gexGrid[j * SPOT_STEPS + i] = v;
394
+ if (v < gexMin) gexMin = v;
395
+ if (v > gexMax) gexMax = v;
396
+ }
397
+ }
398
+ })();
399
+
400
+ // Color scale: norm=0 β†’ deep red (max negative), norm=1 β†’ deep navy (max positive)
401
+ function gexColor(val) {
402
+ var n = Math.max(0, Math.min(1, (val - gexMin) / (gexMax - gexMin)));
403
+ var stops = [
404
+ [0.00, [100,10,20]], [0.12,[180,30,30]], [0.25,[220,70,40]],
405
+ [0.38,[245,158,11]], [0.50,[225,225,225]], [0.60,[160,190,255]],
406
+ [0.72,[59,123,255]], [0.85,[20,70,180]], [1.00,[5,18,75]]
407
+ ];
408
+ for (var s = 0; s < stops.length - 1; s++) {
409
+ if (n >= stops[s][0] && n <= stops[s+1][0]) {
410
+ var t = (n - stops[s][0]) / (stops[s+1][0] - stops[s][0]);
411
+ return [
412
+ Math.round(stops[s][1][0] + t*(stops[s+1][1][0]-stops[s][1][0])),
413
+ Math.round(stops[s][1][1] + t*(stops[s+1][1][1]-stops[s][1][1])),
414
+ Math.round(stops[s][1][2] + t*(stops[s+1][1][2]-stops[s][1][2]))
415
+ ];
416
+ }
417
+ }
418
+ return stops[stops.length-1][1];
419
+ }
420
+
421
+ function drawHeatmap() {
422
+ var wrap = document.getElementById('hmWrap');
423
+ var W = wrap.offsetWidth || 620;
424
+ var H = Math.round(W * 0.56);
425
+ var hc = document.getElementById('heatmapCanvas');
426
+ var oc = document.getElementById('overlayCanvas');
427
+ hc.width = SPOT_STEPS; hc.height = IV_STEPS;
428
+ hc.style.width = W + 'px'; hc.style.height = H + 'px';
429
+ oc.width = W; oc.height = H;
430
+ oc.style.width = W + 'px'; oc.style.height = H + 'px';
431
+
432
+ var ctx = hc.getContext('2d');
433
+ var img = ctx.createImageData(SPOT_STEPS, IV_STEPS);
434
+ var d = img.data;
435
+ for (var j = 0; j < IV_STEPS; j++) {
436
+ var row = IV_STEPS - 1 - j; // flip: high IV at top
437
+ for (var i = 0; i < SPOT_STEPS; i++) {
438
+ var v = gexGrid[j * SPOT_STEPS + i];
439
+ var rgb = gexColor(v);
440
+ var idx = (row * SPOT_STEPS + i) * 4;
441
+ d[idx] = rgb[0]; d[idx+1] = rgb[1]; d[idx+2] = rgb[2]; d[idx+3] = 255;
442
+ }
443
+ }
444
+ ctx.putImageData(img, 0, 0);
445
+ drawOverlay(oc, W, H);
446
+ }
447
+
448
+ function drawOverlay(oc, W, H) {
449
+ var ctx = oc.getContext('2d');
450
+ ctx.clearRect(0, 0, W, H);
451
+
452
+ function spotToX(pct) { return ((pct - SPOT_MIN) / (SPOT_MAX - SPOT_MIN)) * W; }
453
+ function ivToY(mult) { return H - ((mult - IV_MIN) / (IV_MAX - IV_MIN)) * H; }
454
+
455
+ // Zero-contour
456
+ ctx.beginPath();
457
+ ctx.strokeStyle = 'rgba(255,255,255,0.88)';
458
+ ctx.lineWidth = 1.8;
459
+ ctx.setLineDash([5,4]);
460
+ var started = false;
461
+ for (var j = 0; j < IV_STEPS; j++) {
462
+ var ivMult = IV_MIN + (j / (IV_STEPS-1)) * (IV_MAX-IV_MIN);
463
+ for (var i = 0; i < SPOT_STEPS-1; i++) {
464
+ var v0 = gexGrid[j*SPOT_STEPS+i], v1 = gexGrid[j*SPOT_STEPS+i+1];
465
+ if ((v0 <= 0 && v1 > 0) || (v0 > 0 && v1 <= 0)) {
466
+ var t = Math.abs(v0) / (Math.abs(v0) + Math.abs(v1) + 1e-10);
467
+ var sPct = SPOT_MIN + ((i+t) / SPOT_STEPS) * (SPOT_MAX-SPOT_MIN);
468
+ var px = spotToX(sPct), py = ivToY(ivMult);
469
+ if (!started) { ctx.moveTo(px, py); started = true; }
470
+ else ctx.lineTo(px, py);
471
+ break;
472
+ }
473
+ }
474
+ }
475
+ ctx.stroke(); ctx.setLineDash([]);
476
+
477
+ // HVL vertical
478
+ var hvlX = spotToX(6860/SPOT - 1);
479
+ ctx.strokeStyle = 'rgba(245,158,11,0.65)';
480
+ ctx.lineWidth = 1.2; ctx.setLineDash([3,4]);
481
+ ctx.beginPath(); ctx.moveTo(hvlX,0); ctx.lineTo(hvlX,H); ctx.stroke();
482
+ ctx.setLineDash([]);
483
+ ctx.fillStyle = 'rgba(245,158,11,.9)'; ctx.font = '9px monospace';
484
+ ctx.fillText('HVL 6860', hvlX+3, 12);
485
+
486
+ // Zero-gamma vertical
487
+ var zgX = spotToX(6184/SPOT - 1);
488
+ ctx.strokeStyle = 'rgba(239,68,68,0.65)';
489
+ ctx.lineWidth = 1.2; ctx.setLineDash([3,4]);
490
+ ctx.beginPath(); ctx.moveTo(zgX,0); ctx.lineTo(zgX,H); ctx.stroke();
491
+ ctx.setLineDash([]);
492
+ ctx.fillStyle = 'rgba(239,68,68,.9)';
493
+ ctx.fillText('Zero-\u03937 6184', zgX+3, 24);
494
+
495
+ // Current crosshair
496
+ var cx = spotToX(0), cy = ivToY(0);
497
+ ctx.strokeStyle = 'rgba(252,211,77,0.7)';
498
+ ctx.lineWidth = 1; ctx.setLineDash([3,3]);
499
+ ctx.beginPath(); ctx.moveTo(cx,0); ctx.lineTo(cx,H); ctx.stroke();
500
+ ctx.beginPath(); ctx.moveTo(0,cy); ctx.lineTo(W,cy); ctx.stroke();
501
+ ctx.setLineDash([]);
502
+ ctx.beginPath(); ctx.arc(cx, cy, 5, 0, 2*Math.PI);
503
+ ctx.fillStyle = '#facc15'; ctx.fill();
504
+ ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.5; ctx.stroke();
505
+ ctx.fillStyle = 'rgba(252,211,77,.9)'; ctx.font = 'bold 9px monospace';
506
+ ctx.fillText('\u25CF SPX 7126', cx+8, cy-6);
507
+
508
+ // Zone labels
509
+ ctx.font = '10px monospace';
510
+ ctx.fillStyle = 'rgba(239,68,68,.7)';
511
+ ctx.fillText('\u2190 AMPLIFYING', 6, H-8);
512
+ ctx.textAlign = 'right'; ctx.fillStyle = 'rgba(59,123,255,.7)';
513
+ ctx.fillText('DAMPENING \u2192', W-6, H-8);
514
+ ctx.textAlign = 'left'; ctx.fillStyle = 'rgba(255,255,255,.55)';
515
+ ctx.fillText('\u2500\u2500 Zero-\u0393 contour', 6, 38);
516
+ }
517
+
518
+ // ─── Heatmap tooltip ─────────────────────────────────────
519
+ document.getElementById('overlayCanvas').addEventListener('mousemove', function(e) {
520
+ var rect = this.getBoundingClientRect();
521
+ var px = (e.clientX - rect.left) / rect.width;
522
+ var py = 1 - (e.clientY - rect.top) / rect.height;
523
+ var spotPct = SPOT_MIN + px * (SPOT_MAX - SPOT_MIN);
524
+ var ivMult = IV_MIN + py * (IV_MAX - IV_MIN);
525
+ var spot = SPOT * (1 + spotPct);
526
+ var gex = computeNetGex(spotPct, ivMult);
527
+ var regime = gex > 0.2 ? 'Dampening' : gex > 0 ? 'Weak' : 'Amplifying';
528
+ var regimeColor = gex > 0.2 ? '#3b7bff' : gex > 0 ? '#f59e0b' : '#ef4444';
529
+
530
+ var tip = document.getElementById('hmTooltip');
531
+ tip.style.display = 'block';
532
+ tip.style.left = (e.clientX + 14) + 'px';
533
+ tip.style.top = (e.clientY - 10) + 'px';
534
+
535
+ var spotSign = spotPct >= 0 ? '+' : '';
536
+ document.getElementById('tipSpot').textContent =
537
+ 'Spot: ' + spot.toFixed(0) + ' (' + spotSign + (spotPct*100).toFixed(1) + '%)';
538
+ document.getElementById('tipIV').textContent =
539
+ 'IV Shock: +' + (ivMult*100).toFixed(0) + '%';
540
+ var gexSign = gex >= 0 ? '+' : '';
541
+ document.getElementById('tipGex').textContent =
542
+ 'Net GEX+: ' + gexSign + gex.toFixed(3) + 'B';
543
+ var regimeEl = document.getElementById('tipRegime');
544
+ regimeEl.textContent = 'Regime: ' + regime;
545
+ regimeEl.style.color = regimeColor;
546
+ });
547
+ document.getElementById('overlayCanvas').addEventListener('mouseleave', function() {
548
+ document.getElementById('hmTooltip').style.display = 'none';
549
+ });
550
+
551
+ // ─── DOM table builders ────────────��─────────────────────
552
+ function mkTr(cells) {
553
+ // cells = [{text, cls}] β€” cls is optional className
554
+ var tr = document.createElement('tr');
555
+ cells.forEach(function(c) {
556
+ var td = document.createElement('td');
557
+ td.textContent = c.text;
558
+ if (c.cls) td.className = c.cls;
559
+ if (c.style) td.style.cssText = c.style;
560
+ tr.appendChild(td);
561
+ });
562
+ return tr;
563
+ }
564
+
565
+ function buildSkewTable() {
566
+ var data = [
567
+ {exp:'0DTE', call:'9.35%', put:'15.50%', skew:'6.15%'},
568
+ {exp:'1DTE', call:'11.12%', put:'16.46%', skew:'5.34%'},
569
+ {exp:'4DTE', call:'12.97%', put:'17.26%', skew:'4.29%'},
570
+ {exp:'44DTE', call:'15.15%', put:'17.47%', skew:'2.32%'},
571
+ {exp:'Dec31', call:'17.85%', put:'19.24%', skew:'1.39%'}
572
+ ];
573
+ var tbody = document.getElementById('skewTable');
574
+ data.forEach(function(r) {
575
+ tbody.appendChild(mkTr([{text:r.exp},{text:r.call},{text:r.put},{text:r.skew,cls:'neg'}]));
576
+ });
577
+ }
578
+
579
+ function buildDrawdownTable() {
580
+ var levels = [
581
+ {dd:'0%',pct:0},{dd:'-3%',pct:-0.03},{dd:'-5%',pct:-0.05},
582
+ {dd:'-7%',pct:-0.07},{dd:'-10%',pct:-0.10},
583
+ {dd:'-13.2%',pct:-0.132},{dd:'-15%',pct:-0.15},{dd:'-20%',pct:-0.20}
584
+ ];
585
+ var tbody = document.getElementById('drawdownTable');
586
+ levels.forEach(function(lv) {
587
+ var spot = (SPOT * (1 + lv.pct)).toFixed(0);
588
+ var gex = computeNetGex(lv.pct, 0.25);
589
+ var cls = gex > 0.3 ? 'pos' : gex > 0 ? 'warn' : 'neg';
590
+ var reg = gex > 0.3 ? 'Dampening' : gex > 0 ? 'Transitional' : 'Amplifying';
591
+ var gSign = gex >= 0 ? '+' : '';
592
+ tbody.appendChild(mkTr([
593
+ {text:lv.dd, cls:'neg'},
594
+ {text:spot},
595
+ {text:gSign + gex.toFixed(2) + 'B', cls:cls},
596
+ {text:reg, cls:cls}
597
+ ]));
598
+ });
599
+ }
600
+
601
+ function buildStaticTables() {
602
+ var kl = document.getElementById('keyLevelsTable');
603
+ [{l:'Call Wall',p:'7,100',n:'Gamma cap',c:'pos'},
604
+ {l:'Put Wall',p:'6,900',n:'Gamma floor',c:'warn'},
605
+ {l:'HVL',p:'6,860',n:'Regime flip',c:''},
606
+ {l:'Zero-Gamma',p:'6,184',n:'Cascade start',c:'neg'},
607
+ {l:'Spot',p:'7,126',n:'Current',c:'',cs:'color:var(--muted)'}
608
+ ].forEach(function(r) {
609
+ kl.appendChild(mkTr([{text:r.l,cls:r.c,style:r.cs||''},{text:r.p,cls:r.c},{text:r.n}]));
610
+ });
611
+
612
+ var fm = document.getElementById('flowMetricsTable');
613
+ [{m:'DEX',v:'$2.43T',p:'86th',c:'pos'},{m:'Net GEX',v:'$1.195B',p:'71st',c:'pos'},
614
+ {m:'Charm (3M)',v:'+3.3M \u0394/day',p:'\u2014',c:'pos'},{m:'VGR',v:'1,086\u00D7',p:'High',c:'warn'},
615
+ {m:'0DTE %',v:'34.2%',p:'Elevated',c:''}
616
+ ].forEach(function(r) {
617
+ fm.appendChild(mkTr([{text:r.m},{text:r.v,cls:r.c},{text:r.p}]));
618
+ });
619
+
620
+ var rg = document.getElementById('regimeTable');
621
+ [{s:'Gamma Regime',st:'Long Gamma',c:'pos'},{s:'Vol Regime',st:'Elevated',c:'warn'},
622
+ {s:'Flow Bias',st:'Bullish',c:'pos'},{s:'Skew Trend',st:'Put premium',c:'neg'},
623
+ {s:'Charm Bias',st:'Upward drift',c:'pos'}
624
+ ].forEach(function(r) {
625
+ rg.appendChild(mkTr([{text:r.s},{text:r.st,cls:r.c}]));
626
+ });
627
+
628
+ var sc = document.getElementById('scenarioTable');
629
+ [{sc:'HVL Break',t:'6,860',m:'-3.7%',g:'Transition',p:'28%',c:'warn'},
630
+ {sc:'Zero-Gamma',t:'6,184',m:'-13.2%',g:'Cascade',p:'12%',c:'neg'},
631
+ {sc:'Vol Cascade',t:'5,850',m:'-17.9%',g:'Amplifying',p:'7%',c:'neg'},
632
+ {sc:'Tail Event',t:'5,200',m:'-27.0%',g:'Maximum',p:'2%',c:'neg'}
633
+ ].forEach(function(r) {
634
+ sc.appendChild(mkTr([{text:r.sc,cls:r.c},{text:r.t},{text:r.m,cls:'neg'},{text:r.g,cls:'neg'},{text:r.p}]));
635
+ });
636
+
637
+ var pt = document.getElementById('probForecastTable');
638
+ [{h:'1-Day',bu:'7,180',be:'7,060',pu:'52%',pd:'48%'},
639
+ {h:'3-Day',bu:'7,240',be:'6,980',pu:'49%',pd:'51%'},
640
+ {h:'5-Day',bu:'7,350',be:'6,860',pu:'42%',pd:'58%'},
641
+ {h:'10-Day',bu:'7,450',be:'6,700',pu:'38%',pd:'62%'},
642
+ {h:'21-Day',bu:'7,600',be:'6,400',pu:'34%',pd:'66%'}
643
+ ].forEach(function(r) {
644
+ pt.appendChild(mkTr([{text:r.h},{text:r.bu,cls:'pos'},{text:r.be,cls:'neg'},{text:r.pu,cls:'pos'},{text:r.pd,cls:'neg'}]));
645
+ });
646
+
647
+ var et = document.getElementById('emTable');
648
+ [{w:'0DTE',p:'+67',m:'-67',r:'134 pts',iv:'12.4%'},
649
+ {w:'1-Day',p:'+89',m:'-89',r:'178 pts',iv:'14.1%'},
650
+ {w:'1-Week',p:'+199',m:'-199',r:'398 pts',iv:'15.8%'},
651
+ {w:'1-Month',p:'+412',m:'-412',r:'824 pts',iv:'16.5%'},
652
+ {w:'3-Month',p:'+714',m:'-714',r:'1,428 pts',iv:'17.2%'}
653
+ ].forEach(function(r) {
654
+ et.appendChild(mkTr([{text:r.w},{text:r.p,cls:'pos'},{text:r.m,cls:'neg'},{text:r.r},{text:r.iv}]));
655
+ });
656
+ }
657
+
658
+ function buildScenarioCards() {
659
+ var grid = document.getElementById('scenarioCards');
660
+ var cards = [
661
+ {title:'BULL SCENARIO (42%)', cls:'pos', border:'var(--blue)', bg:'rgba(59,123,255,.06)',
662
+ rows:[['Target','7,350','pos'],['Move','+3.1%','pos'],['Trigger','7,100 call wall break',''],['Charm','+3.3M \u0394/day','pos'],['VIX Target','22\u201324','']]},
663
+ {title:'BEAR SCENARIO (28%)', cls:'neg', border:'var(--red)', bg:'rgba(239,68,68,.06)',
664
+ rows:[['Target','6,860','neg'],['Move','-3.7%','neg'],['Trigger','HVL 6,860 loss',''],['VIX Target','32\u201338','warn'],['GEX Regime','Amplifying','neg']]},
665
+ {title:'RANGE SCENARIO (30%)', cls:'muted', border:'var(--muted)', bg:'rgba(100,116,139,.06)',
666
+ rows:[['Range','6,900\u20137,200',''],['Pivot','7,050',''],['GEX Support','Pinning','pos'],['VIX Target','26\u201330',''],['Charm','Mild upward','pos']]},
667
+ {title:'TAIL SCENARIO (2%)', cls:'purple', border:'#7c3aed', bg:'rgba(124,58,237,.06)',
668
+ rows:[['Target','5,200\u20135,800','neg'],['Move','-19% to -27%','neg'],['Trigger','Zero-Gamma + macro',''],['VIX Target','50+','neg'],['GEX','Max Amplifying','neg']]}
669
+ ];
670
+ var colorMap = {pos:'var(--blue)',neg:'var(--red)',warn:'var(--amber)',purple:'#a78bfa',muted:'var(--muted)','':`var(--text)`};
671
+ cards.forEach(function(card) {
672
+ var div = document.createElement('div');
673
+ div.className = 'sc-card';
674
+ div.style.borderLeft = '3px solid ' + card.border;
675
+ div.style.background = card.bg;
676
+
677
+ var title = document.createElement('div');
678
+ title.className = 'sc-title';
679
+ title.textContent = card.title;
680
+ title.style.color = colorMap[card.cls] || 'var(--text)';
681
+ div.appendChild(title);
682
+
683
+ card.rows.forEach(function(r) {
684
+ var row = document.createElement('div');
685
+ row.className = 'sc-row';
686
+ var label = document.createElement('span');
687
+ label.textContent = r[0];
688
+ var val = document.createElement('span');
689
+ val.textContent = r[1];
690
+ if (r[2]) val.className = r[2];
691
+ row.appendChild(label); row.appendChild(val);
692
+ div.appendChild(row);
693
+ });
694
+ grid.appendChild(div);
695
+ });
696
+ }
697
+
698
+ // ─── Chart.js defaults ───────────────────────────────────
699
+ Chart.defaults.color = '#64748b';
700
+ Chart.defaults.borderColor = '#1e2a38';
701
+ Chart.defaults.font.family = "'SF Mono','Fira Code',monospace";
702
+ Chart.defaults.font.size = 10;
703
+ var rCI = false, crCI = false, fcCI = false;
704
+
705
+ function initRiskCharts() {
706
+ if (rCI) return; rCI = true;
707
+
708
+ // GEX by strike β€” stacked call/put
709
+ var strikes = Object.keys(CALLS_OI).map(Number)
710
+ .concat(Object.keys(PUTS_OI).map(Number))
711
+ .filter(function(v,i,a){return a.indexOf(v)===i;})
712
+ .sort(function(a,b){return a-b;});
713
+ var callGV = strikes.map(function(K){
714
+ var o = CALLS_OI[K]||0;
715
+ return o*bsGamma(SPOT,K,0.158,7/365)*SPOT*SPOT*100/1e6;
716
+ });
717
+ var putGV = strikes.map(function(K){
718
+ var o = PUTS_OI[K]||0;
719
+ return -(o*bsGamma(SPOT,K,0.158,7/365)*SPOT*SPOT*100/1e6);
720
+ });
721
+ new Chart(document.getElementById('gexChart').getContext('2d'), {
722
+ type:'bar',
723
+ data:{labels:strikes,datasets:[
724
+ {label:'Call GEX ($M)',data:callGV,backgroundColor:'rgba(59,123,255,.7)',borderWidth:0},
725
+ {label:'Put GEX ($M)', data:putGV, backgroundColor:'rgba(239,68,68,.7)', borderWidth:0}
726
+ ]},
727
+ options:{responsive:true,maintainAspectRatio:false,
728
+ plugins:{legend:{position:'top'}},
729
+ scales:{x:{grid:{color:'#1e2a38'},stacked:true},y:{grid:{color:'#1e2a38'},stacked:true}}}
730
+ });
731
+
732
+ // IV Skew
733
+ new Chart(document.getElementById('skewChart').getContext('2d'), {
734
+ type:'line',
735
+ data:{labels:['0DTE','1DTE','4DTE','44DTE','Dec31'],datasets:[
736
+ {label:'Put IV', data:[15.50,16.46,17.26,17.47,19.24],borderColor:'#ef4444',backgroundColor:'rgba(239,68,68,.1)',fill:true,tension:.4},
737
+ {label:'Call IV',data:[9.35,11.12,12.97,15.15,17.85],borderColor:'#3b7bff',backgroundColor:'rgba(59,123,255,.1)',fill:true,tension:.4},
738
+ {label:'Skew', data:[6.15,5.34,4.29,2.32,1.39], borderColor:'#f59e0b',borderDash:[4,3],tension:.4}
739
+ ]},
740
+ options:{responsive:true,maintainAspectRatio:false,
741
+ plugins:{legend:{position:'top'}},
742
+ scales:{x:{grid:{color:'#1e2a38'}},y:{grid:{color:'#1e2a38'},ticks:{callback:function(v){return v+'%';}}}}}
743
+ });
744
+
745
+ // Net GEX sensitivity
746
+ var sL=[], sV=[];
747
+ for(var i=-20;i<=10;i++){sL.push(i+'%');sV.push(computeNetGex(i/100,0));}
748
+ new Chart(document.getElementById('sensitivityChart').getContext('2d'), {
749
+ type:'line',
750
+ data:{labels:sL,datasets:[{label:'Net GEX ($B)',data:sV,
751
+ segment:{borderColor:function(ctx){return ctx.p0.parsed.y>=0?'#3b7bff':'#ef4444';}},
752
+ backgroundColor:'transparent',tension:.3,pointRadius:0,borderWidth:2}]},
753
+ options:{responsive:true,maintainAspectRatio:false,
754
+ plugins:{legend:{display:false}},
755
+ scales:{x:{grid:{color:'#1e2a38'},ticks:{maxTicksLimit:7}},
756
+ y:{grid:{color:'#1e2a38'},ticks:{callback:function(v){return v.toFixed(1)+'B';}}}}}
757
+ });
758
+
759
+ // Vanna
760
+ var vS=[6800,6850,6900,6950,7000,7050,7100,7150,7200];
761
+ var vV=vS.map(function(K){
762
+ var co=CALLS_OI[K]||0, po=PUTS_OI[K]||0;
763
+ var T=7/365,sig=0.158,sqT=Math.sqrt(T);
764
+ var d1=(Math.log(SPOT/K)+.5*sig*sig*T)/(sig*sqT);
765
+ return (co-po)*(-normalPDF(d1)*d1/sig)*SPOT/1e6;
766
+ });
767
+ new Chart(document.getElementById('vannaChart').getContext('2d'), {
768
+ type:'bar',
769
+ data:{labels:vS,datasets:[{label:'Vanna ($M)',data:vV,
770
+ backgroundColor:vV.map(function(v){return v>=0?'rgba(59,123,255,.7)':'rgba(239,68,68,.7)';}),borderWidth:0}]},
771
+ options:{responsive:true,maintainAspectRatio:false,
772
+ plugins:{legend:{display:false}},
773
+ scales:{x:{grid:{color:'#1e2a38'}},y:{grid:{color:'#1e2a38'}}}}
774
+ });
775
+ }
776
+
777
+ function initCrashCharts() {
778
+ if (crCI) return; crCI = true;
779
+
780
+ // Risk factor table
781
+ var rfT = document.getElementById('riskFactors');
782
+ var factors=[
783
+ {n:'Put Skew Elevation',s:72,w:25,c:18.0},
784
+ {n:'VIX Term Structure', s:58,w:20,c:11.6},
785
+ {n:'GEX vs Zero-Gamma', s:23,w:20,c:4.6},
786
+ {n:'Macro Regime', s:55,w:15,c:8.25},
787
+ {n:'0DTE Volume', s:44,w:10,c:4.4},
788
+ {n:'Vol-of-Vol', s:38,w:10,c:3.8}
789
+ ];
790
+ factors.forEach(function(f){
791
+ var cls = f.s>60?'neg':f.s>40?'warn':'pos';
792
+ rfT.appendChild(mkTr([{text:f.n},{text:String(f.s),cls:cls},{text:f.w+'%'},{text:f.c.toFixed(1),cls:cls}]));
793
+ });
794
+
795
+ // GEX levels table
796
+ var glT = document.getElementById('gexLevelsTable');
797
+ [-0.15,-0.10,-0.07,-0.05,-0.03,0,0.03,0.05,0.07].forEach(function(pct){
798
+ var spot = (SPOT*(1+pct)).toFixed(0);
799
+ var gex = computeNetGex(pct, 0.20);
800
+ var cls = gex>0.3?'pos':gex>0?'warn':'neg';
801
+ var st = gex>0.3?'\u25B2 Dampening':gex>0?'\u25C6 Weak':'\u25BC Amplifying';
802
+ var gSign = gex>=0?'+':'';
803
+ glT.appendChild(mkTr([{text:spot},{text:(pct*100).toFixed(0)+'%'},{text:gSign+gex.toFixed(2)+'B',cls:cls},{text:st,cls:cls}]));
804
+ });
805
+
806
+ // Probability distribution
807
+ var pS=[], pV=[];
808
+ var mu=Math.log(SPOT)+(0-.5*.158*.158)*21/365, sig=.158*Math.sqrt(21/365);
809
+ for(var K=5500;K<=8200;K+=40){
810
+ pS.push(K);
811
+ var x=(Math.log(K)-mu)/sig;
812
+ pV.push(normalPDF(x)/(K*sig)*40);
813
+ }
814
+ new Chart(document.getElementById('probChart').getContext('2d'),{
815
+ type:'line',
816
+ data:{labels:pS,datasets:[{label:'Implied PDF',data:pV,
817
+ borderColor:'#3b7bff',
818
+ backgroundColor:function(ctx){
819
+ var ch=ctx.chart,ca=ch.chartArea;
820
+ if(!ca)return'rgba(59,123,255,.2)';
821
+ var gr=ch.ctx.createLinearGradient(ca.left,0,ca.right,0);
822
+ gr.addColorStop(0,'rgba(239,68,68,.3)');
823
+ gr.addColorStop(.45,'rgba(245,158,11,.2)');
824
+ gr.addColorStop(.7,'rgba(59,123,255,.3)');
825
+ gr.addColorStop(1,'rgba(34,197,94,.2)');
826
+ return gr;
827
+ },
828
+ fill:true,tension:.4,borderWidth:2,pointRadius:0}]},
829
+ options:{responsive:true,maintainAspectRatio:false,
830
+ plugins:{legend:{display:false}},
831
+ scales:{x:{grid:{color:'#1e2a38'},ticks:{maxTicksLimit:9}},y:{display:false}}}
832
+ });
833
+
834
+ // Gamma cliff
835
+ var cL=[], cV=[];
836
+ for(var i2=-18;i2<=8;i2+=0.5){cL.push((SPOT*(1+i2/100)).toFixed(0));cV.push(computeNetGex(i2/100,.15));}
837
+ new Chart(document.getElementById('cliffChart').getContext('2d'),{
838
+ type:'line',
839
+ data:{labels:cL.filter(function(_,i){return i%4===0;}),
840
+ datasets:[{label:'Net GEX ($B)',data:cV.filter(function(_,i){return i%4===0;}),
841
+ segment:{
842
+ borderColor:function(ctx){return ctx.p0.parsed.y>=0?'#3b7bff':'#ef4444';},
843
+ backgroundColor:function(ctx){return ctx.p0.parsed.y>=0?'rgba(59,123,255,.12)':'rgba(239,68,68,.12)';}
844
+ },
845
+ fill:true,tension:.3,borderWidth:2,pointRadius:0}]},
846
+ options:{responsive:true,maintainAspectRatio:false,
847
+ plugins:{legend:{display:false}},
848
+ scales:{x:{grid:{color:'#1e2a38'},ticks:{maxTicksLimit:6}},
849
+ y:{grid:{color:'#1e2a38'},ticks:{callback:function(v){return v.toFixed(1)+'B';}}}}}
850
+ });
851
+ }
852
+
853
+ function initForecastCharts() {
854
+ if (fcCI) return; fcCI = true;
855
+
856
+ new Chart(document.getElementById('forecastChart').getContext('2d'),{
857
+ type:'line',
858
+ data:{labels:['Now','Day 1','Day 2','Day 3','Day 4','Day 5'],datasets:[
859
+ {label:'Bull (42%)',data:[SPOT,7180,7220,7270,7310,7350],borderColor:'#22c55e',backgroundColor:'rgba(34,197,94,.08)',fill:'+2',tension:.35},
860
+ {label:'Base (30%)',data:[SPOT,7126,7100,7090,7070,7040],borderColor:'#94a3b8',backgroundColor:'transparent',tension:.35,borderDash:[4,3]},
861
+ {label:'Bear (28%)',data:[SPOT,7060,7010,6960,6910,6860],borderColor:'#ef4444',backgroundColor:'rgba(239,68,68,.08)',fill:'-2',tension:.35}
862
+ ]},
863
+ options:{responsive:true,maintainAspectRatio:false,
864
+ plugins:{legend:{position:'top'}},
865
+ scales:{x:{grid:{color:'#1e2a38'}},y:{grid:{color:'#1e2a38'},ticks:{callback:function(v){return v.toLocaleString();}}}}}
866
+ });
867
+
868
+ var emL=[], emV=[], emSig=.158*Math.sqrt(5/365);
869
+ for(var K=6400;K<=7900;K+=25){emL.push(K);emV.push(normalPDF((K-SPOT)/(SPOT*emSig)));}
870
+ new Chart(document.getElementById('emChart').getContext('2d'),{
871
+ type:'line',
872
+ data:{labels:emL,datasets:[{label:'5-Day EM',data:emV,
873
+ borderColor:'#3b7bff',
874
+ backgroundColor:function(ctx){
875
+ var ch=ctx.chart,ca=ch.chartArea;
876
+ if(!ca)return'rgba(59,123,255,.2)';
877
+ var gr=ch.ctx.createLinearGradient(ca.left,0,ca.right,0);
878
+ gr.addColorStop(0,'rgba(239,68,68,.25)');
879
+ gr.addColorStop(.5,'rgba(59,123,255,.25)');
880
+ gr.addColorStop(1,'rgba(34,197,94,.25)');
881
+ return gr;
882
+ },
883
+ fill:true,tension:.4,borderWidth:2,pointRadius:0}]},
884
+ options:{responsive:true,maintainAspectRatio:false,
885
+ plugins:{legend:{display:false}},
886
+ scales:{x:{grid:{color:'#1e2a38'},ticks:{maxTicksLimit:8}},y:{display:false}}}
887
+ });
888
+ }
889
+
890
+ // ─── Bootstrap ───────────────────────────────────────────
891
+ window.addEventListener('DOMContentLoaded', function() {
892
+ drawHeatmap();
893
+ buildSkewTable();
894
+ buildDrawdownTable();
895
+ buildStaticTables();
896
+ buildScenarioCards();
897
+ window.addEventListener('resize', function() { drawHeatmap(); });
898
+ });
899
+ </script>
900
+ </body>
901
+ </html>