{"spec_id":"depth-order-book","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' depth-order-book: Order Book Depth Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 86/100 | Created: 2026-06-15\n\nlibrary(ggplot2)\nlibrary(scales)\nlibrary(ragg)\n\nset.seed(42)\n\n# Theme tokens\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nELEVATED_BG <- if (THEME == \"light\") \"#FFFDF6\" else \"#242420\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\n\n# Imprint palette — semantic: green = bids (buy), red = asks (sell)\nBID_COLOR <- \"#009E73\"  # Imprint position 1 (brand green)\nASK_COLOR <- \"#AE3030\"  # Imprint position 5 (semantic: sell/loss)\nGRID_COL  <- adjustcolor(INK, alpha.f = 0.12)\n\n# Market parameters: BTC/USD snapshot near $60,000\nmid_price   <- 60000\nhalf_spread <- 5        # $10 total spread\nn_levels    <- 50\ntick_size   <- 5        # $5 between price levels\n\n# Price grids — index 1 = best (closest to mid), index 50 = worst\nbid_prices <- mid_price - half_spread - (seq_len(n_levels) - 1) * tick_size\nask_prices <- mid_price + half_spread + (seq_len(n_levels) - 1) * tick_size\n\n# Individual order sizes with mild trend (deeper levels accumulate more liquidity)\nqty_trend <- 1 + (seq_len(n_levels) - 1) * 0.04\nbid_qtys  <- rlnorm(n_levels, meanlog = 1.5, sdlog = 0.5) * qty_trend\nask_qtys  <- rlnorm(n_levels, meanlog = 1.5, sdlog = 0.5) * qty_trend\n\n# Insert liquidity walls — large resting orders that act as support/resistance\nbid_qtys[12] <- bid_qtys[12] * 7\nask_qtys[18] <- ask_qtys[18] * 5\n\n# Cumulative volume from mid price outward\nbid_cum <- cumsum(bid_qtys)\nask_cum <- cumsum(ask_qtys)\n\n# Build step polygon data — vectorized, no loops\nmake_step_poly <- function(prices, cums, side_label) {\n    n  <- length(prices)\n    xs <- rep(prices, each = 2)\n    ys <- c(0, rep(cums, each = 2))[seq_len(2 * n)]\n    data.frame(\n        x    = c(xs, prices[n], prices[1]),\n        y    = c(ys, 0, 0),\n        side = side_label\n    )\n}\n\nbid_poly <- make_step_poly(bid_prices, bid_cum, \"Bid (Buy)\")\nask_poly <- make_step_poly(ask_prices, ask_cum, \"Ask (Sell)\")\norder_book <- rbind(bid_poly, ask_poly)\n\n# Step outline data for geom_step — prepend (best_price, 0) for clean initial vertical\nbid_step <- data.frame(\n    price   = c(bid_prices[1], bid_prices),\n    cum_vol = c(0, bid_cum),\n    side    = \"Bid (Buy)\"\n)\nask_step <- data.frame(\n    price   = c(ask_prices[1], ask_prices),\n    cum_vol = c(0, ask_cum),\n    side    = \"Ask (Sell)\"\n)\ndepth_df <- rbind(bid_step, ask_step)\n\nmax_cum    <- max(bid_cum[n_levels], ask_cum[n_levels])\nlabel_text <- sprintf(\"Mid: $%s\\nSpread: $%d\",\n                      format(mid_price, big.mark = \",\", scientific = FALSE),\n                      half_spread * 2)\n\nplot_title <- \"BTC/USD Order Book · depth-order-book · r · ggplot2 · anyplot.ai\"\ntitle_size <- max(8, round(12 * 67 / max(nchar(plot_title), 67)))\n\np <- ggplot() +\n    geom_polygon(\n        data  = order_book,\n        aes(x = x, y = y, fill = side, group = side),\n        color = NA, alpha = 0.22\n    ) +\n    geom_step(\n        data      = depth_df,\n        aes(x = price, y = cum_vol, color = side, group = side),\n        direction = \"hv\", linewidth = 0.85\n    ) +\n    geom_vline(\n        xintercept = mid_price,\n        linetype = \"dashed\", color = INK_SOFT, linewidth = 0.5\n    ) +\n    annotate(\n        \"label\",\n        x = mid_price, y = max_cum * 0.88,\n        label = label_text, color = INK, size = 3.5,\n        hjust = 0.5, lineheight = 1.3,\n        fill = ELEVATED_BG, label.size = 0.25\n    ) +\n    scale_fill_manual(\n        name   = NULL,\n        values = c(\"Bid (Buy)\" = BID_COLOR, \"Ask (Sell)\" = ASK_COLOR),\n        guide  = guide_legend(override.aes = list(alpha = 0.7))\n    ) +\n    scale_color_manual(\n        name   = NULL,\n        values = c(\"Bid (Buy)\" = BID_COLOR, \"Ask (Sell)\" = ASK_COLOR),\n        guide  = \"none\"\n    ) +\n    scale_x_continuous(\n        labels = label_dollar(accuracy = 1),\n        breaks = seq(59750, 60250, by = 100),\n        expand = expansion(mult = 0.01)\n    ) +\n    scale_y_continuous(\n        labels = label_comma(accuracy = 1),\n        limits = c(0, max_cum * 1.12),\n        expand = expansion(mult = c(0, 0))\n    ) +\n    labs(\n        title = plot_title,\n        x     = \"Price (USD)\",\n        y     = \"Cumulative Volume (BTC)\"\n    ) +\n    theme_minimal(base_size = 8) +\n    theme(\n        plot.background   = element_rect(fill = PAGE_BG,  color = PAGE_BG),\n        panel.background  = element_rect(fill = PAGE_BG,  color = NA),\n        panel.grid.major  = element_line(color = GRID_COL, linewidth = 0.3),\n        panel.grid.minor  = element_blank(),\n        panel.border      = element_blank(),\n        axis.line         = element_line(color = INK_SOFT, linewidth = 0.4),\n        axis.title        = element_text(color = INK,      size = 10),\n        axis.text         = element_text(color = INK_SOFT, size = 8),\n        axis.text.x       = element_text(color = INK_SOFT, size = 8,\n                                         angle = 30, hjust = 1),\n        plot.title        = element_text(color = INK, size = title_size,\n                                         face = \"bold\", margin = margin(b = 8)),\n        legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT,\n                                         linewidth = 0.3),\n        legend.text       = element_text(color = INK_SOFT, size = 8),\n        legend.key        = element_rect(fill = NA, color = NA),\n        plot.margin       = margin(t = 12, r = 16, b = 8, l = 8)\n    )\n\nggsave(\n    filename = sprintf(\"plot-%s.png\", THEME),\n    plot     = p,\n    device   = ragg::agg_png,\n    width    = 8,\n    height   = 4.5,\n    units    = \"in\",\n    dpi      = 400\n)\n"}