{"spec_id":"renko-basic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// renko-basic: Basic Renko Chart\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-09-02\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: synthetic daily closing prices (deterministic LCG) --------------\nfunction lcg(seed) {\n  let state = seed;\n  return () => {\n    state = (state * 1103515245 + 12345) & 0x7fffffff;\n    return state / 0x7fffffff;\n  };\n}\nconst rand = lcg(42);\n\n// Trending segments (up / pullback / up / correction / recovery) so the\n// resulting bricks show clear runs and reversals, not just noise.\nconst segments = [\n  { steps: 45, drift: 0.9 },\n  { steps: 35, drift: -0.75 },\n  { steps: 50, drift: 0.55 },\n  { steps: 40, drift: -1.05 },\n  { steps: 50, drift: 0.85 },\n];\nconst closingPrices = [150];\nfor (const seg of segments) {\n  for (let i = 0; i < seg.steps; i++) {\n    const noise = (rand() - 0.5) * 2.2;\n    closingPrices.push(closingPrices[closingPrices.length - 1] + seg.drift + noise);\n  }\n}\n\n// --- Renko bricks: fixed price step, direction reverses on trend change ----\nconst brickSize = 4;\nconst bricks = [];\nlet basePrice = closingPrices[0];\nfor (let i = 1; i < closingPrices.length; i++) {\n  const diff = closingPrices[i] - basePrice;\n  const stepsUp = Math.floor(diff / brickSize);\n  const stepsDown = Math.floor(-diff / brickSize);\n  if (stepsUp >= 1) {\n    for (let b = 0; b < stepsUp; b++) {\n      bricks.push({ direction: \"up\", low: basePrice });\n      basePrice += brickSize;\n    }\n  } else if (stepsDown >= 1) {\n    for (let b = 0; b < stepsDown; b++) {\n      basePrice -= brickSize;\n      bricks.push({ direction: \"down\", low: basePrice });\n    }\n  }\n}\n\nconst yMin = Math.floor((Math.min(...bricks.map((b) => b.low)) - brickSize) / brickSize) * brickSize;\nconst yMax = Math.ceil((Math.max(...bricks.map((b) => b.low)) + brickSize) / brickSize) * brickSize;\n\n// --- Chart -------------------------------------------------------------\n// Bricks are drawn as independent rects positioned via axis.toPixels() from\n// a chart.events.render hook, rather than via a stacked-column series: core\n// Highcharts has no columnrange/candlestick series (those live in the\n// highcharts-more / stock modules, which aren't loaded), and simulating a\n// floating bar with an invisible stacked base column breaks once the yAxis\n// min sits far from the stack threshold (0). Drawing directly with the SVG\n// renderer sidesteps that and gives exact control over each brick's [low, high].\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"column\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    events: {\n      render() {\n        const chart = this;\n        const xAxis = chart.xAxis[0];\n        const yAxis = chart.yAxis[0];\n        if (chart.renkoGroup) chart.renkoGroup.destroy();\n        const group = chart.renderer.g(\"renko-bricks\").add();\n        const colStep = xAxis.toPixels(2) - xAxis.toPixels(1);\n        const colWidth = Math.abs(colStep) * 0.78;\n        bricks.forEach((brick, i) => {\n          const xCenter = xAxis.toPixels(i + 1);\n          const yTop = yAxis.toPixels(brick.low + brickSize);\n          const yBottom = yAxis.toPixels(brick.low);\n          chart.renderer\n            .rect(xCenter - colWidth / 2, yTop, colWidth, Math.abs(yBottom - yTop), 2)\n            .attr({ fill: brick.direction === \"up\" ? t.palette[0] : t.palette[4] })\n            .add(group);\n        });\n        chart.renkoGroup = group;\n      },\n    },\n  },\n  credits: { enabled: false },\n  title: {\n    text: \"renko-basic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: `Brick size: $${brickSize.toFixed(2)} · ${bricks.length} bricks`,\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    min: 0.5,\n    max: bricks.length + 0.5,\n    tickInterval: Math.ceil(bricks.length / 18),\n    title: { text: \"Brick Sequence\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    min: yMin,\n    max: yMax,\n    title: { text: \"Price ($)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  plotOptions: {\n    series: { animation: false, enableMouseTracking: false },\n  },\n  series: [\n    { name: \"Bullish\", type: \"column\", data: [], color: t.palette[0] },\n    { name: \"Bearish\", type: \"column\", data: [], color: t.palette[4] },\n  ],\n});\n"}