{"spec_id":"ohlc-bar","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nohlc-bar: OHLC Bar Chart\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport matplotlib.dates as mdates\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom matplotlib.lines import Line2D\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# imprint semantic anchors\nCOLOR_UP = \"#009E73\"  # green — up bars\nCOLOR_DOWN = \"#AE3030\"  # red — down bars\n\n# Data - Generate 45 trading days of synthetic stock OHLC data\nnp.random.seed(42)\nn_days = 45\n\n# Start from a base price and simulate random walk with some trend\nbase_price = 150.0\ndates = pd.bdate_range(start=\"2024-06-01\", periods=n_days)\n\n# Generate price movements\nreturns = np.random.normal(0.001, 0.02, n_days)  # Daily returns with slight upward bias\ncumulative_returns = np.cumprod(1 + returns)\nclose_prices = base_price * cumulative_returns\n\n# Generate OHLC data with realistic intraday ranges\nhigh_add = np.random.uniform(0.5, 3.0, n_days)\nlow_sub = np.random.uniform(0.5, 3.0, n_days)\n\n# Open is close of previous day (with small gap)\nopen_prices = np.roll(close_prices, 1) * (1 + np.random.uniform(-0.005, 0.005, n_days))\nopen_prices[0] = base_price\n\n# High and low must encompass open and close\nhigh_prices = np.maximum(open_prices, close_prices) + high_add\nlow_prices = np.minimum(open_prices, close_prices) - low_sub\n\n# Create DataFrame\ndf = pd.DataFrame({\"date\": dates, \"open\": open_prices, \"high\": high_prices, \"low\": low_prices, \"close\": close_prices})\n\n# Plot\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Draw OHLC bars\ntick_width = 0.4  # Width of open/close ticks in days\nline_width = 2.0\n\nfor _idx, row in df.iterrows():\n    date_num = mdates.date2num(row[\"date\"])\n\n    # Determine color based on price direction\n    color = COLOR_UP if row[\"close\"] >= row[\"open\"] else COLOR_DOWN\n\n    # Draw high-low vertical line\n    ax.plot([date_num, date_num], [row[\"low\"], row[\"high\"]], color=color, linewidth=line_width, solid_capstyle=\"round\")\n\n    # Draw open tick (left side)\n    ax.plot(\n        [date_num - tick_width, date_num],\n        [row[\"open\"], row[\"open\"]],\n        color=color,\n        linewidth=line_width,\n        solid_capstyle=\"butt\",\n    )\n\n    # Draw close tick (right side)\n    ax.plot(\n        [date_num, date_num + tick_width],\n        [row[\"close\"], row[\"close\"]],\n        color=color,\n        linewidth=line_width,\n        solid_capstyle=\"butt\",\n    )\n\n# Style\nax.set_xlabel(\"Date\", fontsize=20, color=INK)\nax.set_ylabel(\"Price (USD)\", fontsize=20, color=INK)\nax.set_title(\"ohlc-bar · matplotlib · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Format x-axis dates\nax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MONDAY))\nax.xaxis.set_major_formatter(mdates.DateFormatter(\"%b %d\"))\nax.xaxis.set_minor_locator(mdates.DayLocator())\nfig.autofmt_xdate(rotation=45)\n\n# Spine styling\nfor spine in (\"top\", \"right\"):\n    ax.spines[spine].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax.spines[spine].set_color(INK_SOFT)\n\n# Grid for reading price levels\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\nax.xaxis.grid(True, alpha=0.08, linewidth=0.8, color=INK)\n\n# Add padding to y-axis\ny_min, y_max = ax.get_ylim()\ny_padding = (y_max - y_min) * 0.05\nax.set_ylim(y_min - y_padding, y_max + y_padding)\n\n# Add legend for up/down bars\nlegend_elements = [\n    Line2D([0], [0], color=COLOR_UP, linewidth=3, label=\"Up (Close ≥ Open)\"),\n    Line2D([0], [0], color=COLOR_DOWN, linewidth=3, label=\"Down (Close < Open)\"),\n]\nlegend = ax.legend(handles=legend_elements, fontsize=16, loc=\"upper left\")\nlegend.get_frame().set_facecolor(ELEVATED_BG)\nlegend.get_frame().set_edgecolor(INK_SOFT)\nfor text in legend.get_texts():\n    text.set_color(INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}