{"spec_id":"depth-order-book","library":"altair","language":"python","code":"\"\"\" anyplot.ai\ndepth-order-book: Order Book Depth Chart\nLibrary: altair 6.2.1 | Python 3.13.13\nQuality: 89/100 | Created: 2026-06-15\n\"\"\"\n\nimport importlib\nimport os\nimport sys\n\n\n# Remove script directory from sys.path so `altair` resolves to the package, not this file\nsys.path[:] = [p for p in sys.path if os.path.abspath(p or \".\") != os.path.dirname(os.path.abspath(__file__))]\nalt = importlib.import_module(\"altair\")\nnp = importlib.import_module(\"numpy\")\npd = importlib.import_module(\"pandas\")\nfrom PIL import Image\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 colors for bid/ask sides\nBID_COLOR = \"#009E73\"  # Imprint position 1 (brand green) — buy orders\nASK_COLOR = \"#AE3030\"  # Imprint position 5 (matte red) — sell orders\n\n# Data — BTC/USD order book snapshot\nnp.random.seed(42)\n\nMID_PRICE = 60_000\nBEST_BID = 59_990\nBEST_ASK = 60_010\nN_LEVELS = 50\n\n# Bid levels: 59941 → 59990 (50 levels, $1 step)\nbid_prices = np.arange(BEST_BID - N_LEVELS + 1, BEST_BID + 1)\nbid_raw = 0.3 + np.random.exponential(scale=0.9, size=N_LEVELS)\nbid_raw[5] += 12.0  # large support wall near best bid\nbid_raw[24] += 9.0  # mid-depth support wall\nbid_raw[40] += 6.0  # deeper support level\n\n# Cumulative from best bid outward (index -1 = best bid, index 0 = worst bid)\nbid_cumulative = np.cumsum(bid_raw[::-1])[::-1]\n\nbid_df = pd.DataFrame({\"price\": bid_prices, \"cumulative\": bid_cumulative, \"side\": \"Bid (Buy)\"})\n\n# Ask levels: 60010 → 60059 (50 levels, $1 step)\nask_prices = np.arange(BEST_ASK, BEST_ASK + N_LEVELS)\nask_raw = 0.3 + np.random.exponential(scale=0.9, size=N_LEVELS)\nask_raw[10] += 11.0  # resistance wall near best ask\nask_raw[28] += 8.5  # mid-depth resistance wall\nask_raw[42] += 5.5  # deeper resistance level\n\nask_cumulative = np.cumsum(ask_raw)\n\nask_df = pd.DataFrame({\"price\": ask_prices, \"cumulative\": ask_cumulative, \"side\": \"Ask (Sell)\"})\n\ndf = pd.concat([bid_df, ask_df], ignore_index=True)\n\n# Chart parameters\nx_min = int(bid_prices.min()) - 5\nx_max = int(ask_prices.max()) + 10\ny_max = max(float(bid_cumulative.max()), float(ask_cumulative.max())) * 1.08\n\n# Title with fontsize scaling\ntitle = \"BTC/USD Order Book · depth-order-book · python · altair · anyplot.ai\"\nn = len(title)\nratio = 67 / n if n > 67 else 1.0\ntitle_fontsize = max(11, round(16 * ratio))\n\n# Step-area chart (bid and ask grouped by 'side')\narea = (\n    alt.Chart(df)\n    .mark_area(interpolate=\"step-after\", fillOpacity=0.35, line={\"strokeWidth\": 2.5})\n    .encode(\n        x=alt.X(\n            \"price:Q\",\n            title=\"Price (USD)\",\n            axis=alt.Axis(format=\",.0f\", labelAngle=0, tickCount=10),\n            scale=alt.Scale(domain=[x_min, x_max]),\n        ),\n        y=alt.Y(\"cumulative:Q\", title=\"Cumulative Volume (BTC)\", scale=alt.Scale(domain=[0, y_max])),\n        color=alt.Color(\n            \"side:N\",\n            scale=alt.Scale(domain=[\"Bid (Buy)\", \"Ask (Sell)\"], range=[BID_COLOR, ASK_COLOR]),\n            legend=alt.Legend(title=\"Order Side\"),\n        ),\n        tooltip=[\n            alt.Tooltip(\"side:N\", title=\"Side\"),\n            alt.Tooltip(\"price:Q\", title=\"Price (USD)\", format=\",.0f\"),\n            alt.Tooltip(\"cumulative:Q\", title=\"Cum. Volume (BTC)\", format=\".2f\"),\n        ],\n    )\n)\n\n# Dashed vertical rule at mid price\nmid_rule = (\n    alt.Chart(pd.DataFrame({\"price\": [MID_PRICE]}))\n    .mark_rule(strokeDash=[5, 3], strokeWidth=1.5, color=INK_MUTED, opacity=0.8)\n    .encode(x=\"price:Q\")\n)\n\n# Mid-price / spread annotation label\nSPREAD = BEST_ASK - BEST_BID\nmid_label = (\n    alt.Chart(pd.DataFrame({\"price\": [MID_PRICE], \"y\": [y_max * 0.96]}))\n    .mark_text(text=f\"Mid: ${MID_PRICE:,} | Spread: ${SPREAD}\", color=INK_SOFT, fontSize=9, align=\"center\", dy=-4)\n    .encode(\n        x=alt.X(\"price:Q\", scale=alt.Scale(domain=[x_min, x_max])), y=alt.Y(\"y:Q\", scale=alt.Scale(domain=[0, y_max]))\n    )\n)\n\nchart = (\n    alt.layer(area, mid_rule, mid_label)\n    .properties(\n        width=620,\n        height=320,\n        background=PAGE_BG,\n        padding={\"left\": 0, \"right\": 0, \"top\": 0, \"bottom\": 0},\n        title=alt.TitleParams(text=title, fontSize=title_fontsize, color=INK),\n    )\n    .configure_view(fill=PAGE_BG, stroke=None, continuousWidth=620, continuousHeight=320)\n    .configure_axis(\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        gridOpacity=0.12,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        labelFontSize=10,\n        titleFontSize=12,\n    )\n    .configure_title(color=INK, fontSize=title_fontsize)\n    .configure_legend(\n        fillColor=ELEVATED_BG,\n        strokeColor=INK_SOFT,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        labelFontSize=10,\n        titleFontSize=10,\n    )\n)\n\n# Save PNG\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\n# Pad to exact canvas size 3200×1800 — do NOT crop\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\n# Save HTML (interactive)\nchart.save(f\"plot-{THEME}.html\")\n"}