4.0 - 4.0 Implement real-time strategy execution and data integration features
- Added `realtime_execution.py` for real-time strategy execution, enabling live signal generation and integration with the dashboard's chart refresh cycle. - Introduced `data_integration.py` to manage market data orchestration, caching, and technical indicator calculations for strategy signal generation. - Implemented `validation.py` for comprehensive validation and quality assessment of strategy-generated signals, ensuring reliability and consistency. - Developed `batch_processing.py` to facilitate efficient backtesting of multiple strategies across large datasets with memory management and performance optimization. - Updated `__init__.py` files to include new modules and ensure proper exports, enhancing modularity and maintainability. - Enhanced unit tests for the new features, ensuring robust functionality and adherence to project standards. These changes establish a solid foundation for real-time strategy execution and data integration, aligning with project goals for modularity, performance, and maintainability.
This commit is contained in:
@@ -6,10 +6,12 @@ from .navigation import register_navigation_callbacks
|
||||
from .charts import register_chart_callbacks
|
||||
from .indicators import register_indicator_callbacks
|
||||
from .system_health import register_system_health_callbacks
|
||||
from .realtime_strategies import register_realtime_strategy_callbacks
|
||||
|
||||
__all__ = [
|
||||
'register_navigation_callbacks',
|
||||
'register_chart_callbacks',
|
||||
'register_indicator_callbacks',
|
||||
'register_system_health_callbacks'
|
||||
'register_system_health_callbacks',
|
||||
'register_realtime_strategy_callbacks'
|
||||
]
|
||||
291
dashboard/callbacks/realtime_strategies.py
Normal file
291
dashboard/callbacks/realtime_strategies.py
Normal file
@@ -0,0 +1,291 @@
|
||||
"""
|
||||
Real-time Strategy Callbacks
|
||||
|
||||
This module provides callbacks for integrating real-time strategy execution
|
||||
with the dashboard chart refresh cycle and user interactions.
|
||||
"""
|
||||
|
||||
import json
|
||||
from dash import Output, Input, State, Patch, ctx, html, no_update, dcc, callback
|
||||
import dash_bootstrap_components as dbc
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from utils.logger import get_logger
|
||||
from strategies.realtime_execution import (
|
||||
get_realtime_strategy_processor,
|
||||
initialize_realtime_strategy_system,
|
||||
RealTimeConfig,
|
||||
RealTimeSignal
|
||||
)
|
||||
from strategies.manager import StrategyManager
|
||||
from config.strategies.config_utils import StrategyConfigurationManager
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
# Global processor instance
|
||||
_processor = None
|
||||
|
||||
|
||||
def get_processor():
|
||||
"""Get or initialize the real-time strategy processor."""
|
||||
global _processor
|
||||
if _processor is None:
|
||||
config = RealTimeConfig(
|
||||
refresh_interval_seconds=30,
|
||||
max_strategies_concurrent=3,
|
||||
incremental_calculation=True,
|
||||
signal_batch_size=50,
|
||||
enable_signal_broadcasting=True
|
||||
)
|
||||
_processor = initialize_realtime_strategy_system(config)
|
||||
return _processor
|
||||
|
||||
|
||||
def register_realtime_strategy_callbacks(app):
|
||||
"""Register real-time strategy callbacks."""
|
||||
|
||||
@app.callback(
|
||||
Output('realtime-strategies-store', 'data'),
|
||||
[Input('realtime-strategy-toggle', 'value'),
|
||||
Input('symbol-dropdown', 'value'),
|
||||
Input('timeframe-dropdown', 'value'),
|
||||
Input('strategy-dropdown', 'value')],
|
||||
[State('realtime-strategies-store', 'data')],
|
||||
prevent_initial_call=True
|
||||
)
|
||||
def manage_realtime_strategies(enable_realtime, symbol, timeframe, strategy_name, current_data):
|
||||
"""
|
||||
Manage real-time strategy registration based on user selections.
|
||||
|
||||
This callback handles enabling/disabling real-time strategy execution
|
||||
and registers strategies based on current chart selections.
|
||||
"""
|
||||
try:
|
||||
current_data = current_data or {'active_strategies': [], 'enabled': False}
|
||||
processor = get_processor()
|
||||
|
||||
if not enable_realtime:
|
||||
# Disable all strategies
|
||||
for context_id in current_data.get('active_strategies', []):
|
||||
processor.unregister_strategy(context_id)
|
||||
logger.info(f"Unregistered real-time strategy: {context_id}")
|
||||
|
||||
return {'active_strategies': [], 'enabled': False}
|
||||
|
||||
# Enable real-time strategies
|
||||
if symbol and timeframe and strategy_name and strategy_name != 'basic':
|
||||
# Load strategy configuration
|
||||
try:
|
||||
config_manager = StrategyConfigurationManager()
|
||||
strategy_config = config_manager.load_user_strategy_config(strategy_name)
|
||||
|
||||
if not strategy_config:
|
||||
# Load from templates if user config doesn't exist
|
||||
strategy_config = config_manager.load_strategy_template(strategy_name)
|
||||
|
||||
if strategy_config:
|
||||
# Register strategy for real-time execution
|
||||
context_id = processor.register_strategy(
|
||||
strategy_name=strategy_name,
|
||||
strategy_config=strategy_config,
|
||||
symbol=symbol,
|
||||
timeframe=timeframe
|
||||
)
|
||||
|
||||
active_strategies = [context_id]
|
||||
logger.info(f"Registered real-time strategy: {context_id}")
|
||||
|
||||
return {
|
||||
'active_strategies': active_strategies,
|
||||
'enabled': True,
|
||||
'current_symbol': symbol,
|
||||
'current_timeframe': timeframe,
|
||||
'current_strategy': strategy_name
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading strategy configuration for {strategy_name}: {e}")
|
||||
return current_data
|
||||
|
||||
return current_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error managing real-time strategies: {e}")
|
||||
return current_data or {'active_strategies': [], 'enabled': False}
|
||||
|
||||
@app.callback(
|
||||
Output('realtime-strategy-status', 'children'),
|
||||
[Input('realtime-strategies-store', 'data'),
|
||||
Input('interval-component', 'n_intervals')],
|
||||
prevent_initial_call=True
|
||||
)
|
||||
def update_realtime_status(strategy_data, n_intervals):
|
||||
"""
|
||||
Update real-time strategy status display.
|
||||
|
||||
Shows current status of real-time strategy execution including
|
||||
active strategies and performance metrics.
|
||||
"""
|
||||
try:
|
||||
if not strategy_data or not strategy_data.get('enabled'):
|
||||
return dbc.Alert("Real-time strategy execution is disabled", color="secondary", className="mb-2")
|
||||
|
||||
processor = get_processor()
|
||||
active_strategies = processor.get_active_strategies()
|
||||
perf_stats = processor.get_performance_stats()
|
||||
|
||||
if not active_strategies:
|
||||
return dbc.Alert("No active real-time strategies", color="warning", className="mb-2")
|
||||
|
||||
# Build status display
|
||||
status_items = []
|
||||
|
||||
# Active strategies
|
||||
for context_id, context in active_strategies.items():
|
||||
status_items.append(
|
||||
html.Li([
|
||||
html.Strong(f"{context.strategy_name}: "),
|
||||
f"{context.symbol} {context.timeframe}",
|
||||
html.Span(
|
||||
" ✓" if context.is_active else " ⚠️",
|
||||
style={'color': 'green' if context.is_active else 'orange'}
|
||||
)
|
||||
])
|
||||
)
|
||||
|
||||
# Performance metrics
|
||||
success_rate = 0
|
||||
if perf_stats['total_calculations'] > 0:
|
||||
success_rate = (perf_stats['successful_calculations'] / perf_stats['total_calculations']) * 100
|
||||
|
||||
metrics_text = f"Calculations: {perf_stats['total_calculations']} | " \
|
||||
f"Success Rate: {success_rate:.1f}% | " \
|
||||
f"Signals Generated: {perf_stats['signals_generated']}"
|
||||
|
||||
return dbc.Card([
|
||||
dbc.CardHeader("Real-time Strategy Status"),
|
||||
dbc.CardBody([
|
||||
html.H6("Active Strategies:", className="mb-2"),
|
||||
html.Ul(status_items, className="mb-3"),
|
||||
html.P(metrics_text, className="small mb-0")
|
||||
])
|
||||
], className="mb-2")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating real-time status: {e}")
|
||||
return dbc.Alert(f"Error updating status: {str(e)}", color="danger", className="mb-2")
|
||||
|
||||
# Integration with chart refresh cycle
|
||||
@app.callback(
|
||||
Output('realtime-execution-trigger', 'data'),
|
||||
[Input('interval-component', 'n_intervals')],
|
||||
[State('symbol-dropdown', 'value'),
|
||||
State('timeframe-dropdown', 'value'),
|
||||
State('realtime-strategies-store', 'data'),
|
||||
State('analysis-mode-toggle', 'value')],
|
||||
prevent_initial_call=True
|
||||
)
|
||||
def trigger_realtime_execution(n_intervals, symbol, timeframe, strategy_data, analysis_mode):
|
||||
"""
|
||||
Trigger real-time strategy execution when new data is available.
|
||||
|
||||
This callback integrates with the existing chart refresh cycle to
|
||||
execute real-time strategies when new candle data arrives.
|
||||
"""
|
||||
try:
|
||||
# Only execute in live mode
|
||||
if analysis_mode == 'locked':
|
||||
return no_update
|
||||
|
||||
# Only execute if real-time strategies are enabled
|
||||
if not strategy_data or not strategy_data.get('enabled'):
|
||||
return no_update
|
||||
|
||||
# Only execute if we have symbol and timeframe
|
||||
if not symbol or not timeframe:
|
||||
return no_update
|
||||
|
||||
processor = get_processor()
|
||||
|
||||
# Execute real-time strategy update
|
||||
signals = processor.execute_realtime_update(
|
||||
symbol=symbol,
|
||||
timeframe=timeframe,
|
||||
exchange="okx"
|
||||
)
|
||||
|
||||
if signals:
|
||||
logger.info(f"Real-time execution generated {len(signals)} signals for {symbol} {timeframe}")
|
||||
return {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'signals_generated': len(signals),
|
||||
'symbol': symbol,
|
||||
'timeframe': timeframe
|
||||
}
|
||||
|
||||
return no_update
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in real-time strategy execution: {e}")
|
||||
return no_update
|
||||
|
||||
|
||||
def add_realtime_strategy_components():
|
||||
"""
|
||||
Add real-time strategy components to the dashboard layout.
|
||||
|
||||
Returns:
|
||||
List of Dash components for real-time strategy controls
|
||||
"""
|
||||
return [
|
||||
# Real-time strategy toggle
|
||||
dbc.Row([
|
||||
dbc.Col([
|
||||
dbc.Label("Real-time Strategy Execution", className="fw-bold"),
|
||||
dbc.Switch(
|
||||
id="realtime-strategy-toggle",
|
||||
label="Enable Real-time Execution",
|
||||
value=False,
|
||||
className="mb-2"
|
||||
),
|
||||
], width=12)
|
||||
], className="mb-3"),
|
||||
|
||||
# Status display
|
||||
html.Div(id="realtime-strategy-status"),
|
||||
|
||||
# Hidden stores for state management
|
||||
dcc.Store(id="realtime-strategies-store", data={'active_strategies': [], 'enabled': False}),
|
||||
dcc.Store(id="realtime-execution-trigger", data={}),
|
||||
]
|
||||
|
||||
|
||||
def setup_chart_update_callback():
|
||||
"""
|
||||
Setup chart update callback for real-time signals.
|
||||
|
||||
This function configures the real-time processor to trigger
|
||||
chart updates when new signals are generated.
|
||||
"""
|
||||
def chart_update_callback(signal: RealTimeSignal):
|
||||
"""Handle chart updates for real-time signals."""
|
||||
try:
|
||||
# This would trigger chart refresh for the specific symbol/timeframe
|
||||
# For now, we'll log the signal and let the regular refresh cycle handle it
|
||||
logger.debug(
|
||||
f"Chart update requested for signal: {signal.context.strategy_name} "
|
||||
f"on {signal.context.symbol} {signal.context.timeframe}"
|
||||
)
|
||||
|
||||
# Future enhancement: Could trigger specific chart layer updates here
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in chart update callback: {e}")
|
||||
|
||||
processor = get_processor()
|
||||
processor.set_chart_update_callback(chart_update_callback)
|
||||
|
||||
|
||||
# Initialize the chart update callback when module is imported
|
||||
setup_chart_update_callback()
|
||||
Reference in New Issue
Block a user