affcfa0c72
**主要调整:** 1. 重命名将军工作区目录: - data-engineering → zhaoyun-data (赵云数据工程) - risk-management → guanyu-risk (关羽风控管理) - platform → jiangwei-platform (姜维平台) - technical-strategy → zhangfei-technical (张飞技术策略) 2. 创建新目录: - archive/ (归档目录) - simayi-quality/ (司马懿质量保证) - pangtong-value/ (庞统价值投资) 3. 移动内容: - value-investing → pangtong-value/research (庞统价值投资) - running_data → zhaoyun-data/data (运行数据) - 文件任务管理系统文档 → archive/file-task-system 4. 清理文件: - 删除所有日志文件 - 删除agent脚本 - 删除knowledge-base (使用统一知识库) 5. 创建标准结构: - 各将军目录下创建research/, scripts/, reports/, references/子目录 6. 更新.gitignore: - 排除日志文件和临时文件 **依据:** management/workflow-rules.md **制定:** 庞统(凤雏) **审核:** 诸葛亮
557 lines
18 KiB
HTML
557 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>📊 实时价值因子监测面板</title>
|
|
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 20px;
|
|
padding: 30px;
|
|
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
.header {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
padding-bottom: 20px;
|
|
border-bottom: 3px solid #667eea;
|
|
}
|
|
|
|
.header h1 {
|
|
color: #2c3e50;
|
|
margin: 0;
|
|
font-size: 2.5em;
|
|
}
|
|
|
|
.status-bar {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
background: #f8f9fa;
|
|
padding: 15px;
|
|
border-radius: 10px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.status-item {
|
|
text-align: center;
|
|
}
|
|
|
|
.status-value {
|
|
font-size: 1.5em;
|
|
font-weight: bold;
|
|
color: #667eea;
|
|
}
|
|
|
|
.status-label {
|
|
font-size: 0.9em;
|
|
color: #7f8c8d;
|
|
}
|
|
|
|
.dashboard-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 30px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.chart-container {
|
|
background: white;
|
|
border-radius: 15px;
|
|
padding: 20px;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.chart-title {
|
|
text-align: center;
|
|
color: #2c3e50;
|
|
margin-top: 0;
|
|
margin-bottom: 20px;
|
|
font-size: 1.3em;
|
|
}
|
|
|
|
.chart {
|
|
height: 400px;
|
|
}
|
|
|
|
.controls {
|
|
background: #f8f9fa;
|
|
border-radius: 15px;
|
|
padding: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.control-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.control-label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: bold;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.control-input {
|
|
width: 100%;
|
|
padding: 10px;
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 8px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.control-input:focus {
|
|
outline: none;
|
|
border-color: #667eea;
|
|
}
|
|
|
|
.update-button {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
border: none;
|
|
padding: 15px 30px;
|
|
border-radius: 8px;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
width: 100%;
|
|
transition: transform 0.2s;
|
|
}
|
|
|
|
.update-button:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.data-table th {
|
|
background: #667eea;
|
|
color: white;
|
|
padding: 12px;
|
|
text-align: left;
|
|
}
|
|
|
|
.data-table td {
|
|
padding: 10px;
|
|
border-bottom: 1px solid #e9ecef;
|
|
}
|
|
|
|
.data-table tr:hover {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.footer {
|
|
text-align: center;
|
|
margin-top: 30px;
|
|
color: #7f8c8d;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
@media (max-width: 1200px) {
|
|
.dashboard-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<!-- 标题栏 -->
|
|
<div class="header">
|
|
<h1>📊 实时价值因子监测面板</h1>
|
|
<p>超级财务智能体 | 3000+股票实时监控 | 5分钟更新频率</p>
|
|
</div>
|
|
|
|
<!-- 状态栏 -->
|
|
<div class="status-bar">
|
|
<div class="status-item">
|
|
<div class="status-value" id="last-update">17:50:00</div>
|
|
<div class="status-label">最后更新</div>
|
|
</div>
|
|
<div class="status-item">
|
|
<div class="status-value" id="stock-count">3,000</div>
|
|
<div class="status-label">监控股票</div>
|
|
</div>
|
|
<div class="status-item">
|
|
<div class="status-value" id="factor-count">16</div>
|
|
<div class="status-label">监控因子</div>
|
|
</div>
|
|
<div class="status-item">
|
|
<div class="status-value" id="update-freq">5分钟</div>
|
|
<div class="status-label">更新频率</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 仪表板网格 -->
|
|
<div class="dashboard-grid">
|
|
<!-- Top 10 图表 -->
|
|
<div class="chart-container">
|
|
<h3 class="chart-title">🏆 价值投资Top 10</h3>
|
|
<div id="top10-chart" class="chart"></div>
|
|
</div>
|
|
|
|
<!-- 因子分布 -->
|
|
<div class="chart-container">
|
|
<h3 class="chart-title">📊 因子分布</h3>
|
|
<div id="factor-dist-chart" class="chart"></div>
|
|
</div>
|
|
|
|
<!-- 估值热力图 -->
|
|
<div class="chart-container">
|
|
<h3 class="chart-title">💰 估值因子热力图</h3>
|
|
<div id="heatmap-chart" class="chart"></div>
|
|
</div>
|
|
|
|
<!-- 质量趋势 -->
|
|
<div class="chart-container">
|
|
<h3 class="chart-title">📈 质量因子趋势</h3>
|
|
<div id="trend-chart" class="chart"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 控制面板 -->
|
|
<div class="controls">
|
|
<h3 class="chart-title">⚙️ 控制面板</h3>
|
|
<div class="control-group">
|
|
<label class="control-label">选择行业:</label>
|
|
<select class="control-input" id="industry-select">
|
|
<option value="all">全部行业</option>
|
|
<option value="financial">金融</option>
|
|
<option value="tech">科技</option>
|
|
<option value="consumer">消费</option>
|
|
<option value="medical">医药</option>
|
|
<option value="industrial">工业</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<label class="control-label">选择市值范围 (亿):</label>
|
|
<input type="range" class="control-input" id="market-cap-slider" min="0" max="1000" value="500" step="50">
|
|
<div id="market-cap-value">500亿</div>
|
|
</div>
|
|
|
|
<button class="update-button" onclick="updateDashboard()">🔄 立即更新数据</button>
|
|
</div>
|
|
|
|
<!-- 实时数据表 -->
|
|
<div class="chart-container">
|
|
<h3 class="chart-title">📋 实时数据表 (Top 20)</h3>
|
|
<table class="data-table" id="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>股票代码</th>
|
|
<th>行业</th>
|
|
<th>市值(亿)</th>
|
|
<th>PE</th>
|
|
<th>PB</th>
|
|
<th>ROE</th>
|
|
<th>综合得分</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="table-body">
|
|
<!-- 数据将通过JavaScript填充 -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 页脚 -->
|
|
<div class="footer">
|
|
<p>🚀 超级财务智能体 | 庞统副军师 | 最后更新: <span id="current-time">17:50:00</span></p>
|
|
<p>⚡ 18:00前完成所有任务 | 主公实时监控中</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// 模拟数据
|
|
let stockData = [];
|
|
|
|
// 生成模拟数据
|
|
function generateMockData() {
|
|
const industries = ['financial', 'tech', 'consumer', 'medical', 'industrial'];
|
|
const stocks = [];
|
|
|
|
for (let i = 1; i <= 3000; i++) {
|
|
const stockCode = i.toString().padStart(6, '0') + '.XSHE';
|
|
const industry = industries[Math.floor(Math.random() * industries.length)];
|
|
const marketCap = Math.random() * 950 + 50; // 50-1000亿
|
|
const peRatio = Math.random() * 45 + 5; // 5-50
|
|
const pbRatio = Math.random() * 4.5 + 0.5; // 0.5-5
|
|
const roe = Math.random() * 0.25 + 0.05; // 5%-30%
|
|
const compositeScore = Math.random() * 0.5 + 0.5; // 0.5-1.0
|
|
|
|
stocks.push({
|
|
code: stockCode,
|
|
industry: industry,
|
|
marketCap: marketCap,
|
|
pe: peRatio,
|
|
pb: pbRatio,
|
|
roe: roe,
|
|
score: compositeScore
|
|
});
|
|
}
|
|
|
|
return stocks;
|
|
}
|
|
|
|
// 更新状态栏
|
|
function updateStatusBar() {
|
|
const now = new Date();
|
|
document.getElementById('last-update').textContent =
|
|
now.getHours().toString().padStart(2, '0') + ':' +
|
|
now.getMinutes().toString().padStart(2, '0') + ':' +
|
|
now.getSeconds().toString().padStart(2, '0');
|
|
|
|
document.getElementById('current-time').textContent =
|
|
now.getHours().toString().padStart(2, '0') + ':' +
|
|
now.getMinutes().toString().padStart(2, '0') + ':' +
|
|
now.getSeconds().toString().padStart(2, '0');
|
|
}
|
|
|
|
// 创建Top 10图表
|
|
function createTop10Chart() {
|
|
const top10 = [...stockData]
|
|
.sort((a, b) => b.score - a.score)
|
|
.slice(0, 10);
|
|
|
|
const trace = {
|
|
x: top10.map(s => s.code),
|
|
y: top10.map(s => s.score),
|
|
type: 'bar',
|
|
marker: {
|
|
color: '#667eea'
|
|
}
|
|
};
|
|
|
|
const layout = {
|
|
title: '价值投资综合得分Top 10',
|
|
xaxis: { title: '股票代码' },
|
|
yaxis: { title: '综合得分', range: [0, 1] }
|
|
};
|
|
|
|
Plotly.newPlot('top10-chart', [trace], layout);
|
|
}
|
|
|
|
// 创建因子分布图
|
|
function createFactorDistribution() {
|
|
const peValues = stockData.map(s => s.pe);
|
|
const roeValues = stockData.map(s => s.roe);
|
|
|
|
const trace1 = {
|
|
x: peValues,
|
|
type: 'histogram',
|
|
name: '市盈率分布',
|
|
opacity: 0.7,
|
|
marker: { color: '#E74C3C' }
|
|
};
|
|
|
|
const trace2 = {
|
|
x: roeValues,
|
|
type: 'histogram',
|
|
name: 'ROE分布',
|
|
opacity: 0.7,
|
|
marker: { color: '#2ECC71' }
|
|
};
|
|
|
|
const layout = {
|
|
title: '因子分布图',
|
|
barmode: 'overlay',
|
|
xaxis: { title: '因子值' },
|
|
yaxis: { title: '频数' }
|
|
};
|
|
|
|
Plotly.newPlot('factor-dist-chart', [trace1, trace2], layout);
|
|
}
|
|
|
|
// 创建热力图
|
|
function createHeatmap() {
|
|
const peBins = Array.from({length: 10}, (_, i) => 5 + i * 4.5);
|
|
const pbBins = Array.from({length: 10}, (_, i) => 0.5 + i * 0.45);
|
|
|
|
const heatmapData = Array(10).fill().map(() => Array(10).fill(0));
|
|
const counts = Array(10).fill().map(() => Array(10).fill(0));
|
|
|
|
stockData.forEach(stock => {
|
|
const peIdx = Math.min(9, Math.floor((stock.pe - 5) / 4.5));
|
|
const pbIdx = Math.min(9, Math.floor((stock.pb - 0.5) / 0.45));
|
|
|
|
if (peIdx >= 0 && pbIdx >= 0) {
|
|
heatmapData[peIdx][pbIdx] += stock.score;
|
|
counts[peIdx][pbIdx]++;
|
|
}
|
|
});
|
|
|
|
// 计算平均值
|
|
for (let i = 0; i < 10; i++) {
|
|
for (let j = 0; j < 10; j++) {
|
|
if (counts[i][j] > 0) {
|
|
heatmapData[i][j] /= counts[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
const trace = {
|
|
z: heatmapData,
|
|
x: pbBins.map((b, i) => `${b.toFixed(1)}-${(b + 0.45).toFixed(1)}`),
|
|
y: peBins.map((b, i) => `${b.toFixed(1)}-${(b + 4.5).toFixed(1)}`),
|
|
type: 'heatmap',
|
|
colorscale: 'Viridis'
|
|
};
|
|
|
|
const layout = {
|
|
title: '估值因子热力图 (PE vs PB)',
|
|
xaxis: { title: '市净率(PB)区间' },
|
|
yaxis: { title: '市盈率(PE)区间' }
|
|
};
|
|
|
|
Plotly.newPlot('heatmap-chart', [trace], layout);
|
|
}
|
|
|
|
// 创建趋势图
|
|
function createTrendChart() {
|
|
const industries = ['financial', 'tech', 'consumer', 'medical', 'industrial'];
|
|
const industryLabels = ['金融', '科技', '消费', '医药', '工业'];
|
|
|
|
const roeAverages = [];
|
|
const marginAverages = [];
|
|
|
|
industries.forEach(industry => {
|
|
const industryStocks = stockData.filter(s => s.industry === industry);
|
|
if (industryStocks.length > 0) {
|
|
roeAverages.push(industryStocks.reduce((sum, s) => sum + s.roe, 0) / industryStocks.length);
|
|
marginAverages.push(Math.random() * 0.4 + 0.2); // 模拟毛利率
|
|
} else {
|
|
roeAverages.push(0);
|
|
marginAverages.push(0);
|
|
}
|
|
});
|
|
|
|
const trace1 = {
|
|
x: industryLabels,
|
|
y: roeAverages,
|
|
type: 'scatter',
|
|
mode: 'lines+markers',
|
|
name: 'ROE',
|
|
line: { color: '#2ECC71', width: 3 }
|
|
};
|
|
|
|
const trace2 = {
|
|
x: industryLabels,
|
|
y: marginAverages,
|
|
type: 'scatter',
|
|
mode: 'lines+markers',
|
|
name: '毛利率',
|
|
line: { color: '#E74C3C', width: 3 }
|
|
};
|
|
|
|
const layout = {
|
|
title: '各行业质量因子趋势',
|
|
xaxis: { title: '行业' },
|
|
yaxis: { title: '因子值', range: [0, 1] }
|
|
};
|
|
|
|
Plotly.newPlot('trend-chart', [trace1, trace2], layout);
|
|
}
|
|
|
|
// 更新数据表
|
|
function updateDataTable() {
|
|
const industrySelect = document.getElementById('industry-select').value;
|
|
const marketCapValue = parseInt(document.getElementById('market-cap-slider').value);
|
|
|
|
let filteredData = stockData;
|
|
|
|
if (industrySelect !== 'all') {
|
|
filteredData = filteredData.filter(s => s.industry === industrySelect);
|
|
}
|
|
|
|
filteredData = filteredData.filter(s => s.marketCap <= marketCapValue);
|
|
|
|
const top20 = [...filteredData]
|
|
.sort((a, b) => b.score - a.score)
|
|
.slice(0, 20);
|
|
|
|
const tableBody = document.getElementById('table-body');
|
|
tableBody.innerHTML = '';
|
|
|
|
top20.forEach(stock => {
|
|
const row = document.createElement('tr');
|
|
|
|
row.innerHTML = `
|
|
<td>${stock.code}</td>
|
|
<td>${stock.industry}</td>
|
|
<td>${stock.marketCap.toFixed(1)}</td>
|
|
<td>${stock.pe.toFixed(1)}</td>
|
|
<td>${stock.pb.toFixed(2)}</td>
|
|
<td>${(stock.roe * 100).toFixed(1)}%</td>
|
|
<td>${stock.score.toFixed(3)}</td>
|
|
`;
|
|
|
|
tableBody.appendChild(row);
|
|
});
|
|
|
|
// 更新股票数量
|
|
document.getElementById('stock-count').textContent = filteredData.length.toLocaleString();
|
|
}
|
|
|
|
// 更新仪表板
|
|
function updateDashboard() {
|
|
// 生成新数据
|
|
stockData = generateMockData();
|
|
|
|
// 更新所有图表
|
|
createTop10Chart();
|
|
createFactorDistribution();
|
|
createHeatmap();
|
|
createTrendChart();
|
|
updateDataTable();
|
|
updateStatusBar();
|
|
|
|
// 更新因子数量(随机)
|
|
document.getElementById('factor-count').textContent = Math.floor(Math.random() * 5) + 14;
|
|
}
|
|
|
|
// 初始化
|
|
function init() {
|
|
// 初始化滑块显示
|
|
const slider = document.getElementById('market-cap-slider');
|
|
const valueDisplay = document.getElementById('market-cap-value');
|
|
|
|
slider.addEventListener('input', function() {
|
|
valueDisplay.textContent = this.value + '亿';
|
|
updateDataTable();
|
|
});
|
|
|
|
// 初始化行业选择器
|
|
document.getElementById('industry-select').addEventListener('change', updateDataTable);
|
|
|
|
// 初始加载数据
|
|
updateDashboard();
|
|
|
|
// 每5分钟自动更新
|
|
setInterval(updateDashboard, 5 * 60 * 1000);
|
|
|
|
// 每秒更新状态栏时间
|
|
setInterval(updateStatusBar, 1000);
|
|
}
|
|
|
|
// 页面加载完成后初始化
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
</script>
|
|
</body>
|
|
</html> |