/* ui.js */ function loadSymbols() { $.get('/api/symbols', function(data) { if (Array.isArray(data)) { const $select = $('#symbol'); const currentSymbol = $select.val(); // 保存当前选中的值 $select.empty(); data.forEach(function(symbol) { $select.append($('', { value: symbol, text: symbol })); }); // 如果有保存的选中值,恢复它 if (currentSymbol && data.includes(currentSymbol)) { $select.val(currentSymbol); } else { // 设置默认值为BTC/USDT:USDT $select.val('BTC/USDT:USDT'); } } }); } // 设置默认时间范围:最近 1 个月 function setDefaultTimeRange() { const now = new Date(); const daysBack = 30; const start = new Date(now.getTime() - (daysBack * 24 * 60 * 60 * 1000)); // 格式化为datetime-local输入框所需的格式 YYYY-MM-DDThh:mm $('#end_time').val(formatDatetimeLocal(now)); $('#start_time').val(formatDatetimeLocal(start)); } // 格式化日期为datetime-local输入框格式 function formatDatetimeLocal(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day}T${hours}:${minutes}`; } // 页面加载时初始化 $(document).ready(function() { // 从本地存储中恢复时区设置 const savedTimezone = localStorage.getItem('selectedTimezone'); if (savedTimezone) { $('#timezone').val(savedTimezone); console.log('从本地存储恢复时区设置:', savedTimezone); } // 初始化数据源切换:先按数据源重新拉取周期元信息,再切换 UI $('#dataSource').on('change', function() { const dataSource = $(this).val(); const apiSrc = dataSource === 'a_stock' ? 'a_stock' : 'crypto'; $.getJSON('/api/chart_metadata', { source: apiSrc }) .done(function(meta) { applyChartMetadata(meta); }) .always(function() { if (dataSource === 'crypto') { $('#cryptoSymbolContainer').show(); $('#astockSymbolContainer').hide(); if (window.astockStatusInterval) { clearInterval(window.astockStatusInterval); window.astockStatusInterval = null; } loadSymbols(); } else if (dataSource === 'a_stock') { $('#cryptoSymbolContainer').hide(); $('#astockSymbolContainer').show(); loadAStockSymbols(); startAStockStatusUpdater(); } }); }); // 检查初始数据源设置 const initialDataSource = $('#dataSource').val(); if (initialDataSource === 'a_stock') { $.getJSON('/api/chart_metadata', { source: 'a_stock' }) .done(function(meta) { applyChartMetadata(meta); }) .always(function() { loadAStockSymbols(); startAStockStatusUpdater(); // A 股:metadata 完成后再拉数(下方不再重复 updateChart) setTimeout(function() { analyzeChart({ reason: 'astock-init' }); }, 300); }); } // 加密货币:统一在文末单次 updateChart,避免重复请求 // 初始化交易对下拉菜单 $('#symbol').val('BTC/USDT:USDT'); $('#astockSymbol').val('000001'); if (initialDataSource !== 'a_stock') { const mainDefault = window.DEFAULT_MAIN_TIMEFRAME || $('#timeframe option:first').val(); const elementDefault = window.DEFAULT_ELEMENT_TIMEFRAME || $('#elementTimeframe option:first').val(); if (mainDefault) { $('#timeframe').val(mainDefault); } if (elementDefault) { $('#elementTimeframe').val(elementDefault); } } // 测试打印时区偏移量 console.log('当前时区偏移量 (UTC+8):', getTimezoneOffset('Asia/Shanghai')); console.log('当前时区偏移量 (UTC):', getTimezoneOffset('UTC')); const now = new Date(); console.log('当前时间UTC:', now.toUTCString()); console.log('当前时间本地:', now.toString()); console.log('当前时间戳(秒):', now.getTime()/1000); console.log('UTC时间戳:', Math.floor(now.getTime()/1000)); // 设置默认时间范围 setDefaultTimeRange(); // 默认禁用买卖点显示 $('#showTradePoints').prop('checked', false); // 尝试加载更多交易对 loadSymbols(); // 初始化图表:默认加密货币延迟拉取;若首屏为 A 股则在 chart_metadata 完成后再 analyze if (initialDataSource !== 'a_stock') { setTimeout(function() { analyzeChart({ reason: 'crypto-init' }); }, 500); } // 初始化自动刷新功能 initAutoRefresh(); // 确保在文档加载完成后初始化时区设置 // 默认设置为Shanghai时区 if (!$('#timezone').val()) { $('#timezone').val('Asia/Shanghai'); } // 记录当前时区设置 console.log('页面加载完成,当前时区设置:', $('#timezone').val()); // 添加自定义事件处理 - 让时区选择变更立即生效 $('#timezone').on('change', function() { const newTimezone = $(this).val(); console.log('时区已更改为:', newTimezone); // 保存到本地存储,下次访问时自动使用 localStorage.setItem('selectedTimezone', newTimezone); // 如果已有数据,重新渲染图表和表格 if (currentData) { // 先销毁现有图表实例 if (tvWidget.mainChart) { try { // 清理EMA52系列 clearEMA52Series(); // 销毁主图表及其关联的线系列 tvWidget.mainChart = null; tvWidget.volumeChart = null; tvWidget.atrChart = null; tvWidget.macdChart = null; // 重置系列数据 tvWidget.series = { candleSeries: null, lineSeries: null, barSeries: null, areaSeries: null, baselineSeries: null, renkoSeries: null, volumeSeries: null, atrLineSeries: null, macdLineSeries: null, signalLineSeries: null, histogramSeries: null, mainBiSeries: [], mainSegSeries: [], mainZsSeries: [], mainUncompletedZsSeries: [], elementBiSeries: [], elementSegSeries: [], elementZsSeries: [], elementUncompletedZsSeries: [], tradePointSeries: [], mainBollingerSeries: [], elementBollingerSeries: [], maSeries: [], // 添加均线系列 bbSeries: [], // 添加布林带系列 ema52Series: [] // 添加EMA52系列数组 }; } catch (e) { console.error('销毁图表错误:', e); } } // 使用新的时区重新初始化图表 initTradingView($('#symbol').val(), $('#timeframe').val()); // 重新渲染图表数据 renderChart(); // 更新表格 updateTables(currentData); } }); // 页面加载完成后初始化 $(document).ready(function() { // 设置默认的筛选时间(最近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); } }); }); }); // 自动刷新相关变量 let autoRefreshTimer = null; let nextRefreshTime = null; let autoRefreshTick = 0; /** 自动刷新时,缠论全量重算间隔(毫秒);时间戳见 window._lastFullAnalyzeAt */ const AUTO_FULL_ANALYZE_MS = 60 * 1000; // 初始化自动刷新功能 function initAutoRefresh() { // 监听自动刷新勾选框变化 $('#autoRefresh').change(function() { if ($(this).is(':checked')) { startAutoRefresh(); } else { stopAutoRefresh(); } }); // 监听刷新频率变化 $('#refreshInterval').change(function() { if ($('#autoRefresh').is(':checked')) { // 如果自动刷新已开启,重启定时器 stopAutoRefresh(); startAutoRefresh(); } }); } // 开始自动刷新 function startAutoRefresh() { // 停止已有的刷新定时器 stopAutoRefresh(); // 获取刷新频率(分钟) const interval = parseFloat($('#refreshInterval').val()) || (5 / 60); const intervalMs = interval * 60 * 1000; console.log(`开始自动刷新,频率: ${interval}分钟 (${intervalMs}毫秒);缠论全量每 ${AUTO_FULL_ANALYZE_MS / 1000}s`); // 计算下次刷新时间 nextRefreshTime = new Date(Date.now() + intervalMs); updateNextRefreshTimeDisplay(); // 启动定时器 autoRefreshTick = 0; // 进入实时模式:结束时间=现在,立刻走自动刷新全量(视窗由 autoRefreshChart 内 freeze 冻结) updateEndTimeToNow(); autoRefreshChart({ mode: 'full', incremental: false, forceFullRebuild: true, reason: 'auto-refresh-start' }); autoRefreshTimer = setInterval(function() { // 自动刷新专用:结束时间推进到现在 updateEndTimeToNow(); autoRefreshTick += 1; const now = Date.now(); const lastFull = window._lastFullAnalyzeAt || 0; const tf = $('#timeframe').val() || '4h'; const needFull = !lastFull || (now - lastFull >= AUTO_FULL_ANALYZE_MS) || (typeof isLiveBaselineStale === 'function' && isLiveBaselineStale(tf)); if (needFull) { console.log('自动刷新 tick → live 全量'); autoRefreshChart({ mode: 'full', incremental: false, forceFullRebuild: true }); } else { console.log('自动刷新 tick → recent 尾部'); autoRefreshChart({ mode: 'recent' }); } nextRefreshTime = new Date(Date.now() + intervalMs); updateNextRefreshTimeDisplay(); }, intervalMs); // 启动倒计时显示 startCountdownDisplay(); // 显示下次刷新时间 $('#nextRefreshTime').show(); } // 更新结束时间为当前时间 function updateEndTimeToNow() { const now = new Date(); $('#end_time').val(formatDatetimeLocal(now)); console.log('已更新结束时间为当前时间:', formatDatetimeLocal(now)); } // 停止自动刷新 function stopAutoRefresh() { if (autoRefreshTimer) { clearInterval(autoRefreshTimer); autoRefreshTimer = null; } // 停止倒计时显示 clearInterval(countdownTimer); countdownTimer = null; // 隐藏下次刷新时间 $('#nextRefreshTime').hide(); } // 更新下次刷新时间显示 function updateNextRefreshTimeDisplay() { if (!nextRefreshTime) return; const timeStr = nextRefreshTime.toLocaleTimeString(); $('#nextRefreshTime').text(`下次刷新: ${timeStr}`); } // 倒计时定时器 let countdownTimer = null; // 启动倒计时显示 function startCountdownDisplay() { // 清除已有的倒计时 if (countdownTimer) { clearInterval(countdownTimer); } // 启动新的倒计时,每秒更新一次 countdownTimer = setInterval(function() { if (!nextRefreshTime) return; const now = new Date(); const diffMs = nextRefreshTime - now; if (diffMs <= 0) { // 已经到达或超过刷新时间,等待刷新发生 $('#nextRefreshTime').text('正在刷新...'); } else { // 计算剩余时间 const diffSec = Math.floor(diffMs / 1000); // 如果时间超过1分钟,显示分和秒 if (diffSec >= 60) { const minutes = Math.floor(diffSec / 60); const seconds = diffSec % 60; // 格式化显示 const timeStr = `${minutes}分${seconds.toString().padStart(2, '0')}秒后刷新`; $('#nextRefreshTime').text(timeStr); } else { // 少于1分钟只显示秒数 const timeStr = `${diffSec}秒后刷新`; $('#nextRefreshTime').text(timeStr); } } }, 1000); } // 将时间周期映射到数值(保留此函数以供后端API调用) function mapTimeframeToInterval(timeframe) { const mapping = { '1m': '1', '3m': '3', '5m': '5', '15m': '15', '30m': '30', '1h': '60', '2h': '120', '4h': '240', '6h': '360', '8h': '480', '12h': '720', '1d': 'D', '3d': '3D', '1w': 'W', '1M': 'M' }; return mapping[timeframe] || '5'; } // 只重绘分形元素(笔、线段、中枢),保留现有的K线、MACD和成交量 function redrawFractalElements() { if (!tvWidget || !tvWidget.mainChart) return; // 确保使用主周期的K线和MACD数据 if (currentData.original_kline_data) { currentData.kline_data = currentData.original_kline_data; } if (currentData.original_macd) { currentData.macd = currentData.original_macd; } delete currentData.original_kline_data; delete currentData.original_macd; if (typeof reinitTradingViewPreservingViewport === 'function') { reinitTradingViewPreservingViewport(); } else { initTradingView($('#symbol').val(), $('#timeframe').val()); } } // 只更新分形元素(笔、线段、中枢)的表格数据 function updateFractalTables() { if (!currentData) return; const data = currentData; // 笔数据表更新 if (tables.bi) { tables.bi.clear().destroy(); } // 使用小周期笔数据(如果存在) const biData = data.element_bi_list || data.bi_list; const biSource = data.element_bi_list ? '元素周期' : '主周期'; console.log(`表格显示${biSource}笔数据,共${biData ? biData.length : 0}条`); tables.bi = $('#biTable').DataTable({ data: biData || [], order: [[0, 'desc']], pageLength: 25, columns: [ { data: 'start_time', render: formatTime }, { data: 'end_time', render: formatTime }, { data: 'sure_time', render: formatConfirmTime }, { data: 'start_price', render: formatPrice }, { data: 'end_price', render: formatPrice }, { data: 'direction', render: formatDirection }, { data: 'macd_div', render: formatMacdValue } ] }); // 线段数据表更新 if (tables.seg) { tables.seg.clear().destroy(); } // 使用小周期线段数据(如果存在) const segData = data.element_seg_list || data.seg_list; const segSource = data.element_seg_list ? '元素周期' : '主周期'; console.log(`表格显示${segSource}线段数据,共${segData ? segData.length : 0}条`); tables.seg = $('#segTable').DataTable({ data: segData || [], order: [[0, 'desc']], pageLength: 25, columns: [ { data: 'start_time', render: formatTime }, { data: 'end_time', render: formatTime }, { data: 'sure_time', render: formatConfirmTime }, { data: 'start_price', render: formatPrice }, { data: 'end_price', render: formatPrice }, { data: 'direction', render: formatDirection } ] }); // 中枢数据表更新 if (tables.zs) { tables.zs.clear().destroy(); } // 使用小周期中枢数据(如果存在) const zsData = data.element_zs_list || data.zs_list; const zsSource = data.element_zs_list ? '元素周期' : '主周期'; console.log(`表格显示${zsSource}中枢数据,共${zsData ? zsData.length : 0}条`); tables.zs = $('#zsTable').DataTable({ data: zsData || [], order: [[0, 'desc']], pageLength: 25, columns: [ { data: 'start_time', render: formatTime }, { data: 'end_time', render: formatTime }, { data: 'zg', render: formatPrice }, { data: 'zd', render: formatPrice } ] }); // 更新数据源信息 setupDataSourceInfo(data); } // 刷新图表并更新表格 function refreshChart(data, options) { // 检查是否接收到数据 if (!data) { console.error('未收到数据,无法刷新图表'); return; } if (data.element_timeframe) { $('#elementTimeframe').val(data.element_timeframe); } options = options || {}; const preferIncremental = !!options.incremental; const chartsReady = tvWidget && tvWidget.state && tvWidget.state.isInitialized && tvWidget.mainChart; // 自动刷新:增量更新,避免每次销毁/重建 Lightweight Charts if (preferIncremental && chartsReady) { try { // 视窗已在请求发出时 freezeChartViewportBeforeRequest 冻结,勿在此重拍(会弄错 barCount) updateTradingViewData({ tailOnly: !!options.skipTables }); // recent-tail 刷新结构未变,跳过表格重绘以提速 if (!options.skipTables) { updateTables(data); } if (currentData && currentData.ema52_dict) { updateEMA52Display(currentData); } return; } catch (e) { console.warn('增量刷新失败,回退全量重建:', e); } } // 全量重建:优先用请求前冻结的视窗(分析按钮在请求发出时已 capture) if (typeof ensurePendingChartViewportBeforeInit === 'function') { ensurePendingChartViewportBeforeInit(); if (window._preserveViewOnRefresh) { console.log('📌 全量重建:使用请求前冻结视窗'); } else if (window._pendingRestoreView) { console.log('📌 使用已保存图表视图'); } } else if (window._preserveViewOnRefresh) { window._pendingRestoreView = window._preserveViewOnRefresh; console.log('📌 全量重建:使用请求前冻结视窗'); } else if (!window._pendingRestoreView && tvWidget && tvWidget.mainChart) { try { window._pendingRestoreView = captureChartViewState(tvWidget.mainChart); console.log('📌 保存图表视图:', JSON.stringify(window._pendingRestoreView)); } catch (e) { console.warn('保存图表视图失败:', e); window._pendingRestoreView = null; } } else if (window._pendingRestoreView) { console.log('📌 使用已保存图表视图:', JSON.stringify(window._pendingRestoreView)); } initTradingView($('#symbol').val(), $('#timeframe').val()); // 更新表格数据 updateTables(data); if (currentData && currentData.ema52_dict) { updateEMA52Display(currentData); } } function refreshChartOnly() { // 仅使用当前数据刷新图表显示,不从服务器加载新数据 if (currentData) { console.log('仅刷新图表显示,不重新获取数据'); refreshChart(currentData); } else { console.log('没有当前数据,无法刷新显示'); } } // 绑定主/次/次次周期笔背驰、线段背驰、笔面积、线段面积显示开关 $('#showMainMacdDiv, #showMainSegMacdDiv, #showElementMacdDiv, #showElementSegMacdDiv, #showSubSubMacdDiv, #showSubSubSegMacdDiv, #showMainBiArea, #showMainSegArea, #showElementBiArea, #showElementSegArea, #showSubSubBiArea, #showSubSubSegArea').change(function() { updateChartDisplay(); }); // 绑定分型类型显示开关(与笔一致:全量重建,避免增量路径标记未对齐) $('#showKlcFxType').change(function() { updateChartDisplay(); }); // 绑定小周期分型显示开关 $('#showElementKlcFxType').change(function() { updateChartDisplay(); }); // 绑定布林带显示变更事件 $('#showMainBollinger').change(function() { updateChartDisplay(); }); $('#showElementBollinger').change(function() { updateChartDisplay(); }); // K线周期切换由 macd_ui.js 统一走 updateChartDisplay(勿再绑 refreshChart,会重复且易漏对齐) // 绑定主图U显示开关 $('#toggleUOnMain').change(function() { window.showUOnMain = $('#toggleUOnMain').is(':checked'); refreshChartOnly(); }); // 次周期 U 显示开关 $('#toggleUOnElement').change(function() { window.showUOnElement = $('#toggleUOnElement').is(':checked'); refreshChartOnly(); }); // 买卖点显示开关 $('#showMainBsp').change(function() { updateChartDisplay(); }); $('#showElementBsp').change(function() { updateChartDisplay(); }); // 第四类买卖点(B4/S4)显示开关与过滤模式 $('#showMainFastBsp, #showElementFastBsp, #showSubSubFastBsp, #fastBspFilterMode').change(function() { updateChartDisplay(); }); // 在控制台输出当前显示状态 console.log('当前显示状态:', { 'showOriginalKline': $('#showOriginalKline').is(':checked'), 'showMainBi': $('#showMainBi').is(':checked'), 'showMainSeg': $('#showMainSeg').is(':checked'), 'showMainZs': $('#showMainZs').is(':checked'), 'showVolume': false, 'showMacd': $('#showMacd').is(':checked'), 'showKlcFxType': $('#showKlcFxType').is(':checked'), 'showKluFxType': $('#showKluFxType').is(':checked'), 'showElementKlcFxType': $('#showElementKlcFxType').is(':checked'), 'showElementKluFxType': $('#showElementKluFxType').is(':checked'), 'showTradePoints': $('#showTradePoints').is(':checked'), 'showMainBollinger': $('#showMainBollinger').is(':checked'), 'showElementBollinger': $('#showElementBollinger').is(':checked'), 'timeframe': $('#timeframe').val(), 'elementTimeframe': $('#elementTimeframe').val(), 'timezone': $('#timezone').val(), 'start_time': $('#start_time').val(), 'end_time': $('#end_time').val() }); // 初始化提示工具 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl) }) // 获取A股股票列表(全市场,来自 /api/a_stocks) function loadAStockSymbols() { const $select = $('#astockSymbol'); const currentSymbol = $select.val(); $select.prop('disabled', true); $.get('/api/a_stocks', function(data) { $select.prop('disabled', false); if (!Array.isArray(data)) { console.error('加载A股股票列表失败: 返回非数组', data); return; } $select.empty(); data.forEach(function(stock) { $select.append($('', { value: stock.symbol, text: stock.symbol + ' - ' + (stock.name || '') })); }); if (currentSymbol && data.some(stock => stock.symbol === currentSymbol)) { $select.val(currentSymbol); } else { $select.val('000001'); } }).fail(function(xhr) { $select.prop('disabled', false); console.error('加载A股股票列表失败', xhr && xhr.status); }); } // 检测交易对类型并返回相应的配置 function getSymbolConfig(symbol) { const isAStock = symbol && symbol.length === 6 && /^\d+$/.test(symbol); if (isAStock) { return { type: 'a_stock', displayName: symbol, tradingSessions: [ // A股交易时间配置 { start: '09:30', end: '11:30' }, // 上午 { start: '13:00', end: '15:00' } // 下午 ], timezone: 'Asia/Shanghai', // A股的交易日配置(周一到周五,除节假日) tradingDays: [1, 2, 3, 4, 5] // 1=周一, 7=周日 }; } else { return { type: 'crypto', displayName: symbol, tradingSessions: [ { start: '00:00', end: '23:59' } // 24小时交易 ], timezone: 'UTC', tradingDays: [1, 2, 3, 4, 5, 6, 7] // 7天交易 }; } } // 根据交易对类型调整图表配置 function adjustChartForSymbolType(chartOptions, symbolConfig) { if (symbolConfig.type === 'a_stock') { // A股特殊配置 chartOptions.timeScale = { ...chartOptions.timeScale, // 禁用非交易时间的显示 borderVisible: true, borderColor: '#ddd', // 自定义时间格式化,只显示交易时间 timeVisible: true, // 添加A股特定的时间范围限制 rightOffset: 12, barSpacing: 6, minBarSpacing: 3, }; // 添加A股交易时间提示 chartOptions.layout = { ...chartOptions.layout, fontSize: 12, fontFamily: 'Arial, sans-serif' }; } return chartOptions; } // 过滤非交易时间的数据(仅用于显示优化) function filterTradingHours(data, symbolConfig) { if (symbolConfig.type !== 'a_stock') { return data; // 非A股数据不需要过滤 } return data.filter(item => { const date = new Date(item.time * 1000); const hour = date.getHours(); const minute = date.getMinutes(); const timeStr = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; // 检查是否在交易时间内 return symbolConfig.tradingSessions.some(session => { return timeStr >= session.start && timeStr <= session.end; }); }); } // 更新A股交易时间状态 function updateAStockTradingStatus() { const now = new Date(); const chinaTime = new Date(now.toLocaleString("en-US", {timeZone: "Asia/Shanghai"})); const hour = chinaTime.getHours(); const minute = chinaTime.getMinutes(); const dayOfWeek = chinaTime.getDay(); // 0=周日, 1=周一, ..., 6=周六 const statusElement = document.getElementById('tradingTimeStatus'); if (!statusElement) return; // 检查是否为交易日(周一到周五) const isTradingDay = dayOfWeek >= 1 && dayOfWeek <= 5; if (!isTradingDay) { statusElement.className = 'badge bg-secondary'; statusElement.textContent = '非交易日'; return; } // 检查是否在交易时间内 const currentTime = hour * 60 + minute; // 转换为分钟 const morningStart = 9 * 60 + 30; // 09:30 const morningEnd = 11 * 60 + 30; // 11:30 const afternoonStart = 13 * 60; // 13:00 const afternoonEnd = 15 * 60; // 15:00 let status = ''; let className = ''; if (currentTime >= morningStart && currentTime <= morningEnd) { status = '上午交易中'; className = 'badge bg-success'; } else if (currentTime >= afternoonStart && currentTime <= afternoonEnd) { status = '下午交易中'; className = 'badge bg-success'; } else if (currentTime > morningEnd && currentTime < afternoonStart) { status = '午间休市'; className = 'badge bg-warning'; } else if (currentTime < morningStart) { status = '开盘前'; className = 'badge bg-info'; } else if (currentTime > afternoonEnd) { status = '收盘后'; className = 'badge bg-dark'; } else { status = '非交易时间'; className = 'badge bg-secondary'; } statusElement.className = className; statusElement.textContent = status; } // 启动A股交易时间状态更新 function startAStockStatusUpdater() { // 如果已经有定时器在运行,先清除 if (window.astockStatusInterval) { clearInterval(window.astockStatusInterval); } // 立即更新一次 updateAStockTradingStatus(); // 每30秒更新一次 window.astockStatusInterval = setInterval(updateAStockTradingStatus, 30000); console.log('A股交易时间状态更新器已启动'); } // 均线系统全局变量 var movingAverages = []; // 存储所有均线配置 var maIdCounter = 0; // 均线ID计数器 // 布林带系统全局变量 var bollingerBands = []; // 存储所有布林带配置 var bbIdCounter = 0; // 布林带ID计数器 // 清理EMA52系列