{"spec_id":"indicator-macd","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// indicator-macd: MACD Technical Indicator Chart\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 94/100 | Created: 2026-09-05\n\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\nfunction lcg(seed) {\n  let state = seed;\n  return () => {\n    state = (state * 1103515245 + 12345) % 2147483648;\n    return state / 2147483648;\n  };\n}\nconst random = lcg(42);\n\nconst periods = 150;\nconst startDate = Date.UTC(2025, 5, 1);\nconst dayMs = 24 * 60 * 60 * 1000;\n\n// Simulated daily closing price: cyclical drift + noise, deterministic\nconst closingPrices = [];\nlet price = 150;\nfor (let i = 0; i < periods; i++) {\n  const drift = 0.15 * Math.sin(i / 18);\n  const noise = (random() - 0.5) * 2.2;\n  price += drift + noise;\n  closingPrices.push(price);\n}\n\n// EMA seeded with the SMA of the first `period` values, standard MACD practice\nfunction ema(values, period) {\n  const k = 2 / (period + 1);\n  const out = new Array(values.length).fill(null);\n  let sum = 0;\n  for (let i = 0; i < period; i++) sum += values[i];\n  let prev = sum / period;\n  out[period - 1] = prev;\n  for (let i = period; i < values.length; i++) {\n    prev = values[i] * k + prev * (1 - k);\n    out[i] = prev;\n  }\n  return out;\n}\n\nconst ema12 = ema(closingPrices, 12);\nconst ema26 = ema(closingPrices, 26);\n\n// MACD line starts once the slower 26-day EMA is defined\nconst macdValues = [];\nfor (let i = 25; i < periods; i++) {\n  macdValues.push(ema12[i] - ema26[i]);\n}\nconst signalValues = ema(macdValues, 9);\n\nconst macdSeries = [];\nconst signalSeries = [];\nconst histogramSeries = [];\nfor (let j = 0; j < macdValues.length; j++) {\n  const timestamp = startDate + (25 + j) * dayMs;\n  macdSeries.push([timestamp, macdValues[j]]);\n  if (signalValues[j] !== null) {\n    signalSeries.push([timestamp, signalValues[j]]);\n    histogramSeries.push([timestamp, macdValues[j] - signalValues[j]]);\n  }\n}\n\n// Find the deepest bearish stretch (the contiguous run of negative histogram\n// bars around the global minimum) and shade it; the bar right after it is,\n// by construction, the bullish crossover that ends the stretch — call it out.\nlet troughIdx = 0;\nfor (let k = 1; k < histogramSeries.length; k++) {\n  if (histogramSeries[k][1] < histogramSeries[troughIdx][1]) troughIdx = k;\n}\nlet bearStart = troughIdx;\nwhile (bearStart > 0 && histogramSeries[bearStart - 1][1] < 0) bearStart--;\nlet bearEnd = troughIdx;\nwhile (\n  bearEnd < histogramSeries.length - 1 &&\n  histogramSeries[bearEnd + 1][1] < 0\n)\n  bearEnd++;\nconst bearBandFrom = histogramSeries[bearStart][0];\nconst bearBandTo = histogramSeries[bearEnd][0];\n\nconst crossoverIdx = bearEnd + 1;\nconst crossoverPoint =\n  crossoverIdx < histogramSeries.length && histogramSeries[crossoverIdx][1] >= 0\n    ? {\n        x: histogramSeries[crossoverIdx][0],\n        y: signalSeries[crossoverIdx][1] + histogramSeries[crossoverIdx][1],\n      }\n    : null;\nconst mutedMacdColor = Highcharts.color(t.palette[2]).setOpacity(0.35).get();\n\n// --- Chart -----------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"indicator-macd · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"12/26/9 EMA parameters\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    type: \"datetime\",\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    plotBands: [\n      {\n        from: bearBandFrom,\n        to: bearBandTo,\n        color: Highcharts.color(t.palette[4]).setOpacity(0.1).get(),\n        zIndex: 0,\n      },\n    ],\n  },\n  yAxis: {\n    title: {\n      text: \"MACD Value\",\n      style: { color: t.inkSoft, fontSize: \"16px\" },\n    },\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    plotLines: [\n      { value: 0, color: t.inkSoft, width: 1.5, dashStyle: \"Dash\", zIndex: 3 },\n    ],\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  plotOptions: {\n    series: { animation: false },\n    column: { borderWidth: 0, pointPadding: 0.05, groupPadding: 0 },\n    line: { lineWidth: 2.5, marker: { enabled: false } },\n  },\n  series: [\n    {\n      type: \"column\",\n      name: \"Histogram\",\n      data: histogramSeries,\n      color: t.palette[0],\n      negativeColor: t.palette[4],\n    },\n    {\n      type: \"line\",\n      name: \"MACD Line\",\n      data: macdSeries,\n      color: t.palette[2],\n      zoneAxis: \"x\",\n      zones: [\n        { value: bearBandFrom, color: t.palette[2] },\n        { value: bearBandTo, color: mutedMacdColor },\n        { color: t.palette[2] },\n      ],\n    },\n    {\n      type: \"line\",\n      name: \"Signal Line\",\n      data: signalSeries,\n      color: t.palette[3],\n    },\n    ...(crossoverPoint\n      ? [\n          {\n            type: \"scatter\",\n            name: \"Bullish Crossover\",\n            data: [crossoverPoint],\n            color: t.ink,\n            marker: {\n              symbol: \"diamond\",\n              radius: 7,\n              lineWidth: 1.5,\n              lineColor: t.pageBg,\n            },\n            dataLabels: {\n              enabled: true,\n              format: \"Bullish crossover\",\n              align: \"left\",\n              x: 10,\n              y: -12,\n              style: {\n                color: t.ink,\n                fontSize: \"13px\",\n                fontWeight: \"600\",\n                textOutline: \"none\",\n              },\n            },\n            enableMouseTracking: false,\n            showInLegend: false,\n          },\n        ]\n      : []),\n  ],\n});\n"}