{"spec_id":"drawdown-basic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// drawdown-basic: Drawdown Chart\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-08-24\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Tiny fixed-seed LCG — the browser has no seeded RNG.\nlet seed = 20260824;\nfunction lcgRandom() {\n  seed = (seed * 1103515245 + 12345) % 2147483648;\n  return seed / 2147483648;\n}\nfunction gaussian() {\n  const u1 = lcgRandom() || 1e-6;\n  const u2 = lcgRandom();\n  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\nconst numDays = 756; // ~3 years of trading days\nconst startDate = Date.UTC(2023, 0, 3);\nconst dates = [];\nconst navValues = [];\nlet nav = 100000;\nfor (let i = 0; i < numDays; i += 1) {\n  dates.push(startDate + i * 24 * 3600 * 1000);\n  const drift = 0.00035;\n  const shock = gaussian() * 0.011;\n  nav *= 1 + drift + shock;\n  navValues.push(nav);\n}\n\n// Drawdown as % decline from running maximum.\nconst drawdownPoints = [];\nconst recoveryPoints = [];\nlet runningMax = navValues[0];\nlet runningMaxIndex = 0;\nlet maxDrawdown = 0;\nlet maxDrawdownIndex = 0;\nlet maxDrawdownPeakIndex = 0;\nlet inDrawdown = false;\nfor (let i = 0; i < navValues.length; i += 1) {\n  if (navValues[i] >= runningMax) {\n    if (inDrawdown) {\n      recoveryPoints.push([dates[i], 0]);\n      inDrawdown = false;\n    }\n    runningMax = navValues[i];\n    runningMaxIndex = i;\n  } else {\n    inDrawdown = true;\n  }\n  const drawdown = ((navValues[i] - runningMax) / runningMax) * 100;\n  drawdownPoints.push([dates[i], drawdown]);\n  if (drawdown < maxDrawdown) {\n    maxDrawdown = drawdown;\n    maxDrawdownIndex = i;\n    maxDrawdownPeakIndex = runningMaxIndex;\n  }\n}\n\n// Duration/recovery stats for the deepest drawdown episode.\nlet maxDrawdownRecoveryIndex = null;\nfor (let i = maxDrawdownIndex + 1; i < navValues.length; i += 1) {\n  if (drawdownPoints[i][1] === 0) {\n    maxDrawdownRecoveryIndex = i;\n    break;\n  }\n}\nconst maxDrawdownDurationDays = maxDrawdownIndex - maxDrawdownPeakIndex;\nconst recoveryLabel =\n  maxDrawdownRecoveryIndex !== null\n    ? `Recovery: ${maxDrawdownRecoveryIndex - maxDrawdownIndex}d`\n    : \"Recovery: not yet recovered\";\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"area\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"drawdown-basic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"25px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: `Max drawdown ${maxDrawdown.toFixed(1)}% on ${new Date(dates[maxDrawdownIndex]).toISOString().slice(0, 10)} · Duration: ${maxDrawdownDurationDays}d · ${recoveryLabel}`,\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    type: \"datetime\",\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    title: { text: \"Trading Date\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n  },\n  yAxis: {\n    max: 0,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    labels: {\n      style: { color: t.inkSoft, fontSize: \"14px\" },\n      formatter() {\n        return `${this.value}%`;\n      },\n    },\n    title: { text: \"Drawdown from Peak\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    plotLines: [\n      {\n        value: 0,\n        color: t.inkSoft,\n        width: 1.5,\n        zIndex: 3,\n      },\n    ],\n  },\n  legend: { enabled: false },\n  tooltip: {\n    xDateFormat: \"%Y-%m-%d\",\n    valueDecimals: 2,\n    valueSuffix: \"%\",\n  },\n  plotOptions: {\n    series: { animation: false },\n    area: {\n      lineWidth: 2.5,\n      color: t.palette[4],\n      fillColor: {\n        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },\n        stops: [\n          [0, Highcharts.color(t.palette[4]).setOpacity(0.5).get(\"rgba\")],\n          [1, Highcharts.color(t.palette[4]).setOpacity(0.08).get(\"rgba\")],\n        ],\n      },\n      marker: { enabled: false, states: { hover: { enabled: false } } },\n      threshold: 0,\n    },\n  },\n  series: [\n    {\n      name: \"Drawdown\",\n      data: drawdownPoints,\n      zIndex: 1,\n    },\n    {\n      type: \"scatter\",\n      name: \"Maximum drawdown\",\n      data: [[dates[maxDrawdownIndex], maxDrawdown]],\n      color: t.ink,\n      marker: { symbol: \"circle\", radius: 6, lineWidth: 1.5, lineColor: t.pageBg },\n      dataLabels: {\n        enabled: true,\n        format: `Max DD: ${maxDrawdown.toFixed(1)}%`,\n        style: { color: t.ink, fontSize: \"14px\", fontWeight: \"600\", textOutline: \"none\" },\n        y: -14,\n      },\n      zIndex: 2,\n      enableMouseTracking: true,\n    },\n    {\n      type: \"scatter\",\n      name: \"Recovery point\",\n      data: recoveryPoints,\n      color: t.palette[0],\n      marker: { symbol: \"diamond\", radius: 5, lineWidth: 1.5, lineColor: t.pageBg },\n      zIndex: 2,\n      enableMouseTracking: true,\n    },\n  ],\n});\n"}