Candlestick Chart
render_candlestick_chartRender interactive candlestick or OHLC charts for stock, crypto, or forex data. Customize with themes for styled visuals.
Instructions
Render an interactive candlestick or OHLC financial chart. Provide date/OHLC data for stock prices, crypto, forex, or any time-series financial data. Supports themes for styled visuals.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Chart title | |
| data | Yes | Array of {date, o, h, l, c} OHLC data points | |
| options | No | ||
| theme | No | Theme preset: boardroom, corporate, sales-floor, golden-treasury, clinical, startup, ops-control, tokyo-midnight, zen-garden, consultant, black-tron, black-elegance, black-matrix, forest-amber, forest-earth, sky-light, sky-ocean, sky-twilight, gray-hf, gray-copilot | |
| palette | No | Override palette only (mix-and-match) | |
| typography | No | Override typography: professional, luxury, cyberpunk, editorial, mono, bold, system, techno | |
| effects | No | Override effects: none, subtle, shimmer, neon, energetic |
Implementation Reference
- src/charts/candlestick.ts:46-193 (handler)Main handler function that renders a candlestick or OHLC chart. Accepts container element and CandlestickData payload (title, data points, options for type/volume). Builds Chart.js financial chart with themed colors, responsive sizing, custom tooltips showing O/H/L/C and change %, click-to-send interaction, export and refresh buttons.
export function renderCandlestickChart(container: HTMLElement, payload: CandlestickData): void { const { title, data, options = {} } = payload; const chartType = options.type ?? "candlestick"; const showVolume = options.showVolume === true && data.some((d) => d.v !== undefined); // Apply theme if specified const theme = resolveTheme(payload.theme, { palette: payload.palette, typography: payload.typography, effects: payload.effects, }); if (theme) applyTheme(container, theme); const upColor = getCSSVar("--positive") || "#22C55E"; const downColor = getCSSVar("--negative") || "#EF4444"; container.innerHTML = ` <div class="chart-view"> <div class="card chart-card"> <div class="chart-card__header"> <div> <div class="chart-card__title${theme?.effects.shimmerTitle ? " shimmer-text" : ""}">${escapeHtml(title)}</div> <div class="chart-card__subtitle">${data.length} ${chartType === "ohlc" ? "OHLC" : "candlestick"} bars</div> </div> </div> <div class="chart-card__body"> <canvas id="chart-canvas"></canvas> </div> </div> </div> `; const canvas = container.querySelector<HTMLCanvasElement>("#chart-canvas")!; const chartData = data.map((d) => ({ x: new Date(d.date).getTime(), o: d.o, h: d.h, l: d.l, c: d.c, })); // Compute Y-axis range from data to avoid the axis starting at 0 // (which would compress candles into flat lines) const allPrices = data.flatMap((d) => [d.o, d.h, d.l, d.c]); const yMin = Math.min(...allPrices); const yMax = Math.max(...allPrices); const yPadding = (yMax - yMin) * 0.15 || 1; const datasets: any[] = [ { label: title, data: chartData, color: { up: upColor, down: downColor, unchanged: getCSSVar("--text-muted") || "#94A3B8", }, borderColor: { up: upColor, down: downColor, unchanged: getCSSVar("--text-muted") || "#94A3B8", }, }, ]; const chartInstance = new Chart(canvas, { type: chartType, data: { datasets }, options: { responsive: true, maintainAspectRatio: false, onClick: (_event, elements) => { if (elements.length === 0) return; const idx = elements[0].index; const d = data[idx]; sendClickMessage( `${d.date}: O${d.o} H${d.h} L${d.l} C${d.c}${d.v !== undefined ? ` Vol:${d.v.toLocaleString()}` : ""} in "${title}"` ); }, scales: { x: { type: "time", border: { display: false }, grid: { display: false }, ticks: { color: getCSSVar("--text-secondary"), font: { size: 11 }, maxRotation: 0, }, time: { displayFormats: { day: "MMM d", week: "MMM d", month: "MMM yyyy", }, }, }, y: { type: "linear", beginAtZero: false, min: yMin - yPadding, max: yMax + yPadding, border: { display: false }, grid: { color: getCSSVar("--border"), drawTicks: false, }, ticks: { color: getCSSVar("--text-secondary"), font: { size: 11 }, padding: 8, }, }, }, plugins: { legend: { display: false, }, tooltip: { ...tooltipStyle(), callbacks: { title: (items) => { if (items.length === 0) return ""; const raw = items[0].raw as any; return new Date(raw.x).toLocaleDateString(undefined, { dateStyle: "medium" }); }, label: (ctx) => { const raw = ctx.raw as any; const change = raw.c - raw.o; const pct = ((change / raw.o) * 100).toFixed(2); const dir = change >= 0 ? "+" : ""; return [ ` O: ${raw.o.toLocaleString()} H: ${raw.h.toLocaleString()}`, ` L: ${raw.l.toLocaleString()} C: ${raw.c.toLocaleString()}`, ` Change: ${dir}${change.toLocaleString()} (${dir}${pct}%)`, ]; }, }, }, }, }, } as any); deferResize(chartInstance); addExportButton(container, chartInstance, title); addRefreshButton(container, () => (window as any).__mcpRefresh?.()); } - src/charts/candlestick.ts:24-44 (schema)Type definitions (schemas) for CandlestickDataPoint (date, open/high/low/close, optional volume) and CandlestickData (title, data array, options for chart type and volume display, plus theme/palette/typography/effects).
interface CandlestickDataPoint { date: string; o: number; h: number; l: number; c: number; v?: number; } interface CandlestickData { title: string; data: CandlestickDataPoint[]; options: { type?: "candlestick" | "ohlc"; showVolume?: boolean; }; theme?: string; palette?: string; typography?: string; effects?: string; } - src/charts/candlestick.ts:195-195 (registration)Registration of the tool with key 'candlestick', tool name 'render_candlestick_chart', and the renderCandlestickChart handler function. Called as a side-effect when app.ts imports candlestick.js.
registerChart("candlestick", "render_candlestick_chart", renderCandlestickChart); - src/charts/shared.ts:188-194 (helper)Helper function that stores chart renderers in a registry. Couples a chart type key, the MCP tool name string, and the render function together for later dispatch by app.ts.
export function registerChart( type: string, toolName: string, render: (root: HTMLElement, data: any) => void, ): void { CHART_REGISTRY[type] = { toolName, render }; }