{"spec_id":"depth-order-book","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\ndepth-order-book: Order Book Depth Chart\nLibrary: plotnine 0.15.7 | Python 3.13.13\nQuality: 88/100 | Created: 2026-06-15\n\"\"\"\n\nimport os\nimport sys\n\n\nsys.path = [p for p in sys.path if os.path.abspath(p) != os.getcwd()]\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    coord_cartesian,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_line,\n    geom_ribbon,\n    geom_vline,\n    ggplot,\n    labs,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — semantic: green=bids (buy), red=asks (sell)\nBID_COLOR = \"#009E73\"  # Imprint position 1 — first series; green for bid/buy pressure\nASK_COLOR = \"#AE3030\"  # Imprint position 5 — semantic anchor for loss/sell pressure\n\n# Data — synthetic BTC/USD order book snapshot\nnp.random.seed(42)\nmid_price = 60_000.0\nspread = 12.0\nn_levels = 50\n\nbest_bid = mid_price - spread / 2  # 59994.0\nbest_ask = mid_price + spread / 2  # 60006.0\n\nbid_gaps = np.random.uniform(0.5, 4.0, n_levels - 1)\nbid_prices = np.r_[best_bid, best_bid - np.cumsum(bid_gaps)]  # descending\nbid_qtys = np.random.exponential(1.5, n_levels) * (1 + np.linspace(0, 2.0, n_levels))\nbid_cum = np.cumsum(bid_qtys)\n\nask_gaps = np.random.uniform(0.5, 4.0, n_levels - 1)\nask_prices = np.r_[best_ask, best_ask + np.cumsum(ask_gaps)]  # ascending\nask_qtys = np.random.exponential(1.5, n_levels) * (1 + np.linspace(0, 2.0, n_levels))\nask_cum = np.cumsum(ask_qtys)\n\n# Expand to left-continuous step-function data (2n-1 points per side)\nbid_step_x = np.empty(2 * n_levels - 1)\nbid_step_x[::2] = bid_prices\nbid_step_x[1::2] = bid_prices[1:]\nbid_step_y = np.empty(2 * n_levels - 1)\nbid_step_y[::2] = bid_cum\nbid_step_y[1::2] = bid_cum[:-1]\n\nask_step_x = np.empty(2 * n_levels - 1)\nask_step_x[::2] = ask_prices\nask_step_x[1::2] = ask_prices[1:]\nask_step_y = np.empty(2 * n_levels - 1)\nask_step_y[::2] = ask_cum\nask_step_y[1::2] = ask_cum[:-1]\n\nbid_df = pd.DataFrame({\"price\": bid_step_x, \"cum_qty\": bid_step_y, \"ymin\": 0.0})\nask_df = pd.DataFrame({\"price\": ask_step_x, \"cum_qty\": ask_step_y, \"ymin\": 0.0})\ndf = pd.concat([bid_df.assign(side=\"Bids\"), ask_df.assign(side=\"Asks\")], ignore_index=True)\n\ny_max = max(bid_cum[-1], ask_cum[-1])\n\n# Near-mid-price liquidity zone — first 12 levels per side, rendered with elevated alpha\n# to emphasise tight-spread, high-priority orders where market impact is greatest\nn_near = 12\nbid_near_df = pd.DataFrame(\n    {\"price\": bid_step_x[: 2 * n_near - 1], \"cum_qty\": bid_step_y[: 2 * n_near - 1], \"ymin\": 0.0}\n)\nask_near_df = pd.DataFrame(\n    {\"price\": ask_step_x[: 2 * n_near - 1], \"cum_qty\": ask_step_y[: 2 * n_near - 1], \"ymin\": 0.0}\n)\n\nlbl_idx = 25  # label at ~50% depth along each side\nlabel_bid_x = bid_prices[lbl_idx]\nlabel_bid_y = bid_cum[lbl_idx] * 0.45\nlabel_ask_x = ask_prices[lbl_idx]\nlabel_ask_y = ask_cum[lbl_idx] * 0.45\n\ntitle = \"depth-order-book · python · plotnine · anyplot.ai\"\ntitle_size = max(8, round(12 * (67 / len(title) if len(title) > 67 else 1.0)))\n\n# Y-axis: explicit breaks with integer BTC labels\ny_step = 50\ny_breaks = list(range(0, int(y_max) + y_step, y_step))\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"price\"))\n    # Full depth fills — base alpha\n    + geom_ribbon(aes(ymin=\"ymin\", ymax=\"cum_qty\"), data=df[df[\"side\"] == \"Bids\"], fill=BID_COLOR, alpha=0.25)\n    + geom_ribbon(aes(ymin=\"ymin\", ymax=\"cum_qty\"), data=df[df[\"side\"] == \"Asks\"], fill=ASK_COLOR, alpha=0.25)\n    # Near-mid-price zone — elevated alpha for visual hierarchy\n    + geom_ribbon(aes(ymin=\"ymin\", ymax=\"cum_qty\"), data=bid_near_df, fill=BID_COLOR, alpha=0.35)\n    + geom_ribbon(aes(ymin=\"ymin\", ymax=\"cum_qty\"), data=ask_near_df, fill=ASK_COLOR, alpha=0.35)\n    # Outline strokes\n    + geom_line(aes(y=\"cum_qty\"), data=df[df[\"side\"] == \"Bids\"], color=BID_COLOR, size=0.9)\n    + geom_line(aes(y=\"cum_qty\"), data=df[df[\"side\"] == \"Asks\"], color=ASK_COLOR, size=0.9)\n    # Mid-price reference\n    + geom_vline(xintercept=mid_price, color=INK_MUTED, linetype=\"dashed\", size=0.5)\n    + annotate(\n        \"text\",\n        x=mid_price + 5,\n        y=y_max * 0.97,\n        label=f\"${mid_price:,.0f}\",\n        color=INK_MUTED,\n        size=3.5,\n        ha=\"left\",\n        va=\"top\",\n    )\n    + annotate(\n        \"text\",\n        x=mid_price + 5,\n        y=y_max * 0.87,\n        label=f\"Spread: ${spread:.0f}\",\n        color=INK_MUTED,\n        size=3.0,\n        ha=\"left\",\n        va=\"top\",\n    )\n    + annotate(\n        \"text\", x=label_bid_x, y=label_bid_y, label=\"Bids\", color=BID_COLOR, size=3.8, fontweight=\"bold\", ha=\"center\"\n    )\n    + annotate(\n        \"text\", x=label_ask_x, y=label_ask_y, label=\"Asks\", color=ASK_COLOR, size=3.8, fontweight=\"bold\", ha=\"center\"\n    )\n    + scale_x_continuous(labels=lambda breaks: [f\"${x:,.0f}\" for x in breaks])\n    + scale_y_continuous(\n        breaks=y_breaks, labels=lambda breaks: [f\"{int(x)}\" for x in breaks], expand=(0.01, 0, 0.08, 0)\n    )\n    + coord_cartesian(xlim=(bid_prices[-1] - 5, ask_prices[-1] + 5), ylim=(0, y_max * 1.06))\n    + labs(x=\"Price (USD)\", y=\"Cumulative Volume (BTC)\", title=title)\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.15),\n        panel_grid_minor=element_blank(),\n        panel_border=element_blank(),\n        axis_title=element_text(color=INK, size=10),\n        axis_text=element_text(color=INK_SOFT, size=8),\n        axis_line=element_line(color=INK_SOFT),\n        plot_title=element_text(color=INK, size=title_size),\n        legend_position=\"none\",\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\")\n"}