Files
Toolbox/public/tools/markets/index.html
T
yangxiangyuan 6a7a2b089a feat: 新增免费演出雷达工具与定投评估功能,优化周报提醒逻辑
1. 新增免费演出雷达工具:含秀动/猫眼/大麦平台抓取、本地代理鉴权配置
2. 新增建行定投评估模块:四大指数PE-TTM估值与定投档位建议
3. 新增推送告警白名单过滤功能,限制推送指定指数告警
4. 重构周报首页提醒逻辑,移至服务端处理并减少前端请求
5. 新增多套调试探针脚本与单元测试用例
2026-08-04 17:33:14 +08:00

435 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Yang's Toolbox · 市场跟踪</title>
<link rel="icon" href="/icons/markets.svg" type="image/svg+xml" />
<link rel="stylesheet" href="/common/common.css" />
<link rel="stylesheet" href="/tools/markets/markets.css" />
</head>
<body>
<main>
<section class="debug" id="m-debug-section" style="display:none">
<div class="debug-actions">
<button id="m-btn-copy" class="btn">复制调试信息</button>
<button id="m-btn-refresh" class="btn">刷新</button>
<button id="m-btn-clear" class="btn">清空</button>
</div>
<div id="m-debug-output" class="debug-output"></div>
</section>
<div class="subtabs">
<button id="m-tab-realtime" class="subtab active">实时数据</button>
<button id="m-tab-archive" class="subtab">封存数据</button>
<button id="m-tab-calendar" class="subtab">证券日历</button>
<button id="m-tab-weekly" class="subtab">指数周报</button>
<button id="m-tab-news" class="subtab">全球新闻</button>
<button id="m-tab-wisdom" class="subtab">理论与实践</button>
<button id="m-tab-zhizi" class="subtab">知资札记</button>
<button id="m-tab-tools" class="subtab">工具箱</button>
<button id="m-tab-dip" class="subtab">建行定投评估</button>
<div id="m-status" class="status status-inline" style="display:none"></div>
</div>
<div class="markets-layout">
<section id="m-panel-realtime" class="panel">
<div class="bar">
<button id="btn-fetch" class="btn">立即刷新</button>
<input id="rt-date" type="date" />
<button id="rt-btn-prev" class="btn">上一天</button>
<button id="rt-btn-today" class="btn">今天</button>
<button id="rt-btn-next" class="btn">下一天</button>
<button id="rt-btn-save-archive" class="btn">保存至库</button>
<button id="btn-settings" class="btn">设置</button>
<button id="btn-test" class="btn">发送测试邮件</button>
<button id="btn-skills-meta" class="btn">数元汇总</button>
<button id="btn-email-log" class="btn">邮件日志</button>
<span id="threshold-label" class="threshold-label"></span>
</div>
<div id="quotes" class="grid"></div>
</section>
<section id="m-panel-archive" class="panel" style="display:none">
<div class="bar">
<input id="arch-date" type="date" />
<button id="arch-btn-prev" class="btn">上一天</button>
<button id="arch-btn-today" class="btn">今天</button>
<button id="arch-btn-next" class="btn">下一天</button>
<button id="arch-btn-load" class="btn">加载</button>
</div>
<div class="status" id="archive-status" style="display:none"></div>
<div id="archive-view" style="border:1px solid #ddd;border-radius:8px;overflow:hidden"></div>
</section>
<section id="m-panel-calendar" class="panel" style="display:none">
<div class="bar">
<input id="cal-month" type="month" />
<button id="cal-btn-prev" class="btn">上个月</button>
<button id="cal-btn-current" class="btn">本月</button>
<button id="cal-btn-next" class="btn">下个月</button>
<button id="cal-btn-load" class="btn">加载日历</button>
<button id="cal-btn-refresh" class="btn">刷新数据</button>
<button id="cal-btn-ai-verify" class="btn">AI复核本周</button>
</div>
<div id="calendar-status" class="status" style="display:none"></div>
<div id="calendar-summary" class="markets-calendar-summary"></div>
<div class="markets-calendar-board">
<div id="calendar-grid" class="markets-calendar-grid"></div>
<aside id="calendar-detail" class="markets-calendar-detail"></aside>
</div>
</section>
<section id="m-panel-weekly" class="panel" style="display:none">
<div class="bar">
<input id="weekly-week" type="date" />
<button id="weekly-btn-prev" class="btn">上周</button>
<button id="weekly-btn-current" class="btn">本周</button>
<button id="weekly-btn-next" class="btn">下周</button>
<button id="weekly-btn-load" class="btn">加载周报</button>
<button id="weekly-btn-refresh" class="btn">刷新并补存</button>
<button id="btn-weekly-meta" class="btn">周报数元</button>
</div>
<div id="weekly-status" class="status" style="display:none"></div>
<div id="weekly-summary" class="markets-weekly-summary"></div>
<div id="weekly-grid" class="markets-weekly-grid"></div>
</section>
<section id="m-panel-news" class="panel" style="display:none">
<div class="bar">
<input id="news-date" type="date" />
<button id="news-btn-prev" class="btn">◀ 前一天</button>
<button id="news-btn-today" class="btn">昨天</button>
<button id="news-btn-current" class="btn">今天</button>
<button id="news-btn-next" class="btn">后一天 ▶</button>
<button id="news-btn-fetch" class="btn">🔄 手动探针抓取</button>
<button id="news-btn-translate" class="btn">🌐 手工AI翻译</button>
<button id="news-btn-analyze" class="btn">🤖 手工AI研判</button>
<button id="news-btn-logs" class="btn">📋 抓取日志</button>
<span id="news-status" class="status status-inline" style="display:none"></span>
</div>
<div class="news-summary-row" id="news-summary"></div>
<div class="table-responsive">
<table class="data-table" id="news-table">
<thead>
<tr>
<th style="width:55px">大洲</th>
<th style="width:60px">国家</th>
<th style="width:90px">媒体</th>
<th style="width:75px">时间</th>
<th class="news-col-flex">标题</th>
<th class="news-col-flex">简述</th>
<th style="width:50px">链接</th>
<th class="news-col-flex">AI研判</th>
</tr>
</thead>
<tbody id="news-list"></tbody>
</table>
</div>
</section>
<!-- 理论与实践:点击tab直接新窗口打开 -->
<section id="m-panel-tools" class="panel" style="display:none">
<div class="tools-container">
<!-- 工具一:交易计算 -->
<div class="tool-card" id="tool-calc">
<div class="tool-card-header">
<h3>1、交易计算</h3>
</div>
<div class="tool-card-body">
<div class="calc-input-row">
<label class="calc-label">原始价格</label>
<input type="number" id="calc-price" class="calc-input" placeholder="输入价格" step="0.01" min="0" />
<label class="calc-label">股数</label>
<input type="number" id="calc-shares" class="calc-input" placeholder="输入股数" step="100" min="100" />
<label class="calc-label">幅度</label>
<div class="calc-amount-group">
<select id="calc-amount-select" class="calc-select">
<option value="5">5%</option>
<option value="10">10%</option>
<option value="15">15%</option>
<option value="20">20%</option>
<option value="25">25%</option>
<option value="30">30%</option>
</select>
<input type="number" id="calc-amount-input" class="calc-input calc-input-sm" placeholder="自定义%" step="0.1" min="0" />
</div>
<div class="calc-radio-group">
<label class="calc-radio">
<input type="radio" name="calc-direction" value="up" checked />
<span class="calc-radio-label calc-radio-up">涨</span>
</label>
<label class="calc-radio">
<input type="radio" name="calc-direction" value="down" />
<span class="calc-radio-label calc-radio-down">跌</span>
</label>
<span id="calc-sign-display" class="calc-sign-display">+</span>
</div>
<label class="calc-label">成交金额</label>
<input type="text" id="calc-buy-amount" class="calc-input calc-result-input" readonly />
<button id="btn-calc" class="btn">计算</button>
</div>
<div class="calc-result-row">
<span class="calc-result-label">计算得到,最终价格</span>
<input type="text" id="calc-result-price" class="calc-input calc-result-input" readonly />
<span class="calc-result-label">(含交易费</span>
<input type="text" id="calc-result-fee" class="calc-input calc-result-input" readonly />
<span class="calc-result-label">),股数</span>
<input type="text" id="calc-result-shares" class="calc-input calc-result-input" readonly />
<span class="calc-result-label">最终成交金额</span>
<input type="text" id="calc-sell-amount" class="calc-input calc-result-input" readonly />
<span class="calc-result-label">差额</span>
<input type="text" id="calc-diff" class="calc-input calc-result-input" readonly />
</div>
</div>
</div>
<!-- 未来工具预留区域 -->
<div class="tools-placeholder" id="tools-placeholder">
<p class="tools-placeholder-text">更多工具开发中...</p>
</div>
</div>
</section>
<!-- 建行定投评估:场外基金定投/赎回参考,点击按钮按需抓取(无定时任务) -->
<section id="m-panel-dip" class="panel" style="display:none">
<div class="bar">
<button id="dip-btn-run" class="btn">开始评估</button>
<span id="dip-status" class="status status-inline" style="display:none"></span>
</div>
<div class="table-responsive">
<table class="data-table" id="dip-table">
<thead>
<tr>
<th style="width:90px">指数名称</th>
<th style="width:70px">代码</th>
<th style="width:60px">市场</th>
<th style="width:80px">PE-TTM</th>
<th style="width:110px">近10年PE分位</th>
<th style="width:95px">数据日期</th>
<th style="width:130px">数据源</th>
<th>定投建议</th>
</tr>
</thead>
<tbody id="dip-list">
<tr><td colspan="8" class="muted" style="text-align:center;padding:30px">请点击「开始评估」获取四大指数最新 PE 估值与定投档位建议</td></tr>
</tbody>
</table>
</div>
<div id="dip-errors" style="display:none;margin-top:10px"></div>
<div class="dip-thresholds" style="margin-top:14px;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;background:#f8fafc;font-size:13px;line-height:1.9;color:#334155">
<div style="font-weight:700;color:#111827;margin-bottom:4px">我的定投档位阈值(定投/止盈依据)</div>
<div><b>沪深300</b>:PE<12(分位<30%)定投200元/日 | 12~14.5 定投150元/日 | 14.5~16 定投100元/日·可止盈50% | PE>16 暂停定投+止盈清仓</div>
<div><b>中证500</b>:PE<25 定投200元/日 | 25~32 定投150元/日 | 32~36 定投100元/日·可止盈50% | PE>36 暂停定投+止盈清仓</div>
<div><b>纳指100</b>:PE<24 定投200元/日 | 24~30 定投150元/日 | 30~36 定投100元/日·可止盈50% | PE>36 暂停定投+止盈清仓</div>
<div><b>标普500</b>:PE<16 定投200元/日 | 16~21 定投150元/日 | 21~25 定投100元/日·可止盈50% | PE>25 暂停定投+止盈清仓</div>
<div style="margin-top:6px;color:#64748b;font-size:12px">数据源:A股为中证指数官网(近10年日频自算分位),美股为蛋卷基金(分位窗口自2016年,约10年);标普500备源 multpl.com。点击按钮按需抓取,非实时行情,仅供参考。</div>
</div>
<!-- 富国中证红利备忘卡片:纯静态提醒,无数据源,实际盈亏以建行APP为准 -->
<div style="margin-top:14px;padding:12px 14px;border:1px solid #fde68a;border-radius:10px;background:#fffbeb;font-size:13px;line-height:1.9;color:#334155">
<div style="font-weight:700;color:#92400e;margin-bottom:4px">富国中证红利(100033)持仓提醒(备忘 · 无数据源 · 以建行APP实际盈亏为准)</div>
<div><b>收益率提醒</b>:降至 <span style="color:#15803d;font-weight:700">-6%</span> → 大跌后分批加仓信号 | 升至 <span style="color:#b91c1c;font-weight:700">+7%</span> → 维持1000元定投</div>
<div><b>净值精准提醒</b>(参考锚点净值 <b>3.282</b>):降至 <span style="color:#15803d;font-weight:700">3.05</span>(跌幅约7%)→ 提醒加仓 | 升至 <span style="color:#b91c1c;font-weight:700">3.52</span>(涨幅约7%)→ 维持1000元定投</div>
</div>
<!-- 投资纪律座右铭:红字黄底圆角标签 -->
<div style="margin-top:14px;text-align:center">
<span style="display:inline-block;padding:8px 18px;border-radius:999px;background:#fde047;color:#b91c1c;font-weight:700;font-size:14px;letter-spacing:0.5px">现金是未来的期权,不要把弹药消耗在普通波动里。一年真正的大机会没有几次。</span>
</div>
<!-- 六种盈利投资者自我提醒:黑底绿环编号样式,两栏布局,行高=字体120% -->
<div style="margin-top:14px;padding:12px 14px;border-radius:12px;background:#0b0f0a;border:1px solid #24301a;display:grid;grid-template-columns:1fr 1fr;gap:0 22px">
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px;border-bottom:1px solid rgba(163,230,53,0.3)">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">1.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">猎人型:</b>一年出手没几次,80%的时间都在等。不开枪则已,<b style="color:#bef264">一开枪就带着利润离场。</b></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px;border-bottom:1px solid rgba(163,230,53,0.3)">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">2.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">守株型:</b>认准一只好股票,拿三五年。眼里没有分时,<b style="color:#bef264">只有趋势。</b></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px;border-bottom:1px solid rgba(163,230,53,0.3)">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">3.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">工匠型:</b>反复做同一只票,高抛低吸、不断做T,<b style="color:#bef264">把成本一点点磨到接近零。</b></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px;border-bottom:1px solid rgba(163,230,53,0.3)">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">4.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">龙头型:</b>只做主线,只追最强,不碰杂毛。<b style="color:#bef264">纪律比胆子更大,复盘比睡觉还认真。</b></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">5.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">系统型:</b>只信交易系统,不信消息,不猜新闻。<b style="color:#bef264">信号一到,机械执行,毫不犹豫。</b></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 4px">
<div style="flex:0 0 32px;width:32px;height:32px;border-radius:50%;border:3px solid #a3e635;background:#131a10;color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center">6.</div>
<div style="color:#d9f99d;font-size:13px;line-height:1.2"><b style="color:#fff">清醒型:</b>懂得见好就收,<b style="color:#bef264">从不幻想卖在最高点。</b></div>
</div>
</div>
</section>
</div>
</main>
<div id="settings-modal" class="modal hidden">
<div class="modal-body">
<h3>市场配置</h3>
<label>监控列表(JSON)</label>
<textarea id="wl" rows="6" placeholder='[{"label":"沪市","symbol":"sh000001","source":"sina"}]'></textarea>
<label>跌幅告警阈值(%)</label>
<input id="th" type="number" step="0.1" value="-2" />
<label>邮件配置(JSON)</label>
<textarea id="mail" rows="6" placeholder='{"enabled":false,"from":"","to":[""],"smtp":{"host":"","port":465,"secure":true,"auth":{"user":"","pass":""}}}'></textarea>
<div class="modal-actions">
<button id="btn-format-json" class="btn">格式化 JSON</button>
<button id="btn-save" class="btn">保存</button>
<button id="btn-close" class="btn">关闭</button>
</div>
</div>
</div>
<div id="skills-meta-modal" class="modal hidden">
<div class="modal-body skills-meta-body">
<div class="skills-meta-header">
<h3>数元汇总</h3>
<div id="skills-meta-stats" class="skills-meta-stats"></div>
</div>
<div class="skills-meta-content">
<div class="skills-meta-section">
<div class="skills-meta-section-title">📊 卡片数据源总览</div>
<div class="skills-meta-table-wrap">
<table class="skills-meta-table">
<thead><tr>
<th>卡片</th><th>代号</th><th>主源</th><th>备源</th><th>频率</th><th>最近数据</th><th>状态</th>
</tr></thead>
<tbody id="skills-meta-tbody"></tbody>
</table>
</div>
</div>
<div class="skills-meta-section">
<div class="skills-meta-section-title">🏗️ Skill 构成简述</div>
<div id="skills-meta-structure" class="skills-meta-structure"></div>
</div>
<div class="skills-meta-section">
<div class="skills-meta-section-title">⚠️ 异常排查</div>
<div id="skills-meta-anomalies" class="skills-meta-anomalies"></div>
<div class="skills-meta-section-title" style="margin-top:12px">🔗 数据源连通性</div>
<div id="skills-meta-heartbeats" class="skills-meta-heartbeats"></div>
</div>
</div>
<div class="modal-actions">
<button id="btn-skills-meta-close" class="btn">关闭</button>
</div>
</div>
</div>
<div id="email-log-modal" class="modal hidden">
<div class="modal-body" style="width:90vw;max-width:1000px;max-height:85vh;display:flex;flex-direction:column;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;flex-shrink:0">
<h3 style="margin:0;font-size:18px;color:#111827">邮件日志</h3>
<div style="display:flex;gap:8px;align-items:center">
<span id="email-log-count" style="font-size:13px;color:#64748b">共 0 条</span>
<button id="btn-email-log-refresh" class="btn" style="font-size:13px;padding:6px 12px">刷新</button>
<button id="btn-email-log-close" class="btn" style="font-size:13px;padding:6px 12px">关闭</button>
</div>
</div>
<div style="overflow:auto;flex:1">
<table class="email-log-table">
<thead>
<tr>
<th style="width:60px">ID</th>
<th style="width:100px">时间</th>
<th style="width:100px">来源</th>
<th style="width:180px">告警ID</th>
<th>主题</th>
<th style="width:80px">状态</th>
<th>详情</th>
</tr>
</thead>
<tbody id="email-log-tbody"></tbody>
</table>
</div>
</div>
</div>
<div id="weekly-meta-modal" class="modal hidden">
<div class="modal-body skills-meta-body">
<div class="skills-meta-header">
<h3>指数周报 · 数元汇总</h3>
<div id="weekly-meta-stats" class="skills-meta-stats"></div>
</div>
<div class="skills-meta-content">
<div class="skills-meta-section">
<div class="skills-meta-section-title">📊 周报卡片数据源总览</div>
<div class="skills-meta-table-wrap">
<table class="skills-meta-table">
<thead><tr>
<th>卡片</th><th>代号</th><th>主源</th><th>备源</th><th>分组</th><th>可靠性</th>
</tr></thead>
<tbody id="weekly-meta-tbody"></tbody>
</table>
</div>
</div>
<div class="skills-meta-section">
<div class="skills-meta-section-title">🔗 数据源连通性</div>
<div id="weekly-meta-heartbeats" class="skills-meta-heartbeats"></div>
</div>
<div class="skills-meta-section">
<div class="skills-meta-section-title">⚠️ 风险诊断</div>
<div id="weekly-meta-diagnosis" class="skills-meta-anomalies"></div>
</div>
</div>
<div class="modal-actions">
<button id="btn-weekly-meta-close" class="btn">关闭</button>
</div>
</div>
</div>
<div id="news-logs-modal" class="modal hidden">
<div class="modal-body" style="width:90vw;max-width:90vw;height:90vh;max-height:90vh;display:flex;flex-direction:column;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;flex-shrink:0">
<h3 style="margin:0;font-size:18px;color:#111827">📋 抓取日志</h3>
<div style="display:flex;gap:8px;align-items:center">
<span id="news-logs-count" style="font-size:13px;color:#64748b"></span>
<button id="news-btn-copy-logs" class="btn" style="font-size:13px;padding:6px 12px">复制全部</button>
<button id="news-btn-clear-logs" class="btn" style="font-size:13px;padding:6px 12px;background:linear-gradient(135deg,#ef4444,#dc2626)">清空日志</button>
<button id="news-btn-logs-close" class="btn" style="font-size:13px;padding:6px 12px">关闭</button>
</div>
</div>
<div id="news-logs-content" style="flex:1;overflow:auto;background:#1e1e2e;color:#cdd6f4;padding:16px;font-family:'Cascadia Code','Fira Code','JetBrains Mono','Consolas',monospace;font-size:13px;line-height:1.6;border-radius:10px;border:1px solid #313244;white-space:pre-wrap;word-break:break-all"></div>
</div>
</div>
<div id="interaction-modal" class="modal hidden">
<div class="modal-body interaction-modal-body">
<div class="interaction-modal-head">
<div>
<h3 id="interaction-title">交互详情</h3>
<div id="interaction-meta" class="interaction-meta"></div>
</div>
<span id="interaction-badge" class="interaction-badge">进行中</span>
</div>
<div id="interaction-summary" class="interaction-summary">等待执行...</div>
<pre id="interaction-log" class="interaction-log"></pre>
<div class="modal-actions interaction-actions">
<span id="interaction-hint" class="interaction-hint"></span>
<button id="interaction-copy" class="btn">复制详情</button>
<button id="interaction-close" class="btn">关闭</button>
</div>
</div>
</div>
<script src="/common/common.js"></script>
<script src="/tools/markets/markets.js?v=3"></script>
<script src="/tools/markets/markets_tools.js?v=1"></script>
<script src="/tools/markets/markets_dip_eval.js?v=1"></script>
<script>
(async function(){
try {
const res = await fetch('/api/flags')
const data = await res.json()
if (data && data.debug && data.debug.markets) {
const sec = document.getElementById('m-debug-section')
if (sec) sec.style.display = ''
}
} catch {}
})()
</script>
</body>
</html>