// ==================== 主渲染函数 ==================== function renderResultBoard(reportData, viewMode = 'B', params = {}) { console.log('[最终版] 开始渲染'); // 强制依赖 params 对象,不再提供后备默认值 if (!params || typeof params !== 'object') { var div = document.createElement('div'); div.className = 'no-data error-message'; div.textContent = '❌ 参数缺失,无法渲染看板。请刷新页面或重新获取数据。'; return div; } // 从 params 动态读取阈值(提供后备默认值,与配置文件一致) var MACRO_ADX_THRESHOLD = params.MACRO_ADX_THRESHOLD; var DROP_THRESHOLD_PCT = params.DROP_THRESHOLD_PCT; var L1_ADX_THRESHOLD = params.L1_ADX_THRESHOLD; var RSI_L2_THRESHOLD = params.RSI_L2_THRESHOLD; var L1_PASS_SCORE = params.L1_PASS_SCORE; var L2_PASS_SCORE = params.L2_PASS_SCORE; var RSI_PRELIM_THRESHOLD = params.RSI_PRELIM_THRESHOLD; // 可选检查:如果任意必要参数缺失,返回错误 if (MACRO_ADX_THRESHOLD === undefined || DROP_THRESHOLD_PCT === undefined || L1_ADX_THRESHOLD === undefined || RSI_L2_THRESHOLD === undefined || L1_PASS_SCORE === undefined || L2_PASS_SCORE === undefined || RSI_PRELIM_THRESHOLD === undefined) { var div = document.createElement('div'); div.className = 'no-data error-message'; div.textContent = '❌ 参数不完整,无法渲染看板。请检查参数加载是否成功。'; return div; } if (!reportData || reportData.error || !reportData.coins || Object.keys(reportData.coins).length === 0) { var div = document.createElement('div'); div.className = 'no-data'; div.textContent = '【结果看板】暂无有效数据,请先获取K线数据并确保后端评分计算正常。'; return div; } // 辅助函数已由 08.05a 提供(在全局作用域中) // 此处直接使用 safeNum, icon, formatCooldown, getSubColorClass, getGroupColorClass, // createSpacer, formatValueHtml, addStageAndGroupRow, addRowOnlySubValue, addSingleRow function getTotalScore(coin) { var summary = coin.summary || {}; var bl = summary.bl_score ?? 0; var r = summary.r_score ?? 0; var l1 = summary.l1_score ?? 0; var l2 = summary.l2_score ?? 0; return bl * (r + l1 + l2); } function buildCoinTable(coin, displaySymbol, globalRC, macroGo, macroAdx) { if (!coin) return null; var rc = globalRC; var rcGo = rc.go; var groupResultText = rcGo ? 'GO ✅' : 'NOTGO ❌'; var tableWrapper = document.createElement('div'); tableWrapper.className = 'board-wrapper'; var caption = document.createElement('div'); caption.className = 'board-caption'; var totalScore = getTotalScore(coin); if (totalScore !== 0) { caption.innerHTML = '📊 ' + displaySymbol + ' 评分详情 ' + totalScore + ''; } else { caption.textContent = '📊 ' + displaySymbol + ' 评分详情'; } var table = document.createElement('table'); table.className = 'result-board-table'; var thead = document.createElement('thead'); var secondHeader = (viewMode === 'A') ? '组结果' : '组'; var theadHtml = '阶段' + secondHeader + '子结果数值/条件'; thead.innerHTML = theadHtml; table.appendChild(thead); var tbody = document.createElement('tbody'); // 宏观风控 var macroStageHtml = '宏观风控 BTC
2pm-2:30pm

需满足全部条件'; var bl01Sub = 'BL01 ' + (rc.bl01 ? '❌' : '✅'); var bl01Val = '禁止:4H价格 > EMA200
必需:4H价格 ≤ EMA200
当前:4H价格 ' + safeNum(rc.current?.price_4h) + ' | EMA200 ' + safeNum(rc.current?.ema200_4h); addStageAndGroupRow(tbody, macroStageHtml, groupResultText, bl01Sub, bl01Val, 3, 3, 'macro', rcGo); var bl03Sub = 'BL03 ' + (rc.bl03 ? '❌' : '✅'); var bl03Val = '禁止:1H MACD 0轴上死叉
必需:MACD ≤0 且 无死叉
当前:MACD ' + safeNum(rc.current?.macd_line_1h) + ' | Signal ' + safeNum(rc.current?.macd_signal_1h); addRowOnlySubValue(tbody, bl03Sub, bl03Val, 'macro'); var bl02Sub = 'BL02 ' + (rc.bl02 ? '❌' : '✅'); var bl02Val = '禁止:出现 15m HL(Higher Low)
当前:HL ' + (rc.bl02 ? '已形成' : '未形成'); addRowOnlySubValue(tbody, bl02Sub, bl02Val, 'macro'); tbody.appendChild(createSpacer()); // 限时否决 var bigGreenNow = coin.cooldown?.big_green_now || false; var remainingSec = coin.cooldown?.remaining_sec || 0; var isCooldownPass = (!bigGreenNow && remainingSec <= 0); var cooldownGroupResult = isCooldownPass ? 'GO ✅' : 'NOTGO ❌'; var cooldownStageHtml = '限时否决
(30分钟)'; var bl05Sub = 'BL05 ' + (isCooldownPass ? '✅' : '❌'); var statusText = bigGreenNow ? '大阳线形成' : '大阳线未形成'; var cooldownDisplay = formatCooldown(remainingSec); var bl05Val = '禁止:出现一根大阳线
当前:' + statusText + '【禁空 ' + cooldownDisplay + '】'; addSingleRow(tbody, cooldownStageHtml, cooldownGroupResult, bl05Sub, bl05Val, 'cooldown', isCooldownPass); tbody.appendChild(createSpacer()); // 宏观定调(使用动态阈值 MACRO_ADX_THRESHOLD) var macroCallStageHtml = '宏观定调 BTC
2pm-2:30pm'; var adxSub = 'ADX ' + (macroGo ? '✅' : '❌'); var adxVal = '必需:ADX > ' + MACRO_ADX_THRESHOLD + '
当前:' + safeNum(macroAdx); addSingleRow(tbody, macroCallStageHtml, macroGo ? 'GO ✅' : 'NOTGO ❌', adxSub, adxVal, 'call', macroGo); tbody.appendChild(createSpacer()); // 初步筛选(使用动态阈值 DROP_THRESHOLD_PCT) var prelim = coin.prelim || {}; var prelimGo = prelim.go || false; var prelimStageHtml = '初步筛选
3:30pm-4:30pm

需满足全部条件'; var dropSub = '跌幅 ' + (prelim.drop_ok ? '✅' : '❌'); var dropVal = '必需:跌 > ' + DROP_THRESHOLD_PCT + '%
当前:' + safeNum(prelim.drop_val) + '%'; addStageAndGroupRow(tbody, prelimStageHtml, prelimGo ? 'GO ✅' : 'NOTGO ❌', dropSub, dropVal, 3, 3, 'prelim', prelimGo); var turnoverSub = '成交额 ' + (prelim.turnover_ok ? '✅' : '❌'); var turnoverVal = '必需:成交额 > 阈值M USDT
当前:' + safeNum(prelim.turnover_val) + 'M'; addRowOnlySubValue(tbody, turnoverSub, turnoverVal, 'prelim'); var rsiSub = 'RSI ' + (prelim.rsi_ok ? '✅' : '❌'); var rsiVal = '必需:RSI < ' + RSI_PRELIM_THRESHOLD + '
当前:' + safeNum(prelim.rsi_val); addRowOnlySubValue(tbody, rsiSub, rsiVal, 'prelim'); tbody.appendChild(createSpacer()); // L1 趋势层(使用动态 L1_PASS_SCORE 和 L1_ADX_THRESHOLD) var l1 = coin.l1 || {}; var l1d = l1.details || {}; if (Object.keys(l1d).length > 0) { var l1Current = l1.total ?? 0; var l1Pass = L1_PASS_SCORE; var l1Max = l1.max_score ?? 37; var l1StageHtml = 'L1 趋势层指标

当前:' + l1Current + '
合格:' + l1Pass + '
总分:' + l1Max + ''; var groupHtml = (l1.go ? 'GO ✅' : 'NOTGO ❌') + '
(' + l1Current + '/' + l1Max + ')'; var mtfSub = icon(l1d.mtf_bool) + ' ' + (l1d.mtf ?? 0); var mtfVal = '必需:4H空头 且 1H空头
当前:4H多头,1H多头'; addStageAndGroupRow(tbody, l1StageHtml, groupHtml, mtfSub, mtfVal, 6, 6, 'l1', l1.go); var alignSub = icon(l1d.alignment_bool) + ' ' + (l1d.alignment ?? 0); var alignVal = '必需:EMA20 < EMA50 < EMA100(空头排列)
当前:' + (l1d.alignment_bool ? '空头排列' : '多头排列'); addRowOnlySubValue(tbody, alignSub, alignVal, 'l1'); var slopeSub = icon(l1d.slope_bool) + ' ' + (l1d.slope ?? 0); var slopeVal = '必需:三条均线均向下
当前:' + (l1d.slope_bool ? '三线皆下行' : '不满足'); addRowOnlySubValue(tbody, slopeSub, slopeVal, 'l1'); var priceSub = icon(l1d.price_pos_bool) + ' ' + (l1d.price_pos ?? 0); var priceVal = '必需:收盘价 < 所有均线
当前:' + (l1d.price_pos_bool ? '价格在所有EMA下方' : '价格在所有EMA上方'); addRowOnlySubValue(tbody, priceSub, priceVal, 'l1'); var adxSubL1 = icon(l1d.adx_bool) + ' ' + (l1d.adx ?? 0); var adxValL1 = '必需:ADX > ' + L1_ADX_THRESHOLD + ' 且 上升 且 价格下跌
当前:ADX ' + safeNum(l1d.adx_val) + ',' + (l1d.adx_rising ? '上升' : '下降') + ',' + (l1d.price_dropping ? '价格下跌' : '价格上涨'); addRowOnlySubValue(tbody, adxSubL1, adxValL1, 'l1'); var volSub = icon(l1d.volume_bool) + ' ' + (l1d.volume ?? 0); var volVal = '必需:放量下跌(量 > SMA20 且 阴线)
当前:量 ' + safeNum(l1d.volume_val) + ' | SMA20 ' + safeNum(l1d.vol_sma_val) + ' | ' + (l1d.volume_bool ? '阴线' : '阳线'); addRowOnlySubValue(tbody, volSub, volVal, 'l1'); tbody.appendChild(createSpacer()); } // L2 执行层(使用动态 L2_PASS_SCORE 和 RSI_L2_THRESHOLD) var l2 = coin.l2 || {}; var l2d = l2.details || {}; if (Object.keys(l2d).length > 0) { var l2Current = l2.total ?? 0; var l2Pass = L2_PASS_SCORE; var l2Max = l2.max_score ?? 25; var l2StageHtml = 'L2 执行层

当前:' + l2Current + '
合格:' + l2Pass + '
总分:' + l2Max + ''; var groupHtml = (l2.go ? 'GO ✅' : 'NOTGO ❌') + '
(' + l2Current + '/' + l2Max + ')'; var mfSub = icon(l2d.mf) + ' ' + (l2d.mf ? 5 : 0); var mfVal = '必需:RSI < ' + RSI_L2_THRESHOLD + ' 且 MACD柱为负且扩大
当前:RSI ' + safeNum(l2d.rsi_val) + ' | MACD柱 ' + safeNum(l2d.macd_hist_val); addStageAndGroupRow(tbody, l2StageHtml, groupHtml, mfSub, mfVal, 4, 4, 'l2', l2.go); var a3Sub = icon(l2d.a3) + ' ' + (l2d.a3 ? 5 : 0); var a3Val = '必需:跌破近期低点 + 弱回抽(RSI 52-55,缩量)
当前:跌破=' + (l2d.a3 ? '满足' : '不满足') + ' | RSI ' + safeNum(l2d.rsi_val) + ' | 量