Add tab system to right sidebar with Indicators and Strategies
- Add two-tab navigation (Indicators, Strategies) in right sidebar - Move all strategy-related content to Strategies tab - Implement sidebar collapse/expand functionality - Add indicator visibility toggle (eye button) - Fix bug where wrong interval data was deleted on TF switch - Add localStorage persistence for sidebar state and active tab - Ensure indicators recalculate when TF changes
This commit is contained in:
@ -193,21 +193,19 @@ export function renderIndicatorPanel() {
|
||||
}
|
||||
|
||||
function renderIndicatorItem(indicator, isFavorite) {
|
||||
const colorDots = '';
|
||||
|
||||
return `
|
||||
<div class="indicator-item ${isFavorite ? 'favorite' : ''}" data-type="${indicator.type}">
|
||||
<div class="indicator-item-main">
|
||||
<span class="indicator-name">${indicator.name}</span>
|
||||
<span class="indicator-desc">${indicator.description || ''}</span>
|
||||
</div>
|
||||
<div class="indicator-actions">
|
||||
<button class="indicator-btn add" data-type="${indicator.type}" title="Add to chart">+</button>
|
||||
${isFavorite ? '' : `
|
||||
<button class="indicator-btn favorite" data-type="${indicator.type}" title="Add to favorites">
|
||||
${userPresets.favorites?.includes(indicator.type) ? '★' : '☆'}
|
||||
</button>
|
||||
`}
|
||||
<div class="indicator-actions">
|
||||
<button class="indicator-btn add" data-type="${indicator.type}" title="Add to chart">+</button>
|
||||
${isFavorite ? '' : `
|
||||
<button class="indicator-btn favorite" data-type="${indicator.type}" title="Add to favorites">
|
||||
${userPresets.favorites?.includes(indicator.type) ? '★' : '☆'}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -238,7 +236,7 @@ function renderActiveIndicator(indicator) {
|
||||
<button class="indicator-btn favorite" onclick="event.stopPropagation(); window.toggleFavorite && window.toggleFavorite('${indicator.type}')" title="Add to favorites">
|
||||
${isFavorite ? '★' : '☆'}
|
||||
</button>
|
||||
<button class="indicator-btn expand ${isExpanded ? 'rotated' : ''}" data-id="${indicator.id}" title="Show settings">
|
||||
<button class="indicator-btn expand ${isExpanded ? 'rotated' : ''}" data-id="${indicator.id}" onclick="event.stopPropagation(); window.toggleIndicatorExpand && window.toggleIndicatorExpand('${indicator.id}')" title="Show settings">
|
||||
${isExpanded ? '▼' : '▶'}
|
||||
</button>
|
||||
</div>
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user