UI and stability
This commit is contained in:
@ -62,7 +62,12 @@ logging.getLogger('dash').setLevel(logging.WARNING)
|
||||
logging.getLogger('dash.dash').setLevel(logging.WARNING)
|
||||
|
||||
# Import core components
|
||||
from core.config import get_config
|
||||
try:
|
||||
from core.config import get_config
|
||||
except ImportError:
|
||||
# Fallback if config module is not available
|
||||
def get_config():
|
||||
return {}
|
||||
from core.data_provider import DataProvider
|
||||
from core.standardized_data_provider import StandardizedDataProvider
|
||||
from core.orchestrator import TradingOrchestrator
|
||||
@ -117,12 +122,17 @@ class CleanTradingDashboard:
|
||||
"""Clean, modular trading dashboard implementation"""
|
||||
|
||||
def __init__(self, data_provider=None, orchestrator: Optional[Any] = None, trading_executor: Optional[TradingExecutor] = None):
|
||||
self.config = get_config()
|
||||
# Load configuration safely
|
||||
try:
|
||||
self.config = get_config()
|
||||
except Exception as e:
|
||||
logger.warning(f"Error loading config, using empty config: {e}")
|
||||
self.config = {}
|
||||
|
||||
# Removed batch counter - now using proper interval separation for performance
|
||||
|
||||
# Initialize components
|
||||
self.data_provider = data_provider or DataProvider()
|
||||
self.data_provider = data_provider or StandardizedDataProvider()
|
||||
self.trading_executor = trading_executor or TradingExecutor()
|
||||
|
||||
# Initialize unified orchestrator with full ML capabilities
|
||||
@ -174,10 +184,35 @@ class CleanTradingDashboard:
|
||||
self.standardized_cnn = None
|
||||
self._initialize_standardized_cnn()
|
||||
|
||||
# Initialize trading mode and cold start settings from config
|
||||
self.trading_mode_live = False # Default to simulation mode
|
||||
self.cold_start_enabled = True # Default to cold start enabled
|
||||
|
||||
# Load config values if available
|
||||
try:
|
||||
if hasattr(self, 'config') and self.config:
|
||||
# Check if trading mode is live based on config
|
||||
exchanges = self.config.get('exchanges', {})
|
||||
if exchanges:
|
||||
for exchange_name, exchange_config in exchanges.items():
|
||||
if exchange_config.get('enabled', False):
|
||||
trading_mode = exchange_config.get('trading_mode', 'simulation')
|
||||
if trading_mode == 'live':
|
||||
self.trading_mode_live = True
|
||||
break
|
||||
|
||||
# Check cold start setting
|
||||
cold_start_config = self.config.get('cold_start', {})
|
||||
self.cold_start_enabled = cold_start_config.get('enabled', True)
|
||||
except Exception as e:
|
||||
logger.warning(f"Error loading config settings, using defaults: {e}")
|
||||
# Keep default values
|
||||
|
||||
# Initialize layout and component managers
|
||||
self.layout_manager = DashboardLayoutManager(
|
||||
starting_balance=self._get_initial_balance(),
|
||||
trading_executor=self.trading_executor
|
||||
trading_executor=self.trading_executor,
|
||||
dashboard=self
|
||||
)
|
||||
self.component_manager = DashboardComponentManager()
|
||||
|
||||
@ -206,6 +241,19 @@ class CleanTradingDashboard:
|
||||
# ENHANCED: Model control toggles - separate inference and training
|
||||
self.dqn_inference_enabled = True # Default: enabled
|
||||
self.dqn_training_enabled = True # Default: enabled
|
||||
|
||||
# Trading mode and cold start settings from config
|
||||
from core.config import get_config
|
||||
config = get_config()
|
||||
|
||||
# Initialize trading mode from config (default to simulation)
|
||||
default_trading_mode = config.get('exchanges', {}).get('bybit', {}).get('trading_mode', 'simulation')
|
||||
self.trading_mode_live = (default_trading_mode == 'live')
|
||||
|
||||
# Initialize cold start from config (default to enabled)
|
||||
self.cold_start_enabled = config.get('cold_start', {}).get('enabled', True)
|
||||
|
||||
logger.info(f"Dashboard initialized - Trading Mode: {'LIVE' if self.trading_mode_live else 'SIM'}, Cold Start: {'ON' if self.cold_start_enabled else 'OFF'}")
|
||||
self.cnn_inference_enabled = True
|
||||
self.cnn_training_enabled = True
|
||||
|
||||
@ -611,13 +659,51 @@ class CleanTradingDashboard:
|
||||
logger.error(f"Error getting model status: {e}")
|
||||
return {'loaded_models': {}, 'total_models': 0, 'system_status': 'ERROR'}
|
||||
|
||||
def _convert_utc_to_local(self, utc_timestamp):
|
||||
"""Convert UTC timestamp to local timezone for display"""
|
||||
try:
|
||||
if utc_timestamp is None:
|
||||
return datetime.now()
|
||||
|
||||
# Handle different input types
|
||||
if isinstance(utc_timestamp, str):
|
||||
try:
|
||||
utc_timestamp = pd.to_datetime(utc_timestamp)
|
||||
except:
|
||||
return datetime.now()
|
||||
|
||||
# If it's already a datetime object
|
||||
if isinstance(utc_timestamp, datetime):
|
||||
# If it has timezone info and is UTC, convert to local
|
||||
if utc_timestamp.tzinfo is not None:
|
||||
if str(utc_timestamp.tzinfo) == 'UTC':
|
||||
# Convert UTC to local timezone
|
||||
local_timestamp = utc_timestamp.replace(tzinfo=timezone.utc).astimezone()
|
||||
return local_timestamp.replace(tzinfo=None) # Remove timezone info for display
|
||||
else:
|
||||
# Already has timezone, convert to local
|
||||
return utc_timestamp.astimezone().replace(tzinfo=None)
|
||||
else:
|
||||
# No timezone info, assume it's already local
|
||||
return utc_timestamp
|
||||
|
||||
# Fallback
|
||||
return datetime.now()
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error converting UTC to local time: {e}")
|
||||
return datetime.now()
|
||||
|
||||
def _safe_strftime(self, timestamp_val, format_str='%H:%M:%S'):
|
||||
"""Safely format timestamp, handling both string and datetime objects"""
|
||||
try:
|
||||
if isinstance(timestamp_val, str):
|
||||
return timestamp_val
|
||||
elif hasattr(timestamp_val, 'strftime'):
|
||||
return timestamp_val.strftime(format_str)
|
||||
# Convert to local time first
|
||||
local_timestamp = self._convert_utc_to_local(timestamp_val)
|
||||
|
||||
if isinstance(local_timestamp, str):
|
||||
return local_timestamp
|
||||
elif hasattr(local_timestamp, 'strftime'):
|
||||
return local_timestamp.strftime(format_str)
|
||||
else:
|
||||
return datetime.now().strftime(format_str)
|
||||
except Exception as e:
|
||||
@ -1158,6 +1244,93 @@ class CleanTradingDashboard:
|
||||
else:
|
||||
return [html.I(className="fas fa-exclamation-triangle me-1"), "Store Failed"]
|
||||
return [html.I(className="fas fa-save me-1"), "Store All Models"]
|
||||
|
||||
# Trading Mode Toggle
|
||||
@self.app.callback(
|
||||
Output('trading-mode-display', 'children'),
|
||||
Output('trading-mode-display', 'className'),
|
||||
[Input('trading-mode-switch', 'value')]
|
||||
)
|
||||
def update_trading_mode(switch_value):
|
||||
"""Update trading mode display and apply changes"""
|
||||
try:
|
||||
is_live = 'live' in (switch_value or [])
|
||||
self.trading_mode_live = is_live
|
||||
|
||||
# Update trading executor mode if available
|
||||
if hasattr(self, 'trading_executor') and self.trading_executor:
|
||||
if hasattr(self.trading_executor, 'set_trading_mode'):
|
||||
# Use the new set_trading_mode method
|
||||
success = self.trading_executor.set_trading_mode('live' if is_live else 'simulation')
|
||||
if success:
|
||||
logger.info(f"TRADING MODE: {'LIVE' if is_live else 'SIMULATION'} - Mode updated successfully")
|
||||
else:
|
||||
logger.error(f"Failed to update trading mode to {'LIVE' if is_live else 'SIMULATION'}")
|
||||
else:
|
||||
# Fallback to direct property setting
|
||||
if is_live:
|
||||
self.trading_executor.trading_mode = 'live'
|
||||
self.trading_executor.simulation_mode = False
|
||||
logger.info("TRADING MODE: LIVE - Real orders will be executed!")
|
||||
else:
|
||||
self.trading_executor.trading_mode = 'simulation'
|
||||
self.trading_executor.simulation_mode = True
|
||||
logger.info("TRADING MODE: SIMULATION - Orders are simulated")
|
||||
|
||||
# Return display text and styling
|
||||
if is_live:
|
||||
return "LIVE", "fw-bold text-danger"
|
||||
else:
|
||||
return "SIM", "fw-bold text-warning"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating trading mode: {e}")
|
||||
return "ERROR", "fw-bold text-danger"
|
||||
|
||||
# Cold Start Toggle
|
||||
@self.app.callback(
|
||||
Output('cold-start-display', 'children'),
|
||||
Output('cold-start-display', 'className'),
|
||||
[Input('cold-start-switch', 'value')]
|
||||
)
|
||||
def update_cold_start(switch_value):
|
||||
"""Update cold start training mode"""
|
||||
try:
|
||||
is_enabled = 'enabled' in (switch_value or [])
|
||||
self.cold_start_enabled = is_enabled
|
||||
|
||||
# Update orchestrator cold start mode if available
|
||||
if hasattr(self, 'orchestrator') and self.orchestrator:
|
||||
if hasattr(self.orchestrator, 'set_cold_start_training_enabled'):
|
||||
# Use the new set_cold_start_training_enabled method
|
||||
success = self.orchestrator.set_cold_start_training_enabled(is_enabled)
|
||||
if success:
|
||||
logger.info(f"COLD START: {'ON' if is_enabled else 'OFF'} - Training mode updated successfully")
|
||||
else:
|
||||
logger.error(f"Failed to update cold start training to {'ON' if is_enabled else 'OFF'}")
|
||||
else:
|
||||
# Fallback to direct property setting
|
||||
if hasattr(self.orchestrator, 'cold_start_enabled'):
|
||||
self.orchestrator.cold_start_enabled = is_enabled
|
||||
|
||||
# Update training frequency based on cold start mode
|
||||
if hasattr(self.orchestrator, 'training_frequency'):
|
||||
if is_enabled:
|
||||
self.orchestrator.training_frequency = 'high' # Train on every signal
|
||||
logger.info("COLD START: ON - Excessive training enabled")
|
||||
else:
|
||||
self.orchestrator.training_frequency = 'normal' # Normal training
|
||||
logger.info("COLD START: OFF - Normal training frequency")
|
||||
|
||||
# Return display text and styling
|
||||
if is_enabled:
|
||||
return "ON", "fw-bold text-success"
|
||||
else:
|
||||
return "OFF", "fw-bold text-secondary"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating cold start mode: {e}")
|
||||
return "ERROR", "fw-bold text-danger"
|
||||
|
||||
def _get_current_price(self, symbol: str) -> Optional[float]:
|
||||
"""Get current price for symbol - ONLY using our data providers"""
|
||||
|
Reference in New Issue
Block a user