{"spec_id":"candlestick-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ncandlestick-basic: Basic Candlestick Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.collections import PatchCollection\nfrom matplotlib.lines import Line2D\nfrom matplotlib.patches import Patch, Rectangle\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\n# Theme-adaptive chrome tokens\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 palette — finance semantic exception: profit/up→green, loss/down→red\nBULLISH_COLOR = \"#009E73\"  # Imprint position 1 (brand green)\nBEARISH_COLOR = \"#AE3030\"  # Imprint position 5 (matte red)\nBB_COLOR = \"#4467A3\"  # Imprint position 3 (blue) — Bollinger Bands\n\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data — 30 trading days: rally phase then reversal/selloff\nnp.random.seed(42)\nn_days = 30\ndates = pd.date_range(\"2024-01-02\", periods=n_days, freq=\"B\")\n\nprice = 145.0\ndrift = np.concatenate(\n    [\n        np.linspace(0.4, 0.8, 12),  # Uptrend phase\n        np.linspace(-0.1, -0.6, 18),  # Reversal and selloff\n    ]\n)\nopens, highs, lows, closes = [], [], [], []\nfor i in range(n_days):\n    change = drift[i] + np.random.randn() * 2.5\n    volatility = abs(np.random.randn()) * 1.5 + 0.8\n    open_price = price\n    close_price = price + change\n    high_price = max(open_price, close_price) + abs(np.random.randn()) * volatility\n    low_price = min(open_price, close_price) - abs(np.random.randn()) * volatility\n    opens.append(open_price)\n    highs.append(high_price)\n    lows.append(low_price)\n    closes.append(close_price)\n    price = close_price\n\ndf = pd.DataFrame({\"date\": dates, \"open\": opens, \"high\": highs, \"low\": lows, \"close\": closes})\ndf[\"bullish\"] = df[\"close\"] >= df[\"open\"]\ndf[\"x\"] = range(n_days)\n\n# Bollinger Bands: 20-day SMA ± 2σ\nwindow = 20\ndf[\"sma20\"] = df[\"close\"].rolling(window=window).mean()\ndf[\"std20\"] = df[\"close\"].rolling(window=window).std()\ndf[\"bb_upper\"] = df[\"sma20\"] + 2 * df[\"std20\"]\ndf[\"bb_lower\"] = df[\"sma20\"] - 2 * df[\"std20\"]\n\n# Canvas: 3200×1800 px (landscape 16:9)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\n\n# Wicks (high-low range)\nwick_colors = [BULLISH_COLOR if b else BEARISH_COLOR for b in df[\"bullish\"]]\nax.vlines(df[\"x\"], df[\"low\"], df[\"high\"], colors=wick_colors, linewidth=0.8, alpha=0.8)\n\n# Candle bodies (open-close range)\nbody_width = 0.6\nrects, fcolors = [], []\nfor _, row in df.iterrows():\n    body_lo = min(row[\"open\"], row[\"close\"])\n    body_hi = max(row[\"open\"], row[\"close\"])\n    height = max(body_hi - body_lo, 0.15)\n    if body_hi - body_lo < 0.15:\n        body_lo = (row[\"open\"] + row[\"close\"]) / 2 - 0.075\n    rects.append(Rectangle((row[\"x\"] - body_width / 2, body_lo), body_width, height))\n    fcolors.append(BULLISH_COLOR if row[\"bullish\"] else BEARISH_COLOR)\n\nbodies = PatchCollection(rects, facecolors=fcolors, edgecolors=fcolors, linewidths=0.4, alpha=0.9)\nax.add_collection(bodies)\n\n# Bollinger Bands overlay via seaborn lineplot\nbb_valid = df.dropna(subset=[\"sma20\"])\nsns.lineplot(data=bb_valid, x=\"x\", y=\"sma20\", color=BB_COLOR, linewidth=1.8, ax=ax, legend=False)\nsns.lineplot(\n    data=bb_valid, x=\"x\", y=\"bb_upper\", color=BB_COLOR, linewidth=1.0, linestyle=\"--\", alpha=0.65, ax=ax, legend=False\n)\nsns.lineplot(\n    data=bb_valid, x=\"x\", y=\"bb_lower\", color=BB_COLOR, linewidth=1.0, linestyle=\"--\", alpha=0.65, ax=ax, legend=False\n)\nax.fill_between(bb_valid[\"x\"], bb_valid[\"bb_lower\"], bb_valid[\"bb_upper\"], color=BB_COLOR, alpha=0.06)\n\n# X-axis date ticks\ntick_positions = list(range(0, n_days, 5))\nax.set_xticks(tick_positions)\nax.set_xticklabels([dates[i].strftime(\"%b %d\") for i in tick_positions])\n\nax.set_xlabel(\"Date\", fontsize=10)\nax.set_ylabel(\"Price ($)\", fontsize=10)\nax.set_title(\"candlestick-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", pad=12)\nax.tick_params(axis=\"both\", labelsize=8, length=0)\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\n\nax.yaxis.grid(True, alpha=0.15, linewidth=0.7, color=INK)\nax.xaxis.grid(False)\nax.set_axisbelow(True)\n\nlegend_handles = [\n    Patch(facecolor=BULLISH_COLOR, edgecolor=BULLISH_COLOR, alpha=0.9, label=\"Bullish\"),\n    Patch(facecolor=BEARISH_COLOR, edgecolor=BEARISH_COLOR, alpha=0.9, label=\"Bearish\"),\n    Line2D([0], [0], color=BB_COLOR, linewidth=1.8, label=\"SMA 20\"),\n    Line2D([0], [0], color=BB_COLOR, linewidth=1.0, linestyle=\"--\", alpha=0.65, label=\"BB ±2σ\"),\n]\nax.legend(\n    handles=legend_handles,\n    fontsize=8,\n    loc=\"upper right\",\n    framealpha=0.9,\n    edgecolor=INK_SOFT,\n    facecolor=ELEVATED_BG,\n    labelcolor=INK,\n)\n\nax.set_xlim(-0.8, n_days - 0.2)\ny_range = df[\"high\"].max() - df[\"low\"].min()\ny_pad = y_range * 0.06\nax.set_ylim(df[\"low\"].min() - y_pad, df[\"high\"].max() + y_pad * 3.0)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\nplt.close()\n"}