{"spec_id":"indicator-ema","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// indicator-ema: Exponential Moving Average (EMA) Indicator Chart\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 86/100 | Created: 2026-09-02\n\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic fixed-seed LCG) -------------------------\nlet seed = 42;\nfunction rand() {\n  seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n  return seed / 0x7fffffff;\n}\n\nconst periods = 120;\nconst shortPeriod = 12;\nconst longPeriod = 26;\n\nconst dates = [];\nlet cursor = new Date(2024, 0, 2);\nwhile (dates.length < periods) {\n  const day = cursor.getDay();\n  if (day !== 0 && day !== 6) {\n    dates.push(new Date(cursor));\n  }\n  cursor.setDate(cursor.getDate() + 1);\n}\nconst labels = dates.map((d) => d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" }));\n\nconst close = [];\nlet price = 148;\nlet drift = 0.35;\nfor (let i = 0; i < periods; i++) {\n  if (i % 18 === 0) drift = (rand() - 0.45) * 1.4;\n  price += drift + (rand() - 0.5) * 3.2;\n  price = Math.max(price, 40);\n  close.push(price);\n}\n\nfunction ema(values, period) {\n  const alpha = 2 / (period + 1);\n  const out = [values[0]];\n  for (let i = 1; i < values.length; i++) {\n    out.push(values[i] * alpha + out[i - 1] * (1 - alpha));\n  }\n  return out;\n}\n\nconst emaShort = ema(close, shortPeriod);\nconst emaLong = ema(close, longPeriod);\n\n// Crossover markers on the short EMA line: bullish (golden cross) → brand\n// green, bearish (death cross) → matte red — the finance color convention.\nconst crossPointRadius = new Array(periods).fill(0);\nconst crossPointColor = new Array(periods).fill(\"rgba(0,0,0,0)\");\nfor (let i = 1; i < periods; i++) {\n  const prevDiff = emaShort[i - 1] - emaLong[i - 1];\n  const currDiff = emaShort[i] - emaLong[i];\n  if (prevDiff <= 0 && currDiff > 0) {\n    crossPointRadius[i] = 7;\n    crossPointColor[i] = t.palette[0];\n  } else if (prevDiff >= 0 && currDiff < 0) {\n    crossPointRadius[i] = 7;\n    crossPointColor[i] = t.palette[4];\n  }\n}\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: \"Close\",\n        data: close,\n        borderColor: t.ink,\n        backgroundColor: t.ink,\n        borderWidth: 3,\n        pointRadius: 0,\n        tension: 0,\n        order: 3,\n      },\n      {\n        label: `EMA ${longPeriod}`,\n        data: emaLong,\n        borderColor: t.palette[1],\n        backgroundColor: t.palette[1],\n        borderWidth: 2.2,\n        pointRadius: 0,\n        tension: 0.1,\n        order: 2,\n      },\n      {\n        label: `EMA ${shortPeriod}`,\n        data: emaShort,\n        borderColor: t.palette[0],\n        backgroundColor: t.palette[0],\n        borderWidth: 2.2,\n        tension: 0.1,\n        pointRadius: crossPointRadius,\n        pointBackgroundColor: crossPointColor,\n        pointBorderColor: t.pageBg,\n        pointBorderWidth: 2,\n        order: 1,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    interaction: { intersect: false, mode: \"index\" },\n    plugins: {\n      title: {\n        display: true,\n        text: \"indicator-ema · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22 },\n      },\n      legend: {\n        position: \"top\",\n        align: \"end\",\n        labels: { color: t.ink, font: { size: 16 }, boxWidth: 24, usePointStyle: true, pointStyle: \"line\" },\n      },\n    },\n    scales: {\n      x: {\n        ticks: { color: t.inkSoft, font: { size: 14 }, autoSkip: true, maxRotation: 0, maxTicksLimit: 10 },\n        grid: { display: false },\n        title: { display: true, text: \"Trading Date\", color: t.ink, font: { size: 16 } },\n      },\n      y: {\n        ticks: { color: t.inkSoft, font: { size: 14 }, callback: (v) => `$${v.toFixed(0)}` },\n        grid: { color: t.grid },\n        title: { display: true, text: \"Price (USD)\", color: t.ink, font: { size: 16 } },\n      },\n    },\n  },\n});\n"}