Basic Candlestick Chart — ggplot2

A candlestick chart displays open, high, low, and close (OHLC) price data for financial instruments over time. Each candlestick shows the price range within a specific period, with the body indicating the open-close range and the wicks (shadows) showing the high-low range. Color coding distinguishes bullish (price increase) from bearish (price decrease) periods, making it easy to identify trends and price patterns at a glance.

Basic Candlestick Chart rendered with ggplot2

Renders

R source (ggplot2)

#' anyplot.ai
#' candlestick-basic: Basic Candlestick Chart
#' Library: ggplot2 3.5.1 | R 4.4.1
#' Quality: 91/100 | Created: 2026-05-30

library(ggplot2)
library(scales)
library(ragg)

set.seed(42)

# --- Theme tokens ------------------------------------------------------------
THEME       <- Sys.getenv("ANYPLOT_THEME", "light")
PAGE_BG     <- if (THEME == "light") "#FAF8F1" else "#1A1A17"
ELEVATED_BG <- if (THEME == "light") "#FFFDF6" else "#242420"
INK         <- if (THEME == "light") "#1A1A17" else "#F0EFE8"
INK_SOFT    <- if (THEME == "light") "#4A4A44" else "#B8B7B0"

# Imprint palette — semantic finance mapping (position 1: gain, position 5: loss)
BULL_COLOR <- "#009E73"  # bullish / gain
BEAR_COLOR <- "#AE3030"  # bearish / loss

# --- Data --------------------------------------------------------------------
# NovaTech Corp (NVTK) — 40 trading days, Jan–Mar 2024
all_dates   <- seq(as.Date("2024-01-02"), by = "day", length.out = 60)
trade_dates <- all_dates[!weekdays(all_dates) %in% c("Saturday", "Sunday")]
trade_dates <- head(trade_dates, 40)
n           <- length(trade_dates)

price  <- 148.0
opens  <- numeric(n)
highs  <- numeric(n)
lows   <- numeric(n)
closes <- numeric(n)

for (i in seq_len(n)) {
    daily_range <- runif(1, 1.5, 4.5)
    open_i      <- price + rnorm(1, 0, 0.5)
    close_i     <- open_i + rnorm(1, 0.2, daily_range * 0.45)
    high_i      <- max(open_i, close_i) + runif(1, 0.2, daily_range * 0.35)
    low_i       <- min(open_i, close_i) - runif(1, 0.2, daily_range * 0.35)
    opens[i]    <- open_i
    highs[i]    <- high_i
    lows[i]     <- low_i
    closes[i]   <- close_i
    price       <- close_i
}

df <- data.frame(
    date      = trade_dates,
    x         = seq_len(n),
    open      = opens,
    high      = highs,
    low       = lows,
    close     = closes
)
df$direction   <- ifelse(df$close >= df$open, "up", "down")
df$body_top    <- pmax(df$open, df$close)
df$body_bottom <- pmin(df$open, df$close)
df$xmin        <- df$x - 0.38
df$xmax        <- df$x + 0.38

# Closing price trend line (linear fit) for visual storytelling
trend_fit <- lm(close ~ x, data = df)
trend_y   <- fitted(trend_fit)

# --- X-axis breaks -----------------------------------------------------------
break_idx    <- seq(1, n, by = 5)
break_labels <- format(trade_dates[break_idx], "%b %d")

# --- Plot --------------------------------------------------------------------
p <- ggplot(df) +
    # High-low wicks
    geom_segment(
        aes(x = x, xend = x, y = low, yend = high, color = direction),
        linewidth = 0.45, show.legend = FALSE
    ) +
    # Subtle trend overlay (closing prices)
    geom_line(
        data = data.frame(x = df$x, close = trend_y),
        aes(x = x, y = close),
        color = INK_SOFT, linewidth = 0.5, linetype = "dashed",
        inherit.aes = FALSE, alpha = 0.55
    ) +
    # Open-close bodies
    geom_rect(
        aes(xmin = xmin, xmax = xmax, ymin = body_bottom, ymax = body_top,
            fill = direction, color = direction),
        linewidth = 0.2
    ) +
    scale_color_manual(
        values = c("up" = BULL_COLOR, "down" = BEAR_COLOR),
        guide  = "none"
    ) +
    scale_fill_manual(
        values = c("up" = BULL_COLOR, "down" = BEAR_COLOR),
        labels = c("up" = "Bullish", "down" = "Bearish"),
        breaks = c("up", "down"),
        name   = NULL
    ) +
    scale_x_continuous(
        breaks = break_idx,
        labels = break_labels,
        expand = expansion(mult = c(0.02, 0.02))
    ) +
    scale_y_continuous(
        labels = label_dollar(accuracy = 0.01),
        expand = expansion(mult = c(0.03, 0.04))
    ) +
    labs(
        title = "NovaTech Corp (NVTK) · candlestick-basic · r · ggplot2 · anyplot.ai",
        x     = NULL,
        y     = "Price (USD)"
    ) +
    theme_minimal(base_size = 8) +
    theme(
        plot.background    = element_rect(fill = PAGE_BG,     color = PAGE_BG),
        panel.background   = element_rect(fill = PAGE_BG,     color = NA),
        panel.grid.major.y = element_line(color = INK_SOFT,   linewidth = 0.2),
        panel.grid.major.x = element_blank(),
        panel.grid.minor   = element_blank(),
        axis.title         = element_text(color = INK,        size = 10),
        axis.text          = element_text(color = INK_SOFT,   size = 8),
        axis.text.x        = element_text(angle = 40, hjust = 1),
        axis.line          = element_line(color = INK_SOFT,   linewidth = 0.3),
        axis.ticks         = element_line(color = INK_SOFT,   linewidth = 0.3),
        plot.title         = element_text(color = INK,        size = 12,
                                          margin = margin(b = 8)),
        legend.background  = element_rect(fill = ELEVATED_BG, color = INK_SOFT,
                                          linewidth = 0.3),
        legend.text        = element_text(color = INK_SOFT,   size = 8),
        legend.key.size    = unit(0.9, "lines"),
        legend.position    = "top",
        legend.direction   = "horizontal",
        plot.margin        = margin(t = 10, r = 14, b = 8, l = 8)
    )

# --- Save --------------------------------------------------------------------
ggsave(
    filename = sprintf("plot-%s.png", THEME),
    plot     = p,
    device   = ragg::agg_png,
    width    = 8,
    height   = 4.5,
    units    = "in",
    dpi      = 400
)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/candlestick-basic/ggplot2/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "candlestick-basic",
  "language": "r",
  "library": "ggplot2",
  "page": "https://anyplot.ai/candlestick-basic/r/ggplot2",
  "hub": "https://anyplot.ai/candlestick-basic",
  "code_json": "https://api.anyplot.ai/specs/candlestick-basic/ggplot2/code",
  "spec_json": "https://api.anyplot.ai/specs/candlestick-basic",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/candlestick-basic/r/ggplot2/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/candlestick-basic/r/ggplot2/plot-dark.png",
  "quality_score": 91.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Basic Candlestick Chart on anyplot.ai.

Other implementations