{"spec_id":"renko-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nrenko-basic: Basic Renko Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\nnp.random.seed(42)\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# imprint semantic anchors: bullish (up) uses #009E73 green, bearish (down) uses #AE3030 red\nBULLISH = \"#009E73\"  # Okabe-Ito position 1 (brand green)\nBEARISH = \"#AE3030\"  # imprint red — bearish\n\n# Generate synthetic stock price data (6 months of daily closes)\nn_days = 180\ninitial_price = 100\nreturns = np.random.normal(0.001, 0.02, n_days)\nprices = initial_price * np.cumprod(1 + returns)\n\n# Renko brick calculation\nbrick_size = 2.0\n\n# Build Renko bricks from price data\nbricks = []\ncurrent_brick_price = round(prices[0] / brick_size) * brick_size\ndirection = None\n\nfor price in prices:\n    while True:\n        if direction is None:\n            if price >= current_brick_price + brick_size:\n                bricks.append({\"price\": current_brick_price, \"direction\": \"up\"})\n                current_brick_price += brick_size\n                direction = \"up\"\n            elif price <= current_brick_price - brick_size:\n                bricks.append({\"price\": current_brick_price - brick_size, \"direction\": \"down\"})\n                current_brick_price -= brick_size\n                direction = \"down\"\n            else:\n                break\n        elif direction == \"up\":\n            if price >= current_brick_price + brick_size:\n                bricks.append({\"price\": current_brick_price, \"direction\": \"up\"})\n                current_brick_price += brick_size\n            elif price <= current_brick_price - 2 * brick_size:\n                current_brick_price -= brick_size\n                bricks.append({\"price\": current_brick_price - brick_size, \"direction\": \"down\"})\n                current_brick_price -= brick_size\n                direction = \"down\"\n            else:\n                break\n        else:\n            if price <= current_brick_price - brick_size:\n                bricks.append({\"price\": current_brick_price - brick_size, \"direction\": \"down\"})\n                current_brick_price -= brick_size\n            elif price >= current_brick_price + 2 * brick_size:\n                current_brick_price += brick_size\n                bricks.append({\"price\": current_brick_price, \"direction\": \"up\"})\n                current_brick_price += brick_size\n                direction = \"up\"\n            else:\n                break\n\nbricks = bricks[:40] if len(bricks) > 40 else bricks\n\n# Calculate price range\nmin_price = min(b[\"price\"] for b in bricks)\nmax_price = max(b[\"price\"] for b in bricks) + brick_size\ny_min = min_price - brick_size\ny_max = max_price + brick_size\n\n# Custom style with theme-adaptive colors\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=(PAGE_BG, BULLISH, BEARISH),  # Spacer (invisible), Bullish, Bearish\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\n# Create chart\nchart = pygal.StackedBar(\n    width=4800,\n    height=2700,\n    title=\"renko-basic · pygal · anyplot.ai\",\n    x_title=\"Brick Index\",\n    y_title=\"Price ($)\",\n    style=custom_style,\n    show_legend=True,\n    legend_at_bottom=True,\n    show_y_guides=True,\n    show_x_guides=False,\n    print_values=False,\n    spacing=6,\n)\n\n# Set x-axis labels (show every 5th index)\nchart.x_labels = [str(i) if i % 5 == 0 else \"\" for i in range(len(bricks))]\n\n# Create y-axis labels with actual price values\ny_labels = []\nfor y in range(int(y_min), int(y_max) + 1, int(brick_size * 2)):\n    y_labels.append(f\"${y}\")\nchart.y_labels = y_labels\n\n# Build data for stacked bar representation\nspacer_values = []\nup_values = []\ndown_values = []\n\nfor brick in bricks:\n    spacer_height = brick[\"price\"] - y_min\n    spacer_values.append(spacer_height)\n\n    if brick[\"direction\"] == \"up\":\n        up_values.append(brick_size)\n        down_values.append(None)\n    else:\n        up_values.append(None)\n        down_values.append(brick_size)\n\n# Add series (spacer is invisible, then bullish and bearish)\nchart.add(\"\", spacer_values)\nchart.add(\"Bullish (Up)\", up_values)\nchart.add(\"Bearish (Down)\", down_values)\n\n# Save outputs\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}