File size: 5,218 Bytes
452f691 dd7ffbd 452f691 b068b76 dd7ffbd b068b76 dd7ffbd 452f691 dd7ffbd 452f691 dd7ffbd 452f691 dd7ffbd 452f691 dd7ffbd 452f691 dd7ffbd 452f691 dd7ffbd 2a37caa dd7ffbd 452f691 dd7ffbd b068b76 dd7ffbd 452f691 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
import apiClient from './apiClient.js';
class ChartLabView {
constructor(section) {
this.section = section;
this.symbolSelect = section.querySelector('[data-chart-symbol]');
this.timeframeButtons = section.querySelectorAll('[data-chart-timeframe]');
this.indicatorInputs = section.querySelectorAll('[data-indicator]');
this.analyzeButton = section.querySelector('[data-run-analysis]');
this.canvas = section.querySelector('#chart-lab-canvas');
this.insightsContainer = section.querySelector('[data-ai-insights]');
this.chart = null;
this.symbol = 'BTC';
this.timeframe = '7d';
}
async init() {
await this.loadChart();
this.bindEvents();
}
bindEvents() {
if (this.symbolSelect) {
this.symbolSelect.addEventListener('change', async () => {
this.symbol = this.symbolSelect.value;
await this.loadChart();
});
}
this.timeframeButtons.forEach((btn) => {
btn.addEventListener('click', async () => {
this.timeframeButtons.forEach((b) => b.classList.remove('active'));
btn.classList.add('active');
this.timeframe = btn.dataset.chartTimeframe;
await this.loadChart();
});
});
if (this.analyzeButton) {
this.analyzeButton.addEventListener('click', () => this.runAnalysis());
}
}
async loadChart() {
if (!this.canvas) return;
const result = await apiClient.getPriceChart(this.symbol, this.timeframe);
const container = this.canvas.parentElement;
if (!result.ok) {
if (container) {
let errorNode = container.querySelector('.chart-error');
if (!errorNode) {
errorNode = document.createElement('div');
errorNode.className = 'inline-message inline-error chart-error';
container.appendChild(errorNode);
}
errorNode.textContent = result.error;
}
return;
}
if (container) {
const errorNode = container.querySelector('.chart-error');
if (errorNode) errorNode.remove();
}
const points = result.data || [];
const labels = points.map((point) => point.time || point.timestamp || '');
const prices = points.map((point) => point.price || point.close || point.value);
if (this.chart) {
this.chart.destroy();
}
this.chart = new Chart(this.canvas, {
type: 'line',
data: {
labels,
datasets: [
{
label: `${this.symbol} (${this.timeframe})`,
data: prices,
borderColor: '#f472b6',
backgroundColor: 'rgba(244, 114, 182, 0.2)',
fill: true,
tension: 0.4,
},
],
},
options: {
scales: {
x: { ticks: { color: 'var(--text-muted)' } },
y: { ticks: { color: 'var(--text-muted)' } },
},
plugins: {
legend: { display: false },
},
},
});
}
async runAnalysis() {
if (!this.insightsContainer) return;
const enabledIndicators = Array.from(this.indicatorInputs)
.filter((input) => input.checked)
.map((input) => input.value);
this.insightsContainer.innerHTML = '<p>Running AI analysis...</p>';
const result = await apiClient.analyzeChart(this.symbol, this.timeframe, enabledIndicators);
if (!result.ok) {
this.insightsContainer.innerHTML = `<div class="inline-message inline-error">${result.error}</div>`;
return;
}
const payload = result.data || {};
const insights = payload.insights || result.insights || payload;
if (!insights) {
this.insightsContainer.innerHTML = '<p>No AI insights returned.</p>';
return;
}
const summary =
insights.narrative?.summary?.summary || insights.narrative?.summary || insights.narrative?.summary_text;
const signals = insights.narrative?.signals || {};
const bullets = Object.entries(signals)
.map(([key, value]) => `<li><strong>${key}:</strong> ${(value?.label || 'n/a')} (${value?.score ?? 'β'})</li>`)
.join('');
this.insightsContainer.innerHTML = `
<h4>AI Insights</h4>
<p><strong>Direction:</strong> ${insights.change_direction || 'N/A'} (${insights.change_percent ?? 'β'}%)</p>
<p><strong>Range:</strong> High ${insights.high ?? 'β'} / Low ${insights.low ?? 'β'}</p>
<p>${summary || insights.narrative?.summary?.summary || insights.narrative?.summary || ''}</p>
<ul>${bullets || '<li>No sentiment signals provided.</li>'}</ul>
`;
}
}
export default ChartLabView;
|