737 lines
28 KiB
Python
737 lines
28 KiB
Python
"""
|
|
Bot Management Integration for Chart Signal Layers
|
|
|
|
This module provides integration points between the signal layer system and the bot management
|
|
system, including data fetching utilities, bot filtering, and integration helpers.
|
|
"""
|
|
|
|
import pandas as pd
|
|
from typing import Dict, Any, Optional, List, Union, Tuple
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timedelta
|
|
from decimal import Decimal
|
|
|
|
from database.connection import get_session
|
|
from database.models import Bot, Signal, Trade, BotPerformance
|
|
from database.operations import DatabaseOperationError
|
|
from utils.logger import get_logger
|
|
|
|
# Initialize logger
|
|
logger = get_logger()
|
|
|
|
|
|
@dataclass
|
|
class BotFilterConfig:
|
|
"""Configuration for filtering bot data for chart layers"""
|
|
bot_ids: Optional[List[int]] = None # Specific bot IDs to include
|
|
bot_names: Optional[List[str]] = None # Specific bot names to include
|
|
strategies: Optional[List[str]] = None # Specific strategies to include
|
|
symbols: Optional[List[str]] = None # Specific symbols to include
|
|
statuses: Optional[List[str]] = None # Bot statuses to include
|
|
date_range: Optional[Tuple[datetime, datetime]] = None # Date range filter
|
|
active_only: bool = False # Only include active bots
|
|
|
|
def __post_init__(self):
|
|
if self.statuses is None:
|
|
self.statuses = ['active', 'inactive', 'paused'] # Exclude 'error' by default
|
|
|
|
|
|
class BotDataService:
|
|
"""
|
|
Service for fetching bot-related data for chart layers.
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""Initialize bot data service."""
|
|
self.logger = logger
|
|
|
|
def get_bots(self, filter_config: BotFilterConfig = None) -> pd.DataFrame:
|
|
"""
|
|
Get bot information based on filter configuration.
|
|
|
|
Args:
|
|
filter_config: Filter configuration (optional)
|
|
|
|
Returns:
|
|
DataFrame with bot information
|
|
"""
|
|
try:
|
|
if filter_config is None:
|
|
filter_config = BotFilterConfig()
|
|
|
|
with get_session() as session:
|
|
query = session.query(Bot)
|
|
|
|
# Apply filters
|
|
if filter_config.bot_ids:
|
|
query = query.filter(Bot.id.in_(filter_config.bot_ids))
|
|
|
|
if filter_config.bot_names:
|
|
query = query.filter(Bot.name.in_(filter_config.bot_names))
|
|
|
|
if filter_config.strategies:
|
|
query = query.filter(Bot.strategy_name.in_(filter_config.strategies))
|
|
|
|
if filter_config.symbols:
|
|
query = query.filter(Bot.symbol.in_(filter_config.symbols))
|
|
|
|
if filter_config.statuses:
|
|
query = query.filter(Bot.status.in_(filter_config.statuses))
|
|
|
|
if filter_config.active_only:
|
|
query = query.filter(Bot.status == 'active')
|
|
|
|
# Execute query
|
|
bots = query.all()
|
|
|
|
# Convert to DataFrame
|
|
bot_data = []
|
|
for bot in bots:
|
|
bot_data.append({
|
|
'id': bot.id,
|
|
'name': bot.name,
|
|
'strategy_name': bot.strategy_name,
|
|
'symbol': bot.symbol,
|
|
'timeframe': bot.timeframe,
|
|
'status': bot.status,
|
|
'config_file': bot.config_file,
|
|
'virtual_balance': float(bot.virtual_balance) if bot.virtual_balance else 0.0,
|
|
'current_balance': float(bot.current_balance) if bot.current_balance else 0.0,
|
|
'pnl': float(bot.pnl) if bot.pnl else 0.0,
|
|
'is_active': bot.is_active,
|
|
'last_heartbeat': bot.last_heartbeat,
|
|
'created_at': bot.created_at,
|
|
'updated_at': bot.updated_at
|
|
})
|
|
|
|
df = pd.DataFrame(bot_data)
|
|
self.logger.info(f"Bot Integration: Retrieved {len(df)} bots with filters: {filter_config}")
|
|
|
|
return df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error retrieving bots: {e}")
|
|
raise DatabaseOperationError(f"Failed to retrieve bots: {e}")
|
|
|
|
def get_signals_for_bots(self,
|
|
bot_ids: Union[int, List[int]] = None,
|
|
start_time: datetime = None,
|
|
end_time: datetime = None,
|
|
signal_types: List[str] = None,
|
|
min_confidence: float = 0.0) -> pd.DataFrame:
|
|
"""
|
|
Get signals for specific bots or all bots.
|
|
|
|
Args:
|
|
bot_ids: Bot ID(s) to fetch signals for (None for all bots)
|
|
start_time: Start time for signal filtering
|
|
end_time: End time for signal filtering
|
|
signal_types: Signal types to include (['buy', 'sell', 'hold'])
|
|
min_confidence: Minimum confidence threshold
|
|
|
|
Returns:
|
|
DataFrame with signal data
|
|
"""
|
|
try:
|
|
# Default time range if not provided
|
|
if end_time is None:
|
|
end_time = datetime.now()
|
|
if start_time is None:
|
|
start_time = end_time - timedelta(days=7) # Last 7 days by default
|
|
|
|
# Normalize bot_ids to list
|
|
if isinstance(bot_ids, int):
|
|
bot_ids = [bot_ids]
|
|
|
|
with get_session() as session:
|
|
query = session.query(Signal)
|
|
|
|
# Apply filters
|
|
if bot_ids is not None:
|
|
query = query.filter(Signal.bot_id.in_(bot_ids))
|
|
|
|
query = query.filter(
|
|
Signal.timestamp >= start_time,
|
|
Signal.timestamp <= end_time
|
|
)
|
|
|
|
if signal_types:
|
|
query = query.filter(Signal.signal_type.in_(signal_types))
|
|
|
|
if min_confidence > 0:
|
|
query = query.filter(Signal.confidence >= min_confidence)
|
|
|
|
# Order by timestamp
|
|
query = query.order_by(Signal.timestamp.asc())
|
|
|
|
# Execute query
|
|
signals = query.all()
|
|
|
|
# Convert to DataFrame
|
|
signal_data = []
|
|
for signal in signals:
|
|
signal_data.append({
|
|
'id': signal.id,
|
|
'bot_id': signal.bot_id,
|
|
'timestamp': signal.timestamp,
|
|
'signal_type': signal.signal_type,
|
|
'price': float(signal.price) if signal.price else None,
|
|
'confidence': float(signal.confidence) if signal.confidence else None,
|
|
'indicators': signal.indicators, # JSONB data
|
|
'created_at': signal.created_at
|
|
})
|
|
|
|
df = pd.DataFrame(signal_data)
|
|
self.logger.info(f"Bot Integration: Retrieved {len(df)} signals for bots: {bot_ids}")
|
|
|
|
return df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error retrieving signals: {e}")
|
|
raise DatabaseOperationError(f"Failed to retrieve signals: {e}")
|
|
|
|
def get_trades_for_bots(self,
|
|
bot_ids: Union[int, List[int]] = None,
|
|
start_time: datetime = None,
|
|
end_time: datetime = None,
|
|
sides: List[str] = None) -> pd.DataFrame:
|
|
"""
|
|
Get trades for specific bots or all bots.
|
|
|
|
Args:
|
|
bot_ids: Bot ID(s) to fetch trades for (None for all bots)
|
|
start_time: Start time for trade filtering
|
|
end_time: End time for trade filtering
|
|
sides: Trade sides to include (['buy', 'sell'])
|
|
|
|
Returns:
|
|
DataFrame with trade data
|
|
"""
|
|
try:
|
|
# Default time range if not provided
|
|
if end_time is None:
|
|
end_time = datetime.now()
|
|
if start_time is None:
|
|
start_time = end_time - timedelta(days=7) # Last 7 days by default
|
|
|
|
# Normalize bot_ids to list
|
|
if isinstance(bot_ids, int):
|
|
bot_ids = [bot_ids]
|
|
|
|
with get_session() as session:
|
|
query = session.query(Trade)
|
|
|
|
# Apply filters
|
|
if bot_ids is not None:
|
|
query = query.filter(Trade.bot_id.in_(bot_ids))
|
|
|
|
query = query.filter(
|
|
Trade.timestamp >= start_time,
|
|
Trade.timestamp <= end_time
|
|
)
|
|
|
|
if sides:
|
|
query = query.filter(Trade.side.in_(sides))
|
|
|
|
# Order by timestamp
|
|
query = query.order_by(Trade.timestamp.asc())
|
|
|
|
# Execute query
|
|
trades = query.all()
|
|
|
|
# Convert to DataFrame
|
|
trade_data = []
|
|
for trade in trades:
|
|
trade_data.append({
|
|
'id': trade.id,
|
|
'bot_id': trade.bot_id,
|
|
'signal_id': trade.signal_id,
|
|
'timestamp': trade.timestamp,
|
|
'side': trade.side,
|
|
'price': float(trade.price),
|
|
'quantity': float(trade.quantity),
|
|
'fees': float(trade.fees),
|
|
'pnl': float(trade.pnl) if trade.pnl else None,
|
|
'balance_after': float(trade.balance_after) if trade.balance_after else None,
|
|
'trade_value': float(trade.trade_value),
|
|
'net_pnl': float(trade.net_pnl),
|
|
'created_at': trade.created_at
|
|
})
|
|
|
|
df = pd.DataFrame(trade_data)
|
|
self.logger.info(f"Bot Integration: Retrieved {len(df)} trades for bots: {bot_ids}")
|
|
|
|
return df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error retrieving trades: {e}")
|
|
raise DatabaseOperationError(f"Failed to retrieve trades: {e}")
|
|
|
|
def get_bot_performance(self,
|
|
bot_ids: Union[int, List[int]] = None,
|
|
start_time: datetime = None,
|
|
end_time: datetime = None) -> pd.DataFrame:
|
|
"""
|
|
Get performance data for specific bots.
|
|
|
|
Args:
|
|
bot_ids: Bot ID(s) to fetch performance for (None for all bots)
|
|
start_time: Start time for performance filtering
|
|
end_time: End time for performance filtering
|
|
|
|
Returns:
|
|
DataFrame with performance data
|
|
"""
|
|
try:
|
|
# Default time range if not provided
|
|
if end_time is None:
|
|
end_time = datetime.now()
|
|
if start_time is None:
|
|
start_time = end_time - timedelta(days=30) # Last 30 days by default
|
|
|
|
# Normalize bot_ids to list
|
|
if isinstance(bot_ids, int):
|
|
bot_ids = [bot_ids]
|
|
|
|
with get_session() as session:
|
|
query = session.query(BotPerformance)
|
|
|
|
# Apply filters
|
|
if bot_ids is not None:
|
|
query = query.filter(BotPerformance.bot_id.in_(bot_ids))
|
|
|
|
query = query.filter(
|
|
BotPerformance.timestamp >= start_time,
|
|
BotPerformance.timestamp <= end_time
|
|
)
|
|
|
|
# Order by timestamp
|
|
query = query.order_by(BotPerformance.timestamp.asc())
|
|
|
|
# Execute query
|
|
performance_records = query.all()
|
|
|
|
# Convert to DataFrame
|
|
performance_data = []
|
|
for perf in performance_records:
|
|
performance_data.append({
|
|
'id': perf.id,
|
|
'bot_id': perf.bot_id,
|
|
'timestamp': perf.timestamp,
|
|
'total_value': float(perf.total_value),
|
|
'cash_balance': float(perf.cash_balance),
|
|
'crypto_balance': float(perf.crypto_balance),
|
|
'total_trades': perf.total_trades,
|
|
'winning_trades': perf.winning_trades,
|
|
'total_fees': float(perf.total_fees),
|
|
'win_rate': perf.win_rate,
|
|
'portfolio_allocation': perf.portfolio_allocation,
|
|
'created_at': perf.created_at
|
|
})
|
|
|
|
df = pd.DataFrame(performance_data)
|
|
self.logger.info(f"Bot Integration: Retrieved {len(df)} performance records for bots: {bot_ids}")
|
|
|
|
return df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error retrieving bot performance: {e}")
|
|
raise DatabaseOperationError(f"Failed to retrieve bot performance: {e}")
|
|
|
|
|
|
class BotSignalLayerIntegration:
|
|
"""
|
|
Integration utilities for signal layers with bot management system.
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""Initialize bot signal layer integration."""
|
|
self.data_service = BotDataService()
|
|
self.logger = logger
|
|
|
|
def get_signals_for_chart(self,
|
|
symbol: str,
|
|
timeframe: str = None,
|
|
bot_filter: BotFilterConfig = None,
|
|
time_range: Tuple[datetime, datetime] = None,
|
|
signal_types: List[str] = None,
|
|
min_confidence: float = 0.0) -> pd.DataFrame:
|
|
"""
|
|
Get signals filtered by chart context (symbol, timeframe) and bot criteria.
|
|
|
|
Args:
|
|
symbol: Trading symbol for the chart
|
|
timeframe: Chart timeframe (optional)
|
|
bot_filter: Bot filtering configuration
|
|
time_range: (start_time, end_time) tuple
|
|
signal_types: Signal types to include
|
|
min_confidence: Minimum confidence threshold
|
|
|
|
Returns:
|
|
DataFrame with signals ready for chart rendering
|
|
"""
|
|
try:
|
|
# Get relevant bots for this symbol/timeframe
|
|
if bot_filter is None:
|
|
bot_filter = BotFilterConfig()
|
|
|
|
# Add symbol filter
|
|
if bot_filter.symbols is None:
|
|
bot_filter.symbols = [symbol]
|
|
elif symbol not in bot_filter.symbols:
|
|
bot_filter.symbols.append(symbol)
|
|
|
|
# Get bots matching criteria
|
|
bots_df = self.data_service.get_bots(bot_filter)
|
|
|
|
if bots_df.empty:
|
|
self.logger.info(f"No bots found for symbol {symbol}")
|
|
return pd.DataFrame()
|
|
|
|
bot_ids = bots_df['id'].tolist()
|
|
|
|
# Get time range
|
|
start_time, end_time = time_range if time_range else (None, None)
|
|
|
|
# Get signals for these bots
|
|
signals_df = self.data_service.get_signals_for_bots(
|
|
bot_ids=bot_ids,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
signal_types=signal_types,
|
|
min_confidence=min_confidence
|
|
)
|
|
|
|
# Enrich signals with bot information
|
|
if not signals_df.empty:
|
|
signals_df = signals_df.merge(
|
|
bots_df[['id', 'name', 'strategy_name', 'status']],
|
|
left_on='bot_id',
|
|
right_on='id',
|
|
suffixes=('', '_bot')
|
|
)
|
|
|
|
# Add metadata fields for chart rendering
|
|
signals_df['bot_name'] = signals_df['name']
|
|
signals_df['strategy'] = signals_df['strategy_name']
|
|
signals_df['bot_status'] = signals_df['status']
|
|
|
|
# Clean up duplicate columns
|
|
signals_df = signals_df.drop(['id_bot', 'name', 'strategy_name', 'status'], axis=1)
|
|
|
|
self.logger.info(f"Bot Integration: Retrieved {len(signals_df)} signals for chart {symbol} from {len(bot_ids)} bots")
|
|
return signals_df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error getting signals for chart: {e}")
|
|
return pd.DataFrame()
|
|
|
|
def get_trades_for_chart(self,
|
|
symbol: str,
|
|
timeframe: str = None,
|
|
bot_filter: BotFilterConfig = None,
|
|
time_range: Tuple[datetime, datetime] = None,
|
|
sides: List[str] = None) -> pd.DataFrame:
|
|
"""
|
|
Get trades filtered by chart context (symbol, timeframe) and bot criteria.
|
|
|
|
Args:
|
|
symbol: Trading symbol for the chart
|
|
timeframe: Chart timeframe (optional)
|
|
bot_filter: Bot filtering configuration
|
|
time_range: (start_time, end_time) tuple
|
|
sides: Trade sides to include
|
|
|
|
Returns:
|
|
DataFrame with trades ready for chart rendering
|
|
"""
|
|
try:
|
|
# Get relevant bots for this symbol/timeframe
|
|
if bot_filter is None:
|
|
bot_filter = BotFilterConfig()
|
|
|
|
# Add symbol filter
|
|
if bot_filter.symbols is None:
|
|
bot_filter.symbols = [symbol]
|
|
elif symbol not in bot_filter.symbols:
|
|
bot_filter.symbols.append(symbol)
|
|
|
|
# Get bots matching criteria
|
|
bots_df = self.data_service.get_bots(bot_filter)
|
|
|
|
if bots_df.empty:
|
|
self.logger.info(f"No bots found for symbol {symbol}")
|
|
return pd.DataFrame()
|
|
|
|
bot_ids = bots_df['id'].tolist()
|
|
|
|
# Get time range
|
|
start_time, end_time = time_range if time_range else (None, None)
|
|
|
|
# Get trades for these bots
|
|
trades_df = self.data_service.get_trades_for_bots(
|
|
bot_ids=bot_ids,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
sides=sides
|
|
)
|
|
|
|
# Enrich trades with bot information
|
|
if not trades_df.empty:
|
|
trades_df = trades_df.merge(
|
|
bots_df[['id', 'name', 'strategy_name', 'status']],
|
|
left_on='bot_id',
|
|
right_on='id',
|
|
suffixes=('', '_bot')
|
|
)
|
|
|
|
# Add metadata fields for chart rendering
|
|
trades_df['bot_name'] = trades_df['name']
|
|
trades_df['strategy'] = trades_df['strategy_name']
|
|
trades_df['bot_status'] = trades_df['status']
|
|
|
|
# Clean up duplicate columns
|
|
trades_df = trades_df.drop(['id_bot', 'name', 'strategy_name', 'status'], axis=1)
|
|
|
|
self.logger.info(f"Bot Integration: Retrieved {len(trades_df)} trades for chart {symbol} from {len(bot_ids)} bots")
|
|
return trades_df
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error getting trades for chart: {e}")
|
|
return pd.DataFrame()
|
|
|
|
def get_bot_summary_stats(self, bot_ids: List[int] = None) -> Dict[str, Any]:
|
|
"""
|
|
Get summary statistics for bots.
|
|
|
|
Args:
|
|
bot_ids: Specific bot IDs (None for all bots)
|
|
|
|
Returns:
|
|
Dictionary with summary statistics
|
|
"""
|
|
try:
|
|
# Get bots
|
|
bot_filter = BotFilterConfig(bot_ids=bot_ids) if bot_ids else BotFilterConfig()
|
|
bots_df = self.data_service.get_bots(bot_filter)
|
|
|
|
if bots_df.empty:
|
|
return {
|
|
'total_bots': 0,
|
|
'active_bots': 0,
|
|
'total_balance': 0.0,
|
|
'total_pnl': 0.0,
|
|
'strategies': [],
|
|
'symbols': []
|
|
}
|
|
|
|
# Calculate statistics
|
|
stats = {
|
|
'total_bots': len(bots_df),
|
|
'active_bots': len(bots_df[bots_df['status'] == 'active']),
|
|
'inactive_bots': len(bots_df[bots_df['status'] == 'inactive']),
|
|
'paused_bots': len(bots_df[bots_df['status'] == 'paused']),
|
|
'error_bots': len(bots_df[bots_df['status'] == 'error']),
|
|
'total_virtual_balance': bots_df['virtual_balance'].sum(),
|
|
'total_current_balance': bots_df['current_balance'].sum(),
|
|
'total_pnl': bots_df['pnl'].sum(),
|
|
'average_pnl': bots_df['pnl'].mean(),
|
|
'best_performing_bot': None,
|
|
'worst_performing_bot': None,
|
|
'strategies': bots_df['strategy_name'].unique().tolist(),
|
|
'symbols': bots_df['symbol'].unique().tolist(),
|
|
'timeframes': bots_df['timeframe'].unique().tolist()
|
|
}
|
|
|
|
# Get best and worst performing bots
|
|
if not bots_df.empty:
|
|
best_bot = bots_df.loc[bots_df['pnl'].idxmax()]
|
|
worst_bot = bots_df.loc[bots_df['pnl'].idxmin()]
|
|
|
|
stats['best_performing_bot'] = {
|
|
'id': best_bot['id'],
|
|
'name': best_bot['name'],
|
|
'pnl': best_bot['pnl']
|
|
}
|
|
|
|
stats['worst_performing_bot'] = {
|
|
'id': worst_bot['id'],
|
|
'name': worst_bot['name'],
|
|
'pnl': worst_bot['pnl']
|
|
}
|
|
|
|
return stats
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Bot Integration: Error getting bot summary stats: {e}")
|
|
return {}
|
|
|
|
|
|
# Global instances for easy access
|
|
bot_data_service = BotDataService()
|
|
bot_integration = BotSignalLayerIntegration()
|
|
|
|
|
|
# Convenience functions for common use cases
|
|
|
|
def get_active_bot_signals(symbol: str,
|
|
timeframe: str = None,
|
|
days_back: int = 7,
|
|
signal_types: List[str] = None,
|
|
min_confidence: float = 0.3) -> pd.DataFrame:
|
|
"""
|
|
Get signals from active bots for a specific symbol.
|
|
|
|
Args:
|
|
symbol: Trading symbol
|
|
timeframe: Chart timeframe (optional)
|
|
days_back: Number of days to look back
|
|
signal_types: Signal types to include
|
|
min_confidence: Minimum confidence threshold
|
|
|
|
Returns:
|
|
DataFrame with signals from active bots
|
|
"""
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=days_back)
|
|
|
|
bot_filter = BotFilterConfig(
|
|
symbols=[symbol],
|
|
active_only=True
|
|
)
|
|
|
|
return bot_integration.get_signals_for_chart(
|
|
symbol=symbol,
|
|
timeframe=timeframe,
|
|
bot_filter=bot_filter,
|
|
time_range=(start_time, end_time),
|
|
signal_types=signal_types,
|
|
min_confidence=min_confidence
|
|
)
|
|
|
|
|
|
def get_active_bot_trades(symbol: str,
|
|
timeframe: str = None,
|
|
days_back: int = 7,
|
|
sides: List[str] = None) -> pd.DataFrame:
|
|
"""
|
|
Get trades from active bots for a specific symbol.
|
|
|
|
Args:
|
|
symbol: Trading symbol
|
|
timeframe: Chart timeframe (optional)
|
|
days_back: Number of days to look back
|
|
sides: Trade sides to include
|
|
|
|
Returns:
|
|
DataFrame with trades from active bots
|
|
"""
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=days_back)
|
|
|
|
bot_filter = BotFilterConfig(
|
|
symbols=[symbol],
|
|
active_only=True
|
|
)
|
|
|
|
return bot_integration.get_trades_for_chart(
|
|
symbol=symbol,
|
|
timeframe=timeframe,
|
|
bot_filter=bot_filter,
|
|
time_range=(start_time, end_time),
|
|
sides=sides
|
|
)
|
|
|
|
|
|
def get_bot_signals_by_strategy(strategy_name: str,
|
|
symbol: str = None,
|
|
days_back: int = 7,
|
|
signal_types: List[str] = None) -> pd.DataFrame:
|
|
"""
|
|
Get signals from bots using a specific strategy.
|
|
|
|
Args:
|
|
strategy_name: Strategy name to filter by
|
|
symbol: Trading symbol (optional)
|
|
days_back: Number of days to look back
|
|
signal_types: Signal types to include
|
|
|
|
Returns:
|
|
DataFrame with signals from strategy bots
|
|
"""
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=days_back)
|
|
|
|
bot_filter = BotFilterConfig(
|
|
strategies=[strategy_name],
|
|
symbols=[symbol] if symbol else None
|
|
)
|
|
|
|
# Get bots for this strategy
|
|
bots_df = bot_data_service.get_bots(bot_filter)
|
|
|
|
if bots_df.empty:
|
|
return pd.DataFrame()
|
|
|
|
bot_ids = bots_df['id'].tolist()
|
|
|
|
return bot_data_service.get_signals_for_bots(
|
|
bot_ids=bot_ids,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
signal_types=signal_types
|
|
)
|
|
|
|
|
|
def get_bot_performance_summary(bot_id: int = None,
|
|
days_back: int = 30) -> Dict[str, Any]:
|
|
"""
|
|
Get performance summary for a specific bot or all bots.
|
|
|
|
Args:
|
|
bot_id: Specific bot ID (None for all bots)
|
|
days_back: Number of days to analyze
|
|
|
|
Returns:
|
|
Dictionary with performance summary
|
|
"""
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=days_back)
|
|
|
|
# Get bot summary stats
|
|
bot_ids = [bot_id] if bot_id else None
|
|
bot_stats = bot_integration.get_bot_summary_stats(bot_ids)
|
|
|
|
# Get signals and trades for performance analysis
|
|
signals_df = bot_data_service.get_signals_for_bots(
|
|
bot_ids=bot_ids,
|
|
start_time=start_time,
|
|
end_time=end_time
|
|
)
|
|
|
|
trades_df = bot_data_service.get_trades_for_bots(
|
|
bot_ids=bot_ids,
|
|
start_time=start_time,
|
|
end_time=end_time
|
|
)
|
|
|
|
# Calculate additional performance metrics
|
|
performance = {
|
|
'bot_stats': bot_stats,
|
|
'signal_count': len(signals_df),
|
|
'trade_count': len(trades_df),
|
|
'signals_by_type': signals_df['signal_type'].value_counts().to_dict() if not signals_df.empty else {},
|
|
'trades_by_side': trades_df['side'].value_counts().to_dict() if not trades_df.empty else {},
|
|
'total_trade_volume': trades_df['trade_value'].sum() if not trades_df.empty else 0.0,
|
|
'total_fees': trades_df['fees'].sum() if not trades_df.empty else 0.0,
|
|
'profitable_trades': len(trades_df[trades_df['pnl'] > 0]) if not trades_df.empty else 0,
|
|
'losing_trades': len(trades_df[trades_df['pnl'] < 0]) if not trades_df.empty else 0,
|
|
'win_rate': (len(trades_df[trades_df['pnl'] > 0]) / len(trades_df) * 100) if not trades_df.empty else 0.0,
|
|
'time_range': {
|
|
'start': start_time.isoformat(),
|
|
'end': end_time.isoformat(),
|
|
'days': days_back
|
|
}
|
|
}
|
|
|
|
return performance |