From f2384b151d6fea4185587decfdbf5efc7c454c89 Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Mon, 30 Jun 2025 23:33:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9D=87=E7=BA=BF=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E7=94=A8=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/templates/index.html | 788 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 754 insertions(+), 34 deletions(-) diff --git a/web/templates/index.html b/web/templates/index.html index 43dfd69..35669f4 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -286,6 +286,72 @@ } /* 主次周期元素样式区分 */ + + /* 均线指标样式 */ + .ma-indicators { + position: absolute; + top: 10px; + left: 10px; + z-index: 100; + background-color: rgba(255, 255, 255, 0.95); + padding: 8px 12px; + border-radius: 6px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + max-width: calc(100% - 200px); + } + + .ma-indicator-item { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 6px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; + background-color: rgba(0,0,0,0.05); + border: 1px solid rgba(0,0,0,0.1); + } + + .ma-indicator-color { + width: 12px; + height: 2px; + border-radius: 1px; + } + + .ma-indicator-controls { + display: flex; + margin-left: 4px; + gap: 2px; + opacity: 0.6; + transition: opacity 0.3s ease; + } + + .ma-indicator-item:hover .ma-indicator-controls { + opacity: 1; + } + + .ma-control-btn { + width: 16px; + height: 16px; + border: none; + background: transparent; + color: #666; + cursor: pointer; + border-radius: 2px; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + } + + .ma-control-btn:hover { + background-color: rgba(0,0,0,0.1); + color: #333; + } + + .ma-indicator-value { + font-weight: bold; + } @@ -415,6 +481,14 @@ +
+ + +
@@ -524,6 +598,13 @@
+ +
@@ -778,7 +859,8 @@ elementUncompletedZsSeries: [], tradePointSeries: [], mainBollingerSeries: [], - elementBollingerSeries: [] + elementBollingerSeries: [], + movingAverageSeries: [] }, state: { isInitialized: false, @@ -787,6 +869,506 @@ } }; + // 均线系统相关变量 + let movingAverages = []; + let maCounter = 0; + + // 均线计算函数 + function calculateMovingAverage(data, period, type = 'SMA') { + if (!data || data.length < period) return []; + + const result = []; + + if (type === 'SMA') { + // 简单移动平均线 + for (let i = period - 1; i < data.length; i++) { + const sum = data.slice(i - period + 1, i + 1).reduce((acc, val) => acc + val.value, 0); + result.push({ + time: data[i].time, + value: sum / period + }); + } + } else if (type === 'EMA') { + // 指数移动平均线 + const multiplier = 2 / (period + 1); + let ema = data.slice(0, period).reduce((acc, val) => acc + val.value, 0) / period; + + result.push({ + time: data[period - 1].time, + value: ema + }); + + for (let i = period; i < data.length; i++) { + ema = (data[i].value * multiplier) + (ema * (1 - multiplier)); + result.push({ + time: data[i].time, + value: ema + }); + } + } else if (type === 'WMA') { + // 加权移动平均线 + const weights = []; + let weightSum = 0; + for (let i = 1; i <= period; i++) { + weights.push(i); + weightSum += i; + } + + for (let i = period - 1; i < data.length; i++) { + let weightedSum = 0; + for (let j = 0; j < period; j++) { + weightedSum += data[i - period + 1 + j].value * weights[j]; + } + result.push({ + time: data[i].time, + value: weightedSum / weightSum + }); + } + } + + return result; + } + + // 获取价格数据源 + function getPriceData(klineData, source) { + // 如果没有传入K线数据,使用当前数据源 + if (!klineData) { + // 检查是否使用小周期K线数据 + const useElementPeriod = $('#elementPeriodKline').is(':checked') && + currentData.element_kline_data && + Array.isArray(currentData.element_kline_data); + + console.log('均线使用数据源:', useElementPeriod ? '小周期' : '主周期'); + klineData = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + } + + if (!klineData || !Array.isArray(klineData)) { + console.warn('K线数据无效:', klineData); + return []; + } + + return klineData.map(kline => { + const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); + let value; + + switch (source) { + case 'open': + value = parseFloat(kline.open); + break; + case 'high': + value = parseFloat(kline.high); + break; + case 'low': + value = parseFloat(kline.low); + break; + case 'close': + value = parseFloat(kline.close); + break; + case 'hl2': + value = (parseFloat(kline.high) + parseFloat(kline.low)) / 2; + break; + case 'hlc3': + value = (parseFloat(kline.high) + parseFloat(kline.low) + parseFloat(kline.close)) / 3; + break; + case 'ohlc4': + value = (parseFloat(kline.open) + parseFloat(kline.high) + parseFloat(kline.low) + parseFloat(kline.close)) / 4; + break; + default: + value = parseFloat(kline.close); + } + + return { time: timestamp, value: value }; + }); + } + + // 应用平滑处理 + function applySmoothing(data, smoothingType, smoothingPeriod) { + if (smoothingType === 'none' || !smoothingPeriod || smoothingPeriod < 2) { + return data; + } + return calculateMovingAverage(data, smoothingPeriod, smoothingType); + } + + // 添加均线到图表 + function addMovingAverageToChart(config) { + const ma = { + id: `ma_${++maCounter}`, + ...config, + series: null, + visible: true + }; + + if (!currentData) { + console.error('没有数据,无法添加均线'); + return null; + } + + // 获取价格数据(自动选择数据源) + const priceData = getPriceData(null, config.source); + + // 计算均线 + let maData = calculateMovingAverage(priceData, config.period, config.type); + + // 应用平滑处理 + if (config.smoothing !== 'none' && config.smoothingPeriod > 1) { + maData = applySmoothing(maData, config.smoothing, config.smoothingPeriod); + } + + // 添加到图表 + const lineSeries = tvWidget.mainChart.addLineSeries({ + color: config.color, + lineWidth: config.lineWidth, + lineStyle: config.style === 'dashed' ? 1 : config.style === 'dotted' ? 3 : 0, + title: `${config.type}(${config.period})`, + lastValueVisible: false, + priceLineVisible: false, + crosshairMarkerVisible: true + }); + + lineSeries.setData(maData); + ma.series = lineSeries; + ma.data = maData; + + movingAverages.push(ma); + tvWidget.series.movingAverageSeries.push(lineSeries); + + // 更新显示 + updateMovingAverageIndicators(); + + return ma; + } + + // 删除均线 + function removeMovingAverage(maId) { + console.log('删除均线:', maId); + try { + const index = movingAverages.findIndex(ma => ma.id === maId); + if (index !== -1) { + const ma = movingAverages[index]; + console.log('找到要删除的均线:', ma); + + if (ma.series && tvWidget.mainChart) { + tvWidget.mainChart.removeSeries(ma.series); + + // 从 tvWidget.series.movingAverageSeries 中移除 + const seriesIndex = tvWidget.series.movingAverageSeries.indexOf(ma.series); + if (seriesIndex !== -1) { + tvWidget.series.movingAverageSeries.splice(seriesIndex, 1); + } + } + movingAverages.splice(index, 1); + updateMovingAverageIndicators(); + console.log('均线删除成功'); + } else { + console.warn('未找到要删除的均线:', maId); + } + } catch (error) { + console.error('删除均线时出错:', error); + } + } + + // 切换均线显示/隐藏 + function toggleMovingAverage(maId) { + console.log('切换均线显示状态:', maId); + try { + const ma = movingAverages.find(ma => ma.id === maId); + if (ma && ma.series) { + ma.visible = !ma.visible; + console.log('均线新状态:', ma.visible ? '显示' : '隐藏'); + ma.series.applyOptions({ + visible: ma.visible + }); + updateMovingAverageIndicators(); + console.log('均线状态切换成功'); + } else { + console.warn('未找到均线或series不存在:', maId, ma); + } + } catch (error) { + console.error('切换均线显示状态时出错:', error); + } + } + + // 更新均线指标显示 + function updateMovingAverageIndicators() { + console.log('更新均线指标显示,当前均线数量:', movingAverages.length); + try { + const container = $('#movingAverageIndicators'); + const list = $('#maIndicatorsList'); + + if (movingAverages.length === 0) { + container.hide(); + console.log('没有均线,隐藏指标容器'); + return; + } + + list.empty(); + + movingAverages.forEach((ma, index) => { + console.log(`创建均线指标 ${index + 1}:`, ma.id, ma.type, ma.period); + const latestValue = ma.data && ma.data.length > 0 ? ma.data[ma.data.length - 1].value : 0; + const smoothingText = ma.smoothing !== 'none' ? `/${ma.smoothing}(${ma.smoothingPeriod})` : ''; + + const indicator = $(` +
+
+ ${ma.type}(${ma.period})${smoothingText} + ${latestValue.toFixed(2)} +
+ + + +
+
+ `); + + list.append(indicator); + }); + + container.show(); + console.log('均线指标显示更新完成'); + } catch (error) { + console.error('更新均线指标显示时出错:', error); + } + } + + // 编辑均线配置 + function editMovingAverage(maId) { + console.log('编辑均线配置:', maId); + try { + const ma = movingAverages.find(ma => ma.id === maId); + if (!ma) { + console.warn('未找到要编辑的均线:', maId); + return; + } + + console.log('找到均线配置:', ma); + + // 填充表单 + $('#maType').val(ma.type); + $('#maPeriod').val(ma.period); + $('#maSource').val(ma.source); + $('#maColor').val(ma.color); + $('#maSmoothing').val(ma.smoothing); + $('#maSmoothingPeriod').val(ma.smoothingPeriod); + $('#maLineWidth').val(ma.lineWidth); + $('#lineWidthDisplay').text(ma.lineWidth); + $('#maStyle').val(ma.style); + + // 更新确认按钮 + $('#addMovingAverageConfirm').text('更新均线').data('editId', maId); + + // 启用/禁用平滑周期 + $('#maSmoothingPeriod').prop('disabled', ma.smoothing === 'none'); + + // 显示对话框 + const modal = new bootstrap.Modal(document.getElementById('movingAverageModal')); + modal.show(); + console.log('编辑对话框已显示'); + } catch (error) { + console.error('编辑均线配置时出错:', error); + } + } + + // 更新所有均线数据 + function updateAllMovingAverages() { + if (!currentData) return; + + console.log('更新所有均线数据,均线数量:', movingAverages.length); + + movingAverages.forEach(ma => { + // 自动选择数据源(主周期或次周期) + const priceData = getPriceData(null, ma.source); + + if (priceData.length === 0) { + console.warn('均线数据为空,跳过:', ma.id); + return; + } + + let maData = calculateMovingAverage(priceData, ma.period, ma.type); + + if (ma.smoothing !== 'none' && ma.smoothingPeriod > 1) { + maData = applySmoothing(maData, ma.smoothing, ma.smoothingPeriod); + } + + ma.data = maData; + + // 如果序列不存在或无效,重新创建 + if (!ma.series && tvWidget.mainChart) { + console.log('重新创建均线序列:', ma.type, ma.period); + try { + ma.series = tvWidget.mainChart.addLineSeries({ + color: ma.color, + lineWidth: ma.lineWidth, + lineStyle: ma.style === 'solid' ? 0 : + ma.style === 'dotted' ? 1 : + ma.style === 'dashed' ? 2 : 0, + title: `${ma.type}(${ma.period})`, + visible: ma.visible !== false, + lastValueVisible: false, + priceLineVisible: false, + crosshairMarkerVisible: true + }); + + // 添加到movingAverageSeries数组 + if (!tvWidget.series.movingAverageSeries) { + tvWidget.series.movingAverageSeries = []; + } + tvWidget.series.movingAverageSeries.push(ma.series); + console.log('均线序列创建成功:', ma.id); + } catch (error) { + console.error('创建均线序列失败:', error); + return; + } + } else if (!tvWidget.mainChart) { + console.warn('主图表不存在,跳过均线更新:', ma.id); + return; + } + + // 设置数据 + if (ma.series) { + ma.series.setData(maData); + console.log(`均线 ${ma.type}(${ma.period}) 数据已更新,数据点数:`, maData.length); + } + }); + + updateMovingAverageIndicators(); + } + + // 确保函数在全局作用域中可用 + window.removeMovingAverage = removeMovingAverage; + window.toggleMovingAverage = toggleMovingAverage; + window.editMovingAverage = editMovingAverage; + + // 测试函数 - 用于验证均线系统是否工作 + window.testMovingAverageSystem = function() { + console.log('=== 均线系统测试 ==='); + console.log('当前均线数量:', movingAverages.length); + console.log('均线列表:', movingAverages); + console.log('图表对象:', tvWidget); + console.log('主图表:', tvWidget.mainChart); + console.log('================='); + + if (movingAverages.length === 0) { + alert('当前没有添加任何均线。请先添加一个均线来测试。'); + } else { + alert(`均线系统正常,当前有 ${movingAverages.length} 条均线。请检查浏览器控制台查看详细信息。`); + } + }; + + // 初始化均线系统事件处理程序 + function initMovingAverageEvents() { + // 均线按钮点击事件 + $('#addMovingAverageBtn').click(function() { + // 重置表单 + $('#movingAverageForm')[0].reset(); + $('#maType').val('SMA'); + $('#maPeriod').val(20); + $('#maSource').val('close'); + $('#maColor').val('#2962FF'); + $('#maSmoothing').val('none'); + $('#maSmoothingPeriod').val(3).prop('disabled', true); + $('#maLineWidth').val(2); + $('#lineWidthDisplay').text('2'); + $('#maStyle').val('solid'); + + // 重置确认按钮 + $('#addMovingAverageConfirm').text('添加均线').removeData('editId'); + + // 显示对话框 + const modal = new bootstrap.Modal(document.getElementById('movingAverageModal')); + modal.show(); + }); + + // 平滑算法变更事件 + $('#maSmoothing').change(function() { + const smoothing = $(this).val(); + $('#maSmoothingPeriod').prop('disabled', smoothing === 'none'); + }); + + // 线宽滑块变更事件 + $('#maLineWidth').on('input', function() { + $('#lineWidthDisplay').text($(this).val()); + }); + + // 确认添加/更新均线 + $('#addMovingAverageConfirm').click(function() { + const form = $('#movingAverageForm')[0]; + if (!form.checkValidity()) { + form.reportValidity(); + return; + } + + const editId = $(this).data('editId'); + const config = { + type: $('#maType').val(), + period: parseInt($('#maPeriod').val()), + source: $('#maSource').val(), + color: $('#maColor').val(), + smoothing: $('#maSmoothing').val(), + smoothingPeriod: parseInt($('#maSmoothingPeriod').val()) || 3, + lineWidth: parseInt($('#maLineWidth').val()), + style: $('#maStyle').val() + }; + + if (editId) { + // 更新现有均线 + const ma = movingAverages.find(ma => ma.id === editId); + if (ma) { + // 删除旧系列 + if (ma.series) { + tvWidget.mainChart.removeSeries(ma.series); + const seriesIndex = tvWidget.series.movingAverageSeries.indexOf(ma.series); + if (seriesIndex !== -1) { + tvWidget.series.movingAverageSeries.splice(seriesIndex, 1); + } + } + + // 更新配置 + Object.assign(ma, config); + + // 重新计算和添加 + const klineData = currentData.kline_data; + const priceData = getPriceData(klineData, config.source); + let maData = calculateMovingAverage(priceData, config.period, config.type); + + if (config.smoothing !== 'none' && config.smoothingPeriod > 1) { + maData = applySmoothing(maData, config.smoothing, config.smoothingPeriod); + } + + const lineSeries = tvWidget.mainChart.addLineSeries({ + color: config.color, + lineWidth: config.lineWidth, + lineStyle: config.style === 'dashed' ? 1 : config.style === 'dotted' ? 3 : 0, + title: `${config.type}(${config.period})`, + lastValueVisible: false, + priceLineVisible: false, + crosshairMarkerVisible: true + }); + + lineSeries.setData(maData); + ma.series = lineSeries; + ma.data = maData; + + tvWidget.series.movingAverageSeries.push(lineSeries); + updateMovingAverageIndicators(); + } + } else { + // 添加新均线 + addMovingAverageToChart(config); + } + + // 关闭对话框 + const modal = bootstrap.Modal.getInstance(document.getElementById('movingAverageModal')); + modal.hide(); + }); + } + // 买卖点样式定义 - 根据desc字段直接显示 function getTradePointStyle(point) { const isBuy = point.type > 0; @@ -1308,6 +1890,11 @@ // 刷新图表 refreshChart(data); + + // 更新均线数据 + setTimeout(() => { + updateAllMovingAverages(); + }, 100); }, error: function(jqXHR, textStatus, errorThrown) { // 隐藏加载图标 @@ -1396,7 +1983,13 @@ // 清除图表容器 document.getElementById('tradingview_chart').innerHTML = ''; - // 重置图表对象 + // 重置图表对象(保留均线配置,但清空序列引用) + // 清空所有均线的序列引用(图表重新初始化后序列无效) + movingAverages.forEach(ma => { + ma.series = null; + }); + console.log('已清空均线序列引用,配置保留:', movingAverages.length); + tvWidget = { mainChart: null, volumeChart: null, @@ -1418,7 +2011,8 @@ elementUncompletedZsSeries: [], tradePointSeries: [], mainBollingerSeries: [], - elementBollingerSeries: [] + elementBollingerSeries: [], + movingAverageSeries: [] }, state: { isInitialized: false, @@ -1715,13 +2309,13 @@ tvWidget.series.lineSeries = lineSeries; } - // 转换成交量数据 - 始终使用主K线周期数据 + // 转换成交量数据 - 根据周期选择使用对应数据源 let volumes = []; - // 使用与K线和MACD相同的数据源选择逻辑 - // 强制使用主周期数据源,确保与MACD、ATR图表时间完全一致 - const volumeDataSource = currentData.kline_data; // 总是使用主周期数据 + // 使用已定义的useElementPeriod变量 + const volumeDataSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + const dataSourceType = useElementPeriod ? '小周期' : '主周期'; - console.log('成交量数据源: 主周期(强制与MACD、ATR一致)'); + console.log('成交量数据源:', dataSourceType); console.log('成交量数据长度:', volumeDataSource.length); if (volumeDataSource && Array.isArray(volumeDataSource)) { @@ -1749,8 +2343,12 @@ volumeSeries.setData(volumes); tvWidget.series.volumeSeries = volumeSeries; - // 添加MACD图表 - 始终使用主K线周期的MACD数据 - if (showMacd && currentData.macd && currentData.kline_data && Array.isArray(currentData.kline_data)) { + // 添加MACD图表 - 根据周期选择使用对应数据源 + const macdDataExists = useElementPeriod ? + (currentData.element_macd && currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) : + (currentData.macd && currentData.kline_data && Array.isArray(currentData.kline_data)); + + if (showMacd && macdDataExists) { // 创建MACD线 const macdLineSeries = macdChart.addLineSeries({ color: '#2962FF', @@ -1784,11 +2382,12 @@ const signalData = []; const histogramData = []; - // 强制使用主周期数据源,确保与ATR图表时间完全一致 - const klineDataSource = currentData.kline_data; // 总是使用主周期数据 - const macdDataSource = currentData.macd; // 总是使用主周期MACD数据 + // 根据周期选择使用对应数据源 + const klineDataSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + const macdDataSource = useElementPeriod ? currentData.element_macd : currentData.macd; + const macdSourceType = useElementPeriod ? '小周期' : '主周期'; - console.log('MACD数据源: 主周期(强制与ATR一致)'); + console.log('MACD数据源:', macdSourceType); console.log('K线数据长度:', klineDataSource.length); console.log('MACD数据:', macdDataSource); @@ -1829,8 +2428,12 @@ tvWidget.series.histogramSeries = histogramSeries; } - // 添加ATR图表 - 独立显示ATR数据 - if (showMacd && currentData.kline_data && Array.isArray(currentData.kline_data)) { + // 添加ATR图表 - 根据周期选择使用对应数据源 + const atrDataExists = useElementPeriod ? + (currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) : + (currentData.kline_data && Array.isArray(currentData.kline_data)); + + if (showMacd && atrDataExists) { // 创建ATR线 const atrLineSeries = atrChart.addLineSeries({ color: '#FF9800', @@ -1846,10 +2449,11 @@ // 提取ATR数据 const atrData = []; - // 强制使用主周期数据源,确保与MACD图表时间完全一致 - const klineDataSource = currentData.kline_data; // 总是使用主周期数据 + // 根据周期选择使用对应数据源 + const klineDataSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + const atrSourceType = useElementPeriod ? '小周期' : '主周期'; - console.log('ATR数据源: 主周期(强制与MACD一致)'); + console.log('ATR数据源:', atrSourceType); console.log('ATR K线数据长度:', klineDataSource.length); // 创建一个隐藏的基础数据系列来保持时间轴对齐 @@ -3350,10 +3954,11 @@ tvWidget.series.lineSeries.setData(lineData); } - // 更新成交量数据 - 强制使用主周期数据源确保时间对齐 + // 更新成交量数据 - 根据周期选择使用对应数据源 let volumes = []; - if (currentData.kline_data && Array.isArray(currentData.kline_data)) { - volumes = currentData.kline_data.map(kline => { + const volumeDataSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + if (volumeDataSource && Array.isArray(volumeDataSource)) { + volumes = volumeDataSource.map(kline => { const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); return { time: timestamp, @@ -3367,30 +3972,33 @@ tvWidget.series.volumeSeries.setData(volumes); } - // 更新MACD数据 - if (true && currentData.macd && currentData.kline_data && Array.isArray(currentData.kline_data) && tvWidget.series.macdLineSeries) { + // 更新MACD数据 - 根据周期选择使用对应数据源 + const macdDataSource = useElementPeriod ? currentData.element_macd : currentData.macd; + const macdKlineSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + + if (true && macdDataSource && macdKlineSource && Array.isArray(macdKlineSource) && tvWidget.series.macdLineSeries) { // 提取MACD数据 const macdData = []; const signalData = []; const histogramData = []; - for (let i = 0; i < currentData.kline_data.length; i++) { - const kline = currentData.kline_data[i]; + for (let i = 0; i < macdKlineSource.length; i++) { + const kline = macdKlineSource[i]; const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); - if (currentData.macd && currentData.macd.macd && currentData.macd.macd[i] !== undefined) { + if (macdDataSource && macdDataSource.macd && macdDataSource.macd[i] !== undefined) { macdData.push({ time: timestamp, - value: currentData.macd.macd[i] + value: macdDataSource.macd[i] }); signalData.push({ time: timestamp, - value: currentData.macd.signal[i] + value: macdDataSource.signal[i] }); // 设置直方图颜色 - const histValue = currentData.macd.histogram[i]; + const histValue = macdDataSource.histogram[i]; histogramData.push({ time: timestamp, value: histValue, @@ -3404,12 +4012,13 @@ tvWidget.series.histogramSeries.setData(histogramData); } - // 更新ATR数据 - 保持时间轴对齐 - if (currentData.kline_data && Array.isArray(currentData.kline_data) && tvWidget.series.atrLineSeries) { + // 更新ATR数据 - 根据周期选择使用对应数据源 + const atrKlineSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data; + if (atrKlineSource && Array.isArray(atrKlineSource) && tvWidget.series.atrLineSeries) { const atrData = []; - for (let i = 0; i < currentData.kline_data.length; i++) { - const kline = currentData.kline_data[i]; + for (let i = 0; i < atrKlineSource.length; i++) { + const kline = atrKlineSource[i]; const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); // 只添加ATR>0的有效数据,不显示ATR=0的点 @@ -3692,6 +4301,14 @@ addChartSyncEvents(atrChartContainer, atrChart); } + // 如果有均线配置,用新数据重新计算和显示均线 + if (movingAverages.length > 0) { + console.log('图表重新初始化后,更新均线数据,均线数量:', movingAverages.length); + setTimeout(() => { + updateAllMovingAverages(); + }, 200); + } + // 窗口大小变化时重绘图表 window.addEventListener('resize', () => { // 调整主图大小 @@ -6073,6 +6690,109 @@ // 已禁用突出显示功能,无需错误日志 }, 2000); }); + + // 初始化均线系统 + $(document).ready(function() { + initMovingAverageEvents(); + }); + + + \ No newline at end of file