logging channels; training steps storage
This commit is contained in:
@@ -25,6 +25,7 @@ import threading
|
||||
import uuid
|
||||
import time
|
||||
import torch
|
||||
from utils.logging_config import get_channel_logger, LogChannel
|
||||
|
||||
# Import core components from main system
|
||||
try:
|
||||
@@ -98,6 +99,11 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f"Logging to: {log_file}")
|
||||
|
||||
# Create channel-specific loggers
|
||||
pivot_logger = get_channel_logger(__name__, LogChannel.PIVOTS)
|
||||
api_logger = get_channel_logger(__name__, LogChannel.API)
|
||||
webui_logger = get_channel_logger(__name__, LogChannel.WEBUI)
|
||||
|
||||
|
||||
class BacktestRunner:
|
||||
"""Runs backtest candle-by-candle with model predictions and tracks PnL"""
|
||||
@@ -941,7 +947,7 @@ class AnnotationDashboard:
|
||||
ts_str, idx = last_info['low']
|
||||
pivot_map[ts_str]['lows'][idx]['is_last'] = True
|
||||
|
||||
logger.info(f"Found {len(pivot_map)} pivot candles for {symbol} {timeframe} (from {len(df)} candles)")
|
||||
pivot_logger.info(f"Found {len(pivot_map)} pivot candles for {symbol} {timeframe} (from {len(df)} candles)")
|
||||
return pivot_map
|
||||
|
||||
except Exception as e:
|
||||
@@ -1067,7 +1073,7 @@ class AnnotationDashboard:
|
||||
'error': {'code': 'INVALID_REQUEST', 'message': 'Missing timeframe'}
|
||||
})
|
||||
|
||||
logger.info(f" Recalculating pivots for {symbol} {timeframe} using backend data")
|
||||
pivot_logger.info(f"Recalculating pivots for {symbol} {timeframe} using backend data")
|
||||
|
||||
if not self.data_loader:
|
||||
return jsonify({
|
||||
@@ -1094,7 +1100,7 @@ class AnnotationDashboard:
|
||||
# Recalculate pivot markers
|
||||
pivot_markers = self._get_pivot_markers_for_timeframe(symbol, timeframe, df)
|
||||
|
||||
logger.info(f" Recalculated {len(pivot_markers)} pivot candles")
|
||||
pivot_logger.info(f"Recalculated {len(pivot_markers)} pivot candles")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -1120,11 +1126,11 @@ class AnnotationDashboard:
|
||||
limit = data.get('limit', 2500) # Default 2500 candles for training
|
||||
direction = data.get('direction', 'latest') # 'latest', 'before', or 'after'
|
||||
|
||||
logger.info(f"Chart data request: {symbol} {timeframes} direction={direction} limit={limit}")
|
||||
webui_logger.info(f"Chart data request: {symbol} {timeframes} direction={direction} limit={limit}")
|
||||
if start_time_str:
|
||||
logger.info(f" start_time: {start_time_str}")
|
||||
webui_logger.info(f" start_time: {start_time_str}")
|
||||
if end_time_str:
|
||||
logger.info(f" end_time: {end_time_str}")
|
||||
webui_logger.info(f" end_time: {end_time_str}")
|
||||
|
||||
if not self.data_loader:
|
||||
return jsonify({
|
||||
@@ -1156,7 +1162,7 @@ class AnnotationDashboard:
|
||||
)
|
||||
|
||||
if df is not None and not df.empty:
|
||||
logger.info(f" {timeframe}: {len(df)} candles ({df.index[0]} to {df.index[-1]})")
|
||||
webui_logger.info(f" {timeframe}: {len(df)} candles ({df.index[0]} to {df.index[-1]})")
|
||||
|
||||
# Get pivot points for this timeframe (only if we have enough context)
|
||||
pivot_markers = {}
|
||||
@@ -2386,6 +2392,10 @@ def main():
|
||||
logger.info(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
logger.info("=" * 80)
|
||||
|
||||
# Print logging channel configuration
|
||||
from utils.logging_config import print_channel_status
|
||||
print_channel_status()
|
||||
|
||||
dashboard = AnnotationDashboard()
|
||||
dashboard.run(debug=True)
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ class ChartManager {
|
||||
this.updateTimers = {}; // Track auto-update timers
|
||||
this.autoUpdateEnabled = false; // Auto-update state
|
||||
this.liveMetricsOverlay = null; // Live metrics display overlay
|
||||
this.lastPredictionUpdate = {}; // Track last prediction update per timeframe
|
||||
this.predictionUpdateThrottle = 500; // Min ms between prediction updates
|
||||
this.lastPredictionHash = null; // Track if predictions actually changed
|
||||
|
||||
console.log('ChartManager initialized with timeframes:', timeframes);
|
||||
}
|
||||
@@ -172,6 +175,14 @@ class ChartManager {
|
||||
});
|
||||
});
|
||||
|
||||
// Merge pivot markers
|
||||
if (newData.pivot_markers) {
|
||||
if (!chart.data.pivot_markers) {
|
||||
chart.data.pivot_markers = {};
|
||||
}
|
||||
Object.assign(chart.data.pivot_markers, newData.pivot_markers);
|
||||
}
|
||||
|
||||
// 2. Update existing candles in place if they exist in new data
|
||||
// Iterate backwards to optimize for recent updates
|
||||
let updatesCount = 0;
|
||||
@@ -212,7 +223,12 @@ class ChartManager {
|
||||
if (updatesCount > 0 || remainingTimestamps.length > 0) {
|
||||
console.log(`[${timeframe}] Chart update: ${updatesCount} updated, ${remainingTimestamps.length} new candles`);
|
||||
|
||||
this.recalculatePivots(timeframe, chart.data);
|
||||
// Only recalculate pivots if we have NEW candles (not just updates to existing ones)
|
||||
// This prevents unnecessary pivot recalculation on every live candle update
|
||||
if (remainingTimestamps.length > 0) {
|
||||
this.recalculatePivots(timeframe, chart.data);
|
||||
}
|
||||
|
||||
this.updateSingleChart(timeframe, chart.data);
|
||||
|
||||
window.liveUpdateCount = (window.liveUpdateCount || 0) + 1;
|
||||
@@ -1774,25 +1790,30 @@ class ChartManager {
|
||||
});
|
||||
}
|
||||
|
||||
// Update chart layout with new pivots
|
||||
Plotly.relayout(chart.plotId, {
|
||||
// Batch update: Use Plotly.update to combine layout and trace updates
|
||||
// This reduces flickering by doing both operations in one call
|
||||
const layoutUpdate = {
|
||||
shapes: shapes,
|
||||
annotations: annotations
|
||||
});
|
||||
};
|
||||
|
||||
const traceUpdate = pivotDots.x.length > 0 ? {
|
||||
x: [pivotDots.x],
|
||||
y: [pivotDots.y],
|
||||
text: [pivotDots.text],
|
||||
'marker.color': [pivotDots.marker.color],
|
||||
'marker.size': [pivotDots.marker.size],
|
||||
'marker.symbol': [pivotDots.marker.symbol]
|
||||
} : {};
|
||||
|
||||
// Update pivot dots trace
|
||||
// Use Plotly.update to batch both operations
|
||||
if (pivotDots.x.length > 0) {
|
||||
Plotly.restyle(chart.plotId, {
|
||||
x: [pivotDots.x],
|
||||
y: [pivotDots.y],
|
||||
text: [pivotDots.text],
|
||||
'marker.color': [pivotDots.marker.color],
|
||||
'marker.size': [pivotDots.marker.size],
|
||||
'marker.symbol': [pivotDots.marker.symbol]
|
||||
}, [2]); // Trace index 2 is pivot dots
|
||||
Plotly.update(chart.plotId, traceUpdate, layoutUpdate, [2]); // Trace index 2 is pivot dots
|
||||
} else {
|
||||
Plotly.relayout(chart.plotId, layoutUpdate);
|
||||
}
|
||||
|
||||
console.log(`🎨 Redrawn ${timeframe} chart with updated pivots`);
|
||||
console.log(`Redrawn ${timeframe} chart with updated pivots`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1803,6 +1824,8 @@ class ChartManager {
|
||||
if (!chart) return;
|
||||
|
||||
const plotId = chart.plotId;
|
||||
const plotElement = document.getElementById(plotId);
|
||||
if (!plotElement) return;
|
||||
|
||||
// Create volume colors
|
||||
const volumeColors = data.close.map((close, i) => {
|
||||
@@ -1810,18 +1833,34 @@ class ChartManager {
|
||||
return close >= data.open[i] ? '#10b981' : '#ef4444';
|
||||
});
|
||||
|
||||
// Update traces
|
||||
const update = {
|
||||
x: [data.timestamps, data.timestamps],
|
||||
open: [data.open],
|
||||
high: [data.high],
|
||||
low: [data.low],
|
||||
close: [data.close],
|
||||
y: [undefined, data.volume],
|
||||
'marker.color': [undefined, volumeColors]
|
||||
// Use Plotly.react for smoother, non-flickering updates
|
||||
// It only updates what changed, unlike restyle which can cause flicker
|
||||
const currentData = plotElement.data;
|
||||
|
||||
// Update only the first two traces (candlestick and volume)
|
||||
// Keep other traces (pivots, predictions) intact
|
||||
const updatedTraces = [...currentData];
|
||||
|
||||
// Update candlestick trace (trace 0)
|
||||
updatedTraces[0] = {
|
||||
...updatedTraces[0],
|
||||
x: data.timestamps,
|
||||
open: data.open,
|
||||
high: data.high,
|
||||
low: data.low,
|
||||
close: data.close
|
||||
};
|
||||
|
||||
// Update volume trace (trace 1)
|
||||
updatedTraces[1] = {
|
||||
...updatedTraces[1],
|
||||
x: data.timestamps,
|
||||
y: data.volume,
|
||||
marker: { ...updatedTraces[1].marker, color: volumeColors }
|
||||
};
|
||||
|
||||
Plotly.restyle(plotId, update, [0, 1]);
|
||||
// Use react instead of restyle - it's smarter about what to update
|
||||
Plotly.react(plotId, updatedTraces, plotElement.layout, plotElement.config);
|
||||
|
||||
console.log(`Updated ${timeframe} chart with ${data.timestamps.length} candles`);
|
||||
}
|
||||
@@ -1882,7 +1921,36 @@ class ChartManager {
|
||||
// This ensures predictions appear on the chart the user is watching (e.g., '1s')
|
||||
const timeframe = window.appState?.currentTimeframes?.[0] || '1m';
|
||||
const chart = this.charts[timeframe];
|
||||
if (!chart) return;
|
||||
|
||||
if (!chart) {
|
||||
console.warn(`[updatePredictions] Chart not found for timeframe: ${timeframe}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Throttle prediction updates to avoid flickering
|
||||
const now = Date.now();
|
||||
const lastUpdate = this.lastPredictionUpdate[timeframe] || 0;
|
||||
|
||||
// Create a simple hash of prediction data to detect actual changes
|
||||
const predictionHash = JSON.stringify({
|
||||
action: predictions.transformer?.action,
|
||||
confidence: predictions.transformer?.confidence,
|
||||
predicted_price: predictions.transformer?.predicted_price,
|
||||
timestamp: predictions.transformer?.timestamp
|
||||
});
|
||||
|
||||
// Skip update if:
|
||||
// 1. Too soon since last update (throttle)
|
||||
// 2. Predictions haven't actually changed
|
||||
if (now - lastUpdate < this.predictionUpdateThrottle && predictionHash === this.lastPredictionHash) {
|
||||
console.debug(`[updatePredictions] Skipping update (throttled or unchanged)`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastPredictionUpdate[timeframe] = now;
|
||||
this.lastPredictionHash = predictionHash;
|
||||
|
||||
console.log(`[updatePredictions] Timeframe: ${timeframe}, Predictions:`, predictions);
|
||||
|
||||
const plotId = chart.plotId;
|
||||
const plotElement = document.getElementById(plotId);
|
||||
@@ -1918,7 +1986,9 @@ class ChartManager {
|
||||
|
||||
// Handle Predicted Candles
|
||||
if (predictions.transformer.predicted_candle) {
|
||||
console.log(`[updatePredictions] predicted_candle data:`, predictions.transformer.predicted_candle);
|
||||
const candleData = predictions.transformer.predicted_candle[timeframe];
|
||||
console.log(`[updatePredictions] candleData for ${timeframe}:`, candleData);
|
||||
if (candleData) {
|
||||
// Get the prediction timestamp from the model (when inference was made)
|
||||
const predictionTimestamp = predictions.transformer.timestamp || new Date().toISOString();
|
||||
@@ -2005,8 +2075,8 @@ class ChartManager {
|
||||
// trendVector contains: angle_degrees, steepness, direction, price_delta
|
||||
// We visualize this as a ray from current price
|
||||
|
||||
// Need current candle close and timestamp
|
||||
const timeframe = '1m'; // Default to 1m for now
|
||||
// Use the active timeframe from app state
|
||||
const timeframe = window.appState?.currentTimeframes?.[0] || '1m';
|
||||
const chart = this.charts[timeframe];
|
||||
if (!chart || !chart.data) return;
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
<strong class="small">🔴 LIVE</strong>
|
||||
</div>
|
||||
<div class="small">
|
||||
<div>Timeframe: <span id="active-timeframe" class="fw-bold text-primary">--</span></div>
|
||||
<div>Signal: <span id="latest-signal" class="fw-bold">--</span></div>
|
||||
<div>Confidence: <span id="latest-confidence">--</span></div>
|
||||
<div class="text-muted" style="font-size: 0.7rem;">Predicting <span id="active-steps">1</span> step(s) ahead</div>
|
||||
@@ -572,6 +573,9 @@
|
||||
document.getElementById('inference-status').style.display = 'block';
|
||||
document.getElementById('inference-controls').style.display = 'block';
|
||||
|
||||
// Display active timeframe
|
||||
document.getElementById('active-timeframe').textContent = timeframe.toUpperCase();
|
||||
|
||||
// Clear prediction history and reset PnL tracker
|
||||
predictionHistory = [];
|
||||
pnlTracker = {
|
||||
@@ -1038,6 +1042,9 @@
|
||||
}
|
||||
|
||||
const latest = data.signals[0];
|
||||
console.log('[Signal Polling] Latest signal:', latest);
|
||||
console.log('[Signal Polling] predicted_candle:', latest.predicted_candle);
|
||||
|
||||
document.getElementById('latest-signal').textContent = latest.action;
|
||||
document.getElementById('latest-confidence').textContent =
|
||||
(latest.confidence * 100).toFixed(1) + '%';
|
||||
|
||||
Reference in New Issue
Block a user