preparando step 3 para dejarlo fino
This commit is contained in:
@@ -728,6 +728,179 @@ async function pollStatus(jobId) {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
// =================================================
|
||||
// DIFFERENT RENDER PLOTS
|
||||
// =================================================
|
||||
|
||||
function renderEquityAndReturns(strategyId, s, data) {
|
||||
|
||||
console.log("Plotly object:", Plotly); // Esto debería mostrarte el objeto Plotly completo
|
||||
|
||||
if (Plotly && Plotly.subplots) {
|
||||
console.log("make_subplots is available");
|
||||
} else {
|
||||
console.error("make_subplots is NOT available");
|
||||
}
|
||||
|
||||
// Crea el subplot con dos filas y una columna (1x2)
|
||||
var fig = Plotly.subplots.make_subplots({
|
||||
rows: 2, // 2 filas
|
||||
cols: 1, // 1 columna
|
||||
shared_xaxes: true, // Compartir el eje X entre ambos gráficos
|
||||
vertical_spacing: 0.1, // Espacio entre los gráficos
|
||||
subplot_titles: [`Equity — ${strategyId}`, `Returns & Trades — ${strategyId}`], // Títulos para cada subgráfico
|
||||
column_widths: [0.7] // Ajustar el ancho de las columnas si es necesario
|
||||
});
|
||||
|
||||
// Datos de Equity
|
||||
const equityTrace = {
|
||||
y: s.window_equity, // Datos de la equity
|
||||
type: "scatter", // Tipo de gráfico: línea
|
||||
mode: "lines", // Modo: línea
|
||||
name: "Equity"
|
||||
};
|
||||
|
||||
// Datos de Return %
|
||||
const returnsTrace = {
|
||||
y: s.window_returns_pct || [], // Datos de returns
|
||||
type: "bar", // Tipo de gráfico: barra
|
||||
name: "Return %",
|
||||
marker: { color: "#3b82f6" }, // Color de la barra
|
||||
yaxis: "y1", // Asociar al primer eje Y
|
||||
};
|
||||
|
||||
// Datos de Trades
|
||||
const tradesTrace = {
|
||||
y: s.window_trades || [], // Datos de trades
|
||||
type: "bar", // Tipo de gráfico: barra
|
||||
name: "Trades",
|
||||
marker: { color: "#f59e0b" }, // Color de la barra
|
||||
yaxis: "y2", // Asociar al segundo eje Y
|
||||
};
|
||||
|
||||
// Agregar la traza de "Equity" al subplot (fila 1, columna 1)
|
||||
fig.addTrace(equityTrace, 1, 1);
|
||||
|
||||
// Agregar las trazas de "Returns" y "Trades" al subplot (fila 2, columna 1)
|
||||
fig.addTrace(returnsTrace, 2, 1);
|
||||
fig.addTrace(tradesTrace, 2, 1);
|
||||
|
||||
// Configurar los ejes y los márgenes
|
||||
fig.update_layout({
|
||||
title: `Strategy Overview — ${strategyId}`,
|
||||
yaxis: {
|
||||
title: "Equity",
|
||||
showgrid: true
|
||||
},
|
||||
yaxis2: {
|
||||
title: "Return % / Trades",
|
||||
overlaying: "y",
|
||||
side: "right",
|
||||
showgrid: true
|
||||
},
|
||||
xaxis: {
|
||||
title: "Windows",
|
||||
showgrid: true
|
||||
},
|
||||
showlegend: true
|
||||
});
|
||||
|
||||
// Renderizar en el contenedor del gráfico
|
||||
Plotly.newPlot("plot_strategy", fig);
|
||||
}
|
||||
|
||||
function renderRollingSharpe(strategyId, s, data) {
|
||||
const roll = s.diagnostics?.rolling?.rolling_sharpe_like || [];
|
||||
const x = roll.map((_, i) => i + 1);
|
||||
|
||||
Plotly.newPlot("plot_strategy", [{
|
||||
x,
|
||||
y: roll,
|
||||
type: "scatter",
|
||||
mode: "lines+markers",
|
||||
name: `Rolling Sharpe-like (k=${s.diagnostics?.rolling?.rolling_window ?? "?"})`
|
||||
}], {
|
||||
margin: { t: 40 },
|
||||
title: `Rolling Sharpe-like — ${strategyId}`,
|
||||
xaxis: { title: "Window" },
|
||||
yaxis: { title: "Sharpe-like" }
|
||||
});
|
||||
}
|
||||
|
||||
function renderOOSReturnsDistribution(strategyId, s, data) {
|
||||
const edges = s.diagnostics?.distribution?.hist_bin_edges || [];
|
||||
const counts = s.diagnostics?.distribution?.hist_counts || [];
|
||||
|
||||
const centers = edges.map((_, i) => (edges[i] + edges[i + 1]) / 2);
|
||||
|
||||
Plotly.newPlot("plot_strategy", [{
|
||||
x: centers,
|
||||
y: counts,
|
||||
type: "bar",
|
||||
name: "OOS Return% (bins)"
|
||||
}], {
|
||||
margin: { t: 40 },
|
||||
title: `OOS Returns Distribution — ${strategyId}`,
|
||||
xaxis: { title: "Return % (window)" },
|
||||
yaxis: { title: "Count" }
|
||||
});
|
||||
}
|
||||
|
||||
function renderDrawdownEvolution(strategyId, s, data) {
|
||||
const dd = s.diagnostics?.drawdown?.drawdown_pct || [];
|
||||
const x = dd.map((_, i) => i);
|
||||
|
||||
Plotly.newPlot("plot_strategy", [{
|
||||
x,
|
||||
y: dd,
|
||||
type: "scatter",
|
||||
mode: "lines",
|
||||
name: "Drawdown %"
|
||||
}], {
|
||||
margin: { t: 40 },
|
||||
title: `Drawdown Evolution — ${strategyId}`,
|
||||
xaxis: { title: "Point (initial + windows)" },
|
||||
yaxis: { title: "Drawdown %", zeroline: true }
|
||||
});
|
||||
}
|
||||
|
||||
function renderTradeDensity(strategyId, s, data) {
|
||||
const tpw = s.diagnostics?.trades?.trades_per_window || [];
|
||||
const tpd = s.diagnostics?.trades?.trades_per_day || [];
|
||||
const x = tpw.map((_, i) => i + 1);
|
||||
|
||||
Plotly.newPlot("plot_strategy", [
|
||||
{
|
||||
x,
|
||||
y: tpw,
|
||||
type: "bar",
|
||||
name: "Trades / window",
|
||||
yaxis: "y1"
|
||||
},
|
||||
{
|
||||
x,
|
||||
y: tpd,
|
||||
type: "scatter",
|
||||
mode: "lines+markers",
|
||||
name: "Trades / day",
|
||||
yaxis: "y2"
|
||||
}
|
||||
], {
|
||||
margin: { t: 40 },
|
||||
title: `Trade Density — ${strategyId}`,
|
||||
barmode: "group",
|
||||
xaxis: { title: "Window" },
|
||||
yaxis: { title: "Trades / window" },
|
||||
yaxis2: {
|
||||
title: "Trades / day",
|
||||
overlaying: "y",
|
||||
side: "right",
|
||||
zeroline: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =================================================
|
||||
// RENDER RESULTS
|
||||
// =================================================
|
||||
@@ -854,6 +1027,7 @@ function populatePlotSelector(data) {
|
||||
function selectStrategy(strategyId, data) {
|
||||
if (!strategyId || !data) return;
|
||||
|
||||
// Actualiza selectedStrategyId
|
||||
selectedStrategyId = strategyId;
|
||||
|
||||
const row = (data.results || []).find(r => r.strategy_id === strategyId);
|
||||
@@ -880,35 +1054,26 @@ function selectStrategy(strategyId, data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) Renderizar serie si existe
|
||||
const s = data?.series?.strategies?.[strategyId];
|
||||
if (!s) {
|
||||
// fallback explícito (por si backend antiguo no manda series_available)
|
||||
// 3) Verificar si los datos de la estrategia están disponibles
|
||||
const strategyData = data?.series?.strategies?.[selectedStrategyId];
|
||||
|
||||
if (!strategyData) {
|
||||
showPlotAlert(
|
||||
row?.status === "fail" ? "danger" : "warning",
|
||||
`${(row?.status || "warning").toUpperCase()} — ${strategyId}`,
|
||||
row?.message || "No chart series available for this strategy.",
|
||||
row?.warnings
|
||||
"warning",
|
||||
`No data available — ${strategyId}`,
|
||||
"Strategy data not available for rendering.",
|
||||
[]
|
||||
);
|
||||
clearPlots();
|
||||
highlightSelectedRow(strategyId);
|
||||
return;
|
||||
}
|
||||
|
||||
renderStrategyCharts(strategyId, s, data);
|
||||
highlightSelectedRow(strategyId);
|
||||
// 4) Mantén el gráfico previamente seleccionado en el dropdown
|
||||
const chartType = document.getElementById("plot_strategy_select").value;
|
||||
renderChart(chartType, selectedStrategyId, strategyData, data); // Renderiza el gráfico correctamente
|
||||
|
||||
// 4) Caso “serie vacía” (opción B) -> warning explícito (aunque ya lo tengas)
|
||||
const trd = s.window_trades || [];
|
||||
const hasTrades = Array.isArray(trd) && trd.some(v => (v ?? 0) > 0);
|
||||
if (!hasTrades && row?.status !== "fail") {
|
||||
showPlotAlert(
|
||||
"warning",
|
||||
`NO TRADES — ${strategyId}`,
|
||||
"Walk-forward produced no closed trades in OOS. Charts may be flat/empty.",
|
||||
row?.warnings
|
||||
);
|
||||
}
|
||||
highlightSelectedRow(strategyId);
|
||||
}
|
||||
|
||||
function renderValidateResponse(data) {
|
||||
@@ -1011,115 +1176,27 @@ function renderValidateResponse(data) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderStrategyCharts(strategyId, s, data) {
|
||||
|
||||
if (!s) return
|
||||
|
||||
// ============================
|
||||
// 1️⃣ EQUITY
|
||||
// ============================
|
||||
|
||||
Plotly.newPlot("plot_equity", [{
|
||||
y: s.window_equity,
|
||||
type: "scatter",
|
||||
mode: "lines",
|
||||
name: "Equity"
|
||||
}], {
|
||||
margin: { t: 20 },
|
||||
title: `Equity — ${strategyId}`
|
||||
});
|
||||
|
||||
// ============================
|
||||
// 2️⃣ RETURNS + TRADES
|
||||
// ============================
|
||||
|
||||
const ret = s.window_returns_pct || [];
|
||||
const trd = s.window_trades || [];
|
||||
|
||||
const retMax = Math.max(0, ...ret);
|
||||
const retMin = Math.min(0, ...ret);
|
||||
|
||||
const minTrades = data.config?.wf?.min_trades_test ?? 10;
|
||||
|
||||
const trdMaxRaw = Math.max(0, ...trd);
|
||||
const trdMax = Math.max(trdMaxRaw, minTrades);
|
||||
|
||||
// Evitar divisiones raras
|
||||
const retPosSpan = Math.max(1e-9, retMax);
|
||||
const retNegSpan = Math.abs(retMin);
|
||||
|
||||
// Alinear el 0 visualmente
|
||||
const trdNegSpan = (retNegSpan / retPosSpan) * trdMax;
|
||||
|
||||
const y1Range = [retMin, retMax];
|
||||
const y2Range = [-trdNegSpan, trdMax];
|
||||
|
||||
Plotly.newPlot("plot_returns", [
|
||||
|
||||
{
|
||||
y: ret,
|
||||
type: "bar",
|
||||
name: "Return %",
|
||||
marker: { color: "#3b82f6" },
|
||||
yaxis: "y1",
|
||||
offsetgroup: "returns",
|
||||
alignmentgroup: "group1"
|
||||
},
|
||||
|
||||
{
|
||||
y: trd,
|
||||
type: "bar",
|
||||
name: "Trades",
|
||||
marker: { color: "#f59e0b" },
|
||||
yaxis: "y2",
|
||||
offsetgroup: "trades",
|
||||
alignmentgroup: "group1"
|
||||
}
|
||||
|
||||
], {
|
||||
|
||||
margin: { t: 20 },
|
||||
barmode: "group",
|
||||
|
||||
yaxis: {
|
||||
title: "Return %",
|
||||
range: y1Range,
|
||||
zeroline: true,
|
||||
zerolinewidth: 2
|
||||
},
|
||||
|
||||
yaxis2: {
|
||||
title: "Trades",
|
||||
overlaying: "y",
|
||||
side: "right",
|
||||
range: y2Range,
|
||||
zeroline: true,
|
||||
zerolinewidth: 2
|
||||
},
|
||||
|
||||
shapes: [
|
||||
{
|
||||
type: "line",
|
||||
x0: -0.5,
|
||||
x1: trd.length - 0.5,
|
||||
y0: minTrades,
|
||||
y1: minTrades,
|
||||
yref: "y2",
|
||||
line: {
|
||||
color: "red",
|
||||
width: 2,
|
||||
dash: "dash"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
legend: {
|
||||
orientation: "h"
|
||||
},
|
||||
|
||||
title: `Returns & Trades — ${strategyId}`
|
||||
|
||||
});
|
||||
function renderChart(chartType, strategyId, s, data) {
|
||||
switch (chartType) {
|
||||
case "equity":
|
||||
renderEquityAndReturns(strategyId, s, data);
|
||||
break;
|
||||
case "rolling_sharpe":
|
||||
renderRollingSharpe(strategyId, s, data);
|
||||
break;
|
||||
case "hist_oos_returns":
|
||||
renderOOSReturnsDistribution(strategyId, s, data);
|
||||
break;
|
||||
case "drawdown":
|
||||
renderDrawdownEvolution(strategyId, s, data);
|
||||
break;
|
||||
case "trade_density":
|
||||
renderTradeDensity(strategyId, s, data);
|
||||
break;
|
||||
default:
|
||||
renderEquityAndReturns(strategyId, s, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function highlightSelectedRow(strategyId) {
|
||||
@@ -1309,6 +1386,17 @@ async function init() {
|
||||
.addEventListener("change", updateStopUI);
|
||||
|
||||
wireButtons();
|
||||
|
||||
document.getElementById("plot_strategy_select").addEventListener("change", function() {
|
||||
const chartType = this.value;
|
||||
const strategyData = lastValidationResult.series.strategies[selectedStrategyId];
|
||||
|
||||
// Verifica que selectedStrategyId tenga el valor correcto
|
||||
console.log("selectedStrategyId:", selectedStrategyId);
|
||||
console.log("Strategy Data:", strategyData);
|
||||
|
||||
renderChart(chartType, selectedStrategyId, strategyData, lastValidationResult);
|
||||
});
|
||||
|
||||
const strategies = await fetchAvailableStrategies();
|
||||
renderStrategiesList(strategies);
|
||||
@@ -1329,7 +1417,7 @@ function ensurePlotAlertContainer() {
|
||||
let el = document.getElementById("plot_alert");
|
||||
if (el) return el;
|
||||
|
||||
const anchor = document.getElementById("plot_equity");
|
||||
const anchor = document.getElementById("plot_strategy");
|
||||
if (!anchor || !anchor.parentElement) return null;
|
||||
|
||||
el = document.createElement("div");
|
||||
@@ -1373,10 +1461,8 @@ function clearPlotAlert() {
|
||||
}
|
||||
|
||||
function clearPlots() {
|
||||
const eq = document.getElementById("plot_equity");
|
||||
const ret = document.getElementById("plot_returns");
|
||||
const eq = document.getElementById("plot_strategy");
|
||||
if (eq) eq.innerHTML = "";
|
||||
if (ret) ret.innerHTML = "";
|
||||
}
|
||||
|
||||
document.getElementById("lock_inherited")
|
||||
|
||||
Reference in New Issue
Block a user