{"spec_id":"drawdown-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// drawdown-basic: Drawdown Chart\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-08-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic fixed-seed LCG) -------------------------\nlet seed = 42;\nfunction nextUniform() {\n  seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n  return seed / 0x7fffffff;\n}\nfunction nextGaussian() {\n  const u1 = Math.max(nextUniform(), 1e-9);\n  const u2 = nextUniform();\n  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\nconst TRADING_DAYS = 504; // ~2 years of daily data\nconst DRIFT = 0.00035; // ~9%/yr annualized\nconst VOLATILITY = 0.011; // ~17.5%/yr annualized\n\nconst dates = [];\nconst cursor = new Date(2024, 0, 2);\nwhile (dates.length < TRADING_DAYS) {\n  const weekday = cursor.getDay();\n  if (weekday !== 0 && weekday !== 6) dates.push(new Date(cursor));\n  cursor.setDate(cursor.getDate() + 1);\n}\n\nconst portfolioValue = [100];\nfor (let i = 1; i < TRADING_DAYS; i++) {\n  const dailyReturn = DRIFT + VOLATILITY * nextGaussian();\n  portfolioValue.push(portfolioValue[i - 1] * (1 + dailyReturn));\n}\n\nconst runningMax = [];\nconst drawdown = [];\nlet peak = portfolioValue[0];\nfor (let i = 0; i < TRADING_DAYS; i++) {\n  peak = Math.max(peak, portfolioValue[i]);\n  runningMax.push(peak);\n  drawdown.push(((portfolioValue[i] - peak) / peak) * 100);\n}\n\nlet troughIndex = 0;\nfor (let i = 1; i < TRADING_DAYS; i++) {\n  if (drawdown[i] < drawdown[troughIndex]) troughIndex = i;\n}\nlet peakIndex = troughIndex;\nwhile (peakIndex > 0 && drawdown[peakIndex] < -1e-9) peakIndex--;\nlet recoveryIndex = -1;\nfor (let i = troughIndex + 1; i < TRADING_DAYS; i++) {\n  if (drawdown[i] >= -1e-9) {\n    recoveryIndex = i;\n    break;\n  }\n}\n\nconst durationDays = troughIndex - peakIndex;\nconst recoveryText =\n  recoveryIndex === -1\n    ? \"not yet recovered\"\n    : `recovered in ${recoveryIndex - troughIndex} trading days`;\nconst subtitleText = `Max drawdown ${drawdown[troughIndex].toFixed(1)}% · ${durationDays} trading days to trough · ${recoveryText}`;\n\nconst monthNames = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nconst labels = dates.map((d) => `${monthNames[d.getMonth()]} ${d.getFullYear()}`);\n\nconst maxDrawdownPoint = drawdown.map((v, i) => (i === troughIndex ? v : null));\nconst recoveryPoint = drawdown.map((v, i) => (i === recoveryIndex ? v : null));\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart ---------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"line\",\n  data: {\n    labels,\n    datasets: [\n      {\n        label: \"Portfolio Value\",\n        data: portfolioValue,\n        borderColor: t.inkSoft,\n        backgroundColor: \"transparent\",\n        borderWidth: 1.5,\n        pointRadius: 0,\n        tension: 0,\n        fill: false,\n        yAxisID: \"y1\",\n        order: 0,\n      },\n      {\n        label: \"Drawdown\",\n        data: drawdown,\n        borderColor: t.palette[4],\n        backgroundColor: `${t.palette[4]}33`,\n        borderWidth: 2.5,\n        pointRadius: 0,\n        tension: 0,\n        fill: \"origin\",\n        yAxisID: \"y\",\n        order: 1,\n      },\n      {\n        label: \"Max Drawdown\",\n        data: maxDrawdownPoint,\n        borderColor: \"transparent\",\n        backgroundColor: t.amber,\n        pointRadius: 8,\n        pointBorderColor: t.ink,\n        pointBorderWidth: 1.5,\n        pointStyle: \"rectRot\",\n        showLine: false,\n        yAxisID: \"y\",\n        order: 2,\n      },\n      {\n        label: \"Recovery\",\n        data: recoveryPoint,\n        borderColor: \"transparent\",\n        backgroundColor: t.palette[0],\n        pointRadius: 8,\n        pointBorderColor: t.ink,\n        pointBorderWidth: 1.5,\n        pointStyle: \"circle\",\n        showLine: false,\n        yAxisID: \"y\",\n        order: 2,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    interaction: { mode: \"nearest\", intersect: false },\n    plugins: {\n      title: {\n        display: true,\n        text: \"drawdown-basic · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 38, weight: \"500\" },\n        padding: { bottom: 10 },\n      },\n      subtitle: {\n        display: true,\n        text: subtitleText,\n        color: t.inkSoft,\n        font: { size: 22 },\n        padding: { bottom: 20 },\n      },\n      legend: {\n        labels: { color: t.ink, font: { size: 21 }, usePointStyle: true, boxWidth: 14 },\n      },\n    },\n    scales: {\n      x: {\n        ticks: { color: t.inkSoft, font: { size: 20 }, maxTicksLimit: 10, autoSkip: true },\n        grid: { display: false },\n        title: { display: true, text: \"Date\", color: t.ink, font: { size: 22 } },\n      },\n      y: {\n        position: \"left\",\n        max: 0,\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 20 },\n          callback: (value) => `${value}%`,\n        },\n        grid: { color: t.grid },\n        title: { display: true, text: \"Drawdown (%)\", color: t.ink, font: { size: 22 } },\n      },\n      y1: {\n        position: \"right\",\n        ticks: { color: t.inkSoft, font: { size: 20 } },\n        grid: { display: false },\n        title: { display: true, text: \"Portfolio Value\", color: t.ink, font: { size: 22 } },\n      },\n    },\n  },\n});\n"}