show dummy references

This commit is contained in:
Dobromir Popov
2025-09-09 22:27:07 +03:00
parent 2e1b3be2cd
commit 1f35258a66
4 changed files with 915 additions and 112 deletions

View File

@@ -42,8 +42,26 @@ from dataclasses import asdict
import math
import subprocess
# Conditional imports for optional dependencies
try:
import torch
import torch.nn as nn
HAS_TORCH = True
except ImportError:
torch = None
nn = None
HAS_TORCH = False
try:
import numpy as np
HAS_NUMPY = True
except ImportError:
np = None
HAS_NUMPY = False
# Setup logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) # Ensure we can see INFO messages for predictions
# Reduce Werkzeug/Dash logging noise
logging.getLogger('werkzeug').setLevel(logging.WARNING)
@@ -117,6 +135,9 @@ class CleanTradingDashboard:
# Initialize multi-timeframe prediction system
self.multi_timeframe_predictor = None
self._initialize_multi_timeframe_predictor()
# Initialize 10-minute prediction storage
self.current_10min_prediction = None
# Initialize layout and component managers
self.layout_manager = DashboardLayoutManager(
@@ -1911,11 +1932,155 @@ class CleanTradingDashboard:
self._add_dqn_predictions_to_chart(fig, symbol, df_main, row)
self._add_cnn_predictions_to_chart(fig, symbol, df_main, row)
self._add_cob_rl_predictions_to_chart(fig, symbol, df_main, row)
self._add_iterative_predictions_to_chart(fig, symbol, df_main, row)
self._add_prediction_accuracy_feedback(fig, symbol, df_main, row)
except Exception as e:
logger.warning(f"Error adding model predictions to chart: {e}")
def _add_iterative_predictions_to_chart(self, fig: go.Figure, symbol: str, df_main: pd.DataFrame, row: int = 1):
"""Add 10-minute iterative predictions to the main chart with fading opacity"""
try:
if not hasattr(self, 'multi_timeframe_predictor') or not self.multi_timeframe_predictor:
logger.debug("❌ Multi-timeframe predictor not available")
return
# Run iterative prediction every minute
current_time = datetime.now()
if not hasattr(self, '_last_prediction_time') or \
(current_time - self._last_prediction_time).total_seconds() >= 60:
try:
prediction_result = self.run_iterative_prediction_10min(symbol)
if prediction_result:
self._last_prediction_time = current_time
logger.info("✅ 10-minute iterative prediction completed")
else:
logger.warning("❌ 10-minute iterative prediction returned None")
except Exception as e:
logger.error(f"Error running iterative prediction: {e}")
# Get current predictions from stored result
if hasattr(self, 'current_10min_prediction') and self.current_10min_prediction:
predictions = self.current_10min_prediction.get('predictions', [])
logger.debug(f"🔍 Found {len(predictions)} predictions in current_10min_prediction")
if predictions:
logger.info(f"📊 Processing {len(predictions)} predictions for chart display")
# Group predictions by age for fading effect
prediction_groups = {}
current_time = datetime.now()
for pred in predictions[-50:]: # Last 50 predictions
prediction_time = pred.get('timestamp')
if not prediction_time:
logger.debug(f"❌ Prediction missing timestamp: {pred}")
continue
if isinstance(prediction_time, str):
try:
prediction_time = pd.to_datetime(prediction_time)
except Exception as e:
logger.debug(f"❌ Could not parse timestamp '{prediction_time}': {e}")
continue
# Calculate age in minutes (how long ago this prediction was made)
# For future predictions, use a small positive age to show them as current
if prediction_time > current_time:
age_minutes = 0.1 # Future predictions treated as very recent
else:
age_minutes = (current_time - prediction_time).total_seconds() / 60
logger.debug(f"🔍 Prediction age: {age_minutes:.2f} min, timestamp: {prediction_time}, current: {current_time}")
# Group by age ranges for fading
if age_minutes <= 1:
group = 'current' # Very recent, high opacity
elif age_minutes <= 3:
group = 'recent' # Recent, medium opacity
elif age_minutes <= 5:
group = 'old' # Older, low opacity
else:
continue # Too old, skip
if group not in prediction_groups:
prediction_groups[group] = []
prediction_groups[group].append({
'x': prediction_time,
'y': pred.get('close', 0),
'high': pred.get('high', 0),
'low': pred.get('low', 0),
'confidence': pred.get('confidence', 0),
'age': age_minutes
})
# Add predictions with fading opacity
opacity_levels = {
'current': 0.8, # Bright for very recent
'recent': 0.5, # Medium for recent
'old': 0.3 # Dim for older
}
logger.info(f"📊 Adding {len(prediction_groups)} prediction groups to chart")
for group, preds in prediction_groups.items():
if not preds:
continue
opacity = opacity_levels[group]
logger.info(f"📈 Adding {group} predictions: {len(preds)} points, opacity: {opacity}")
# Add prediction line
fig.add_trace(
go.Scatter(
x=[p['x'] for p in preds],
y=[p['y'] for p in preds],
mode='lines+markers',
line=dict(
color=f'rgba(255, 215, 0, {opacity})', # Gold color
width=2,
dash='dash'
),
marker=dict(
symbol='diamond',
size=6,
color=f'rgba(255, 215, 0, {opacity})',
line=dict(width=1, color='rgba(255, 140, 0, 0.8)')
),
name=f'🔮 10min Pred ({group})',
showlegend=True,
hovertemplate="<b>🔮 10-Minute Prediction</b><br>" +
"Predicted Close: $%{y:.2f}<br>" +
"Time: %{x}<br>" +
"Age: %{customdata:.1f} min<br>" +
"Confidence: %{text:.1%}<extra></extra>",
customdata=[p['age'] for p in preds],
text=[p['confidence'] for p in preds]
),
row=row, col=1
)
# Add confidence bands (high/low range)
if len(preds) > 1:
fig.add_trace(
go.Scatter(
x=[p['x'] for p in preds] + [p['x'] for p in reversed(preds)],
y=[p['high'] for p in preds] + [p['low'] for p in reversed(preds)],
fill='toself',
fillcolor=f'rgba(255, 215, 0, {opacity * 0.2})',
line=dict(width=0),
mode='lines',
name=f'Prediction Range ({group})',
showlegend=False,
hoverinfo='skip'
),
row=row, col=1
)
except Exception as e:
logger.debug(f"Error adding iterative predictions to chart: {e}")
def _add_dqn_predictions_to_chart(self, fig: go.Figure, symbol: str, df_main: pd.DataFrame, row: int = 1):
"""Add DQN action predictions as directional arrows"""
try:
@@ -5133,6 +5298,268 @@ class CleanTradingDashboard:
filename = f"trades_export_{timestamp}.csv"
return self.export_trade_history_csv(filename)
def run_iterative_prediction_10min(self, symbol: str = "ETH/USDT") -> Optional[Dict]:
"""Run 10-minute iterative prediction using the multi-timeframe predictor"""
try:
if not self.multi_timeframe_predictor:
logger.warning("Multi-timeframe predictor not available")
return None
logger.info(f"🔮 Running 10-minute iterative prediction for {symbol}")
# Get current price and market conditions
current_price = self._get_current_price(symbol)
if not current_price:
logger.warning(f"Could not get current price for {symbol}")
return None
# Run iterative prediction for 10 minutes
iterative_predictions = self.multi_timeframe_predictor._generate_iterative_predictions(
symbol=symbol,
base_data=self.multi_timeframe_predictor._get_sequence_data_for_horizon(
symbol, self.multi_timeframe_predictor.horizons[PredictionHorizon.TEN_MINUTES]['sequence_length']
),
num_steps=10, # 10 steps for 10-minute prediction
market_conditions={'confidence_multiplier': 1.0}
)
if iterative_predictions:
# Analyze the 10-minute prediction
config = self.multi_timeframe_predictor.horizons[PredictionHorizon.TEN_MINUTES]
market_conditions = self.multi_timeframe_predictor._assess_market_conditions(symbol)
horizon_prediction = self.multi_timeframe_predictor._analyze_horizon_prediction(
iterative_predictions, config, market_conditions
)
if horizon_prediction:
# Store the prediction for dashboard display
self.current_10min_prediction = {
'symbol': symbol,
'timestamp': datetime.now(),
'predictions': iterative_predictions,
'horizon_analysis': horizon_prediction,
'current_price': current_price
}
logger.info(f"✅ 10-minute iterative prediction completed for {symbol}")
logger.info(f"📊 Generated {len(iterative_predictions)} candle predictions")
return self.current_10min_prediction
logger.warning("Failed to generate 10-minute iterative prediction")
return None
except Exception as e:
logger.error(f"Error running 10-minute iterative prediction: {e}")
return None
def create_10min_prediction_chart(self, opacity: float = 0.4) -> Dict[str, Any]:
"""DEPRECATED: Create a chart visualizing the 10-minute iterative predictions with opacity
Note: Predictions are now integrated directly into the main 1-minute chart"""
try:
if not self.current_10min_prediction or not self.current_10min_prediction.get('predictions'):
# Return empty chart if no predictions available
return {
'data': [],
'layout': {
'title': '10-Minute Iterative Predictions - No Data Available',
'template': 'plotly_dark',
'height': 400,
'annotations': [{
'text': 'Run iterative prediction to see forecast',
'xref': 'paper', 'yref': 'paper',
'x': 0.5, 'y': 0.5,
'showarrow': False,
'font': {'size': 16, 'color': 'gray'}
}]
}
}
predictions = self.current_10min_prediction['predictions']
current_price = self.current_10min_prediction['current_price']
horizon_analysis = self.current_10min_prediction['horizon_analysis']
# Create time points for the next 10 minutes
base_time = self.current_10min_prediction['timestamp']
time_points = [base_time + timedelta(minutes=i) for i in range(11)] # 0 to 10 minutes
# Extract predicted prices
predicted_prices = [current_price] # Start with current price
confidence_levels = [1.0] # Current price has full confidence
for i, pred in enumerate(predictions[:10]): # Limit to 10 predictions
if 'ohlcv_prediction' in pred:
close_price = pred['ohlcv_prediction']['close']
predicted_prices.append(close_price)
# Get confidence for this prediction
confidence = pred.get('action_confidence', 0.5)
confidence_levels.append(confidence)
# Create the main prediction line
prediction_trace = go.Scatter(
x=time_points[:len(predicted_prices)],
y=predicted_prices,
mode='lines+markers',
name='Predicted Price',
line=dict(color='cyan', width=3),
marker=dict(size=6, color='cyan'),
opacity=opacity
)
# Create confidence bands
upper_bound = []
lower_bound = []
for i, price in enumerate(predicted_prices):
if i == 0: # Current price has no uncertainty
upper_bound.append(price)
lower_bound.append(price)
else:
# Create confidence bands based on prediction confidence
confidence = confidence_levels[i]
uncertainty = (1 - confidence) * price * 0.02 # 2% max uncertainty
upper_bound.append(price + uncertainty)
lower_bound.append(price - uncertainty)
# Confidence band fill
confidence_fill = go.Scatter(
x=time_points[:len(predicted_prices)] + time_points[:len(predicted_prices)][::-1],
y=upper_bound + lower_bound[::-1],
fill='toself',
fillcolor=f'rgba(0, 255, 255, {opacity * 0.3})', # Cyan with reduced opacity
line=dict(color='rgba(255,255,255,0)'),
name='Confidence Band',
showlegend=True
)
# Individual candle predictions as scatter points
candle_traces = []
for i, pred in enumerate(predictions[:10]):
if 'ohlcv_prediction' in pred:
ohlcv = pred['ohlcv_prediction']
pred_time = base_time + timedelta(minutes=i+1)
confidence = pred.get('action_confidence', 0.5)
# Color based on price movement
if ohlcv['close'] > ohlcv['open']:
color = f'rgba(0, 255, 0, {opacity})' # Green for bullish
else:
color = f'rgba(255, 0, 0, {opacity})' # Red for bearish
candle_trace = go.Scatter(
x=[pred_time],
y=[ohlcv['close']],
mode='markers',
marker=dict(
size=max(8, int(confidence * 20)), # Size based on confidence
color=color,
symbol='diamond',
line=dict(width=2, color='white')
),
name=f'Candle {i+1}',
showlegend=False,
hovertemplate=f'Candle {i+1}<br>Time: {pred_time.strftime("%H:%M")}<br>Close: ${ohlcv["close"]:.2f}<br>Confidence: {confidence:.2f}<extra></extra>'
)
candle_traces.append(candle_trace)
# Current price marker
current_price_trace = go.Scatter(
x=[base_time],
y=[current_price],
mode='markers',
marker=dict(
size=12,
color='yellow',
symbol='star',
line=dict(width=2, color='white')
),
name='Current Price',
hovertemplate=f'Current Price<br>${current_price:.2f}<extra></extra>'
)
# Create the figure
fig = go.Figure()
# Add traces in order (confidence band first, then prediction line, then candles)
fig.add_trace(confidence_fill)
fig.add_trace(prediction_trace)
fig.add_trace(current_price_trace)
# Add individual candle traces
for trace in candle_traces:
fig.add_trace(trace)
# Calculate overall trend
if len(predicted_prices) > 1:
start_price = predicted_prices[0]
end_price = predicted_prices[-1]
total_change_pct = ((end_price - start_price) / start_price) * 100
trend_color = 'green' if total_change_pct > 0 else 'red'
trend_text = f"Overall Trend: {'↗️ BULLISH' if total_change_pct > 0 else '↘️ BEARISH'} {abs(total_change_pct):.2f}%"
else:
trend_text = "No trend data available"
trend_color = 'gray'
# Update layout
fig.update_layout(
title={
'text': f'🔮 10-Minute Iterative Price Prediction - {trend_text}',
'y': 0.95,
'x': 0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=16, color=trend_color)
},
template='plotly_dark',
height=500,
xaxis=dict(
title='Time',
tickformat='%H:%M',
showgrid=True,
gridcolor='rgba(128,128,128,0.2)'
),
yaxis=dict(
title='Price ($)',
tickformat='.2f',
showgrid=True,
gridcolor='rgba(128,128,128,0.2)'
),
hovermode='x unified',
legend=dict(
yanchor="top",
y=0.99,
xanchor="left",
x=0.01
),
annotations=[
dict(
text="💡 Predictions are iterative - each candle builds on the previous prediction",
x=0.5,
y=-0.15,
xref="paper",
yref="paper",
showarrow=False,
font=dict(size=10, color='gray')
)
]
)
return fig
except Exception as e:
logger.error(f"Error creating 10-minute prediction chart: {e}")
return {
'data': [],
'layout': {
'title': f'Error creating prediction chart: {str(e)[:50]}...',
'template': 'plotly_dark',
'height': 400
}
}
def _train_dqn_on_signal(self, signal: Dict, trade_outcome: Dict):
"""Train DQN agent on executed signal with trade outcome"""
try:
@@ -7771,6 +8198,7 @@ class CleanTradingDashboard:
elif hasattr(network_output, 'dim'):
# Single tensor output - assume it's action logits
action_logits = network_output
device = action_logits.device if hasattr(action_logits, 'device') else torch.device('cpu')
predicted_confidence = torch.tensor(0.5, device=device) # Default confidence
else:
logger.debug(f"Unexpected network output format: {type(network_output)}")
@@ -7779,6 +8207,7 @@ class CleanTradingDashboard:
# Ensure predicted_confidence is a tensor with proper dimensions
if not hasattr(predicted_confidence, 'dim'):
# If it's not a tensor, convert it
device = predicted_confidence.device if hasattr(predicted_confidence, 'device') else torch.device('cpu')
predicted_confidence = torch.tensor(float(predicted_confidence), device=device)
if predicted_confidence.dim() == 0:
@@ -8415,13 +8844,15 @@ class CleanTradingDashboard:
}
def create_clean_dashboard(data_provider: Optional[DataProvider] = None, orchestrator: Optional[TradingOrchestrator] = None, trading_executor: Optional[TradingExecutor] = None):
"""Factory function to create a CleanTradingDashboard instance"""
return CleanTradingDashboard(
data_provider=data_provider,
orchestrator=orchestrator,
trading_executor=trading_executor
)
# test edit
)
# test edit

View File

@@ -455,5 +455,6 @@ class DashboardLayoutManager:
], className="card-body p-2")
], className="card", style={"width": "30%", "marginLeft": "2%"})
], className="d-flex")