|
|
|
|
@ -795,15 +795,22 @@ async function showAIHistoryDetail(recordId) {
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
${Object.entries(result.four_dimensional).map(([period, d]) => `
|
|
|
|
|
<tr>
|
|
|
|
|
<td><strong>${period}</strong></td>
|
|
|
|
|
<td>${d.macd?.trend || '--'}</td>
|
|
|
|
|
<td>${d.volume?.status || '--'}</td>
|
|
|
|
|
<td>${d.kdj?.status || '--'}</td>
|
|
|
|
|
<td>${d.conclusion || '--'}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
`).join('')}
|
|
|
|
|
${(() => {
|
|
|
|
|
const periodNames = { '60min': '60分钟', '30min': '30分钟', '15min': '15分钟', '5min': '5分钟' };
|
|
|
|
|
const periodOrder = ['60min', '30min', '15min', '5min'];
|
|
|
|
|
const sortedEntries = Object.entries(result.four_dimensional).sort((a, b) => {
|
|
|
|
|
return periodOrder.indexOf(a[0]) - periodOrder.indexOf(b[0]);
|
|
|
|
|
});
|
|
|
|
|
return sortedEntries.map(([period, d]) => `
|
|
|
|
|
<tr>
|
|
|
|
|
<td><strong>${periodNames[period] || period}</strong></td>
|
|
|
|
|
<td>${d.macd?.trend || '--'}</td>
|
|
|
|
|
<td>${d.volume?.status || '--'}</td>
|
|
|
|
|
<td>${d.kdj?.status || '--'}</td>
|
|
|
|
|
<td>${d.conclusion || '--'}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
`).join('');
|
|
|
|
|
})()}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
@ -1421,6 +1428,119 @@ function displayAIAnalysisResult(data) {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
// 同步AI分析数据到主面板各个卡片
|
|
|
|
|
syncAIToPanels(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function syncAIToPanels(result) {
|
|
|
|
|
const suggestion = result.trading_suggestion || {};
|
|
|
|
|
const fourDim = result.four_dimensional || {};
|
|
|
|
|
const pivotPoints = result.pivot_points || {};
|
|
|
|
|
const kdjDiag = result.kdj_diagnosis || {};
|
|
|
|
|
const scenarios = result.scenario_plans || {};
|
|
|
|
|
|
|
|
|
|
// 1. 同步到AI交易建议卡片
|
|
|
|
|
const suggestionBadge = document.getElementById('suggestion-badge');
|
|
|
|
|
if (suggestionBadge) {
|
|
|
|
|
suggestionBadge.textContent = suggestion.direction || '--';
|
|
|
|
|
suggestionBadge.className = `suggestion-badge ${suggestion.direction === '做多' ? 'up' : suggestion.direction === '做空' ? 'down' : 'neutral'}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const entryPriceEl = document.getElementById('entry-price');
|
|
|
|
|
if (entryPriceEl) entryPriceEl.textContent = suggestion.entry_range ? `${suggestion.entry_range.min}-${suggestion.entry_range.max}` : '--';
|
|
|
|
|
|
|
|
|
|
const targetPriceEl = document.getElementById('target-price');
|
|
|
|
|
if (targetPriceEl) {
|
|
|
|
|
const takeProfit = suggestion.take_profit?.[0];
|
|
|
|
|
targetPriceEl.textContent = takeProfit?.price || '--';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stopLossEl = document.getElementById('stop-loss');
|
|
|
|
|
if (stopLossEl) stopLossEl.textContent = suggestion.stop_loss || '--';
|
|
|
|
|
|
|
|
|
|
const riskLevelEl = document.getElementById('risk-level');
|
|
|
|
|
if (riskLevelEl) riskLevelEl.textContent = suggestion.position_size || '--';
|
|
|
|
|
|
|
|
|
|
// 2. 同步到技术指标卡片
|
|
|
|
|
// 从60min周期提取MACD和KDJ信息
|
|
|
|
|
const macd60 = fourDim['60min']?.macd || {};
|
|
|
|
|
const kdj60 = fourDim['60min']?.kdj || {};
|
|
|
|
|
|
|
|
|
|
const macdSignalEl = document.getElementById('macd-signal');
|
|
|
|
|
if (macdSignalEl) macdSignalEl.textContent = macd60.trend || '--';
|
|
|
|
|
|
|
|
|
|
const macdDetailEl = document.getElementById('macd-detail');
|
|
|
|
|
if (macdDetailEl) macdDetailEl.textContent = macd60.position ? `${macd60.position} | ${macd60.histogram || ''}` : '--';
|
|
|
|
|
|
|
|
|
|
const kdjSignalEl = document.getElementById('kdj-signal');
|
|
|
|
|
if (kdjSignalEl) kdjSignalEl.textContent = kdj60.status || '--';
|
|
|
|
|
|
|
|
|
|
const kdjDetailEl = document.getElementById('kdj-detail');
|
|
|
|
|
if (kdjDetailEl) kdjDetailEl.textContent = kdj60.signal || '--';
|
|
|
|
|
|
|
|
|
|
// 3. 同步到关键点位卡片
|
|
|
|
|
if (pivotPoints.r1) {
|
|
|
|
|
const r1El = document.getElementById('resistance-1');
|
|
|
|
|
if (r1El) r1El.querySelector('span:last-child').textContent = pivotPoints.r1;
|
|
|
|
|
}
|
|
|
|
|
if (pivotPoints.r2) {
|
|
|
|
|
const r2El = document.getElementById('resistance-2');
|
|
|
|
|
if (r2El) r2El.querySelector('span:last-child').textContent = pivotPoints.r2;
|
|
|
|
|
}
|
|
|
|
|
if (pivotPoints.pp) {
|
|
|
|
|
const ppEl = document.getElementById('pivot-point');
|
|
|
|
|
if (ppEl) ppEl.querySelector('span:last-child').textContent = pivotPoints.pp;
|
|
|
|
|
}
|
|
|
|
|
if (pivotPoints.s1) {
|
|
|
|
|
const s1El = document.getElementById('support-1');
|
|
|
|
|
if (s1El) s1El.querySelector('span:last-child').textContent = pivotPoints.s1;
|
|
|
|
|
}
|
|
|
|
|
if (pivotPoints.s2) {
|
|
|
|
|
const s2El = document.getElementById('support-2');
|
|
|
|
|
if (s2El) s2El.querySelector('span:last-child').textContent = pivotPoints.s2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 同步到多周期趋势卡片
|
|
|
|
|
const periodTrendsEl = document.getElementById('period-trends');
|
|
|
|
|
if (periodTrendsEl && Object.keys(fourDim).length > 0) {
|
|
|
|
|
const periodNames = { '60min': '60分钟', '30min': '30分钟', '15min': '15分钟', '5min': '5分钟' };
|
|
|
|
|
const periodOrder = ['60min', '30min', '15min', '5min'];
|
|
|
|
|
|
|
|
|
|
// 按固定顺序排列周期
|
|
|
|
|
const sortedEntries = Object.entries(fourDim).sort((a, b) => {
|
|
|
|
|
return periodOrder.indexOf(a[0]) - periodOrder.indexOf(b[0]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
periodTrendsEl.innerHTML = sortedEntries.map(([period, data]) => {
|
|
|
|
|
const trend = data.conclusion || data.macd?.trend || 'neutral';
|
|
|
|
|
const trendClass = trend.includes('多') || trend === 'up' ? 'up' : trend.includes('空') || trend === 'down' ? 'down' : 'neutral';
|
|
|
|
|
const trendText = trend.includes('多') ? '偏多' : trend.includes('空') ? '偏空' : '震荡';
|
|
|
|
|
return `<div class="trend-item"><span class="trend-period">${periodNames[period] || period}</span><span class="trend-badge ${trendClass}">${trendText}</span></div>`;
|
|
|
|
|
}).join('');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 同步到情景预案卡片
|
|
|
|
|
const scenarioPanel = document.getElementById('scenario-panel');
|
|
|
|
|
const scenarioPlansEl = document.getElementById('scenario-plans');
|
|
|
|
|
if (scenarioPanel && scenarioPlansEl && Object.keys(scenarios).length > 0) {
|
|
|
|
|
scenarioPanel.style.display = 'block';
|
|
|
|
|
const scenarioNames = {
|
|
|
|
|
'breakthrough': '突破',
|
|
|
|
|
'consolidation': '震荡',
|
|
|
|
|
'reversal': '反转',
|
|
|
|
|
'news_impact': '消息影响'
|
|
|
|
|
};
|
|
|
|
|
scenarioPlansEl.innerHTML = Object.entries(scenarios).map(([key, data]) => `
|
|
|
|
|
<div class="scenario-item">
|
|
|
|
|
<span class="scenario-name">${scenarioNames[key] || key}</span>
|
|
|
|
|
<span class="scenario-probability">${data.probability || 0}%</span>
|
|
|
|
|
<span class="scenario-action">${data.action || '--'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
`).join('');
|
|
|
|
|
} else if (scenarioPanel) {
|
|
|
|
|
scenarioPanel.style.display = 'none';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showAIDetailModal() {
|
|
|
|
|
@ -1433,13 +1553,14 @@ function showAIDetailModal() {
|
|
|
|
|
const modalBody = document.getElementById('ai-analysis-modal-body');
|
|
|
|
|
|
|
|
|
|
let fourDimensionalHTML = '';
|
|
|
|
|
const periods = ['60min', '30min', '15min'];
|
|
|
|
|
const periods = ['60min', '30min', '15min', '5min'];
|
|
|
|
|
const periodNames = { '60min': '60分钟', '30min': '30分钟', '15min': '15分钟', '5min': '5分钟' };
|
|
|
|
|
periods.forEach(period => {
|
|
|
|
|
const data = result.four_dimensional?.[period];
|
|
|
|
|
if (data) {
|
|
|
|
|
fourDimensionalHTML += `
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="period-cell">${period}</td>
|
|
|
|
|
<td class="period-cell">${periodNames[period] || period}</td>
|
|
|
|
|
<td>
|
|
|
|
|
<div>趋势: ${data.macd?.trend || '--'}</div>
|
|
|
|
|
<div>位置: ${data.macd?.position || '--'}</div>
|
|
|
|
|
|