added rally-cycles

This commit is contained in:
2026-05-15 19:09:35 -04:00
parent e234bec1fc
commit 9c16217554
5 changed files with 627 additions and 17 deletions
+15 -14
View File
@@ -44,9 +44,12 @@ h2 { font-size: 0.95rem; color: #aaa; margin-bottom: 16px; text-align: center; f
</head>
<body>
<a href="index.html" class="back-link">&larr; Back to Monthly Returns</a>
<div class="nav-links">
<a href="index.html">&larr; Monthly Returns</a>
<a href="alltime-lows.html">Gains from ATL &rarr;</a>
</div>
<h1>Cumulative Returns & Drawdown Cycles</h1>
<p class="subtitle">Growth of $1 invested, with drawdown from all-time highs</p>
<p class="subtitle">Actual index values and drawdown from all-time highs</p>
<div class="controls">
<div class="control-group">
@@ -61,7 +64,7 @@ h2 { font-size: 0.95rem; color: #aaa; margin-bottom: 16px; text-align: center; f
</div>
<div class="chart-container">
<h2>Cumulative Return (Growth of $1)</h2>
<h2>Index Value Over Time</h2>
<div class="chart-wrapper">
<canvas id="cumulativeChart"></canvas>
</div>
@@ -101,32 +104,30 @@ function buildSeries(indexName) {
if (!raw) return { cumulative: [], drawdown: [], cycles: [] };
const sorted = [...raw].sort((a, b) => a[0] * 100 + a[1] - (b[0] * 100 + b[1]));
let cum = 1;
let ath = 1;
let ath = sorted[0][2];
let athDate = null;
const cumulative = [];
const drawdownSeries = [];
const cycles = [];
let currentCycle = null;
for (const [y, m, ret] of sorted) {
cum *= (1 + ret / 100);
for (const [y, m, price] of sorted) {
const date = new Date(y, m - 1, 1);
cumulative.push({ x: date, y: cum, year: y });
cumulative.push({ x: date, y: price, year: y });
if (cum > ath) {
if (price > ath) {
if (athDate && currentCycle) {
currentCycle.recoveryDate = date;
currentCycle.recoveryDuration = (y - currentCycle.troughYear) * 12 + (m - currentCycle.troughMonth);
cycles.push(currentCycle);
currentCycle = null;
}
ath = cum;
ath = price;
athDate = date;
}
const dd = ((cum - ath) / ath) * 100;
const dd = ((price - ath) / ath) * 100;
drawdownSeries.push({ x: date, y: dd, year: y });
if (dd < 0 && !currentCycle && athDate) {
@@ -138,9 +139,9 @@ function buildSeries(indexName) {
};
}
if (currentCycle && dd < ((currentCycle.troughValue || Infinity) - currentCycle.peakValue) / currentCycle.peakValue * 100) {
if (currentCycle && price < (currentCycle.troughValue || Infinity)) {
currentCycle.troughDate = date;
currentCycle.troughValue = cum;
currentCycle.troughValue = price;
currentCycle.troughYear = y;
currentCycle.troughMonth = m;
}
@@ -174,7 +175,7 @@ function updateCharts() {
type: 'line',
data: {
datasets: [{
label: c.label + ' (Growth of $1)',
label: c.label,
data: cumulative.map(p => ({ x: p.x, y: p.y })),
borderColor: c.border,
backgroundColor: c.bg,