FILE: orn-dashboard.html / orn-styles.css
/* QFPC CORE STYLES - ADD TO CSS */
/* Контейнер трека */
.qfpc-gauge-track {
position: relative;
width: 100%;
height: 12px;
background: #111827; /* gray-900 */
border-radius: 999px;
overflow: hidden;
border: 1px solid rgba(255,255,255,0.1);
display: flex; /* Важно для центрирования */
justify-content: center;
}
/* Маркер центра */
.qfpc-center-marker {
position: absolute;
left: 50%;
top: 0; bottom: 0;
width: 2px;
background: rgba(255,255,255,0.15);
z-index: 10;
transform: translateX(-50%);
}
/* Активный бар */
.qfpc-fill-bar {
position: absolute;
top: 0; bottom: 0;
height: 100%;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Цветовые модификаторы */
.qfpc-fill-bar.buy {
background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
box-shadow: 0 0 10px rgba(16, 185, 129, 0.3);
}
.qfpc-fill-bar.sell {
background: linear-gradient(90deg, #f87171 0%, #ef4444 100%);
box-shadow: 0 0 10px rgba(239, 68, 68, 0.3);
}
.qfpc-fill-bar.extreme-buy {
background: #10b981;
animation: pulse-green 0.8s infinite;
}
.qfpc-fill-bar.extreme-sell {
background: #ef4444;
animation: pulse-red 0.8s infinite;
}
FILE: orn-app.js (Function updateQFPC)
/**
* Обновляет UI модуля QFPC на основе Z-Score
* @param {number} zScore - Значение от -3.0 до 3.0 (из Backend)
*/
function updateQFPCWidget(zScore) {
const bar = document.getElementById('qfpc-bar');
const valueDisplay = document.getElementById('widget-value');
const MAX_SIGMA = 3.0; // Максимальное значение шкалы
// 1. Ограничиваем значение (Clamp)
const clampedScore = Math.max(-MAX_SIGMA, Math.min(MAX_SIGMA, zScore));
// 2. Рассчитываем процент заполнения ПОЛОВИНЫ шкалы (0-50%)
const percentage = (Math.abs(clampedScore) / MAX_SIGMA) * 50;
// 3. Применяем логику "От Центра"
if (clampedScore >= 0) {
// BUY: Начинается с 50%, растет вправо
bar.style.left = '50%';
bar.style.width = percentage + '%';
// Классы стилей
bar.className = 'qfpc-fill-bar buy';
if (clampedScore > 2.0) bar.classList.add('extreme-buy');
} else {
// SELL: Начинается с (50% - ширина), растет влево визуально
bar.style.left = (50 - percentage) + '%';
bar.style.width = percentage + '%';
// Классы стилей
bar.className = 'qfpc-fill-bar sell';
if (clampedScore < -2.0) bar.classList.add('extreme-sell');
}
// Обновляем текст
valueDisplay.innerText = clampedScore.toFixed(2) + ' σ';
valueDisplay.style.color = clampedScore > 0 ? '#34d399' : '#f87171';
}