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();
+ });
+
+
+