/* main.js */ $(document).ready(function() { // 初始化技术指标下拉菜单 initIndicatorDropdown(); // 设置默认的筛选时间(最近7天) const now = new Date(); const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); // 添加页面滚动事件监听器,清除十字线延长线 $(window).on('scroll', function() { try { // 清除所有十字线延长线,防止它们跟着页面滚动 const existingVolumeLines = document.querySelectorAll('.volume-crosshair-line'); existingVolumeLines.forEach(line => line.remove()); const existingAtrLines = document.querySelectorAll('.atr-crosshair-line'); existingAtrLines.forEach(line => line.remove()); const existingMacdLines = document.querySelectorAll('.macd-crosshair-line'); existingMacdLines.forEach(line => line.remove()); const existingChanMacdLines = document.querySelectorAll('.chanmacd-crosshair-line'); existingChanMacdLines.forEach(line => line.remove()); } catch (e) { console.debug('清除滚动中的十字线时出错:', e); } }); }); // ====== ChanMACD图表相关函数 ====== // 清除ChanMACD标注 function clearChanMacdMarkers() { // 清除所有系列的标记 if (tvWidget.series.chanMacdLineSeries) { tvWidget.series.chanMacdLineSeries.setMarkers([]); } if (tvWidget.series.chanMacdSignalSeries) { tvWidget.series.chanMacdSignalSeries.setMarkers([]); } if (tvWidget.series.chanMacdHistSeries) { tvWidget.series.chanMacdHistSeries.setMarkers([]); } // 清空全局UnitTF标记,避免旧数据残留影响主图合并 window.unittfMarkers = []; } // 添加所有ChanMACD标记 function addAllChanMacdMarkers(segList, unittfList, histsetList, stateMarkers) { const macdMarkers = []; const signalMarkers = []; const histMarkers = []; const boundaryMarkers = []; const uTooltipMarkers = []; // 添加段标记到MACD线 console.log('处理段标记,段数量:', segList.length); segList.forEach((seg, index) => { console.log(`段${index}:`, { start_time: seg.start_time, end_time: seg.end_time, seg_dir: seg.seg_dir, has_start: !!seg.start_time, has_end: !!seg.end_time }); if (!seg.start_time) { console.log(`段${index}没有开始时间,跳过`); return; } const startTime = new Date(seg.start_time).getTime() / 1000; console.log(`段${index}开始时间戳:`, startTime); macdMarkers.push({ time: startTime, position: 'aboveBar', color: seg.seg_dir === 'ABOVE' ? '#e91e63' : '#4caf50', shape: 'square', text: `S${index}`, size: 0.5 }); if (seg.end_time) { const endTime = new Date(seg.end_time).getTime() / 1000; console.log(`段${index}结束时间戳:`, endTime); macdMarkers.push({ time: endTime, position: 'aboveBar', color: seg.seg_dir === 'ABOVE' ? '#e91e63' : '#4caf50', shape: 'square', text: `S${index}E`, size: 0.5 }); } }); console.log('生成的段标记数量:', macdMarkers.length); // 添加UnitTF标记(用于U) console.log('DEBUG: U 源数据条数:', Array.isArray(unittfList) ? unittfList.length : 'not array'); unittfList.forEach((unittf, index) => { if (!unittf.start_time || unittf.invalid) return; const startTime = new Date(unittf.start_time).getTime() / 1000; if (index === 0) { console.log('DEBUG: U0 示例:', unittf); } const startMarker = { time: startTime, position: unittf.dir > 0 ? 'aboveBar' : 'belowBar', color: unittf.dir > 0 ? '#ff9800' : '#9c27b0', shape: 'circle', text: `U${index}`, size: 0.5 }; signalMarkers.push(startMarker); // tooltip(开始) uTooltipMarkers.push({ time: startTime, tooltip: `
UnitTF(${unittf.dir > 0 ? '正区' : '负区'}) 开始
峰值: ${unittf.peak_abs ?? '-'} 长度: ${unittf.length ?? '-'}
类型: ${unittf.start_type ?? '-'}
时间: ${unittf.start_time}
` }); if (unittf.end_time) { const endTime = new Date(unittf.end_time).getTime() / 1000; const endMarker = { time: endTime, position: unittf.dir > 0 ? 'aboveBar' : 'belowBar', color: unittf.dir > 0 ? '#ff9800' : '#9c27b0', shape: 'circle', text: `U${index}E`, size: 0.5 }; signalMarkers.push(endMarker); // tooltip(结束) uTooltipMarkers.push({ time: endTime, tooltip: `
UnitTF(${unittf.dir > 0 ? '正区' : '负区'}) 结束
峰值: ${unittf.peak_abs ?? '-'} 长度: ${unittf.length ?? '-'}
类型: ${unittf.end_type ?? '-'}
时间: ${unittf.end_time}
` }); } }); // 识别"U 结束与新 U 开始同一根K"的边界,并显示合成标记(即使前一个U是 invalid 也显示边界) for (let i = 0; i + 1 < unittfList.length; i++) { const cur = unittfList[i]; const nxt = unittfList[i + 1]; if (!cur.end_time || !nxt.start_time) continue; const tEnd = new Date(cur.end_time).getTime(); const tStart = new Date(nxt.start_time).getTime(); if (!isNaN(tEnd) && tEnd === tStart) { const ts = Math.floor(tEnd / 1000); const color = nxt.dir > 0 ? '#ffb74d' : '#ba68c8'; const marker = { time: ts, position: nxt.dir > 0 ? 'aboveBar' : 'belowBar', color: color, shape: 'square', text: 'U↔', size: 0.6 }; boundaryMarkers.push(marker); uTooltipMarkers.push({ time: ts, tooltip: `
\n U 结束 + 新 U 开始 (边界)
\n 结束方向: ${cur.dir > 0 ? '正区' : '负区'} → 新方向: ${nxt.dir > 0 ? '正区' : '负区'}
\n 时间: ${nxt.start_time}\n
` }); } } // 添加HistSet标记到Histogram histsetList.forEach((histset, index) => { if (!histset.start_time) return; const startTime = new Date(histset.start_time).getTime() / 1000; if (false) { histMarkers.push({ time: startTime, position: histset.histset_dir === 'ABOVE' ? 'aboveBar' : 'belowBar', color: histset.histset_dir === 'ABOVE' ? '#4caf50' : '#f44336', shape: 'arrowUp', text: `H${index}`, size: 0.5 }); if (histset.end_time) { const endTime = new Date(histset.end_time).getTime() / 1000; histMarkers.push({ time: endTime, position: histset.histset_dir === 'ABOVE' ? 'aboveBar' : 'belowBar', color: histset.histset_dir === 'ABOVE' ? '#4caf50' : '#f44336', shape: 'arrowDown', text: `H${index}E`, size: 0.5 }); } } }); // 设置所有标记 console.log('设置段标记到图表,标记数量:', macdMarkers.length); if (tvWidget.series.chanMacdLineSeries && macdMarkers.length > 0) { tvWidget.series.chanMacdLineSeries.setMarkers(macdMarkers); console.log('✅ 段标记已设置到chanMacdLineSeries'); } else { console.log('⚠️ 无法设置段标记:', { hasSeries: !!tvWidget.series.chanMacdLineSeries, markersLength: macdMarkers.length }); } // 保存到全局,供主图与分型一起统一合并绘制(仅在开关开启时) console.log('DEBUG: U 标记数量:', signalMarkers.length); const allowUMerge = (window.showUOnMain && window.showUOnElement); window.unittfMarkers = allowUMerge ? [...signalMarkers, ...boundaryMarkers] : []; if (uTooltipMarkers.length > 0) { if (window.fxMarkers) { window.fxMarkers = [ ...window.fxMarkers, ...uTooltipMarkers ]; } else { window.fxMarkers = uTooltipMarkers; } } // 同时在ChanMACD的Signal子图上标注U if (tvWidget.series.chanMacdSignalSeries && (signalMarkers.length > 0 || boundaryMarkers.length > 0)) { tvWidget.series.chanMacdSignalSeries.setMarkers([...signalMarkers, ...boundaryMarkers]); } if (tvWidget.series.chanMacdHistSeries && histMarkers.length > 0) { tvWidget.series.chanMacdHistSeries.setMarkers(histMarkers); } // 添加状态标记 if (stateMarkers) { addStateMarkers(stateMarkers); } } // 添加状态标记 function addStateMarkers(stateMarkers) { const stateMarkersList = []; const stateTooltips = []; // 调试信息 console.log('DEBUG: 状态标记数据:', stateMarkers); console.log('DEBUG: 高位列表长度:', stateMarkers.high_position_list ? stateMarkers.high_position_list.length : 0); console.log('DEBUG: 低位列表长度:', stateMarkers.low_position_list ? stateMarkers.low_position_list.length : 0); console.log('DEBUG: 高位空列表长度:', stateMarkers.high_empty_list ? stateMarkers.high_empty_list.length : 0); console.log('DEBUG: 低位空列表长度:', stateMarkers.low_empty_list ? stateMarkers.low_empty_list.length : 0); // HP/HPE:仅使用高位术语(正负两侧统一展示为HP/HPE) const hpHeTemp = []; let hpIdx = 0; // 高位峰值计数 let heIdx = 0; // 高位空(HPE)计数 (stateMarkers.high_position_list || []).forEach(m => { if (!m.time) return; const t = new Date(m.time).getTime()/1000; const color = '#e91e63'; hpHeTemp.push({ t, position: 'belowBar', color, text: `HP${hpIdx}` }); stateTooltips.push({ time: t, tooltip: `
HP${hpIdx} 峰值
MACD:${(m.macd??'').toFixed?.(4)||m.macd}
SIGNAL:${(m.signal??'').toFixed?.(4)||m.signal}
HIST:${(m.macdhist??'').toFixed?.(4)||m.macdhist}
` }); hpIdx++; }); (stateMarkers.low_position_list || []).forEach(m => { if (!m.time) return; const t = new Date(m.time).getTime()/1000; const color = '#4caf50'; // 低位峰值也统一标记为 HP(按需求不使用 LP) hpHeTemp.push({ t, position: 'aboveBar', color, text: `HP${hpIdx}` }); stateTooltips.push({ time: t, tooltip: `
HP${hpIdx} 峰值(正区)
MACD:${(m.macd??'').toFixed?.(4)||m.macd}
SIGNAL:${(m.signal??'').toFixed?.(4)||m.signal}
HIST:${(m.macdhist??'').toFixed?.(4)||m.macdhist}
` }); hpIdx++; }); (stateMarkers.high_empty_list || []).forEach(m => { if (!m.time) return; const t = new Date(m.time).getTime()/1000; const color = '#ff9800'; hpHeTemp.push({ t, position: 'belowBar', color, text: `HPE${heIdx}` }); stateTooltips.push({ time: t, tooltip: `
HPE${heIdx} 黄白交叉
MACD:${(m.macd??'').toFixed?.(4)||m.macd}
SIGNAL:${(m.signal??'').toFixed?.(4)||m.signal}
HIST:${(m.macdhist??'').toFixed?.(4)||m.macdhist}
` }); heIdx++; }); (stateMarkers.low_empty_list || []).forEach(m => { if (!m.time) return; const t = new Date(m.time).getTime()/1000; const color = '#17a2b8'; // 低位空也统一标记为 HPE(按需求不使用 LPE) hpHeTemp.push({ t, position: 'aboveBar', color, text: `HPE${heIdx}` }); stateTooltips.push({ time: t, tooltip: `
HPE${heIdx} 黄白交叉(正区)
MACD:${(m.macd??'').toFixed?.(4)||m.macd}
SIGNAL:${(m.signal??'').toFixed?.(4)||m.signal}
HIST:${(m.macdhist??'').toFixed?.(4)||m.macdhist}
` }); heIdx++; }); hpHeTemp.sort((a,b)=>a.t-b.t).forEach(it => { stateMarkersList.push({ time: it.t, position: it.position, color: it.color, shape: 'diamond', text: it.text, size: 0.65 }); }); // 设置状态标记到 MACD 线 if (tvWidget.series.chanMacdLineSeries && stateMarkersList.length > 0) { tvWidget.series.chanMacdLineSeries.setMarkers(stateMarkersList); console.log('✅ 状态标记已设置到MACD线,数量:', stateMarkersList.length); } // 将状态标记的 tooltip 合并入全局,主图悬浮可见 if (stateTooltips.length > 0) { if (window.fxMarkers) { window.fxMarkers = [...window.fxMarkers, ...stateTooltips]; } else { window.fxMarkers = stateTooltips; } } } // 保留原函数用于向后兼容(但不使用) function addChanMacdSegMarkers(segList) { const markers = []; segList.forEach((seg, index) => { if (!seg.start_time) return; const startTime = new Date(seg.start_time).getTime() / 1000; if (false){ // 添加起点标记 markers.push({ time: startTime, position: 'aboveBar', color: seg.seg_dir === 'ABOVE' ? '#e91e63' : '#4caf50', shape: 'square', text: `S${index}`, size: 0.5 }); // 如果有结束时间,添加结束标记 if (seg.end_time) { const endTime = new Date(seg.end_time).getTime() / 1000; markers.push({ time: endTime, position: 'aboveBar', color: seg.seg_dir === 'ABOVE' ? '#e91e63' : '#4caf50', shape: 'square', text: `S${index}E`, size: 0.5 }); } } }); // 设置标记到MACD线上 if (tvWidget.series.chanMacdLineSeries && markers.length > 0) { tvWidget.series.chanMacdLineSeries.setMarkers(markers); } } // 添加UnitTF标注 function addChanMacdUnitTFMarkers(unittfList) { const markers = []; unittfList.forEach((unittf, index) => { if (!unittf.start_time || unittf.invalid) return; const startTime = new Date(unittf.start_time).getTime() / 1000; // 添加起点标记 markers.push({ time: startTime, position: 'belowBar', color: unittf.dir > 0 ? '#ff9800' : '#9c27b0', shape: 'circle', text: `U${index}`, size: 0.5 }); // 如果有结束时间,添加结束标记 if (unittf.end_time) { const endTime = new Date(unittf.end_time).getTime() / 1000; markers.push({ time: endTime, position: 'belowBar', color: unittf.dir > 0 ? '#ff9800' : '#9c27b0', shape: 'circle', text: `U${index}E`, size: 0.5 }); } }); // 设置标记到信号线上 if (tvWidget.series.chanMacdSignalSeries && markers.length > 0) { tvWidget.series.chanMacdSignalSeries.setMarkers(markers); } } // 添加HistSet标注 function addChanMacdHistSetMarkers(histsetList) { const markers = []; histsetList.forEach((histset, index) => { if (!histset.start_time) return; const startTime = new Date(histset.start_time).getTime() / 1000; // 添加起点标记 markers.push({ time: startTime, position: histset.histset_dir === 'ABOVE' ? 'aboveBar' : 'belowBar', color: histset.histset_dir === 'ABOVE' ? '#4caf50' : '#f44336', shape: 'arrowUp', text: `H${index}`, size: 0.5 }); // 如果有结束时间,添加结束标记 if (histset.end_time) { const endTime = new Date(histset.end_time).getTime() / 1000; markers.push({ time: endTime, position: histset.histset_dir === 'ABOVE' ? 'aboveBar' : 'belowBar', color: histset.histset_dir === 'ABOVE' ? '#4caf50' : '#f44336', shape: 'arrowDown', text: `H${index}E`, size: 0.5 }); } }); // 设置标记到柱状图上 if (tvWidget.series.chanMacdHistSeries && markers.length > 0) { tvWidget.series.chanMacdHistSeries.setMarkers(markers); } }