0bdf35a461
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>
82 lines
3.2 KiB
C++
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();
|
|
}
|
|
}
|