Files
fn_registry/cpp/functions/viz/candlestick.cpp
T
egutierrez 7eef2544ab feat: add C++ ImGui functions for core UI and visualization
Funciones C++/ImGui para dashboards (grid, panel, docking, sidebar, tabs),
visualizaciones (candlestick, gauge, histogram, pie, sparkline, heatmap,
scatter, line, bar, surface3d, kpi, table), grafos (force layout, renderer,
viewport, spatial hash, types) y utilidades (time series buffer, tracy zones,
memory/fps overlay, plot theme).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 00:10:18 +02:00

82 lines
3.2 KiB
C++

#include "viz/candlestick.h"
#include "imgui.h"
#include "implot.h"
void candlestick(const char* title, const double* dates, const double* opens,
const double* closes, const double* lows, const double* highs,
int count, float width_percent, bool tooltip) {
if (count <= 0) return;
// Compute half-width of each candle body in data coordinates.
// Use spacing between consecutive dates when count > 1, else fallback to 0.5.
double spacing = (count > 1) ? (dates[1] - dates[0]) : 1.0;
double half_w = spacing * (double)width_percent * 0.5;
ImPlot::SetupAxes("Date", "Price", ImPlotAxisFlags_None, ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Time);
// Auto-fit X axis to the data range with a small margin.
ImPlot::SetupAxisLimits(ImAxis_X1,
dates[0] - spacing,
dates[count - 1] + spacing,
ImGuiCond_Always);
if (ImPlot::BeginPlot(title, ImVec2(-1, 0))) {
ImDrawList* draw = ImPlot::GetPlotDrawList();
const ImU32 col_bull = IM_COL32(0, 200, 80, 255); // green — close >= open
const ImU32 col_bear = IM_COL32(220, 50, 50, 255); // red — close < open
int hovered_idx = -1;
for (int i = 0; i < count; i++) {
double x = dates[i];
double open = opens[i];
double close = closes[i];
double low = lows[i];
double high = highs[i];
bool bullish = (close >= open);
ImU32 col = bullish ? col_bull : col_bear;
// Convert data coordinates to screen pixels.
ImVec2 body_tl = ImPlot::PlotToPixels(x - half_w, bullish ? close : open);
ImVec2 body_br = ImPlot::PlotToPixels(x + half_w, bullish ? open : close);
ImVec2 wick_hi = ImPlot::PlotToPixels(x, high);
ImVec2 wick_lo = ImPlot::PlotToPixels(x, low);
float cx = (body_tl.x + body_br.x) * 0.5f;
// Wick (high-low vertical line).
draw->AddLine(ImVec2(cx, wick_hi.y), ImVec2(cx, wick_lo.y), col, 1.5f);
// Body rectangle (open-close).
// Ensure at least 1px height so flat candles are visible.
if (body_br.y <= body_tl.y + 1.0f) body_br.y = body_tl.y + 1.0f;
draw->AddRectFilled(body_tl, body_br, col);
draw->AddRect(body_tl, body_br, col);
// Track hovered candle for tooltip.
if (tooltip && ImPlot::IsPlotHovered()) {
ImVec2 mouse = ImGui::GetMousePos();
if (mouse.x >= body_tl.x - 4 && mouse.x <= body_br.x + 4 &&
mouse.y >= wick_hi.y - 4 && mouse.y <= wick_lo.y + 4) {
hovered_idx = i;
}
}
}
// Tooltip for the hovered candle.
if (tooltip && hovered_idx >= 0) {
int i = hovered_idx;
ImGui::BeginTooltip();
ImGui::Text("O: %.4f", opens[i]);
ImGui::Text("H: %.4f", highs[i]);
ImGui::Text("L: %.4f", lows[i]);
ImGui::Text("C: %.4f", closes[i]);
ImGui::EndTooltip();
}
ImPlot::EndPlot();
}
}