{"spec_id":"ohlc-bar","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nohlc-bar: OHLC Bar Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\nimport sys\n\nimport numpy as np\nimport pandas as pd\n\n\n# Work around file-name shadowing: temporarily remove current dir from path\n_cwd = sys.path[0] if sys.path and sys.path[0] == \"\" or sys.path[0] == \".\" else None\nif sys.path and (sys.path[0] == \"\" or sys.path[0] == \".\"):\n    sys.path.pop(0)\n_script_dir = os.path.dirname(os.path.abspath(__file__))\nwhile _script_dir in sys.path:\n    sys.path.remove(_script_dir)\n\nimport pygal\nfrom pygal.style import Style\n\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_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"  # Bullish (up bars)\nACCENT = \"#AE3030\"  # imprint red — bearish (down bars)\n\n# Data - Generate realistic stock price data with different seed/start than plotnine\nnp.random.seed(77)\nn_days = 45\n\n# Different starting price and return distribution\nstart_price = 185.0\n# Use exponential drift (trending upward) instead of simple normal returns\ndrift = 0.0005\nvolatility = 0.018\ndaily_returns = drift + np.random.normal(0, volatility, n_days)\n\n# Generate OHLC data\ndates = pd.date_range(\"2024-07-01\", periods=n_days, freq=\"B\")  # Business days\ncloses = start_price * np.cumprod(1 + daily_returns)\nopens = np.roll(closes, 1)\nopens[0] = start_price\n\n# Generate highs and lows based on volatility\ndaily_volatility = np.abs(np.random.normal(0.012, 0.006, n_days))\nhighs = np.maximum(opens, closes) * (1 + daily_volatility)\nlows = np.minimum(opens, closes) * (1 - daily_volatility)\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    guide_stroke_color=INK_MUTED,\n    opacity=\".95\",\n    opacity_hover=\".85\",\n    colors=(BRAND, ACCENT),\n    title_font_size=28,\n    label_font_size=18,\n    major_label_font_size=16,\n    legend_font_size=16,\n    value_font_size=14,\n    tooltip_font_size=14,\n    stroke_width=3,\n)\n\n# Create date labels for x-axis (every 5th date for clarity)\ndate_labels = {i: dates[i].strftime(\"%b %d\") for i in range(0, n_days, 5)}\n\n# Create XY chart\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"ohlc-bar · pygal · pyplots.ai\",\n    x_title=\"Date (Jul-Sep 2024)\",\n    y_title=\"Price ($)\",\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_box_size=20,\n    show_x_guides=False,\n    show_y_guides=True,\n    truncate_label=-1,\n    truncate_legend=-1,\n    stroke=True,\n    show_dots=False,\n    x_labels=list(date_labels.values()),\n    x_labels_major_every=1,\n)\n\n# Tick width for open/close marks\ntick_width = 0.4\n\n# Build OHLC bar segments\n# Each bar needs: vertical line (low to high), open tick (left), close tick (right)\nup_bars = []\ndown_bars = []\n\nfor i in range(n_days):\n    x = float(i)\n    o, h, lo, c = opens[i], highs[i], lows[i], closes[i]\n\n    # Each OHLC bar: vertical line + open tick + close tick\n    bar_points = [\n        # Vertical line (low to high)\n        (x, lo),\n        (x, h),\n        # Break\n        (None, None),\n        # Open tick (left horizontal)\n        (x - tick_width, o),\n        (x, o),\n        # Break\n        (None, None),\n        # Close tick (right horizontal)\n        (x, c),\n        (x + tick_width, c),\n        # Break for next bar\n        (None, None),\n    ]\n\n    if c >= o:  # Up bar (bullish)\n        up_bars.extend(bar_points)\n    else:  # Down bar (bearish)\n        down_bars.extend(bar_points)\n\n# Add series with descriptive labels\nchart.add(\"Bullish (Close ≥ Open)\", up_bars)\nchart.add(\"Bearish (Close < Open)\", down_bars)\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"}