- Loading strategies...
+
+
+
-
-
+
+ 📊 Indicators
-
- ⚙️ Configuration
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
+
-
+ 📋 Select Strategy
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 📊 Results
-
-
-
-
-
-
-
-
-
-
-
-
- --
- Trades
-
-
- --
- Win Rate
-
-
- --
- Total P&L
-
-
- --
- Profit Factor
+
+
-
-
-
-
-
+ Loading strategies...
-
- 💾 Saved Simulations
+
+
+
+
-
+ ⚙️ Configuration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
`;
@@ -238,7 +236,7 @@ function renderActiveIndicator(indicator) {
-
@@ -640,7 +638,21 @@ function saveUserPresets() {
}
function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, lineStyleMap) {
+ console.log(`renderIndicatorOnPane for ${indicator.id}, candles.length=${candles.length}, paneIndex=${paneIndex}`);
+
+ // Recalculate with current TF candles
const results = instance.calculate(candles);
+ console.log(`Calculated results for ${indicator.id}:`, results?.length || 0, 'values');
+
+ // Clear previous series for this indicator
+ if (indicator.series && indicator.series.length > 0) {
+ indicator.series.forEach(s => {
+ try {
+ window.dashboard.chart.removeSeries(s);
+ console.log(`Removed series for ${indicator.id}`);
+ } catch(e) { console.error('Error removing series:', e); }
+ });
+ }
indicator.series = [];
const lineStyle = lineStyleMap[indicator.params._lineType] || LightweightCharts.LineStyle.Solid;
@@ -649,10 +661,14 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
const firstNonNull = results?.find(r => r !== null && r !== undefined);
const isObjectResult = firstNonNull && typeof firstNonNull === 'object';
+ let plotsCreated = 0;
meta.plots.forEach((plot, plotIdx) => {
if (isObjectResult) {
const hasData = results.some(r => r && r[plot.id] !== undefined && r[plot.id] !== null);
- if (!hasData) return;
+ if (!hasData) {
+ console.log(`No data for plot ${plot.id} in ${indicator.id}`);
+ return;
+ }
}
const plotColor = indicator.params[`_color_${plotIdx}`] || plot.color || '#2962ff';
@@ -674,6 +690,7 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
}
}
+ console.log(`Plot ${plot.id} has ${data.length} data points`);
if (data.length === 0) return;
let series;
@@ -716,6 +733,8 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
series.setData(data);
indicator.series.push(series);
+ plotsCreated++;
+ console.log(`Created series for ${indicator.id}, plot=${plot.id}, total series now=${indicator.series.length}`);
// Create horizontal band lines for RSI
if (meta.name === 'RSI' && indicator.series.length > 0) {
@@ -756,17 +775,28 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
// Chart drawing
export function drawIndicatorsOnChart() {
- if (!window.dashboard || !window.dashboard.chart) return;
+ if (!window.dashboard || !window.dashboard.chart) {
+ return;
+ }
+ const currentInterval = window.dashboard.currentInterval;
+ const candles = window.dashboard.allData.get(currentInterval);
+
+ if (!candles || candles.length === 0) {
+ return;
+ }
+
+ // Log: Ensure we're using the correct interval candles
+ console.log(`drawIndicatorsOnChart for interval=${currentInterval}, candles=${candles.length}`);
+
+ // First, remove all existing series
activeIndicators.forEach(ind => {
ind.series?.forEach(s => {
try { window.dashboard.chart.removeSeries(s); } catch(e) {}
});
+ ind.series = [];
});
- const candles = window.dashboard.allData.get(window.dashboard.currentInterval);
- if (!candles || candles.length === 0) return;
-
const lineStyleMap = {
'solid': LightweightCharts.LineStyle.Solid,
'dotted': LightweightCharts.LineStyle.Dotted,
@@ -779,7 +809,12 @@ export function drawIndicatorsOnChart() {
const overlayIndicators = [];
const paneIndicators = [];
+ // Process all indicators, filtering by visibility
activeIndicators.forEach(ind => {
+ if (ind.visible === false) {
+ return;
+ }
+
const IndicatorClass = IR?.[ind.type];
if (!IndicatorClass) return;
@@ -793,37 +828,37 @@ export function drawIndicatorsOnChart() {
}
});
+ console.log('Rendering indicators:', { overlayCount: overlayIndicators.length, paneCount: paneIndicators.length });
+
+ // Calculate heights based on VISIBLE indicators only
const totalPanes = 1 + paneIndicators.length;
const mainPaneHeight = paneIndicators.length > 0 ? 60 : 100;
const paneHeight = paneIndicators.length > 0 ? Math.floor(40 / paneIndicators.length) : 0;
window.dashboard.chart.panes()[0]?.setHeight(mainPaneHeight);
+ let totalSeriesCreated = 0;
overlayIndicators.forEach(({ indicator, meta, instance }) => {
- if (indicator.visible === false) {
- indicator.series = [];
- return;
- }
-
+ const oldLen = indicator.series.length;
renderIndicatorOnPane(indicator, meta, instance, candles, 0, lineStyleMap);
+ totalSeriesCreated += indicator.series.length - oldLen;
});
paneIndicators.forEach(({ indicator, meta, instance }, idx) => {
- if (indicator.visible === false) {
- indicator.series = [];
- return;
- }
-
const paneIndex = nextPaneIndex++;
indicatorPanes.set(indicator.id, paneIndex);
+ const oldLen = indicator.series.length;
renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, lineStyleMap);
+ totalSeriesCreated += indicator.series.length - oldLen;
const pane = window.dashboard.chart.panes()[paneIndex];
if (pane) {
pane.setHeight(paneHeight);
}
});
+
+ console.log(`drawIndicatorsOnChart complete - created ${totalSeriesCreated} series for ${overlayIndicators.length + paneIndicators.length} visible indicators`);
}
function resetIndicator(id) {
@@ -849,14 +884,31 @@ function removeIndicator(id) {
removeIndicatorById(id);
}
+function toggleIndicatorVisibility(id) {
+ const indicator = activeIndicators.find(a => a.id === id);
+ if (!indicator) {
+ return;
+ }
+
+ indicator.visible = indicator.visible === false;
+
+ // Full redraw to ensure all indicators render correctly
+ if (typeof drawIndicatorsOnChart === 'function') {
+ drawIndicatorsOnChart();
+ }
+
+ renderIndicatorPanel();
+}
+
// Export functions for module access
-export { addIndicator, removeIndicatorById };
+export { addIndicator, removeIndicatorById, toggleIndicatorVisibility };
// Legacy compatibility functions
window.renderIndicatorList = renderIndicatorPanel;
window.resetIndicator = resetIndicator;
window.removeIndicator = removeIndicator;
window.toggleIndicator = addIndicator;
+window.toggleIndicatorVisibility = toggleIndicatorVisibility;
window.showIndicatorConfig = function(id) {
const ind = activeIndicators.find(a => a.id === id);
if (ind) configuringId = id;
diff --git a/src/api/dashboard/static/js/ui/sidebar.js b/src/api/dashboard/static/js/ui/sidebar.js
index f7bffcd..54434ac 100644
--- a/src/api/dashboard/static/js/ui/sidebar.js
+++ b/src/api/dashboard/static/js/ui/sidebar.js
@@ -22,3 +22,46 @@ export function restoreSidebarState() {
sidebar.classList.add('collapsed');
}
}
+
+// Tab Management
+let activeTab = 'indicators';
+
+export function initSidebarTabs() {
+ const tabs = document.querySelectorAll('.sidebar-tab');
+
+ tabs.forEach(tab => {
+ tab.addEventListener('click', () => {
+ switchTab(tab.dataset.tab);
+ });
+ });
+}
+
+export function switchTab(tabId) {
+ activeTab = tabId;
+ localStorage.setItem('sidebar_active_tab', tabId);
+
+ document.querySelectorAll('.sidebar-tab').forEach(tab => {
+ tab.classList.toggle('active', tab.dataset.tab === tabId);
+ });
+
+ document.querySelectorAll('.sidebar-tab-panel').forEach(panel => {
+ panel.classList.toggle('active', panel.id === `tab-${tabId}`);
+ });
+
+ if (tabId === 'indicators') {
+ setTimeout(() => {
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
+ }, 50);
+ }
+}
+
+export function getActiveTab() {
+ return activeTab;
+}
+
+export function restoreSidebarTabState() {
+ const savedTab = localStorage.getItem('sidebar_active_tab') || 'indicators';
+ switchTab(savedTab);
+}
- No saved simulations
+
+
+
+
+
+
diff --git a/src/api/dashboard/static/js/app.js b/src/api/dashboard/static/js/app.js
index 7b6bb01..c4ff4ce 100644
--- a/src/api/dashboard/static/js/app.js
+++ b/src/api/dashboard/static/js/app.js
@@ -1,5 +1,5 @@
import { TradingDashboard, refreshTA, openAIAnalysis } from './ui/chart.js';
-import { restoreSidebarState, toggleSidebar } from './ui/sidebar.js';
+import { restoreSidebarState, toggleSidebar, initSidebarTabs, restoreSidebarTabState } from './ui/sidebar.js';
import { SimulationStorage } from './ui/storage.js';
import { showExportDialog, closeExportDialog, performExport, exportSavedSimulation } from './ui/export.js';
import {
@@ -70,7 +70,6 @@ window.renderIndicatorList = function() {
// Export init function for global access
window.initIndicatorPanel = initIndicatorPanel;
-window.initIndicatorPanel = initIndicatorPanel;
window.addIndicator = addIndicator;
window.toggleIndicator = addIndicator;
@@ -81,6 +80,8 @@ window.IndicatorRegistry = IndicatorRegistry;
document.addEventListener('DOMContentLoaded', async () => {
window.dashboard = new TradingDashboard();
restoreSidebarState();
+ restoreSidebarTabState();
+ initSidebarTabs();
setDefaultStartDate();
updateTimeframeDisplay();
renderSavedSimulations();
@@ -93,6 +94,24 @@ document.addEventListener('DOMContentLoaded', async () => {
const originalSwitchTimeframe = window.dashboard.switchTimeframe.bind(window.dashboard);
window.dashboard.switchTimeframe = function(interval) {
originalSwitchTimeframe(interval);
- setTimeout(() => drawIndicatorsOnChart(), 500);
+
+ // Force redraw indicators after TF switch with multiple attempts
+ setTimeout(() => {
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
+ }, 100);
+
+ setTimeout(() => {
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
+ }, 300);
+
+ setTimeout(() => {
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
+ }, 500);
};
});
diff --git a/src/api/dashboard/static/js/ui/chart.js b/src/api/dashboard/static/js/ui/chart.js
index ee334ea..219c4d8 100644
--- a/src/api/dashboard/static/js/ui/chart.js
+++ b/src/api/dashboard/static/js/ui/chart.js
@@ -303,7 +303,7 @@ async loadInitialData() {
const response = await fetch(`/api/v1/candles?symbol=BTC&interval=${this.currentInterval}&limit=${limit}`);
const data = await response.json();
- if (data.candles && data.candles.length > 0) {
+if (data.candles && data.candles.length > 0) {
const chartData = data.candles.reverse().map(c => ({
time: Math.floor(new Date(c.time).getTime() / 1000),
open: parseFloat(c.open),
@@ -328,6 +328,11 @@ async loadInitialData() {
const latest = mergedData[mergedData.length - 1];
this.updateStats(latest);
}
+
+ // Always try to redraw indicators after candles are set
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
} catch (error) {
console.error('Error loading data:', error);
} finally {
@@ -342,7 +347,7 @@ async loadInitialData() {
const response = await fetch(`/api/v1/candles?symbol=BTC&interval=${this.currentInterval}&limit=50`);
const data = await response.json();
- if (data.candles && data.candles.length > 0) {
+if (data.candles && data.candles.length > 0) {
const atEdge = this.isAtRightEdge();
const currentSeriesData = this.candleSeries.data();
@@ -374,6 +379,11 @@ async loadInitialData() {
const latest = chartData[chartData.length - 1];
this.updateStats(latest);
+
+ // Redraw indicators when new data loads
+ if (window.drawIndicatorsOnChart) {
+ window.drawIndicatorsOnChart();
+ }
}
} catch (error) {
console.error('Error loading new data:', error);
@@ -586,6 +596,7 @@ async loadTA() {
switchTimeframe(interval) {
if (!this.intervals.includes(interval) || interval === this.currentInterval) return;
+ const oldInterval = this.currentInterval;
this.currentInterval = interval;
this.hasInitialLoad = false;
@@ -593,9 +604,9 @@ async loadTA() {
btn.classList.toggle('active', btn.dataset.interval === interval);
});
- this.allData.delete(interval);
+ // Clear old interval data, not new interval
+ this.allData.delete(oldInterval);
this.loadInitialData();
- // Don't reload TA on timeframe switch - let user refresh manually
window.clearSimulationResults?.();
window.updateTimeframeDisplay?.();
diff --git a/src/api/dashboard/static/js/ui/indicators-panel-new.js b/src/api/dashboard/static/js/ui/indicators-panel-new.js
index 8d30383..bd77e9b 100644
--- a/src/api/dashboard/static/js/ui/indicators-panel-new.js
+++ b/src/api/dashboard/static/js/ui/indicators-panel-new.js
@@ -193,21 +193,19 @@ export function renderIndicatorPanel() {
}
function renderIndicatorItem(indicator, isFavorite) {
- const colorDots = '';
-
return `
+
+
+
+
+ 📊 Results
+
+
+
+
+
+
+
+
+
+
+
+
+
+ --
+ Trades
+
+
+ --
+ Win Rate
+
+
+ --
+ Total P&L
+
+
+ --
+ Profit Factor
+
+
+ 💾 Saved Simulations
+
+
+
+ No saved simulations
+
${indicator.name}
${indicator.description || ''}
-
-
-
- ${isFavorite ? '' : `
-
- `}
+
+
+ ${isFavorite ? '' : `
+
+ `}
+