Add signal markers on main chart with configurable shapes and colors
- Create signal-markers.js module to calculate crossover markers for indicators - Add marker configuration options to indicator config panel: - Show/hide markers toggle - Buy/sell shape selection (built-in or custom Unicode) - Buy/sell color pickers - Integrate markers with lightweight-charts using createSeriesMarkers API - Markers recalculate when indicators change or historical data loads
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import { INTERVALS, COLORS } from '../core/index.js';
|
||||
import { calculateAllIndicatorSignals, calculateSummarySignal } from './signals-calculator.js';
|
||||
import { calculateSignalMarkers } from './signal-markers.js';
|
||||
import { updateIndicatorCandles } from './indicators-panel-new.js';
|
||||
import { TimezoneConfig } from '../config/timezone.js';
|
||||
|
||||
@ -575,6 +576,7 @@ async loadSignals() {
|
||||
try {
|
||||
this.indicatorSignals = calculateAllIndicatorSignals();
|
||||
this.summarySignal = calculateSummarySignal(this.indicatorSignals);
|
||||
this.updateSignalMarkers();
|
||||
} catch (error) {
|
||||
console.error('Error loading signals:', error);
|
||||
this.indicatorSignals = [];
|
||||
@ -582,7 +584,87 @@ async loadSignals() {
|
||||
}
|
||||
}
|
||||
|
||||
renderTA() {
|
||||
updateSignalMarkers() {
|
||||
const candles = this.allData.get(this.currentInterval);
|
||||
if (!candles || candles.length === 0) return;
|
||||
|
||||
const markers = calculateSignalMarkers(candles);
|
||||
|
||||
// If we have a marker controller, update markers through it
|
||||
if (this.markerController) {
|
||||
try {
|
||||
this.markerController.setMarkers(markers);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.warn('[SignalMarkers] setMarkers error:', e.message);
|
||||
this.markerController = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear price lines
|
||||
if (this.markerPriceLines) {
|
||||
this.markerPriceLines.forEach(ml => {
|
||||
try { this.candleSeries.removePriceLine(ml); } catch (e) {}
|
||||
});
|
||||
this.markerPriceLines = [];
|
||||
}
|
||||
|
||||
if (markers.length === 0) return;
|
||||
|
||||
// Create new marker controller
|
||||
if (typeof LightweightCharts.createSeriesMarkers === 'function') {
|
||||
try {
|
||||
this.markerController = LightweightCharts.createSeriesMarkers(this.candleSeries, markers);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.warn('[SignalMarkers] createSeriesMarkers error:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: use price lines
|
||||
this.addMarkerPriceLines(markers);
|
||||
}
|
||||
|
||||
addMarkerPriceLines(markers) {
|
||||
if (this.markerPriceLines) {
|
||||
this.markerPriceLines.forEach(ml => {
|
||||
try { this.candleSeries.removePriceLine(ml); } catch (e) {}
|
||||
});
|
||||
}
|
||||
this.markerPriceLines = [];
|
||||
|
||||
const recentMarkers = markers.slice(-20);
|
||||
|
||||
recentMarkers.forEach(m => {
|
||||
const isBuy = m.position === 'belowBar';
|
||||
const price = isBuy ? this.getMarkerLowPrice(m.time) : this.getMarkerHighPrice(m.time);
|
||||
|
||||
const priceLine = this.candleSeries.createPriceLine({
|
||||
price: price,
|
||||
color: m.color,
|
||||
lineWidth: 2,
|
||||
lineStyle: LightweightCharts.LineStyle.Dashed,
|
||||
axisLabelVisible: true,
|
||||
title: m.text
|
||||
});
|
||||
|
||||
this.markerPriceLines.push(priceLine);
|
||||
});
|
||||
}
|
||||
|
||||
getMarkerLowPrice(time) {
|
||||
const candles = this.allData.get(this.currentInterval);
|
||||
const candle = candles?.find(c => c.time === time);
|
||||
return candle ? candle.low * 0.995 : 0;
|
||||
}
|
||||
|
||||
getMarkerHighPrice(time) {
|
||||
const candles = this.allData.get(this.currentInterval);
|
||||
const candle = candles?.find(c => c.time === time);
|
||||
return candle ? candle.high * 1.005 : 0;
|
||||
}
|
||||
|
||||
renderTA() {
|
||||
if (!this.taData || this.taData.error) {
|
||||
document.getElementById('taContent').innerHTML = `<div class="ta-error">${this.taData?.error || 'No data available'}</div>`;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user