prediction display controls
This commit is contained in:
@@ -413,3 +413,40 @@
|
|||||||
.annotation-mode-inactive {
|
.annotation-mode-inactive {
|
||||||
border: 2px solid var(--text-muted);
|
border: 2px solid var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Prediction Toggle Buttons */
|
||||||
|
.btn-group .btn.active {
|
||||||
|
background-color: rgba(var(--bs-success-rgb), 0.2);
|
||||||
|
border-color: var(--bs-success);
|
||||||
|
color: var(--bs-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group .btn-outline-success.active {
|
||||||
|
background-color: rgba(16, 185, 129, 0.2);
|
||||||
|
border-color: #10b981;
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group .btn-outline-warning.active {
|
||||||
|
background-color: rgba(251, 191, 36, 0.2);
|
||||||
|
border-color: #fbbf24;
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group .btn-outline-info.active {
|
||||||
|
background-color: rgba(59, 130, 246, 0.2);
|
||||||
|
border-color: #3b82f6;
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group .btn-outline-primary.active {
|
||||||
|
background-color: rgba(99, 102, 241, 0.2);
|
||||||
|
border-color: #6366f1;
|
||||||
|
color: #6366f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spacing between button groups */
|
||||||
|
.d-flex.gap-3 {
|
||||||
|
gap: 1rem !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ class ChartManager {
|
|||||||
this.predictionHistory = []; // Store last 20 predictions with fading
|
this.predictionHistory = []; // Store last 20 predictions with fading
|
||||||
this.maxPredictions = 20; // Maximum number of predictions to display
|
this.maxPredictions = 20; // Maximum number of predictions to display
|
||||||
|
|
||||||
|
// Prediction display toggles (all enabled by default)
|
||||||
|
this.displayToggles = {
|
||||||
|
ghostCandles: true,
|
||||||
|
trendLines: true,
|
||||||
|
actions: true,
|
||||||
|
pivots: true
|
||||||
|
};
|
||||||
|
|
||||||
// Helper to ensure all timestamps are in UTC
|
// Helper to ensure all timestamps are in UTC
|
||||||
this.normalizeTimestamp = (timestamp) => {
|
this.normalizeTimestamp = (timestamp) => {
|
||||||
if (!timestamp) return null;
|
if (!timestamp) return null;
|
||||||
@@ -32,6 +40,121 @@ class ChartManager {
|
|||||||
console.log('ChartManager initialized with timeframes:', timeframes);
|
console.log('ChartManager initialized with timeframes:', timeframes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle methods for prediction display - NON-DESTRUCTIVE
|
||||||
|
// These methods only update visibility without redrawing or resetting view
|
||||||
|
toggleGhostCandles(enabled) {
|
||||||
|
this.displayToggles.ghostCandles = enabled;
|
||||||
|
console.log('Ghost candles display:', enabled);
|
||||||
|
|
||||||
|
// Update visibility of ghost candle traces without redrawing
|
||||||
|
this.timeframes.forEach(tf => {
|
||||||
|
const plotElement = document.getElementById(`plot-${tf}`);
|
||||||
|
if (plotElement && plotElement.data) {
|
||||||
|
// Find ghost candle traces (they have name 'Ghost Prediction')
|
||||||
|
const updates = {};
|
||||||
|
plotElement.data.forEach((trace, idx) => {
|
||||||
|
if (trace.name === 'Ghost Prediction') {
|
||||||
|
if (!updates.visible) updates.visible = [];
|
||||||
|
updates.visible[idx] = enabled;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Object.keys(updates).length > 0) {
|
||||||
|
// Update trace visibility without resetting view
|
||||||
|
const indices = Object.keys(updates.visible).map(Number);
|
||||||
|
Plotly.restyle(plotElement, { visible: enabled }, indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTrendLines(enabled) {
|
||||||
|
this.displayToggles.trendLines = enabled;
|
||||||
|
console.log('Trend lines display:', enabled);
|
||||||
|
|
||||||
|
// Update visibility of trend line shapes without redrawing
|
||||||
|
this.timeframes.forEach(tf => {
|
||||||
|
const plotElement = document.getElementById(`plot-${tf}`);
|
||||||
|
if (plotElement && plotElement.layout && plotElement.layout.shapes) {
|
||||||
|
// Filter shapes to show/hide trend lines (yellow dotted lines)
|
||||||
|
const updatedShapes = plotElement.layout.shapes.map(shape => {
|
||||||
|
// Trend lines are yellow dotted lines
|
||||||
|
if (shape.line && shape.line.dash === 'dot' &&
|
||||||
|
shape.line.color && shape.line.color.includes('255, 255, 0')) {
|
||||||
|
return { ...shape, visible: enabled };
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update layout without resetting view
|
||||||
|
Plotly.relayout(plotElement, { shapes: updatedShapes });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleActions(enabled) {
|
||||||
|
this.displayToggles.actions = enabled;
|
||||||
|
console.log('Action predictions display:', enabled);
|
||||||
|
|
||||||
|
// Update visibility of action annotations without redrawing
|
||||||
|
this.timeframes.forEach(tf => {
|
||||||
|
const plotElement = document.getElementById(`plot-${tf}`);
|
||||||
|
if (plotElement && plotElement.layout && plotElement.layout.annotations) {
|
||||||
|
// Filter annotations to show/hide action predictions
|
||||||
|
const updatedAnnotations = plotElement.layout.annotations.map(ann => {
|
||||||
|
// Action annotations have specific text patterns (BUY, SELL, HOLD)
|
||||||
|
if (ann.text && (ann.text.includes('BUY') || ann.text.includes('SELL') || ann.text.includes('HOLD'))) {
|
||||||
|
return { ...ann, visible: enabled };
|
||||||
|
}
|
||||||
|
return ann;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update layout without resetting view
|
||||||
|
Plotly.relayout(plotElement, { annotations: updatedAnnotations });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePivots(enabled) {
|
||||||
|
this.displayToggles.pivots = enabled;
|
||||||
|
console.log('Pivot points display:', enabled);
|
||||||
|
|
||||||
|
// Update visibility of pivot shapes and annotations without redrawing
|
||||||
|
this.timeframes.forEach(tf => {
|
||||||
|
const plotElement = document.getElementById(`plot-${tf}`);
|
||||||
|
if (plotElement && plotElement.layout) {
|
||||||
|
const updates = {};
|
||||||
|
|
||||||
|
// Hide/show pivot shapes (horizontal lines)
|
||||||
|
if (plotElement.layout.shapes) {
|
||||||
|
updates.shapes = plotElement.layout.shapes.map(shape => {
|
||||||
|
// Pivot lines are horizontal lines with specific colors
|
||||||
|
if (shape.type === 'line' && shape.y0 === shape.y1) {
|
||||||
|
return { ...shape, visible: enabled };
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide/show pivot annotations (L1, L2, etc.)
|
||||||
|
if (plotElement.layout.annotations) {
|
||||||
|
updates.annotations = plotElement.layout.annotations.map(ann => {
|
||||||
|
// Pivot annotations have text like 'L1H', 'L2L', etc.
|
||||||
|
if (ann.text && /L\d+[HL]/.test(ann.text)) {
|
||||||
|
return { ...ann, visible: enabled };
|
||||||
|
}
|
||||||
|
return ann;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update layout without resetting view
|
||||||
|
if (Object.keys(updates).length > 0) {
|
||||||
|
Plotly.relayout(plotElement, updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start auto-updating charts
|
* Start auto-updating charts
|
||||||
*/
|
*/
|
||||||
@@ -2847,7 +2970,7 @@ class ChartManager {
|
|||||||
this._addTransformerPrediction(fadedPred, predictionShapes, predictionAnnotations);
|
this._addTransformerPrediction(fadedPred, predictionShapes, predictionAnnotations);
|
||||||
|
|
||||||
// Add trend vector visualization (shorter projection to avoid zoom issues)
|
// Add trend vector visualization (shorter projection to avoid zoom issues)
|
||||||
if (pred.trend_vector) {
|
if (pred.trend_vector && this.displayToggles.trendLines) {
|
||||||
this._addTrendPrediction(pred.trend_vector, predictionShapes, predictionAnnotations);
|
this._addTrendPrediction(pred.trend_vector, predictionShapes, predictionAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2933,8 +3056,10 @@ class ChartManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. Add all ghost candles from history to traces (with accuracy if validated)
|
// 4. Add all ghost candles from history to traces (with accuracy if validated)
|
||||||
for (const ghost of this.ghostCandleHistory[timeframe]) {
|
if (this.displayToggles.ghostCandles) {
|
||||||
this._addGhostCandlePrediction(ghost.candle, timeframe, predictionTraces, ghost.targetTime, ghost.accuracy);
|
for (const ghost of this.ghostCandleHistory[timeframe]) {
|
||||||
|
this._addGhostCandlePrediction(ghost.candle, timeframe, predictionTraces, ghost.targetTime, ghost.accuracy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Store as "Last Prediction" for shadow rendering
|
// 5. Store as "Last Prediction" for shadow rendering
|
||||||
|
|||||||
@@ -4,22 +4,41 @@
|
|||||||
<i class="fas fa-chart-candlestick"></i>
|
<i class="fas fa-chart-candlestick"></i>
|
||||||
Multi-Timeframe Charts
|
Multi-Timeframe Charts
|
||||||
</h5>
|
</h5>
|
||||||
<div class="btn-group btn-group-sm" role="group">
|
<div class="d-flex gap-3">
|
||||||
<button type="button" class="btn btn-outline-light" id="zoom-in-btn" title="Zoom In">
|
<!-- Prediction Display Toggles -->
|
||||||
<i class="fas fa-search-plus"></i>
|
<div class="btn-group btn-group-sm" role="group" aria-label="Prediction toggles">
|
||||||
</button>
|
<button type="button" class="btn btn-outline-success active" id="toggle-ghost-candles" title="Toggle Ghost Candles">
|
||||||
<button type="button" class="btn btn-outline-light" id="zoom-out-btn" title="Zoom Out">
|
<i class="fas fa-ghost"></i> Candles
|
||||||
<i class="fas fa-search-minus"></i>
|
</button>
|
||||||
</button>
|
<button type="button" class="btn btn-outline-warning active" id="toggle-trend-lines" title="Toggle Trend Lines">
|
||||||
<button type="button" class="btn btn-outline-light" id="reset-zoom-btn" title="Reset Zoom">
|
<i class="fas fa-chart-line"></i> Trends
|
||||||
<i class="fas fa-expand"></i>
|
</button>
|
||||||
</button>
|
<button type="button" class="btn btn-outline-info active" id="toggle-actions" title="Toggle Action Predictions">
|
||||||
<button type="button" class="btn btn-outline-light" id="maximize-btn" title="Maximize Chart Area">
|
<i class="fas fa-bullseye"></i> Actions
|
||||||
<i class="fas fa-arrows-alt"></i>
|
</button>
|
||||||
</button>
|
<button type="button" class="btn btn-outline-primary active" id="toggle-pivots" title="Toggle Pivot Points">
|
||||||
<button type="button" class="btn btn-outline-light" id="fullscreen-btn" title="Fullscreen">
|
<i class="fas fa-circle-dot"></i> Pivots
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
</button>
|
||||||
</button>
|
</div>
|
||||||
|
|
||||||
|
<!-- Chart Controls -->
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<button type="button" class="btn btn-outline-light" id="zoom-in-btn" title="Zoom In">
|
||||||
|
<i class="fas fa-search-plus"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-light" id="zoom-out-btn" title="Zoom Out">
|
||||||
|
<i class="fas fa-search-minus"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-light" id="reset-zoom-btn" title="Reset Zoom">
|
||||||
|
<i class="fas fa-expand"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-light" id="maximize-btn" title="Maximize Chart Area">
|
||||||
|
<i class="fas fa-arrows-alt"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-light" id="fullscreen-btn" title="Fullscreen">
|
||||||
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
@@ -159,6 +178,43 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prediction display toggles
|
||||||
|
document.getElementById('toggle-ghost-candles').addEventListener('click', function () {
|
||||||
|
this.classList.toggle('active');
|
||||||
|
const enabled = this.classList.contains('active');
|
||||||
|
if (window.appState && window.appState.chartManager) {
|
||||||
|
window.appState.chartManager.toggleGhostCandles(enabled);
|
||||||
|
}
|
||||||
|
console.log('Ghost candles:', enabled ? 'enabled' : 'disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('toggle-trend-lines').addEventListener('click', function () {
|
||||||
|
this.classList.toggle('active');
|
||||||
|
const enabled = this.classList.contains('active');
|
||||||
|
if (window.appState && window.appState.chartManager) {
|
||||||
|
window.appState.chartManager.toggleTrendLines(enabled);
|
||||||
|
}
|
||||||
|
console.log('Trend lines:', enabled ? 'enabled' : 'disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('toggle-actions').addEventListener('click', function () {
|
||||||
|
this.classList.toggle('active');
|
||||||
|
const enabled = this.classList.contains('active');
|
||||||
|
if (window.appState && window.appState.chartManager) {
|
||||||
|
window.appState.chartManager.toggleActions(enabled);
|
||||||
|
}
|
||||||
|
console.log('Action predictions:', enabled ? 'enabled' : 'disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('toggle-pivots').addEventListener('click', function () {
|
||||||
|
this.classList.toggle('active');
|
||||||
|
const enabled = this.classList.contains('active');
|
||||||
|
if (window.appState && window.appState.chartManager) {
|
||||||
|
window.appState.chartManager.togglePivots(enabled);
|
||||||
|
}
|
||||||
|
console.log('Pivot points:', enabled ? 'enabled' : 'disabled');
|
||||||
|
});
|
||||||
|
|
||||||
// Minimize button functionality
|
// Minimize button functionality
|
||||||
document.querySelectorAll('.minimize-btn').forEach(btn => {
|
document.querySelectorAll('.minimize-btn').forEach(btn => {
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user