AndyKandy26 commited on
Commit
a5ca01f
·
verified ·
1 Parent(s): 2495513

Delete risk.html

Browse files
Files changed (1) hide show
  1. risk.html +0 -618
risk.html DELETED
@@ -1,618 +0,0 @@
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>FinWise — Risk Analyzer</title>
7
- <link rel="stylesheet" href="shared.css">
8
- <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
9
- <style>
10
- .quiz-card { margin-bottom: 16px; transition: opacity 0.3s; }
11
- .quiz-card.inactive { opacity: 0.4; pointer-events: none; }
12
- .question-num {
13
- font-size: 11px; font-weight: 700; text-transform: uppercase;
14
- letter-spacing: 0.1em; color: var(--cyan); margin-bottom: 6px;
15
- }
16
- .question-text { font-size: 16px; font-weight: 600; margin-bottom: 14px; line-height: 1.4; }
17
- .answer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
18
- .answer-btn {
19
- padding: 12px 14px;
20
- background: var(--bg3);
21
- border: 1px solid var(--border);
22
- border-radius: var(--r-sm);
23
- color: var(--text2);
24
- font-family: var(--font-body);
25
- font-size: 13px;
26
- font-weight: 500;
27
- cursor: pointer;
28
- text-align: left;
29
- transition: all var(--transition);
30
- line-height: 1.3;
31
- }
32
- .answer-btn:hover { border-color: var(--border2); color: var(--text); background: var(--card2); }
33
- .answer-btn.selected { border-color: var(--cyan); background: rgba(34,211,238,0.10); color: var(--cyan); }
34
-
35
- /* Risk Gauge */
36
- .gauge-container { position: relative; width: 220px; height: 120px; margin: 0 auto; }
37
- .gauge-svg { width: 220px; height: 120px; }
38
- .gauge-needle {
39
- transform-origin: 110px 110px;
40
- transition: transform 1.2s cubic-bezier(.34,1.56,.64,1);
41
- }
42
- .gauge-center-text {
43
- position: absolute;
44
- bottom: 0; left: 50%;
45
- transform: translateX(-50%);
46
- text-align: center;
47
- }
48
- .gauge-score { font-family: var(--font-head); font-size: 32px; font-weight: 800; }
49
- .gauge-label { font-size: 12px; color: var(--text2); }
50
-
51
- /* Heatmap */
52
- .heatmap-grid {
53
- display: grid;
54
- gap: 3px;
55
- }
56
- .heatmap-cell {
57
- height: 40px;
58
- border-radius: 4px;
59
- display: flex;
60
- align-items: center;
61
- justify-content: center;
62
- font-size: 11px;
63
- font-weight: 700;
64
- color: white;
65
- transition: transform var(--transition);
66
- cursor: default;
67
- }
68
- .heatmap-cell:hover { transform: scale(1.05); }
69
-
70
- .rebal-item {
71
- display: flex;
72
- align-items: center;
73
- gap: 14px;
74
- padding: 14px;
75
- background: var(--bg3);
76
- border-radius: var(--r-sm);
77
- border: 1px solid var(--border);
78
- margin-bottom: 10px;
79
- transition: all var(--transition);
80
- }
81
- .rebal-item:hover { border-color: var(--border2); }
82
- .rebal-action {
83
- font-size: 11px;
84
- font-weight: 700;
85
- text-transform: uppercase;
86
- letter-spacing: 0.08em;
87
- margin-bottom: 3px;
88
- }
89
- .rebal-desc { font-size: 13px; color: var(--text2); }
90
- .rebal-arrow { font-size: 20px; margin-left: auto; }
91
-
92
- .risk-breakdown { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
93
- .rb-item {
94
- background: var(--bg3);
95
- border-radius: var(--r-sm);
96
- padding: 14px;
97
- text-align: center;
98
- }
99
- .rb-val { font-family: var(--font-head); font-size: 22px; font-weight: 800; }
100
- .rb-label { font-size: 11px; color: var(--text2); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.06em; }
101
-
102
- .volatility-bar-wrap { margin-bottom: 12px; }
103
- .vol-header { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 5px; }
104
- .vol-name { color: var(--text2); font-weight: 600; }
105
-
106
- .score-ring {
107
- width: 80px; height: 80px;
108
- border-radius: 50%;
109
- display: flex; align-items: center; justify-content: center;
110
- font-family: var(--font-head);
111
- font-size: 24px;
112
- font-weight: 800;
113
- margin: 0 auto 12px;
114
- position: relative;
115
- }
116
- .score-ring::before {
117
- content: '';
118
- position: absolute;
119
- inset: 4px;
120
- border-radius: 50%;
121
- background: var(--bg2);
122
- }
123
- .score-ring span { position: relative; z-index: 1; }
124
-
125
- .scenario-card {
126
- background: var(--bg3);
127
- border-radius: var(--r-sm);
128
- padding: 16px;
129
- border: 1px solid var(--border);
130
- transition: all var(--transition);
131
- }
132
- .scenario-card:hover { border-color: var(--border2); }
133
- .scenario-icon { font-size: 28px; margin-bottom: 8px; }
134
- .scenario-title { font-weight: 700; font-size: 14px; margin-bottom: 6px; }
135
- .scenario-impact { font-size: 13px; }
136
- </style>
137
- </head>
138
- <body>
139
- <div class="app-shell">
140
- <nav class="sidebar">
141
- <div class="sidebar-logo">
142
- <div class="logo-mark">
143
- <div class="logo-icon">📈</div>
144
- <div><div class="logo-text">FinWise</div><div class="logo-sub">Smart Investing</div></div>
145
- </div>
146
- </div>
147
- <div class="nav-section">
148
- <div class="nav-label">Main</div>
149
- <a href="index.html" class="nav-item"><span class="nav-icon">🏠</span> Dashboard</a>
150
- <a href="portfolio.html" class="nav-item"><span class="nav-icon">📊</span> Portfolio Builder</a>
151
- <a href="risk.html" class="nav-item"><span class="nav-icon">🎯</span> Risk Analyzer</a>
152
- <a href="tracker.html" class="nav-item"><span class="nav-icon">📈</span> Tracker</a>
153
- <div class="nav-label">Tools</div>
154
- <a href="calculators.html" class="nav-item"><span class="nav-icon">🧮</span> Calculators</a>
155
- <a href="insights.html" class="nav-item"><span class="nav-icon">💡</span> Insights</a>
156
- </div>
157
- <div class="sidebar-footer">
158
- <div class="market-ticker">Live Market</div>
159
- <div id="sidebar-tickers"></div>
160
- </div>
161
- </nav>
162
-
163
- <main class="main-content">
164
- <div class="page-header fade-in">
165
- <div class="page-title">Risk <span>Analyzer</span></div>
166
- <div class="page-subtitle">Understand and optimize your portfolio's risk profile</div>
167
- </div>
168
-
169
- <div class="grid-60-40">
170
- <!-- Left Column -->
171
- <div>
172
-
173
- <!-- Quiz -->
174
- <div class="card fade-in" id="quiz-section">
175
- <div class="section-title">🧠 Risk Tolerance Assessment</div>
176
- <div class="text-muted text-sm" style="margin-bottom:20px">Answer 5 quick questions — no typing needed</div>
177
-
178
- <div id="quiz-container"></div>
179
-
180
- <div id="quiz-result" class="hidden" style="margin-top:16px">
181
- <div style="text-align:center;padding:20px">
182
- <div style="font-size:48px;margin-bottom:8px" id="result-icon">⚖️</div>
183
- <div style="font-family:var(--font-head);font-size:24px;font-weight:800;margin-bottom:8px" id="result-title">Moderate Investor</div>
184
- <div style="color:var(--text2);font-size:14px;max-width:360px;margin:0 auto" id="result-desc"></div>
185
- </div>
186
- </div>
187
-
188
- <div class="flex gap-12" style="margin-top:16px">
189
- <button class="btn btn-ghost btn-sm" onclick="resetQuiz()">↺ Retake</button>
190
- <button class="btn btn-primary" id="analyze-btn" onclick="runAnalysis()">Analyze My Risk →</button>
191
- </div>
192
- </div>
193
-
194
- <!-- Volatility Breakdown -->
195
- <div class="card fade-in fade-in-2" style="margin-top:20px">
196
- <div class="section-title">📊 Asset Volatility</div>
197
- <div id="volatility-bars"></div>
198
- </div>
199
-
200
- <!-- Scenarios -->
201
- <div class="card fade-in fade-in-3" style="margin-top:20px">
202
- <div class="section-title">🌪️ Scenario Simulation</div>
203
- <div class="text-muted text-sm" style="margin-bottom:16px">How would your portfolio perform in these scenarios?</div>
204
- <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px" id="scenarios-grid"></div>
205
- </div>
206
-
207
- </div>
208
-
209
- <!-- Right Column -->
210
- <div>
211
-
212
- <!-- Risk Gauge -->
213
- <div class="card fade-in-1">
214
- <div class="card-title">🎯 Risk Score</div>
215
- <div class="gauge-container">
216
- <svg class="gauge-svg" viewBox="0 0 220 120">
217
- <!-- Background arcs -->
218
- <path d="M 20 110 A 90 90 0 0 1 200 110" fill="none" stroke="var(--bg3)" stroke-width="18" stroke-linecap="round"/>
219
- <!-- Colored sections -->
220
- <path d="M 20 110 A 90 90 0 0 1 65 29" fill="none" stroke="#10b981" stroke-width="18" stroke-linecap="round" opacity="0.8"/>
221
- <path d="M 65 29 A 90 90 0 0 1 110 20" fill="none" stroke="#22d3ee" stroke-width="18" opacity="0.8"/>
222
- <path d="M 110 20 A 90 90 0 0 1 155 29" fill="none" stroke="#f59e0b" stroke-width="18" opacity="0.8"/>
223
- <path d="M 155 29 A 90 90 0 0 1 200 110" fill="none" stroke="#f43f5e" stroke-width="18" stroke-linecap="round" opacity="0.8"/>
224
- <!-- Needle -->
225
- <g class="gauge-needle" id="gauge-needle" style="transform:rotate(-90deg)">
226
- <line x1="110" y1="110" x2="110" y2="30" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
227
- <circle cx="110" cy="110" r="6" fill="white"/>
228
- </g>
229
- </svg>
230
- <div class="gauge-center-text">
231
- <div class="gauge-score" id="gauge-score">—</div>
232
- <div class="gauge-label">Risk Score</div>
233
- </div>
234
- </div>
235
- <div style="text-align:center;margin-top:16px">
236
- <span class="badge" id="gauge-badge" style="font-size:13px;padding:6px 16px">Calculating...</span>
237
- </div>
238
-
239
- <div class="divider"></div>
240
- <div class="risk-breakdown">
241
- <div class="rb-item">
242
- <div class="rb-val" id="rb-div" style="color:var(--emerald)">—</div>
243
- <div class="rb-label">Diversification</div>
244
- </div>
245
- <div class="rb-item">
246
- <div class="rb-val" id="rb-concentrate" style="color:var(--amber)">—</div>
247
- <div class="rb-label">Concentration</div>
248
- </div>
249
- <div class="rb-item">
250
- <div class="rb-val" id="rb-equity" style="color:var(--violet)">—</div>
251
- <div class="rb-label">Equity %</div>
252
- </div>
253
- <div class="rb-item">
254
- <div class="rb-val" id="rb-safe" style="color:var(--cyan)">—</div>
255
- <div class="rb-label">Safe Assets</div>
256
- </div>
257
- </div>
258
- </div>
259
-
260
- <!-- Rebalancing Suggestions -->
261
- <div class="card fade-in-2" style="margin-top:20px">
262
- <div class="card-title">⚖️ Rebalancing Suggestions</div>
263
- <div id="rebal-list">
264
- <div style="color:var(--text2);font-size:13px;text-align:center;padding:20px">
265
- Complete the risk assessment to see suggestions
266
- </div>
267
- </div>
268
- </div>
269
-
270
- <!-- Allocation Type Chart -->
271
- <div class="card fade-in-3" style="margin-top:20px">
272
- <div class="card-title">🏦 Asset Type Breakdown</div>
273
- <div style="height:180px;position:relative">
274
- <canvas id="typeChart"></canvas>
275
- </div>
276
- </div>
277
-
278
- </div>
279
- </div>
280
-
281
- </main>
282
- </div>
283
-
284
- <nav class="bottom-nav">
285
- <div class="bottom-nav-inner">
286
- <a href="index.html" class="bottom-nav-item"><span class="bnav-icon">🏠</span>Home</a>
287
- <a href="portfolio.html" class="bottom-nav-item"><span class="bnav-icon">📊</span>Portfolio</a>
288
- <a href="risk.html" class="bottom-nav-item"><span class="bnav-icon">🎯</span>Risk</a>
289
- <a href="tracker.html" class="bottom-nav-item"><span class="bnav-icon">📈</span>Track</a>
290
- <a href="calculators.html" class="bottom-nav-item"><span class="bnav-icon">🧮</span>Calc</a>
291
- <a href="insights.html" class="bottom-nav-item"><span class="bnav-icon">💡</span>Insights</a>
292
- </div>
293
- </nav>
294
-
295
- <script src="shared.js"></script>
296
- <script>
297
- const QUESTIONS = [
298
- {
299
- q: "How long do you plan to keep your investments?",
300
- answers: [
301
- { text: "⏱️ Less than 1 year", score: 1 },
302
- { text: "📅 1–3 years", score: 2 },
303
- { text: "📆 3–10 years", score: 4 },
304
- { text: "🗓️ 10+ years", score: 5 },
305
- ]
306
- },
307
- {
308
- q: "If your portfolio dropped 20% suddenly, you would:",
309
- answers: [
310
- { text: "😱 Sell everything immediately", score: 1 },
311
- { text: "😟 Sell some to reduce exposure", score: 2 },
312
- { text: "😐 Hold and wait for recovery", score: 4 },
313
- { text: "😏 Buy more at lower prices", score: 5 },
314
- ]
315
- },
316
- {
317
- q: "What's your primary investment objective?",
318
- answers: [
319
- { text: "🛡️ Preserve what I have", score: 1 },
320
- { text: "🌱 Steady, modest growth", score: 2 },
321
- { text: "⚖️ Balance growth and safety", score: 3 },
322
- { text: "🚀 Maximum long-term growth", score: 5 },
323
- ]
324
- },
325
- {
326
- q: "What % of your monthly income do you invest?",
327
- answers: [
328
- { text: "💸 Less than 5%", score: 1 },
329
- { text: "💰 5–10%", score: 2 },
330
- { text: "📈 10–25%", score: 4 },
331
- { text: "🏦 More than 25%", score: 5 },
332
- ]
333
- },
334
- {
335
- q: "Which describes your investing experience?",
336
- answers: [
337
- { text: "🐣 Complete beginner", score: 1 },
338
- { text: "📖 Read a bit about it", score: 2 },
339
- { text: "🤓 Have some investments", score: 3 },
340
- { text: "💹 Active investor / trader", score: 5 },
341
- ]
342
- },
343
- ];
344
-
345
- let answers = new Array(QUESTIONS.length).fill(null);
346
- let quizComplete = false;
347
-
348
- function renderQuiz() {
349
- const container = document.getElementById('quiz-container');
350
- container.innerHTML = QUESTIONS.map((q, qi) => `
351
- <div class="card quiz-card ${answers[qi] === null && qi > 0 && answers[qi-1] === null ? 'inactive' : ''}"
352
- id="quiz-card-${qi}" style="padding:16px;margin-bottom:12px;background:var(--bg3);border:1px solid var(--border)">
353
- <div class="question-num">Question ${qi+1} of ${QUESTIONS.length}</div>
354
- <div class="question-text">${q.q}</div>
355
- <div class="answer-grid">
356
- ${q.answers.map((a, ai) => `
357
- <button class="answer-btn ${answers[qi] === ai ? 'selected' : ''}"
358
- onclick="selectAnswer(${qi}, ${ai})">${a.text}</button>
359
- `).join('')}
360
- </div>
361
- </div>
362
- `).join('');
363
- }
364
-
365
- function selectAnswer(qi, ai) {
366
- answers[qi] = ai;
367
- document.querySelectorAll(`#quiz-card-${qi} .answer-btn`).forEach((btn, i) => {
368
- btn.classList.toggle('selected', i === ai);
369
- });
370
- const next = document.getElementById('quiz-card-' + (qi+1));
371
- if (next) next.classList.remove('inactive');
372
-
373
- quizComplete = answers.every(a => a !== null);
374
- if (quizComplete) {
375
- document.getElementById('analyze-btn').style.background = 'linear-gradient(135deg,var(--emerald-d),var(--emerald))';
376
- }
377
- }
378
-
379
- function resetQuiz() {
380
- answers.fill(null);
381
- quizComplete = false;
382
- renderQuiz();
383
- document.getElementById('quiz-result').classList.add('hidden');
384
- }
385
-
386
- function getTotalScore() {
387
- return answers.reduce((s, ai, qi) => s + (ai !== null ? QUESTIONS[qi].answers[ai].score : 0), 0);
388
- }
389
-
390
- const RISK_RESULTS = [
391
- null,
392
- { icon:'🐢', title:'Very Conservative', desc:'You prefer capital safety above all. Bonds and stable assets suit you best. Low risk, low return.', color:'var(--emerald)' },
393
- { icon:'🛡️', title:'Conservative', desc:'Modest growth with downside protection. A mix of bonds and blue-chip stocks works for you.', color:'var(--cyan)' },
394
- { icon:'⚖️', title:'Moderate', desc:'Balanced approach. You accept some volatility for reasonable long-term gains.', color:'var(--amber)' },
395
- { icon:'🚀', title:'Aggressive', desc:'Growth-focused investor. You can stomach volatility and aim for superior long-term returns.', color:'var(--rose)' },
396
- { icon:'🦁', title:'Very Aggressive', desc:'Maximum growth seeker. High risk, high reward. Concentrated in equities and high-growth assets.', color:'var(--rose)' },
397
- ];
398
-
399
- function getProfileFromScore(score) {
400
- if (score <= 8) return RISK_RESULTS[1];
401
- if (score <= 12) return RISK_RESULTS[2];
402
- if (score <= 16) return RISK_RESULTS[3];
403
- if (score <= 20) return RISK_RESULTS[4];
404
- return RISK_RESULTS[5];
405
- }
406
-
407
- function runAnalysis() {
408
- if (!quizComplete) { showToast('Please answer all 5 questions first', 'error'); return; }
409
-
410
- const score = getTotalScore();
411
- const profile = getProfileFromScore(score);
412
- document.getElementById('quiz-result').classList.remove('hidden');
413
- document.getElementById('result-icon').textContent = profile.icon;
414
- document.getElementById('result-title').textContent = profile.title;
415
- document.getElementById('result-desc').textContent = profile.desc;
416
-
417
- const portfolio = getPortfolio();
418
- const riskScore = calcRiskScore(portfolio);
419
- const divScore = calcDiversification(portfolio);
420
-
421
- // Gauge
422
- const deg = -90 + (riskScore / 100) * 180;
423
- document.getElementById('gauge-needle').style.transform = `rotate(${deg}deg)`;
424
- document.getElementById('gauge-score').textContent = riskScore;
425
-
426
- const riskColors = ['badge-emerald','badge-cyan','badge-amber','badge-amber','badge-rose'];
427
- const riskNames = ['Low Risk','Moderate-Low','Moderate','Moderate-High','High Risk'];
428
- const rIdx = Math.floor(riskScore / 25);
429
- const badge = document.getElementById('gauge-badge');
430
- badge.className = 'badge ' + riskColors[rIdx];
431
- badge.textContent = riskNames[rIdx];
432
-
433
- // Breakdown
434
- const equityPct = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0);
435
- const safePct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
436
- const maxPct = Math.max(...portfolio.assets.map(a=>a.pct));
437
- document.getElementById('rb-div').textContent = divScore + '%';
438
- document.getElementById('rb-concentrate').textContent = maxPct + '%';
439
- document.getElementById('rb-equity').textContent = equityPct + '%';
440
- document.getElementById('rb-safe').textContent = safePct + '%';
441
-
442
- renderRebalSuggestions(portfolio, riskScore, equityPct);
443
- renderVolatility(portfolio);
444
- renderScenarios(portfolio);
445
- renderTypeChart(portfolio);
446
- }
447
-
448
- function renderRebalSuggestions(portfolio, riskScore, equityPct) {
449
- const list = document.getElementById('rebal-list');
450
- const suggestions = [];
451
-
452
- const maxAsset = portfolio.assets.reduce((m, a) => a.pct > m.pct ? a : m, portfolio.assets[0]);
453
- if (maxAsset.pct > 35) suggestions.push({
454
- type:'REDUCE', color:'var(--rose)',
455
- action: `Reduce ${maxAsset.ticker}`,
456
- desc: `${maxAsset.ticker} is ${maxAsset.pct}% of your portfolio — consider trimming to under 30% for better balance.`,
457
- arrow: '↓'
458
- });
459
-
460
- const bondPct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
461
- if (bondPct < 10 && riskScore < 60) suggestions.push({
462
- type:'ADD', color:'var(--emerald)',
463
- action: 'Add Bonds (BND)',
464
- desc: 'Your portfolio has little fixed income. Adding 10-15% bonds reduces volatility significantly.',
465
- arrow: '+'
466
- });
467
-
468
- if (equityPct > 85) suggestions.push({
469
- type:'DIVERSIFY', color:'var(--amber)',
470
- action: 'Add Alternative Assets',
471
- desc: 'Over 85% in equities. Consider Gold (GLD) or REITs for non-correlated returns.',
472
- arrow: '↗'
473
- });
474
-
475
- const hasIntl = portfolio.assets.some(a=>a.ticker==='VEA'||a.ticker==='VXUS');
476
- if (!hasIntl) suggestions.push({
477
- type:'CONSIDER', color:'var(--cyan)',
478
- action: 'Consider International Exposure',
479
- desc: 'Adding 10-15% international ETFs (VEA, VXUS) can reduce US-market concentration risk.',
480
- arrow: '🌍'
481
- });
482
-
483
- if (suggestions.length === 0) suggestions.push({
484
- type:'OK', color:'var(--emerald)',
485
- action: '✅ Portfolio looks healthy!',
486
- desc: 'Your diversification and risk levels are well-balanced. Keep up with regular contributions.',
487
- arrow: '👍'
488
- });
489
-
490
- list.innerHTML = suggestions.map(s => `
491
- <div class="rebal-item">
492
- <div>
493
- <div class="rebal-action" style="color:${s.color}">${s.type}</div>
494
- <div style="font-weight:700;font-size:14px;margin-bottom:4px">${s.action}</div>
495
- <div class="rebal-desc">${s.desc}</div>
496
- </div>
497
- <div class="rebal-arrow">${s.arrow}</div>
498
- </div>
499
- `).join('');
500
- }
501
-
502
- const VOLATILITY_DATA = {
503
- 'VOO': { vol: 15, beta: 1.00, color: '#22d3ee' },
504
- 'QQQ': { vol: 22, beta: 1.18, color: '#8b5cf6' },
505
- 'NVDA': { vol: 48, beta: 1.85, color: '#10b981' },
506
- 'AAPL': { vol: 25, beta: 1.22, color: '#f59e0b' },
507
- 'BND': { vol: 4, beta: 0.10, color: '#6366f1' },
508
- 'GLD': { vol: 12, beta: 0.05, color: '#fbbf24' },
509
- 'AMZN': { vol: 30, beta: 1.35, color: '#0ea5e9' },
510
- 'VTI': { vol: 15, beta: 1.00, color: '#34d399' },
511
- 'TSLA': { vol: 62, beta: 2.10, color: '#f43f5e' },
512
- 'WMT': { vol: 8, beta: 0.55, color: '#34d399' },
513
- 'MCD': { vol: 9, beta: 0.70, color: '#fb923c' },
514
- };
515
-
516
- function renderVolatility(portfolio) {
517
- const container = document.getElementById('volatility-bars');
518
- container.innerHTML = portfolio.assets.map(a => {
519
- const vdata = VOLATILITY_DATA[a.ticker] || { vol: 20, beta: 1.0, color: '#22d3ee' };
520
- const volColor = vdata.vol < 10 ? '#10b981' : vdata.vol < 25 ? '#f59e0b' : '#f43f5e';
521
- return `
522
- <div class="volatility-bar-wrap">
523
- <div class="vol-header">
524
- <span class="vol-name">${a.ticker} <span style="color:var(--text3);font-weight:400;font-size:11px">— ${a.name || ''}</span></span>
525
- <span style="color:${volColor};font-family:var(--font-mono);font-size:12px">±${vdata.vol}% vol · β ${vdata.beta}</span>
526
- </div>
527
- <div class="progress-bar">
528
- <div class="progress-fill" style="width:${Math.min(vdata.vol*1.2,100)}%;background:${volColor}"></div>
529
- </div>
530
- </div>
531
- `;
532
- }).join('');
533
- }
534
-
535
- function renderScenarios(portfolio) {
536
- const equity = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0)/100;
537
- const bond = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0)/100;
538
- const gold = portfolio.assets.filter(a=>a.type==='Commodity').reduce((s,a)=>s+a.pct,0)/100;
539
-
540
- const scenarios = [
541
- { icon:'📉', title:'2008 Financial Crisis', impact: ((-38*equity) + (5*bond) + (8*gold)).toFixed(1), desc:'Worst-case equity selloff' },
542
- { icon:'🦠', title:'2020 COVID Crash', impact: ((-30*equity) + (8*bond) + (5*gold)).toFixed(1), desc:'Fast drop, rapid recovery' },
543
- { icon:'🔥', title:'Inflation Spike (10%)', impact: ((-15*equity) + (-8*bond) + (20*gold)).toFixed(1), desc:'Rising rates environment' },
544
- { icon:'🚀', title:'Bull Market (+30%)', impact: ((30*equity) + (3*bond) + (8*gold)).toFixed(1), desc:'Strong economic growth' },
545
- ];
546
-
547
- document.getElementById('scenarios-grid').innerHTML = scenarios.map(s => {
548
- const isPos = parseFloat(s.impact) >= 0;
549
- return `
550
- <div class="scenario-card">
551
- <div class="scenario-icon">${s.icon}</div>
552
- <div class="scenario-title">${s.title}</div>
553
- <div class="scenario-impact" style="color:${isPos?'var(--emerald)':'var(--rose)'};font-family:var(--font-mono);font-size:18px;font-weight:700">
554
- ${isPos?'+':''}${s.impact}%
555
- </div>
556
- <div style="font-size:11px;color:var(--text2);margin-top:4px">${s.desc}</div>
557
- </div>
558
- `;
559
- }).join('');
560
- }
561
-
562
- function renderTypeChart(portfolio) {
563
- const types = { ETF:0, Stock:0, Bond:0, Commodity:0 };
564
- portfolio.assets.forEach(a => { types[a.type] = (types[a.type]||0) + a.pct; });
565
-
566
- const ctx = document.getElementById('typeChart').getContext('2d');
567
- new Chart(ctx, {
568
- type: 'bar',
569
- data: {
570
- labels: Object.keys(types),
571
- datasets: [{
572
- data: Object.values(types),
573
- backgroundColor: ['rgba(34,211,238,0.7)','rgba(16,185,129,0.7)','rgba(99,102,241,0.7)','rgba(245,158,11,0.7)'],
574
- borderRadius: 6,
575
- borderSkipped: false,
576
- }]
577
- },
578
- options: {
579
- responsive: true, maintainAspectRatio: false,
580
- plugins: { legend: { display: false } },
581
- scales: {
582
- x: { grid: { display: false } },
583
- y: { grid: { color: 'rgba(34,211,238,0.06)' }, ticks: { callback: v => v + '%' } }
584
- }
585
- }
586
- });
587
- }
588
-
589
- document.addEventListener('DOMContentLoaded', () => {
590
- applyChartDefaults();
591
- renderQuiz();
592
- // Auto-run analysis from saved portfolio
593
- const portfolio = getPortfolio();
594
- const riskScore = calcRiskScore(portfolio);
595
- const deg = -90 + (riskScore/100)*180;
596
- setTimeout(() => {
597
- document.getElementById('gauge-needle').style.transform = `rotate(${deg}deg)`;
598
- document.getElementById('gauge-score').textContent = riskScore;
599
- const rIdx = Math.floor(riskScore/25);
600
- const badge = document.getElementById('gauge-badge');
601
- badge.className = 'badge ' + ['badge-emerald','badge-cyan','badge-amber','badge-amber','badge-rose'][rIdx];
602
- badge.textContent = ['Low Risk','Moderate-Low','Moderate','Moderate-High','High Risk'][rIdx];
603
- const equityPct = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0);
604
- const safePct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
605
- const maxPct = Math.max(...portfolio.assets.map(a=>a.pct));
606
- document.getElementById('rb-div').textContent = calcDiversification(portfolio) + '%';
607
- document.getElementById('rb-concentrate').textContent = maxPct + '%';
608
- document.getElementById('rb-equity').textContent = equityPct + '%';
609
- document.getElementById('rb-safe').textContent = safePct + '%';
610
- renderRebalSuggestions(portfolio, riskScore, equityPct);
611
- renderVolatility(portfolio);
612
- renderScenarios(portfolio);
613
- renderTypeChart(portfolio);
614
- }, 400);
615
- });
616
- </script>
617
- </body>
618
- </html>