const urlParams = new URLSearchParams(window.location.search); const symbol = urlParams.get('symbol'); const time = urlParams.get('time'); //window.dispatchEvent(new Event('resize')); function timeToLocal(originalTime) { const d = new Date(originalTime * 1000); return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()) / 1000; } function parseCSV(data) { const rows = data.split("\n"); const result = []; let start = Math.max(rows.length - 298, 0); let lastElements = rows.slice(start) for (let i = start; i < rows.length; i++) { const cols = rows[i].split(","); if (cols.length >= 23 && cols.every(element => element !== undefined && element !== null)) { // check for existing lines // parse the date so seconds since 1970 cols[0] = Date.parse(cols[0])/1000,result.push(cols); cols[0] = timeToLocal(cols[0]); // coloring for MACD-Histogram if (cols[20] < 0) { cols[100] = "orange"; if (cols[23] > 20) { cols[100] = "red"; } } else { cols[100] = "lightgreen"; if (cols[23] > 20) { cols[100] = "green"; } } } else { console.log("invalid line on linenr " + i + ": " +rows[i]); } } return result; } // Create the Lightweight Chart within the container element const chart = LightweightCharts.createChart(document.getElementById('container'), { rightPriceScale: { minimumWidth: 100, borderVisible: false }, height: 500, crosshair: { mode: 0, }, timeScale: { timeVisible: true, secondsVisible: false, }, layout: { background: { type: 'solid', color: '#222', }, textColor: '#DDD', }, grid: { vertLines: { color: '#444' }, horzLines: { color: '#444' }, }, }); chart.applyOptions({ watermark: { visible: true, fontSize: 18, horzAlign: 'top', vertAlign: 'left', color: '#DDD', text: symbol + " " + time, }}); // define chart const candleSeries = chart.addCandlestickSeries(); const lineSeriesEMA12 = chart.addLineSeries({ color: 'red', lineWidth: 1, priceLineVisible: false}); const lineSeriesEMA26 = chart.addLineSeries({ color: 'pink', lineWidth: 1, lineStyle: 2, priceLineVisible: false}); const lineSeriesEMA50 = chart.addLineSeries({ color: 'cyan', lineWidth: 1, priceLineVisible: false}); const lineSeriesEMA100 = chart.addLineSeries({ color: 'yellow', lineWidth: 1, priceLineVisible: false}); const lineSeriesEMA200 = chart.addLineSeries({ color: 'white', lineWidth: 1, priceLineVisible: false}); const lineSeriesEMA400 = chart.addLineSeries({ color: 'orange', lineWidth: 1, priceLineVisible: false}); const lineSeriesEMA800 = chart.addLineSeries({ color: 'purple', lineWidth: 1, priceLineVisible: false}); // RSI Chart const chartrsi = LightweightCharts.createChart(document.getElementById("container"), { rightPriceScale: { minimumWidth: 100, borderVisible: false }, height: 200, timeScale: { visible: false, }, layout: { background: { type: 'solid', color: '#222', }, textColor: '#DDD', }, grid: { vertLines: { color: '#444' }, horzLines: { color: '#444' }, }, }); chartrsi.applyOptions({ watermark: { visible: true, fontSize: 18, horzAlign: 'top', vertAlign: 'left', color: '#DDD', text: 'RSI 5,14,21', }}); const lineSeriesRSI5 = chartrsi.addLineSeries({ color: 'orange', lineWidth: 1, lineStyle: 2, priceLineVisible: false}); const lineSeriesRSI14 = chartrsi.addLineSeries({ color: 'yellow', lineWidth: 2, priceLineVisible: false}); const lineSeriesRSI21 = chartrsi.addLineSeries({ color: 'lightgreen', lineWidth: 1, lineStyle: 2, priceLineVisible: false}); // MACD Chart const chartmacd = LightweightCharts.createChart(document.getElementById("container"), { rightPriceScale: { minimumWidth: 100, borderVisible: false }, height: 200, timeScale: { timeVisible: true, secondsVisible: false, }, layout: { background: { type: 'solid', color: '#222', }, textColor: '#DDD', }, grid: { vertLines: { color: '#444' }, horzLines: { color: '#444' }, }, }); chartmacd.applyOptions({ watermark: { visible: true, fontSize: 18, horzAlign: 'top', vertAlign: 'left', color: '#DDD', text: 'MACD 12 26', }}); const lineSeriesMACD = chartmacd.addLineSeries({ color: 'blue', lineWidth: 1, lineStyle: 0, priceLineVisible: false}); const lineSeriesMACDSignal = chartmacd.addLineSeries({ color: 'orange', lineWidth: 1, lineStyle: 0, priceLineVisible: false}); const histogramSeriesMACD = chartmacd.addHistogramSeries({ priceFormat: { type: 'volume', color: 'orange', }, //priceScaleId: '', // set as an overlay by setting a blank priceScaleId }); fetch("/botdata/asset-histories/" + symbol + ".history." + time + ".csv") .then(response => response.text()) .then(data => { const parsedData = parseCSV(data); // OHLC Data const bars = parsedData.map(item => ({ time: item[0], open: item[1], high: item[2], low: item[3], close: item[4] })); candleSeries.setData(bars); // EMA Data candleSeries.setData(bars); const lineSeriesEMA12Data = parsedData.map(item => ({ time: item[0], value: item[8] })); lineSeriesEMA12.setData(lineSeriesEMA12Data); const lineSeriesEMA26Data = parsedData.map(item => ({ time: item[0], value: item[9] })); lineSeriesEMA26.setData(lineSeriesEMA26Data); const lineSeriesEMA50Data = parsedData.map(item => ({ time: item[0], value: item[10] })); lineSeriesEMA50.setData(lineSeriesEMA50Data); const lineSeriesEMA100Data = parsedData.map(item => ({ time: item[0], value: item[11] })); lineSeriesEMA100.setData(lineSeriesEMA100Data); const lineSeriesEMA200Data = parsedData.map(item => ({ time: item[0], value: item[12] })); lineSeriesEMA200.setData(lineSeriesEMA200Data); const lineSeriesEMA400Data = parsedData.map(item => ({ time: item[0], value: item[13] })); lineSeriesEMA400.setData(lineSeriesEMA400Data); const lineSeriesEMA800Data = parsedData.map(item => ({ time: item[0], value: item[14] })); lineSeriesEMA800.setData(lineSeriesEMA800Data); // RSI Data const lineSeriesRSI5Data = parsedData.map(item => ({ time: item[0], value: item[15] })); lineSeriesRSI5.setData(lineSeriesRSI5Data); const lineSeriesRSI14Data = parsedData.map(item => ({ time: item[0], value: item[16] })); lineSeriesRSI14.setData(lineSeriesRSI14Data); const lineSeriesRSI21Data = parsedData.map(item => ({ time: item[0], value: item[17] })); lineSeriesRSI21.setData(lineSeriesRSI21Data); // MACD Data const lineSeriesMACDData = parsedData.map(item => ({ time: item[0], value: item[18] })); lineSeriesMACD.setData(lineSeriesMACDData); const lineSeriesMACDSignalData = parsedData.map(item => ({ time: item[0], value: item[19] })); lineSeriesMACDSignal.setData(lineSeriesMACDSignalData); const histogramSeriesMACDData = parsedData.map(item => ({ time: item[0], value: item[20], color: item[100] })); histogramSeriesMACD.setData(histogramSeriesMACDData); }); // Lines for price levels fetch("/botdata/asset-histories/" + symbol + ".history.csv.levels") .then(response => response.text()) .then(text => { const levels = text.split('\n'); levels.forEach(function(level) { candleSeries.createPriceLine({price: level, color: "darkblue", lineWidth: 0.5, lineStyle: 0, axisLabelVisible: true, title: 'Level'}); }); }); // Sync charts timeScale chart.timeScale().fitContent(); chart.timeScale().subscribeVisibleLogicalRangeChange(timeRange => { chartrsi.timeScale().setVisibleLogicalRange(timeRange); chartmacd.timeScale().setVisibleLogicalRange(timeRange); }); chartrsi.timeScale().subscribeVisibleLogicalRangeChange(timeRange => { chart.timeScale().setVisibleLogicalRange(timeRange); }); chartmacd.timeScale().subscribeVisibleLogicalRangeChange(timeRange => { chart.timeScale().setVisibleLogicalRange(timeRange); }); function getCrosshairDataPoint(series, param) { if (!param.time) { return null; } const dataPoint = param.seriesData.get(series); return dataPoint || null; } function syncCrosshair(chart, series, dataPoint) { if (dataPoint) { chart.setCrosshairPosition(dataPoint.value, dataPoint.time, series); return; } chart.clearCrosshairPosition(); } chart.subscribeCrosshairMove(param => { const dataPoint = getCrosshairDataPoint(lineSeriesEMA50, param); syncCrosshair(chartrsi, lineSeriesRSI14, dataPoint); const dataPointmacd = getCrosshairDataPoint(lineSeriesEMA50, param); syncCrosshair(chartmacd, lineSeriesMACD, dataPointmacd); }); chartrsi.subscribeCrosshairMove(param => { const dataPoint = getCrosshairDataPoint(lineSeriesRSI14, param); syncCrosshair(chart, lineSeriesEMA50, dataPoint); const dataPointmacd = getCrosshairDataPoint(lineSeriesRSI14, param); syncCrosshair(chartmacd, lineSeriesMACD, dataPointmacd); }); chartmacd.subscribeCrosshairMove(param => { const dataPoint = getCrosshairDataPoint(lineSeriesMACD, param); syncCrosshair(chart, lineSeriesEMA50, dataPoint); const dataPointrsi = getCrosshairDataPoint(lineSeriesMACD, param); syncCrosshair(chartrsi, lineSeriesRSI14, dataPointrsi); });