85 lines
2.8 KiB
JavaScript
85 lines
2.8 KiB
JavaScript
class ConfluenceChart {
|
|
constructor() {
|
|
this.chart = null;
|
|
this.candles = null;
|
|
this.resizeObserver = null;
|
|
this.levelSeries = new Map();
|
|
}
|
|
|
|
create(el) {
|
|
this.chart = LightweightCharts.createChart(el, {
|
|
autoSize: true,
|
|
layout: {
|
|
background: { color: getComputedStyle(document.documentElement).getPropertyValue('--chart-bg').trim() },
|
|
textColor: getComputedStyle(document.documentElement).getPropertyValue('--muted').trim(),
|
|
},
|
|
grid: {
|
|
vertLines: { color: 'rgba(128,128,128,.10)' },
|
|
horzLines: { color: 'rgba(128,128,128,.10)' },
|
|
},
|
|
timeScale: { timeVisible: true, secondsVisible: false },
|
|
rightPriceScale: { borderVisible: false },
|
|
});
|
|
this.candles = this.chart.addSeries(LightweightCharts.CandlestickSeries, {
|
|
upColor: '#3fb984', downColor: '#e45757', borderVisible: false,
|
|
wickUpColor: '#3fb984', wickDownColor: '#e45757',
|
|
});
|
|
this.resizeObserver = new ResizeObserver(() => {
|
|
this.chart.applyOptions({ width: el.clientWidth, height: el.clientHeight });
|
|
});
|
|
this.resizeObserver.observe(el);
|
|
}
|
|
|
|
setBars(bars) {
|
|
this.candles.setData(bars.map(this.toCandle));
|
|
this.chart.timeScale().fitContent();
|
|
}
|
|
|
|
updateBar(bar) { this.candles.update(this.toCandle(bar)); }
|
|
|
|
syncLevels(levels) {
|
|
const wanted = new Set(levels.filter(level => !level.hidden).map(level => level.id));
|
|
for (const [id, entry] of this.levelSeries) {
|
|
if (!wanted.has(id)) {
|
|
this.chart.removeSeries(entry.series);
|
|
this.levelSeries.delete(id);
|
|
}
|
|
}
|
|
for (const level of levels) {
|
|
if (level.hidden) continue;
|
|
let entry = this.levelSeries.get(level.id);
|
|
const options = {
|
|
color: ConfluenceChart.tfColors[level.tf],
|
|
lineWidth: level.tf === '1d' ? 2 : 1,
|
|
lineType: LightweightCharts.LineType.WithSteps,
|
|
lineStyle: level.provisional ? LightweightCharts.LineStyle.Dashed : LightweightCharts.LineStyle.Solid,
|
|
priceLineVisible: false,
|
|
lastValueVisible: true,
|
|
title: level.label,
|
|
};
|
|
if (!entry) {
|
|
entry = { series: this.chart.addSeries(LightweightCharts.LineSeries, options) };
|
|
this.levelSeries.set(level.id, entry);
|
|
} else {
|
|
entry.series.applyOptions(options);
|
|
}
|
|
entry.series.setData((level.points || []).map(([time, value]) => ({ time, value })));
|
|
}
|
|
}
|
|
|
|
toCandle(bar) {
|
|
return { time: bar.t, open: bar.o, high: bar.h, low: bar.l, close: bar.c };
|
|
}
|
|
|
|
destroy() {
|
|
if (this.resizeObserver) this.resizeObserver.disconnect();
|
|
if (this.chart) this.chart.remove();
|
|
}
|
|
}
|
|
|
|
ConfluenceChart.tfColors = {
|
|
'1m':'#82909f', '2m':'#8a92df', '5m':'#65b7cf', '15m':'#45c39b',
|
|
'30m':'#a8c85d', '1h':'#efb643', '4h':'#ec7b42', '1d':'#d96073',
|
|
};
|
|
|
|
window.ConfluenceChart = ConfluenceChart;
|