{"spec_id":"candlestick-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# candlestick-basic: Basic Candlestick Chart\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-05-30\n\nusing CairoMakie\nusing Makie\nusing Colors\nusing Random\nusing Dates\nusing Statistics\n\nRandom.seed!(42)\n\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\n\n# Semantic colors: finance convention — green for gains, red for losses\nconst BULL_COLOR = colorant\"#009E73\"  # Imprint position 1 — bullish / price up\nconst BEAR_COLOR = colorant\"#AE3030\"  # Imprint position 5, semantic anchor: loss/down\nconst SMA_COLOR  = colorant\"#2ABCCD\"  # Imprint position 6 — cyan for trend overlay\n\n# Data: 40 trading days of tech stock OHLC\nn = 40\nstart_price = 182.50\n\nopens  = zeros(n)\ncloses = zeros(n)\nhighs  = zeros(n)\nlows   = zeros(n)\n\nopens[1]  = start_price\ncloses[1] = start_price * (1.0 + 0.015 * randn())\nhighs[1]  = max(opens[1], closes[1]) * (1.0 + 0.007 * abs(randn()))\nlows[1]   = min(opens[1], closes[1]) * (1.0 - 0.007 * abs(randn()))\n\nfor i in 2:n\n    opens[i]  = closes[i-1] * (1.0 + 0.003 * randn())\n    closes[i] = opens[i] * (1.0 + 0.020 * randn())\n    highs[i]  = max(opens[i], closes[i]) * (1.0 + 0.008 * abs(randn()))\n    lows[i]   = min(opens[i], closes[i]) * (1.0 - 0.008 * abs(randn()))\nend\n\nis_bull     = closes .>= opens\nbody_colors = [is_bull[i] ? BULL_COLOR : BEAR_COLOR for i in 1:n]\n\n# 10-day SMA — creates a narrative focal point and trend context\nsma_window = 10\nsma = [i < sma_window ? NaN : mean(closes[i-sma_window+1:i]) for i in 1:n]\nsma_valid_idx = findall(!isnan, sma)\n\n# Date labels for x-axis ticks\nstart_date    = Date(2024, 6, 3)\ntrading_dates = filter(x -> dayofweek(x) <= 5,\n    [start_date + Day(k) for k in 0:80])[1:n]\n\ntick_idx    = [1, 10, 20, 30, n]\ntick_labels = [string(Dates.monthabbr(Dates.month(trading_dates[i])), \" \",\n               Dates.day(trading_dates[i])) for i in tick_idx]\n\n# Figure\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title             = \"candlestick-basic · julia · makie · anyplot.ai\",\n    titlesize         = 20,\n    titlecolor        = INK,\n    titlegap          = 12,\n    xlabel            = \"Date (2024)\",\n    ylabel            = \"Price (USD)\",\n    xlabelsize        = 14,\n    ylabelsize        = 14,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\n    xticklabelsize    = 11,\n    yticklabelsize    = 12,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\n    xticksize         = 0,\n    yticksize         = 0,\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xticks            = (tick_idx, tick_labels),\n    xgridvisible      = false,\n    ygridvisible      = true,\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    yminorgridvisible = false,\n    xminorgridvisible = false,\n)\n\nxlims!(ax, 0.5, n + 0.5)\n\nxs = collect(1:n)\n\n# Wicks: thin vertical lines spanning low to high\nrangebars!(ax, xs, lows, highs;\n    color        = body_colors,\n    linewidth    = 1.5,\n    whiskerwidth = 0,\n)\n\n# Bodies: filled rectangles with thin CVD-friendly outline for deuteranopia robustness\nhalf_w       = 0.32\nbody_bottoms = [min(opens[i], closes[i]) for i in 1:n]\nbody_heights = [max(abs(closes[i] - opens[i]), 0.05) for i in 1:n]\nbody_rects   = [Rect2f(i - half_w, body_bottoms[i], 2 * half_w, body_heights[i]) for i in 1:n]\npoly!(ax, body_rects;\n    color       = body_colors,\n    strokewidth = 0.5,\n    strokecolor = RGBAf(INK.r, INK.g, INK.b, 0.3),\n)\n\n# 10-day SMA trend line in Imprint cyan — provides visual hierarchy and price context\nlines!(ax, sma_valid_idx, sma[sma_valid_idx];\n    color     = SMA_COLOR,\n    linewidth = 2.0,\n)\n\n# Legend\nelem_bull = PolyElement(\n    color       = BULL_COLOR,\n    strokecolor = RGBAf(INK.r, INK.g, INK.b, 0.3),\n    strokewidth = 0.5,\n)\nelem_bear = PolyElement(\n    color       = BEAR_COLOR,\n    strokecolor = RGBAf(INK.r, INK.g, INK.b, 0.3),\n    strokewidth = 0.5,\n)\nelem_sma = LineElement(color = SMA_COLOR, linewidth = 2.0)\nLegend(\n    fig[1, 2],\n    [elem_bull, elem_bear, elem_sma],\n    [\"Bullish (↑)\", \"Bearish (↓)\", \"SMA (10)\"];\n    framevisible    = false,\n    backgroundcolor = ELEVATED_BG,\n    labelcolor      = INK,\n    labelsize       = 12,\n    padding         = (10, 10, 8, 8),\n    rowgap          = 6,\n)\n\ncolsize!(fig.layout, 1, Relative(0.87))\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}