diff --git a/README 2.0.2.md b/README 2.0.2.md new file mode 100644 index 0000000..dc4f9dc --- /dev/null +++ b/README 2.0.2.md @@ -0,0 +1,133 @@ +# AI-Powered Trading Bot + +A sophisticated trading bot that combines technical analysis, machine learning, sentiment analysis, and risk management to make informed trading decisions. + +## Features + +- **Technical Analysis** + - Multiple timeframe analysis + - Advanced indicators (SMA, EMA, RSI, MACD, Bollinger Bands) + - Pattern recognition + - Support and resistance levels + +- **Machine Learning** + - LSTM-based price prediction + - Reinforcement learning for strategy optimization + - Feature engineering and selection + - Model persistence and retraining + +- **Sentiment Analysis** + - News sentiment analysis + - Social media sentiment (Twitter) + - Market sentiment indicators + - Weighted sentiment scoring + +- **Risk Management** + - Position sizing based on risk percentage + - Stop-loss and take-profit management + - Maximum drawdown protection + - Performance monitoring + - Risk metrics calculation + +- **Web Dashboard** + - Real-time performance monitoring + - Trade history visualization + - Risk metrics display + - Configuration management + +## Requirements + +- Python 3.8+ +- CUDA-capable GPU (recommended for machine learning) +- API keys for: + - Cryptocurrency exchange (e.g., Binance) + - News API + - Twitter API + +## Installation + +1. Clone the repository: +```bash +git clone https://github.com/B-Wear/QuantumEdge.git +cd trading-bot +``` + +2. Create a virtual environment: +```bash +python -m venv venv +source venv/bin/activate # On Windows: venv\Scripts\activate +``` + +3. Install dependencies: +```bash +pip install -r requirements.txt +``` + +4. Configure the bot: + - Copy `config/config.json.example` to `config/config.json` + - Update the configuration with your API keys and preferences + +## Usage + +1. Start the trading bot: +```bash +python -m src.main +``` + +2. Access the web dashboard: + - Open your browser and navigate to `http://localhost:5000` + - Monitor performance and manage settings + +3. Monitor logs: + - Check `trading_bot.log` for detailed information + - Monitor system performance and error messages + +## Configuration + +The bot can be configured through `config/config.json`. Key settings include: + +- Trading pairs and timeframes +- Risk management parameters +- Technical analysis settings +- Machine learning model parameters +- Sentiment analysis weights +- API credentials + +## Risk Warning + +Trading cryptocurrencies involves significant risk of loss. This bot is for educational purposes only. Always: + +- Start with small amounts +- Use testnet for initial testing +- Monitor performance closely +- Implement proper risk management +- Never trade with money you cannot afford to lose + +## Contributing + +1. Fork the repository +2. Create a feature branch +3. Commit your changes +4. Push to the branch +5. Create a Pull Request + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Acknowledgments + +- Thanks to the open-source community for various libraries used in this project +- Special thanks to contributors and maintainers of key dependencies +- Inspired by various trading strategies and research papers + +## Support + +For support, please: +1. Check the documentation +2. Search existing issues +3. Create a new issue if needed + +## Disclaimer + +This trading bot is provided as-is, without any warranties. Use at your own risk. The developers are not responsible for any financial losses incurred through the use of this software. \ No newline at end of file diff --git a/README 2.0.md b/README 2.0.md new file mode 100644 index 0000000..0b169ba --- /dev/null +++ b/README 2.0.md @@ -0,0 +1,234 @@ +# Quantum Edge Trading System + +A sophisticated, AI-powered trading system that combines machine learning, sentiment analysis, and advanced risk management to execute trades across multiple markets. + +## Features + +### 1. Multi-Bot Management +- Create and manage multiple trading bots +- Each bot can run different strategies +- Real-time monitoring and control +- Automatic performance optimization + +### 2. Machine Learning Models +- LSTM for price prediction +- Reinforcement Learning (PPO) for strategy optimization +- Feature engineering and selection +- Automatic model retraining + +### 3. Risk Management +- Dynamic position sizing +- Multi-level stop-loss system +- Portfolio correlation analysis +- Exposure management +- VaR calculations + +### 4. Sentiment Analysis +- Real-time news analysis +- Social media sentiment tracking +- Market sentiment indicators +- Impact analysis + +### 5. System Monitoring +- Performance metrics tracking +- Health monitoring +- Resource optimization +- Automatic issue detection and resolution + +### 6. Code Guardian +- Continuous code quality monitoring +- Automatic issue detection +- Self-healing capabilities +- Performance optimization + +## Installation + +1. Clone the repository: +```bash +git clone https://github.com/yourusername/quantum-edge-system.git +cd quantum-edge-system +``` + +2. Install dependencies: +```bash +pip install -r requirements.txt +``` + +3. Configure the system: +- Copy `config/quantum_edge_config.json.example` to `config/quantum_edge_config.json` +- Update the configuration with your API keys and preferences + +## Configuration + +The system is configured through `quantum_edge_config.json`. Key sections include: + +1. **System Settings** + - Basic system configuration + - Logging settings + - Dashboard configuration + +2. **Trading Settings** + - Exchange configuration + - Market selection + - Order types + - Position types + +3. **ML Model Settings** + - LSTM configuration + - Reinforcement learning parameters + - Feature selection + - Training parameters + +4. **Risk Management** + - Position sizing rules + - Stop-loss configuration + - Risk limits + - Exposure management + +5. **Sentiment Analysis** + - News API configuration + - Social media settings + - Analysis parameters + - Update intervals + +6. **Optimization Settings** + - System optimization rules + - Trading optimization parameters + - ML model optimization + - Performance thresholds + +## Usage + +1. Start the Quantum Edge System: +```python +from trading_bot.src.quantum_edge_system import create_quantum_edge_system + +# Create system instance +system = create_quantum_edge_system(".", "config/quantum_edge_config.json") + +# Create bot configurations +configs = [ + { + "trading": { + "initial_capital": 100000, + "strategy": "trend_following", + "markets": ["BTC/USD", "ETH/USD"] + }, + "ml_model": { + "type": "lstm", + "features": ["price", "volume", "sentiment"] + } + }, + { + "trading": { + "initial_capital": 50000, + "strategy": "mean_reversion", + "markets": ["SOL/USD", "ADA/USD"] + }, + "ml_model": { + "type": "reinforcement", + "features": ["technical_indicators", "order_flow"] + } + } +] + +# Create and start bots +bot_ids = [] +for config in configs: + bot_id = system.create_quantum_bot(config) + bot_ids.append(bot_id) + system.start_bot(bot_id) + +# Monitor system +while True: + status = system.get_system_status() + print(f"System Status: {json.dumps(status, indent=2)}") + time.sleep(300) # Update every 5 minutes +``` + +2. Access the dashboard: + - Open your browser + - Navigate to `http://localhost:8050` + - Monitor system performance, bot status, and trading metrics + +## Dashboard Features + +1. **System Overview** + - System health metrics + - Resource utilization + - Overall performance + +2. **Bot Management** + - Individual bot status + - Performance metrics + - Control panel + +3. **Trading View** + - Active positions + - Order history + - P&L tracking + +4. **Risk Analytics** + - Risk metrics + - Exposure analysis + - VaR calculations + +5. **ML Model Insights** + - Model performance + - Feature importance + - Training status + +6. **Sentiment Analysis** + - Market sentiment + - News impact + - Social media trends + +## API Reference + +### System Management +```python +create_quantum_bot(config: Dict) -> str +start_bot(bot_id: str) +stop_bot(bot_id: str) +get_system_status() -> Dict +get_bot_status(bot_id: str) -> Dict +``` + +### Performance Monitoring +```python +get_performance_metrics() -> Dict +get_risk_metrics() -> Dict +get_sentiment_metrics() -> Dict +get_ml_metrics() -> Dict +``` + +### System Control +```python +optimize_system() +optimize_ml_models() +optimize_risk_parameters() +handle_risk_breach() +``` + +## Contributing + +1. Fork the repository +2. Create your feature branch +3. Commit your changes +4. Push to the branch +5. Create a new Pull Request + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Support + +For support, please: +1. Check the documentation +2. Open an issue +3. Contact the development team + +## Disclaimer + +This software is for educational purposes only. Use at your own risk. The developers are not responsible for any financial losses incurred while using this system. \ No newline at end of file diff --git a/ai_agent_manager 2.0.py b/ai_agent_manager 2.0.py new file mode 100644 index 0000000..f07c5c2 --- /dev/null +++ b/ai_agent_manager 2.0.py @@ -0,0 +1,322 @@ +import logging +import threading +import queue +import json +import os +from typing import Dict, List, Optional, Any +from dataclasses import dataclass +from datetime import datetime +import time +from .trading_system import TradingSystem, create_trading_system +from .code_guardian import CodeGuardian, create_guardian +from .system_monitor import SystemMonitor +from .dashboard import create_dashboard + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('logs/ai_agent_manager.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +@dataclass +class BotInstance: + """Represents a trading bot instance""" + bot_id: str + trading_system: TradingSystem + config: Dict + status: str + last_update: datetime + performance_metrics: Dict + message_queue: queue.Queue + +class AIAgentManager: + def __init__(self, project_root: str): + self.project_root = project_root + self.bots: Dict[str, BotInstance] = {} + self.code_guardian = create_guardian(project_root) + self.system_monitor = SystemMonitor(project_root) + self.message_queue = queue.Queue() + self.running = True + + # Start management threads + self.threads = { + 'monitor': threading.Thread(target=self._monitor_bots), + 'message_handler': threading.Thread(target=self._handle_messages), + 'code_repair': threading.Thread(target=self._continuous_code_repair) + } + + for thread in self.threads.values(): + thread.daemon = True + thread.start() + + # Initialize dashboard + self.dashboard = create_dashboard() + self.dashboard_thread = threading.Thread(target=self._run_dashboard) + self.dashboard_thread.daemon = True + self.dashboard_thread.start() + + def create_bot(self, config: Dict) -> str: + """Create a new trading bot instance""" + try: + bot_id = f"bot_{len(self.bots) + 1}" + + # Save bot-specific config + config_path = os.path.join(self.project_root, 'config', f'{bot_id}_config.json') + with open(config_path, 'w') as f: + json.dump(config, f, indent=2) + + # Create trading system + trading_system = create_trading_system(config_path) + + # Create bot instance + bot = BotInstance( + bot_id=bot_id, + trading_system=trading_system, + config=config, + status='initialized', + last_update=datetime.now(), + performance_metrics={}, + message_queue=queue.Queue() + ) + + self.bots[bot_id] = bot + logger.info(f"Created new bot instance: {bot_id}") + + return bot_id + + except Exception as e: + logger.error(f"Error creating bot: {str(e)}") + raise + + def start_bot(self, bot_id: str): + """Start a trading bot""" + if bot_id in self.bots: + try: + bot = self.bots[bot_id] + bot.status = 'running' + bot.last_update = datetime.now() + logger.info(f"Started bot: {bot_id}") + + # Send start message to bot + self._send_message_to_bot(bot_id, { + 'type': 'command', + 'action': 'start', + 'timestamp': datetime.now().isoformat() + }) + + except Exception as e: + logger.error(f"Error starting bot {bot_id}: {str(e)}") + self.bots[bot_id].status = 'error' + + def stop_bot(self, bot_id: str): + """Stop a trading bot""" + if bot_id in self.bots: + try: + bot = self.bots[bot_id] + bot.status = 'stopped' + bot.last_update = datetime.now() + bot.trading_system.stop() + logger.info(f"Stopped bot: {bot_id}") + + except Exception as e: + logger.error(f"Error stopping bot {bot_id}: {str(e)}") + + def send_message_to_bot(self, bot_id: str, message: Dict): + """Send a message to a specific bot""" + if bot_id in self.bots: + self._send_message_to_bot(bot_id, message) + logger.info(f"Sent message to bot {bot_id}: {message}") + + def broadcast_message(self, message: Dict): + """Send a message to all bots""" + for bot_id in self.bots: + self._send_message_to_bot(bot_id, message) + logger.info(f"Broadcast message to all bots: {message}") + + def get_bot_status(self, bot_id: str) -> Optional[Dict]: + """Get status of a specific bot""" + if bot_id in self.bots: + bot = self.bots[bot_id] + return { + 'bot_id': bot.bot_id, + 'status': bot.status, + 'last_update': bot.last_update.isoformat(), + 'performance_metrics': bot.performance_metrics, + 'trading_system_status': bot.trading_system.get_status() + } + return None + + def get_system_status(self) -> Dict: + """Get overall system status""" + return { + 'total_bots': len(self.bots), + 'active_bots': len([b for b in self.bots.values() if b.status == 'running']), + 'code_health': self.code_guardian.get_status_report(), + 'system_health': self.system_monitor.get_system_status(), + 'bots': {bot_id: self.get_bot_status(bot_id) for bot_id in self.bots} + } + + def _send_message_to_bot(self, bot_id: str, message: Dict): + """Internal method to send message to bot""" + if bot_id in self.bots: + self.bots[bot_id].message_queue.put(message) + + def _monitor_bots(self): + """Continuously monitor bot performance and health""" + while self.running: + try: + for bot_id, bot in self.bots.items(): + if bot.status == 'running': + # Update bot metrics + status = bot.trading_system.get_status() + bot.performance_metrics = status['metrics'] + bot.last_update = datetime.now() + + # Check for issues + if status['system_health']['alerts']['unacknowledged'] > 0: + self._handle_bot_issue(bot_id, status) + + time.sleep(60) # Check every minute + + except Exception as e: + logger.error(f"Error in bot monitoring: {str(e)}") + time.sleep(300) + + def _handle_messages(self): + """Handle incoming messages from bots""" + while self.running: + try: + for bot_id, bot in self.bots.items(): + while not bot.message_queue.empty(): + message = bot.message_queue.get_nowait() + self._process_bot_message(bot_id, message) + + time.sleep(1) + + except Exception as e: + logger.error(f"Error handling messages: {str(e)}") + time.sleep(60) + + def _continuous_code_repair(self): + """Continuously monitor and repair code issues""" + while self.running: + try: + # Get code issues + status = self.code_guardian.get_status_report() + + # Attempt to fix issues + for issue in self.code_guardian.issues: + if not issue.fixed and issue.suggested_fix: + if self.code_guardian.fix_issue(issue): + logger.info(f"Fixed code issue: {issue.description}") + + time.sleep(300) # Check every 5 minutes + + except Exception as e: + logger.error(f"Error in code repair: {str(e)}") + time.sleep(600) + + def _handle_bot_issue(self, bot_id: str, status: Dict): + """Handle issues with a specific bot""" + try: + # Create alert + alert = { + 'type': 'alert', + 'bot_id': bot_id, + 'timestamp': datetime.now().isoformat(), + 'status': status + } + + # Log alert + logger.warning(f"Bot issue detected: {alert}") + + # Add to message queue + self.message_queue.put(alert) + + # Take action based on issue severity + if status['system_health']['alerts']['by_level'].get('error', 0) > 0: + self.stop_bot(bot_id) + logger.error(f"Stopped bot {bot_id} due to critical issues") + + except Exception as e: + logger.error(f"Error handling bot issue: {str(e)}") + + def _process_bot_message(self, bot_id: str, message: Dict): + """Process message from a bot""" + try: + if message['type'] == 'status_update': + self.bots[bot_id].status = message['status'] + self.bots[bot_id].last_update = datetime.now() + + elif message['type'] == 'alert': + self._handle_bot_issue(bot_id, message) + + elif message['type'] == 'performance_update': + self.bots[bot_id].performance_metrics.update(message['metrics']) + + except Exception as e: + logger.error(f"Error processing bot message: {str(e)}") + + def _run_dashboard(self): + """Run the dashboard""" + try: + self.dashboard.run_server(debug=True, port=8050) + except Exception as e: + logger.error(f"Error running dashboard: {str(e)}") + + def stop(self): + """Stop the AI Agent Manager""" + self.running = False + + # Stop all bots + for bot_id in self.bots: + self.stop_bot(bot_id) + + # Stop components + self.code_guardian.stop() + self.system_monitor.stop() + + # Wait for threads + for thread in self.threads.values(): + if thread.is_alive(): + thread.join() + +def create_agent_manager(project_root: str) -> AIAgentManager: + """Create and initialize an AI Agent Manager""" + return AIAgentManager(project_root) + +if __name__ == "__main__": + # Example usage + manager = create_agent_manager(".") + + try: + # Create some test bots + config1 = { + "trading": {"initial_capital": 100000}, + "strategy": {"name": "trend_following"}, + "risk_management": {"max_positions": 5} + } + + config2 = { + "trading": {"initial_capital": 50000}, + "strategy": {"name": "mean_reversion"}, + "risk_management": {"max_positions": 3} + } + + # Create and start bots + bot1_id = manager.create_bot(config1) + bot2_id = manager.create_bot(config2) + + manager.start_bot(bot1_id) + manager.start_bot(bot2_id) + + # Monitor for a while + time.sleep(3600) # Run for 1 hour + + finally: + manager.stop() \ No newline at end of file diff --git a/backtesting 2.0.py b/backtesting 2.0.py new file mode 100644 index 0000000..cf2c18a --- /dev/null +++ b/backtesting 2.0.py @@ -0,0 +1,266 @@ +import pandas as pd +import numpy as np +from datetime import datetime, timedelta +import logging +from typing import Dict, List, Optional +import ccxt +from concurrent.futures import ThreadPoolExecutor +import json +import os + +from .trading_strategy import TradingStrategy +from .config import load_config + +logger = logging.getLogger(__name__) + +class Backtester: + def __init__(self, config_path: str): + # Load configuration + self.config = load_config(config_path) + + # Initialize exchange + self.exchange = self._initialize_exchange() + + # Initialize trading strategy + self.strategy = TradingStrategy(self.config) + + # Initialize results storage + self.results = { + 'trades': [], + 'equity_curve': [], + 'performance_metrics': {} + } + + def _initialize_exchange(self) -> ccxt.Exchange: + """Initialize the cryptocurrency exchange""" + try: + exchange_class = getattr(ccxt, self.config['exchange']['name']) + exchange = exchange_class({ + 'apiKey': self.config['exchange']['api_key'], + 'secret': self.config['exchange']['api_secret'], + 'enableRateLimit': True + }) + + # Test connection + exchange.load_markets() + logger.info(f"Successfully connected to {self.config['exchange']['name']}") + + return exchange + + except Exception as e: + logger.error(f"Error initializing exchange: {str(e)}") + raise + + def fetch_historical_data(self, + symbol: str, + timeframe: str, + start_date: datetime, + end_date: datetime) -> pd.DataFrame: + """Fetch historical market data""" + try: + # Convert dates to timestamps + start_timestamp = int(start_date.timestamp() * 1000) + end_timestamp = int(end_date.timestamp() * 1000) + + # Fetch OHLCV data + ohlcv = self.exchange.fetch_ohlcv( + symbol, + timeframe=timeframe, + since=start_timestamp, + limit=1000 # Maximum limit per request + ) + + # Convert to DataFrame + df = pd.DataFrame( + ohlcv, + columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'] + ) + + # Convert timestamp to datetime + df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') + df.set_index('timestamp', inplace=True) + + return df + + except Exception as e: + logger.error(f"Error fetching historical data for {symbol}: {str(e)}") + return None + + def run_backtest(self, + symbol: str, + timeframe: str, + start_date: datetime, + end_date: datetime, + initial_capital: float = 50.0) -> Dict: + """Run backtest for a given period""" + try: + logger.info(f"Starting backtest for {symbol} from {start_date} to {end_date}") + + # Fetch historical data + df = self.fetch_historical_data(symbol, timeframe, start_date, end_date) + if df is None: + raise ValueError("Failed to fetch historical data") + + # Initialize variables + current_capital = initial_capital + position = 0 + entry_price = 0 + trades = [] + equity_curve = [] + + # Iterate through data + for i in range(len(df)): + current_data = df.iloc[:i+1] + current_price = current_data['close'].iloc[-1] + + # Generate trading signal + signal = self.strategy.analyze_market(symbol, current_data) + + if signal: + # Execute trade if conditions are met + if signal.action == 'buy' and position <= 0: + position = 1 + entry_price = current_price + trades.append({ + 'timestamp': current_data.index[-1], + 'action': 'buy', + 'price': current_price, + 'position_size': signal.position_size + }) + + elif signal.action == 'sell' and position >= 0: + position = -1 + entry_price = current_price + trades.append({ + 'timestamp': current_data.index[-1], + 'action': 'sell', + 'price': current_price, + 'position_size': signal.position_size + }) + + # Update position PnL + if position != 0: + pnl = position * (current_price - entry_price) * signal.position_size + current_capital += pnl + + # Record equity + equity_curve.append({ + 'timestamp': current_data.index[-1], + 'equity': current_capital + }) + + # Calculate performance metrics + self.results['trades'] = trades + self.results['equity_curve'] = equity_curve + self.results['performance_metrics'] = self._calculate_performance_metrics(trades) + + return self.results + + except Exception as e: + logger.error(f"Error running backtest: {str(e)}") + return None + + def _calculate_performance_metrics(self, trades: List[Dict]) -> Dict: + """Calculate performance metrics from trades""" + if not trades: + return {} + + # Convert trades to DataFrame + df = pd.DataFrame(trades) + + # Calculate basic metrics + total_trades = len(df) + winning_trades = len(df[df['action'] == 'buy']) + losing_trades = len(df[df['action'] == 'sell']) + win_rate = winning_trades / total_trades if total_trades > 0 else 0 + + # Calculate returns + returns = df['price'].pct_change() + total_return = (1 + returns).prod() - 1 + annual_return = (1 + total_return) ** (252 / len(df)) - 1 + + # Calculate risk metrics + volatility = returns.std() * np.sqrt(252) + sharpe_ratio = annual_return / volatility if volatility > 0 else 0 + + # Calculate drawdown + cumulative_returns = (1 + returns).cumprod() + rolling_max = cumulative_returns.expanding().max() + drawdowns = (cumulative_returns - rolling_max) / rolling_max + max_drawdown = drawdowns.min() + + return { + 'total_trades': total_trades, + 'winning_trades': winning_trades, + 'losing_trades': losing_trades, + 'win_rate': win_rate, + 'total_return': total_return, + 'annual_return': annual_return, + 'volatility': volatility, + 'sharpe_ratio': sharpe_ratio, + 'max_drawdown': max_drawdown + } + + def save_results(self, filepath: str): + """Save backtest results to file""" + try: + with open(filepath, 'w') as f: + json.dump(self.results, f, default=str) + logger.info(f"Backtest results saved to {filepath}") + return True + except Exception as e: + logger.error(f"Error saving results: {str(e)}") + return False + + def load_results(self, filepath: str): + """Load backtest results from file""" + try: + with open(filepath, 'r') as f: + self.results = json.load(f) + logger.info(f"Backtest results loaded from {filepath}") + return True + except Exception as e: + logger.error(f"Error loading results: {str(e)}") + return False + +def main(): + # Load configuration + config_path = os.path.join(os.path.dirname(__file__), '..', 'config', 'config.json') + + # Create backtester + backtester = Backtester(config_path) + + # Define backtest parameters + symbol = "BTC/USDT" + timeframe = "1h" + start_date = datetime.now() - timedelta(days=30) + end_date = datetime.now() + initial_capital = 50.0 + + # Run backtest + results = backtester.run_backtest( + symbol=symbol, + timeframe=timeframe, + start_date=start_date, + end_date=end_date, + initial_capital=initial_capital + ) + + if results: + # Print performance metrics + metrics = results['performance_metrics'] + print("\nBacktest Results:") + print(f"Total Trades: {metrics['total_trades']}") + print(f"Win Rate: {metrics['win_rate']:.2%}") + print(f"Total Return: {metrics['total_return']:.2%}") + print(f"Annual Return: {metrics['annual_return']:.2%}") + print(f"Sharpe Ratio: {metrics['sharpe_ratio']:.2f}") + print(f"Max Drawdown: {metrics['max_drawdown']:.2%}") + + # Save results + backtester.save_results('backtest_results.json') + else: + print("Backtest failed to complete") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/code_guardian 2.0.py b/code_guardian 2.0.py new file mode 100644 index 0000000..6cdc8dd --- /dev/null +++ b/code_guardian 2.0.py @@ -0,0 +1,287 @@ +import inspect +import logging +import sys +import traceback +import ast +import typing +from dataclasses import dataclass +from typing import Dict, List, Optional, Any, Tuple +import numpy as np +from datetime import datetime +import importlib +import threading +import time +import json +import os + +logger = logging.getLogger(__name__) + +@dataclass +class CodeIssue: + """Represents a code issue found by the guardian""" + file_path: str + line_number: int + issue_type: str + description: str + severity: str + suggested_fix: Optional[str] = None + fixed: bool = False + +class CodeGuardian: + def __init__(self, project_root: str): + self.project_root = project_root + self.issues: List[CodeIssue] = [] + self.module_states: Dict[str, float] = {} # Module path -> last modified timestamp + self.performance_metrics: Dict[str, List[float]] = {} + self.error_patterns: Dict[str, str] = self._load_error_patterns() + + # Start monitoring thread + self.running = True + self.monitor_thread = threading.Thread(target=self._continuous_monitoring) + self.monitor_thread.daemon = True + self.monitor_thread.start() + + def _load_error_patterns(self) -> Dict[str, str]: + """Load known error patterns and their fixes""" + return { + "IndexError": "Check array bounds and data availability", + "KeyError": "Verify dictionary keys exist before access", + "AttributeError": "Ensure object attributes exist", + "TypeError": "Check type compatibility", + "ValueError": "Validate input values", + "ZeroDivisionError": "Add zero-value checking", + "ImportError": "Verify module installation and import path", + "MemoryError": "Optimize memory usage or add cleanup", + "RuntimeError": "Check execution flow and state", + } + + def analyze_code(self, file_path: str) -> List[CodeIssue]: + """Analyze code for potential issues""" + try: + with open(file_path, 'r') as f: + code = f.read() + + issues = [] + tree = ast.parse(code) + + # Check for common issues + issues.extend(self._check_error_handling(tree, file_path)) + issues.extend(self._check_resource_management(tree, file_path)) + issues.extend(self._check_performance_patterns(tree, file_path)) + issues.extend(self._check_code_style(tree, file_path)) + + return issues + + except Exception as e: + logger.error(f"Error analyzing {file_path}: {str(e)}") + return [] + + def _check_error_handling(self, tree: ast.AST, file_path: str) -> List[CodeIssue]: + """Check for proper error handling""" + issues = [] + for node in ast.walk(tree): + # Check for bare except clauses + if isinstance(node, ast.Try): + for handler in node.handlers: + if handler.type is None: + issues.append(CodeIssue( + file_path=file_path, + line_number=handler.lineno, + issue_type="error_handling", + description="Bare except clause found", + severity="warning", + suggested_fix="Specify exception type(s) to catch" + )) + return issues + + def _check_resource_management(self, tree: ast.AST, file_path: str) -> List[CodeIssue]: + """Check for proper resource management""" + issues = [] + for node in ast.walk(tree): + # Check for file operations without context manager + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Name) and node.func.id in ['open']: + if not isinstance(node.parent, ast.withitem): + issues.append(CodeIssue( + file_path=file_path, + line_number=node.lineno, + issue_type="resource_management", + description="File opened without context manager", + severity="warning", + suggested_fix="Use 'with' statement for file operations" + )) + return issues + + def _check_performance_patterns(self, tree: ast.AST, file_path: str) -> List[CodeIssue]: + """Check for performance-related issues""" + issues = [] + for node in ast.walk(tree): + # Check for inefficient list operations + if isinstance(node, ast.For): + if isinstance(node.target, ast.Name) and isinstance(node.iter, ast.Call): + if isinstance(node.iter.func, ast.Name) and node.iter.func.id == 'range': + if len(node.iter.args) == 1 and isinstance(node.iter.args[0], ast.Call): + if isinstance(node.iter.args[0].func, ast.Name) and node.iter.args[0].func.id == 'len': + issues.append(CodeIssue( + file_path=file_path, + line_number=node.lineno, + issue_type="performance", + description="Inefficient list iteration", + severity="info", + suggested_fix="Use 'for item in items' instead of range(len(items))" + )) + return issues + + def _check_code_style(self, tree: ast.AST, file_path: str) -> List[CodeIssue]: + """Check for code style issues""" + issues = [] + for node in ast.walk(tree): + # Check for overly complex functions + if isinstance(node, ast.FunctionDef): + if len(node.body) > 50: # Arbitrary threshold + issues.append(CodeIssue( + file_path=file_path, + line_number=node.lineno, + issue_type="code_style", + description="Function is too long", + severity="info", + suggested_fix="Consider breaking down into smaller functions" + )) + return issues + + def monitor_performance(self, module_name: str, execution_time: float): + """Monitor module performance""" + if module_name not in self.performance_metrics: + self.performance_metrics[module_name] = [] + + self.performance_metrics[module_name].append(execution_time) + + # Check for performance degradation + if len(self.performance_metrics[module_name]) > 10: + recent_avg = np.mean(self.performance_metrics[module_name][-10:]) + overall_avg = np.mean(self.performance_metrics[module_name]) + + if recent_avg > overall_avg * 1.5: # 50% slower than average + self.issues.append(CodeIssue( + file_path=module_name, + line_number=0, + issue_type="performance_degradation", + description=f"Performance degradation detected in {module_name}", + severity="warning" + )) + + def fix_issue(self, issue: CodeIssue) -> bool: + """Attempt to fix a code issue""" + try: + if not issue.suggested_fix: + return False + + with open(issue.file_path, 'r') as f: + lines = f.readlines() + + if issue.issue_type == "error_handling": + # Fix bare except + if "Bare except clause found" in issue.description: + lines[issue.line_number - 1] = lines[issue.line_number - 1].replace( + "except:", "except Exception:" + ) + + elif issue.issue_type == "resource_management": + # Fix file operations + if "File opened without context manager" in issue.description: + indent = len(lines[issue.line_number - 1]) - len(lines[issue.line_number - 1].lstrip()) + lines[issue.line_number - 1] = " " * indent + "with " + lines[issue.line_number - 1].lstrip() + + with open(issue.file_path, 'w') as f: + f.writelines(lines) + + issue.fixed = True + return True + + except Exception as e: + logger.error(f"Error fixing issue: {str(e)}") + return False + + def _continuous_monitoring(self): + """Continuously monitor code for issues""" + while self.running: + try: + # Check all Python files in project + for root, _, files in os.walk(self.project_root): + for file in files: + if file.endswith('.py'): + file_path = os.path.join(root, file) + + # Check if file was modified + current_mtime = os.path.getmtime(file_path) + if file_path not in self.module_states or current_mtime > self.module_states[file_path]: + self.module_states[file_path] = current_mtime + + # Analyze code + new_issues = self.analyze_code(file_path) + self.issues.extend(new_issues) + + # Try to fix issues + for issue in new_issues: + if issue.suggested_fix: + self.fix_issue(issue) + + # Sleep for a while + time.sleep(60) # Check every minute + + except Exception as e: + logger.error(f"Error in continuous monitoring: {str(e)}") + time.sleep(300) # Wait longer if there's an error + + def get_status_report(self) -> Dict[str, Any]: + """Generate a status report""" + return { + 'total_issues': len(self.issues), + 'fixed_issues': len([i for i in self.issues if i.fixed]), + 'active_issues': len([i for i in self.issues if not i.fixed]), + 'issues_by_type': self._count_issues_by_type(), + 'performance_metrics': self._summarize_performance_metrics() + } + + def _count_issues_by_type(self) -> Dict[str, int]: + """Count issues by type""" + counts = {} + for issue in self.issues: + if issue.issue_type not in counts: + counts[issue.issue_type] = 0 + counts[issue.issue_type] += 1 + return counts + + def _summarize_performance_metrics(self) -> Dict[str, Dict[str, float]]: + """Summarize performance metrics""" + summary = {} + for module, metrics in self.performance_metrics.items(): + if metrics: + summary[module] = { + 'avg': np.mean(metrics), + 'min': np.min(metrics), + 'max': np.max(metrics), + 'std': np.std(metrics) + } + return summary + + def stop(self): + """Stop the guardian""" + self.running = False + if self.monitor_thread.is_alive(): + self.monitor_thread.join() + +def create_guardian(project_root: str) -> CodeGuardian: + """Create and start a code guardian instance""" + return CodeGuardian(project_root) + +if __name__ == "__main__": + # Example usage + guardian = create_guardian(".") + try: + while True: + status = guardian.get_status_report() + print(json.dumps(status, indent=2)) + time.sleep(300) # Print status every 5 minutes + except KeyboardInterrupt: + guardian.stop() \ No newline at end of file diff --git a/config 2.0.2.json b/config 2.0.2.json new file mode 100644 index 0000000..8c77250 --- /dev/null +++ b/config 2.0.2.json @@ -0,0 +1,105 @@ +{ + "exchange": { + "name": "binance", + "api_key": "YOUR_API_KEY", + "api_secret": "YOUR_API_SECRET", + "testnet": true + }, + "trading": { + "symbols": ["BTC/USDT", "ETH/USDT"], + "timeframes": ["1m", "5m", "15m", "1h", "4h", "1d"], + "lookback_periods": 100, + "state_file": "trading_state.json", + "initial_capital": 50.0, + "max_positions": 3, + "leverage": 1 + }, + "risk_management": { + "risk_per_trade": 0.02, + "max_daily_loss": 0.05, + "max_drawdown": 0.15, + "stop_loss_pct": 0.02, + "take_profit_pct": 0.04, + "min_win_rate": 0.45, + "min_profit_factor": 1.2 + }, + "technical_analysis": { + "indicators": { + "sma": [20, 50, 200], + "ema": [20], + "rsi": [14], + "macd": { + "fast": 12, + "slow": 26, + "signal": 9 + }, + "bollinger_bands": { + "period": 20, + "std_dev": 2 + } + }, + "patterns": { + "candlestick": true, + "chart": true + } + }, + "machine_learning": { + "model_type": "lstm", + "features": [ + "open", "high", "low", "close", "volume", + "sma_20", "sma_50", "sma_200", + "rsi_14", "macd", "macd_signal", "macd_hist", + "bb_upper", "bb_middle", "bb_lower" + ], + "train_test_split": 0.2, + "validation_split": 0.1, + "rl": { + "learning_rate": 0.0003, + "n_steps": 2048, + "batch_size": 64, + "n_epochs": 10, + "gamma": 0.99, + "gae_lambda": 0.95, + "clip_range": 0.2, + "ent_coef": 0.01, + "vf_coef": 0.5 + } + }, + "sentiment_analysis": { + "news_api_key": "YOUR_NEWS_API_KEY", + "twitter_api_key": "YOUR_TWITTER_API_KEY", + "twitter_api_secret": "YOUR_TWITTER_API_SECRET", + "twitter_access_token": "YOUR_TWITTER_ACCESS_TOKEN", + "twitter_access_token_secret": "YOUR_TWITTER_ACCESS_TOKEN_SECRET", + "sentiment_weights": { + "news": 0.4, + "twitter": 0.3, + "market": 0.3 + }, + "sentiment_thresholds": { + "positive": 0.3, + "negative": -0.3 + } + }, + "signal_weights": { + "technical": 0.4, + "ml": 0.3, + "sentiment": 0.2, + "risk": 0.1 + }, + "signal_thresholds": { + "buy": 0.6, + "sell": -0.6 + }, + "logging": { + "level": "INFO", + "file": "trading_bot.log", + "max_size": 10485760, + "backup_count": 5 + }, + "web_dashboard": { + "host": "localhost", + "port": 5000, + "debug": false + } +} \ No newline at end of file diff --git a/config 2.0.py b/config 2.0.py new file mode 100644 index 0000000..5d56fb1 --- /dev/null +++ b/config 2.0.py @@ -0,0 +1,134 @@ +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +# Exchange Configuration +EXCHANGE_CONFIG = { + 'name': 'binance', + 'api_key': os.getenv('BINANCE_API_KEY', ''), + 'api_secret': os.getenv('BINANCE_API_SECRET', ''), + 'testnet': True # Use testnet for development +} + +# Trading Parameters +TRADING_CONFIG = { + 'symbols': ['BTC/USDT', 'ETH/USDT', 'EUR/USD'], + 'timeframes': ['1h', '4h', '1d'], + 'initial_capital': 10000, + 'risk_per_trade': 0.02, # 2% risk per trade + 'max_positions': 3, + 'position_sizing': { + 'method': 'fixed_fractional', + 'fraction': 0.02 # 2% of capital per trade + } +} + +# Technical Analysis Parameters +TECHNICAL_CONFIG = { + 'indicators': { + 'bollinger_bands': { + 'period': 20, + 'std_dev': 2 + }, + 'rsi': { + 'period': 14, + 'overbought': 70, + 'oversold': 30 + }, + 'macd': { + 'fast_period': 12, + 'slow_period': 26, + 'signal_period': 9 + }, + 'atr': { + 'period': 14 + } + }, + 'patterns': { + 'head_and_shoulders': True, + 'double_top_bottom': True, + 'triangles': True + } +} + +# Machine Learning Configuration +ML_CONFIG = { + 'model_type': 'lstm', # Options: 'lstm', 'rf', 'xgboost' + 'features': [ + 'open', 'high', 'low', 'close', 'volume', + 'sma_20', 'sma_50', 'rsi', 'macd', 'atr', + 'bb_upper', 'bb_lower', 'bb_width' + ], + 'sequence_length': 10, + 'prediction_horizon': 1, + 'train_test_split': 0.8, + 'validation_split': 0.1 +} + +# Reinforcement Learning Configuration +RL_CONFIG = { + 'algorithm': 'PPO', + 'learning_rate': 0.0003, + 'n_steps': 2048, + 'batch_size': 64, + 'n_epochs': 10, + 'gamma': 0.99, + 'gae_lambda': 0.95, + 'clip_range': 0.2, + 'ent_coef': 0.01, + 'vf_coef': 0.5 +} + +# Risk Management Configuration +RISK_CONFIG = { + 'stop_loss': { + 'method': 'atr', + 'atr_multiplier': 2 + }, + 'take_profit': { + 'method': 'risk_reward', + 'risk_reward_ratio': 2 + }, + 'trailing_stop': { + 'enabled': True, + 'activation_percentage': 0.02, + 'trail_percentage': 0.01 + } +} + +# Sentiment Analysis Configuration +SENTIMENT_CONFIG = { + 'sources': [ + 'reuters', + 'bloomberg', + 'forexfactory' + ], + 'update_interval': 3600, # 1 hour + 'weight': 0.2 # Weight in final decision +} + +# Backtesting Configuration +BACKTEST_CONFIG = { + 'start_date': '2020-01-01', + 'end_date': '2023-12-31', + 'initial_capital': 10000, + 'commission': 0.001, # 0.1% + 'slippage': 0.0001 # 0.01% +} + +# Logging Configuration +LOGGING_CONFIG = { + 'level': 'INFO', + 'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + 'file': 'logs/trading_bot.log' +} + +# Web Dashboard Configuration +DASHBOARD_CONFIG = { + 'host': '0.0.0.0', + 'port': 5000, + 'debug': False, + 'update_interval': 5 # seconds +} \ No newline at end of file diff --git a/dashboard 2.0.py b/dashboard 2.0.py new file mode 100644 index 0000000..2ebae54 --- /dev/null +++ b/dashboard 2.0.py @@ -0,0 +1,372 @@ +import dash +from dash import dcc, html +from dash.dependencies import Input, Output, State +import plotly.graph_objects as go +from plotly.subplots import make_subplots +import pandas as pd +import json +import os +from datetime import datetime +import numpy as np +from .code_guardian import create_guardian, CodeGuardian + +def load_backtest_results(results_dir): + """Load all backtest results from directory""" + results = {} + for file in os.listdir(results_dir): + if file.startswith('backtest_results_') and file.endswith('.json'): + with open(os.path.join(results_dir, file), 'r') as f: + scenario_name = file.replace('backtest_results_', '').replace('.json', '') + results[scenario_name] = json.load(f) + return results + +def create_dashboard(results_dir='backtest_results'): + """Create and run the dashboard""" + app = dash.Dash(__name__) + + # Load results + results = load_backtest_results(results_dir) + + # Initialize Code Guardian + guardian = create_guardian(os.path.dirname(os.path.dirname(__file__))) + + # Dashboard layout + app.layout = html.Div([ + # Header + html.Div([ + html.H1('AI Trading Bot - Backtest Results & System Health Dashboard', + style={'textAlign': 'center', 'color': '#2c3e50', 'marginBottom': 30}), + ], style={'backgroundColor': '#ecf0f1', 'padding': '20px'}), + + # Tabs for different sections + dcc.Tabs([ + # Backtest Results Tab + dcc.Tab(label='Backtest Results', children=[ + # Scenario Selection + html.Div([ + html.Label('Select Scenario:'), + dcc.Dropdown( + id='scenario-dropdown', + options=[{'label': k, 'value': k} for k in results.keys()], + value=list(results.keys())[0] if results else None, + style={'width': '100%'} + ), + ], style={'margin': '20px'}), + + # Main Charts + html.Div([ + # Trading Chart + html.Div([ + dcc.Graph(id='trading-chart') + ], style={'width': '100%', 'marginBottom': '20px'}), + + # Performance Metrics Cards + html.Div([ + html.Div([ + html.Div(id='metrics-cards'), + ], style={'display': 'flex', 'flexWrap': 'wrap', 'justifyContent': 'space-around'}) + ], style={'marginBottom': '20px'}), + + # Trade Distribution Chart + html.Div([ + dcc.Graph(id='trade-distribution') + ], style={'width': '100%', 'marginBottom': '20px'}), + + # Drawdown Chart + html.Div([ + dcc.Graph(id='drawdown-chart') + ], style={'width': '100%'}) + ], style={'padding': '20px'}) + ]), + + # System Health Tab + dcc.Tab(label='System Health', children=[ + html.Div([ + # Code Health Overview + html.Div([ + html.H2('Code Health Overview', style={'textAlign': 'center'}), + html.Div(id='code-health-cards', style={ + 'display': 'flex', + 'flexWrap': 'wrap', + 'justifyContent': 'space-around', + 'margin': '20px' + }) + ]), + + # Code Issues Table + html.Div([ + html.H3('Active Code Issues'), + html.Div(id='code-issues-table') + ], style={'margin': '20px'}), + + # Performance Metrics + html.Div([ + html.H3('Module Performance'), + dcc.Graph(id='performance-chart') + ], style={'margin': '20px'}), + + # Auto-Fix Controls + html.Div([ + html.H3('Issue Resolution'), + html.Button('Auto-Fix Selected Issues', id='auto-fix-button'), + html.Div(id='auto-fix-status') + ], style={'margin': '20px'}) + ]) + ]), + + # System Logs Tab + dcc.Tab(label='System Logs', children=[ + html.Div([ + html.H2('System Logs'), + dcc.Interval(id='log-update', interval=5000), # Update every 5 seconds + html.Pre(id='log-content', style={ + 'backgroundColor': '#2c3e50', + 'color': '#ecf0f1', + 'padding': '20px', + 'borderRadius': '5px', + 'height': '500px', + 'overflow': 'auto' + }) + ], style={'margin': '20px'}) + ]) + ]) + ]) + + @app.callback( + [Output('trading-chart', 'figure'), + Output('metrics-cards', 'children'), + Output('trade-distribution', 'figure'), + Output('drawdown-chart', 'figure')], + [Input('scenario-dropdown', 'value')] + ) + def update_charts(selected_scenario): + if not selected_scenario or selected_scenario not in results: + return {}, [], {}, {} + + result = results[selected_scenario] + trades_df = pd.DataFrame(result['trades']) + equity_df = pd.DataFrame(result['equity_curve']) + metrics = result['performance_metrics'] + + # 1. Trading Chart + trading_fig = make_subplots( + rows=2, cols=1, + shared_xaxes=True, + vertical_spacing=0.03, + subplot_titles=('Price and Trades', 'Equity Curve'), + row_heights=[0.7, 0.3] + ) + + # Add price line + trading_fig.add_trace( + go.Scatter( + x=trades_df['timestamp'], + y=trades_df['price'], + name='Price', + line=dict(color='#2980b9') + ), + row=1, col=1 + ) + + # Add buy/sell markers + for action, color in [('buy', '#27ae60'), ('sell', '#c0392b')]: + mask = trades_df['action'] == action + trading_fig.add_trace( + go.Scatter( + x=trades_df[mask]['timestamp'], + y=trades_df[mask]['price'], + mode='markers', + name=action.capitalize(), + marker=dict(color=color, size=10) + ), + row=1, col=1 + ) + + # Add equity curve + trading_fig.add_trace( + go.Scatter( + x=equity_df['timestamp'], + y=equity_df['equity'], + name='Equity', + line=dict(color='#8e44ad') + ), + row=2, col=1 + ) + + trading_fig.update_layout( + title='Trading Activity and Equity Curve', + height=800, + template='plotly_white' + ) + + # 2. Metrics Cards + cards = [] + metrics_style = { + 'width': '200px', + 'margin': '10px', + 'padding': '15px', + 'borderRadius': '5px', + 'boxShadow': '2px 2px 5px rgba(0,0,0,0.1)', + 'textAlign': 'center' + } + + metrics_data = [ + ('Total Return', f"{metrics['total_return']:.2%}", '#27ae60'), + ('Win Rate', f"{metrics['win_rate']:.2%}", '#2980b9'), + ('Sharpe Ratio', f"{metrics['sharpe_ratio']:.2f}", '#8e44ad'), + ('Max Drawdown', f"{metrics['max_drawdown']:.2%}", '#c0392b'), + ('Total Trades', str(metrics['total_trades']), '#2c3e50') + ] + + for label, value, color in metrics_data: + cards.append(html.Div([ + html.H4(label, style={'color': '#7f8c8d'}), + html.H3(value, style={'color': color}) + ], style=metrics_style)) + + # 3. Trade Distribution + returns = pd.Series([float(x) for x in trades_df['price'].pct_change().dropna()]) + dist_fig = go.Figure() + dist_fig.add_trace(go.Histogram( + x=returns, + nbinsx=30, + name='Returns Distribution', + marker_color='#3498db' + )) + + dist_fig.update_layout( + title='Trade Returns Distribution', + xaxis_title='Return', + yaxis_title='Frequency', + template='plotly_white' + ) + + # 4. Drawdown Chart + equity_series = pd.Series([float(x) for x in equity_df['equity']]) + rolling_max = equity_series.expanding().max() + drawdowns = (equity_series - rolling_max) / rolling_max + + dd_fig = go.Figure() + dd_fig.add_trace(go.Scatter( + x=equity_df['timestamp'], + y=drawdowns, + fill='tozeroy', + name='Drawdown', + line=dict(color='#e74c3c') + )) + + dd_fig.update_layout( + title='Drawdown Over Time', + xaxis_title='Date', + yaxis_title='Drawdown', + template='plotly_white' + ) + + return trading_fig, cards, dist_fig, dd_fig + + @app.callback( + [Output('code-health-cards', 'children'), + Output('code-issues-table', 'children'), + Output('performance-chart', 'figure'), + Output('auto-fix-status', 'children')], + [Input('auto-fix-button', 'n_clicks')], + [State('code-issues-table', 'selected_rows')] + ) + def update_system_health(n_clicks, selected_rows): + # Get guardian status + status = guardian.get_status_report() + + # Create health cards + health_cards = [] + health_metrics = [ + ('Total Issues', status['total_issues'], '#e74c3c'), + ('Fixed Issues', status['fixed_issues'], '#27ae60'), + ('Active Issues', status['active_issues'], '#f39c12'), + ('Code Coverage', '85%', '#3498db') # Example metric + ] + + for label, value, color in health_metrics: + health_cards.append(html.Div([ + html.H4(label), + html.H3(str(value)) + ], style={ + 'width': '200px', + 'margin': '10px', + 'padding': '15px', + 'borderRadius': '5px', + 'boxShadow': '2px 2px 5px rgba(0,0,0,0.1)', + 'textAlign': 'center', + 'backgroundColor': color, + 'color': 'white' + })) + + # Create issues table + issues_table = html.Table([ + html.Thead(html.Tr([ + html.Th('File'), + html.Th('Line'), + html.Th('Type'), + html.Th('Severity'), + html.Th('Description'), + html.Th('Status') + ])), + html.Tbody([ + html.Tr([ + html.Td(issue.file_path), + html.Td(issue.line_number), + html.Td(issue.issue_type), + html.Td(issue.severity), + html.Td(issue.description), + html.Td('Fixed' if issue.fixed else 'Active') + ]) for issue in guardian.issues + ]) + ], style={'width': '100%'}) + + # Create performance chart + perf_data = status['performance_metrics'] + perf_fig = go.Figure() + + for module, metrics in perf_data.items(): + perf_fig.add_trace(go.Scatter( + x=list(range(len(guardian.performance_metrics[module]))), + y=guardian.performance_metrics[module], + name=module, + mode='lines+markers' + )) + + perf_fig.update_layout( + title='Module Performance Over Time', + xaxis_title='Execution Count', + yaxis_title='Execution Time (s)', + template='plotly_white' + ) + + # Handle auto-fix status + fix_status = None + if n_clicks and selected_rows: + fixed_count = sum(1 for i in selected_rows if guardian.fix_issue(guardian.issues[i])) + fix_status = f"Fixed {fixed_count} out of {len(selected_rows)} selected issues" + + return health_cards, issues_table, perf_fig, fix_status + + @app.callback( + Output('log-content', 'children'), + [Input('log-update', 'n_intervals')] + ) + def update_logs(_): + try: + with open('analysis.log', 'r') as f: + logs = f.readlines() + return ''.join(logs[-100:]) # Show last 100 lines + except Exception as e: + return f"Error reading logs: {str(e)}" + + return app + +def run_dashboard(port=8050): + """Run the dashboard""" + app = create_dashboard() + app.run_server(debug=True, port=port) + +if __name__ == '__main__': + run_dashboard() \ No newline at end of file diff --git a/machine_learning 2.0.py b/machine_learning 2.0.py new file mode 100644 index 0000000..688ec63 --- /dev/null +++ b/machine_learning 2.0.py @@ -0,0 +1,271 @@ +import numpy as np +import pandas as pd +from sklearn.preprocessing import StandardScaler +from sklearn.model_selection import train_test_split +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import LSTM, Dense, Dropout +from tensorflow.keras.optimizers import Adam +from stable_baselines3 import PPO +from stable_baselines3.common.vec_env import DummyVecEnv +import gym +import logging +from typing import Dict, List, Tuple, Optional +import joblib +import os + +logger = logging.getLogger(__name__) + +class MachineLearningModel: + def __init__(self, config: Dict): + self.config = config + self.model_type = config['model_type'] + self.features = config['features'] + self.scaler = StandardScaler() + self.model = None + self.env = None + + def prepare_data(self, df: pd.DataFrame) -> Tuple[np.ndarray, np.ndarray]: + """ + Prepare data for machine learning + """ + # Select features + X = df[self.features].copy() + + # Create target variable (price movement direction) + y = np.where(df['close'].shift(-1) > df['close'], 1, 0) + + # Drop NaN values + valid_idx = ~np.isnan(y) + X = X[valid_idx] + y = y[valid_idx] + + # Scale features + X_scaled = self.scaler.fit_transform(X) + + return X_scaled, y + + def train_lstm(self, X: np.ndarray, y: np.ndarray): + """ + Train LSTM model + """ + # Reshape data for LSTM [samples, time steps, features] + X_reshaped = np.reshape(X, (X.shape[0], 1, X.shape[1])) + + # Split data + X_train, X_test, y_train, y_test = train_test_split( + X_reshaped, y, + test_size=self.config['train_test_split'], + random_state=42 + ) + + # Create model + model = Sequential([ + LSTM(50, activation='relu', input_shape=(1, X.shape[1]), return_sequences=True), + Dropout(0.2), + LSTM(50, activation='relu'), + Dropout(0.2), + Dense(1, activation='sigmoid') + ]) + + # Compile model + model.compile( + optimizer=Adam(learning_rate=0.001), + loss='binary_crossentropy', + metrics=['accuracy'] + ) + + # Train model + model.fit( + X_train, y_train, + epochs=50, + batch_size=32, + validation_split=self.config['validation_split'], + verbose=0 + ) + + # Evaluate model + _, accuracy = model.evaluate(X_test, y_test, verbose=0) + logger.info(f"LSTM model accuracy: {accuracy:.4f}") + + self.model = model + return model + + def train_reinforcement_learning(self, df: pd.DataFrame): + """ + Train reinforcement learning model + """ + # Create custom trading environment + self.env = TradingEnvironment(df) + self.env = DummyVecEnv([lambda: self.env]) + + # Create and train PPO model + model = PPO( + "MlpPolicy", + self.env, + learning_rate=self.config['rl']['learning_rate'], + n_steps=self.config['rl']['n_steps'], + batch_size=self.config['rl']['batch_size'], + n_epochs=self.config['rl']['n_epochs'], + gamma=self.config['rl']['gamma'], + gae_lambda=self.config['rl']['gae_lambda'], + clip_range=self.config['rl']['clip_range'], + ent_coef=self.config['rl']['ent_coef'], + vf_coef=self.config['rl']['vf_coef'], + verbose=1 + ) + + # Train model + model.learn(total_timesteps=10000) + + self.model = model + return model + + def predict(self, X: np.ndarray) -> np.ndarray: + """ + Make predictions using the trained model + """ + if self.model is None: + logger.error("Model not trained. Call train() first.") + return None + + if self.model_type == 'lstm': + X_reshaped = np.reshape(X, (X.shape[0], 1, X.shape[1])) + predictions = self.model.predict(X_reshaped) + else: # reinforcement learning + predictions = self.model.predict(X) + + return predictions + + def save_model(self, filepath: str): + """ + Save the trained model + """ + if self.model is None: + logger.error("Model not trained. Call train() first.") + return None + + try: + if self.model_type == 'lstm': + self.model.save(filepath) + else: + self.model.save(f"{filepath}_rl") + + # Save scaler separately + joblib.dump(self.scaler, f"{filepath}_scaler") + + logger.info(f"Model saved to {filepath}") + return True + except Exception as e: + logger.error(f"Error saving model: {str(e)}") + return False + + def load_model(self, filepath: str): + """ + Load a trained model + """ + try: + if self.model_type == 'lstm': + self.model = tf.keras.models.load_model(filepath) + else: + self.model = PPO.load(f"{filepath}_rl") + + # Load scaler + self.scaler = joblib.load(f"{filepath}_scaler") + + logger.info(f"Model loaded from {filepath}") + return True + except Exception as e: + logger.error(f"Error loading model: {str(e)}") + return False + + +class TradingEnvironment(gym.Env): + """ + Custom trading environment for reinforcement learning + """ + def __init__(self, df: pd.DataFrame): + super(TradingEnvironment, self).__init__() + + self.df = df + self.current_step = 0 + self.initial_balance = 10000 + self.balance = self.initial_balance + self.position = 0 + self.position_size = 0 + + # Define action and observation space + self.action_space = gym.spaces.Discrete(3) # Buy, Sell, Hold + self.observation_space = gym.spaces.Box( + low=-np.inf, + high=np.inf, + shape=(len(df.columns),), + dtype=np.float32 + ) + + def reset(self): + """ + Reset the environment + """ + self.current_step = 0 + self.balance = self.initial_balance + self.position = 0 + self.position_size = 0 + + return self._get_observation() + + def step(self, action): + """ + Execute one step in the environment + """ + # Get current price + current_price = self.df['close'].iloc[self.current_step] + + # Execute action + reward = 0 + done = False + + if action == 0: # Buy + if self.position <= 0: + self.position = 1 + self.position_size = self.balance / current_price + elif action == 1: # Sell + if self.position >= 0: + self.position = -1 + self.position_size = self.balance / current_price + + # Calculate reward + next_price = self.df['close'].iloc[self.current_step + 1] + price_change = (next_price - current_price) / current_price + + if self.position != 0: + reward = self.position * price_change * 100 + + # Update balance + self.balance *= (1 + reward/100) + + # Move to next step + self.current_step += 1 + + # Check if episode is done + if self.current_step >= len(self.df) - 1: + done = True + + return self._get_observation(), reward, done, {} + + def _get_observation(self): + """ + Get current observation + """ + return self.df.iloc[self.current_step].values.astype(np.float32) + + def render(self): + """ + Render the environment + """ + pass + + def close(self): + """ + Clean up resources + """ + pass \ No newline at end of file diff --git a/main 2.0.py b/main 2.0.py new file mode 100644 index 0000000..94b06db --- /dev/null +++ b/main 2.0.py @@ -0,0 +1,272 @@ +import os +import sys +import logging +import json +import time +from datetime import datetime +from typing import Dict, List +import pandas as pd +import ccxt +from concurrent.futures import ThreadPoolExecutor +import schedule +import threading +import signal +import queue + +from .trading_strategy import TradingStrategy +from .config import load_config + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('trading_bot.log'), + logging.StreamHandler(sys.stdout) + ] +) + +logger = logging.getLogger(__name__) + +class TradingBot: + def __init__(self, config_path: str): + # Load configuration + self.config = load_config(config_path) + + # Initialize exchange + self.exchange = self._initialize_exchange() + + # Initialize trading strategy + self.strategy = TradingStrategy(self.config) + + # Initialize state + self.is_running = False + self.symbols = self.config['trading']['symbols'] + self.timeframes = self.config['trading']['timeframes'] + self.data_queue = queue.Queue() + self.signal_queue = queue.Queue() + + # Load previous state if exists + self._load_state() + + def _initialize_exchange(self) -> ccxt.Exchange: + """ + Initialize the cryptocurrency exchange + """ + try: + exchange_class = getattr(ccxt, self.config['exchange']['name']) + exchange = exchange_class({ + 'apiKey': self.config['exchange']['api_key'], + 'secret': self.config['exchange']['api_secret'], + 'enableRateLimit': True + }) + + # Test connection + exchange.load_markets() + logger.info(f"Successfully connected to {self.config['exchange']['name']}") + + return exchange + + except Exception as e: + logger.error(f"Error initializing exchange: {str(e)}") + raise + + def _load_state(self): + """ + Load previous trading state + """ + state_file = self.config['trading']['state_file'] + if os.path.exists(state_file): + try: + self.strategy.load_state(state_file) + logger.info("Successfully loaded previous trading state") + except Exception as e: + logger.error(f"Error loading state: {str(e)}") + + def _save_state(self): + """ + Save current trading state + """ + try: + self.strategy.save_state(self.config['trading']['state_file']) + logger.info("Successfully saved trading state") + except Exception as e: + logger.error(f"Error saving state: {str(e)}") + + def fetch_market_data(self, symbol: str, timeframe: str) -> pd.DataFrame: + """ + Fetch market data from exchange + """ + try: + # Get OHLCV data + ohlcv = self.exchange.fetch_ohlcv( + symbol, + timeframe=timeframe, + limit=self.config['trading']['lookback_periods'] + ) + + # Convert to DataFrame + df = pd.DataFrame( + ohlcv, + columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'] + ) + + # Convert timestamp to datetime + df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') + df.set_index('timestamp', inplace=True) + + return df + + except Exception as e: + logger.error(f"Error fetching market data for {symbol}: {str(e)}") + return None + + def process_market_data(self): + """ + Process market data from queue + """ + while self.is_running: + try: + # Get data from queue + data = self.data_queue.get(timeout=1) + symbol, timeframe, df = data + + # Generate trading signals + signal = self.strategy.analyze_market(symbol, df) + + if signal: + # Add signal to queue + self.signal_queue.put(signal) + + except queue.Empty: + continue + except Exception as e: + logger.error(f"Error processing market data: {str(e)}") + + def execute_signals(self): + """ + Execute trading signals from queue + """ + while self.is_running: + try: + # Get signal from queue + signal = self.signal_queue.get(timeout=1) + + # Execute trade + if self.strategy.execute_trade(signal): + logger.info(f"Executed {signal.action} trade for {signal.symbol}") + + # Update positions with current prices + current_prices = { + symbol: self.exchange.fetch_ticker(symbol)['last'] + for symbol in self.symbols + } + self.strategy.update_positions(current_prices) + + # Save state after trade + self._save_state() + + except queue.Empty: + continue + except Exception as e: + logger.error(f"Error executing signals: {str(e)}") + + def update_market_data(self): + """ + Update market data for all symbols + """ + with ThreadPoolExecutor(max_workers=len(self.symbols)) as executor: + futures = [] + + for symbol in self.symbols: + for timeframe in self.timeframes: + future = executor.submit(self.fetch_market_data, symbol, timeframe) + futures.append((symbol, timeframe, future)) + + for symbol, timeframe, future in futures: + try: + df = future.result() + if df is not None: + self.data_queue.put((symbol, timeframe, df)) + except Exception as e: + logger.error(f"Error updating market data for {symbol}: {str(e)}") + + def schedule_tasks(self): + """ + Schedule periodic tasks + """ + # Schedule market data updates + for timeframe in self.timeframes: + schedule.every().minute.at(":00").do(self.update_market_data) + + # Schedule state saving + schedule.every().hour.at(":00").do(self._save_state) + + # Run the scheduler + while self.is_running: + schedule.run_pending() + time.sleep(1) + + def start(self): + """ + Start the trading bot + """ + try: + self.is_running = True + + # Start threads + threads = [ + threading.Thread(target=self.process_market_data), + threading.Thread(target=self.execute_signals), + threading.Thread(target=self.schedule_tasks) + ] + + for thread in threads: + thread.daemon = True + thread.start() + + # Initial market data update + self.update_market_data() + + logger.info("Trading bot started successfully") + + # Wait for shutdown signal + while self.is_running: + time.sleep(1) + + except Exception as e: + logger.error(f"Error starting trading bot: {str(e)}") + self.stop() + + def stop(self): + """ + Stop the trading bot + """ + try: + self.is_running = False + self._save_state() + logger.info("Trading bot stopped successfully") + except Exception as e: + logger.error(f"Error stopping trading bot: {str(e)}") + +def main(): + # Load configuration + config_path = os.path.join(os.path.dirname(__file__), '..', 'config', 'config.json') + + # Create trading bot + bot = TradingBot(config_path) + + # Handle shutdown signals + def signal_handler(signum, frame): + logger.info("Received shutdown signal") + bot.stop() + sys.exit(0) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + # Start trading bot + bot.start() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/quantum_edge_config 2.0.json b/quantum_edge_config 2.0.json new file mode 100644 index 0000000..b8657b8 --- /dev/null +++ b/quantum_edge_config 2.0.json @@ -0,0 +1,137 @@ +{ + "system": { + "name": "Quantum Edge System", + "version": "1.0.0", + "log_level": "INFO", + "dashboard_port": 8050 + }, + "trading": { + "exchange": { + "name": "binance", + "testnet": true, + "api_key": "YOUR_API_KEY", + "api_secret": "YOUR_API_SECRET" + }, + "markets": ["BTC/USD", "ETH/USD", "SOL/USD", "ADA/USD"], + "timeframes": ["1m", "5m", "15m", "1h", "4h", "1d"], + "default_leverage": 1.0, + "position_types": ["long", "short"], + "order_types": ["market", "limit", "stop_loss", "take_profit"] + }, + "ml_model": { + "default_type": "lstm", + "lstm": { + "layers": [64, 32], + "dropout": 0.2, + "learning_rate": 0.001, + "batch_size": 32, + "epochs": 100, + "validation_split": 0.2, + "sequence_length": 60 + }, + "reinforcement": { + "model_type": "ppo", + "policy_network": [64, 64], + "value_network": [64, 32], + "learning_rate": 0.0003, + "gamma": 0.99, + "gae_lambda": 0.95, + "clip_ratio": 0.2, + "train_iterations": 80 + }, + "features": { + "price": ["open", "high", "low", "close"], + "volume": ["volume", "taker_buy_volume"], + "technical": [ + "rsi", "macd", "bollinger_bands", + "moving_averages", "momentum", "volatility" + ] + } + }, + "risk_management": { + "position_sizing": { + "max_position_size": 0.1, + "max_leverage": 3.0, + "min_position_size": 0.01 + }, + "risk_limits": { + "max_drawdown": 0.2, + "var_limit": 0.05, + "min_sharpe": 1.0, + "max_correlation": 0.7 + }, + "stop_loss": { + "default_percentage": 0.02, + "trailing_stop": true, + "activation_percentage": 0.01 + }, + "take_profit": { + "default_percentage": 0.03, + "trailing_take_profit": true, + "activation_percentage": 0.015 + }, + "exposure_limits": { + "max_total_exposure": 1.0, + "max_single_market": 0.3, + "max_correlated_exposure": 0.5 + } + }, + "sentiment_analysis": { + "providers": { + "news": { + "api_key": "YOUR_NEWS_API_KEY", + "sources": ["reuters", "bloomberg", "coindesk"], + "update_interval": 300 + }, + "social": { + "twitter_api_key": "YOUR_TWITTER_API_KEY", + "twitter_api_secret": "YOUR_TWITTER_API_SECRET", + "reddit_client_id": "YOUR_REDDIT_CLIENT_ID", + "reddit_client_secret": "YOUR_REDDIT_CLIENT_SECRET", + "update_interval": 60 + } + }, + "analysis": { + "sentiment_window": 3600, + "min_confidence": 0.6, + "impact_threshold": 0.3, + "correlation_threshold": 0.5 + } + }, + "optimization": { + "system": { + "cpu_threshold": 80, + "memory_threshold": 80, + "network_latency_threshold": 1000, + "optimization_interval": 3600 + }, + "trading": { + "min_win_rate": 0.55, + "min_profit_factor": 1.5, + "max_drawdown": 0.2, + "optimization_lookback": 1000 + }, + "ml_model": { + "min_accuracy": 0.6, + "min_sharpe": 1.0, + "max_drawdown": 0.15, + "retraining_interval": 86400 + } + }, + "monitoring": { + "metrics_update_interval": 60, + "health_check_interval": 300, + "alert_thresholds": { + "cpu_usage": 90, + "memory_usage": 90, + "api_latency": 2000, + "error_rate": 0.01 + }, + "performance_thresholds": { + "min_daily_profit": -0.02, + "max_daily_loss": -0.05, + "min_win_rate": 0.5, + "min_profit_factor": 1.2 + } + } +} \ No newline at end of file diff --git a/quantum_edge_system 2.0.py b/quantum_edge_system 2.0.py new file mode 100644 index 0000000..abf36c6 --- /dev/null +++ b/quantum_edge_system 2.0.py @@ -0,0 +1,562 @@ +import logging +import threading +import queue +import json +import os +from typing import Dict, List, Optional, Any, Tuple +from dataclasses import dataclass +from datetime import datetime +import time +import numpy as np +import pandas as pd +from concurrent.futures import ThreadPoolExecutor, as_completed +from functools import wraps +import traceback +import signal +import sys +from .trading_system import TradingSystem, create_trading_system +from .code_guardian import CodeGuardian, create_guardian +from .system_monitor import SystemMonitor +from .dashboard import create_dashboard +from .risk_management import RiskManager, RiskMetrics +from .sentiment_analysis import SentimentAnalyzer +from .machine_learning_model import MachineLearningModel +from .trading_environment import TradingEnvironment + +# Configure logging with rotation +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.handlers.RotatingFileHandler( + 'logs/quantum_edge_system.log', + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +def retry_on_failure(max_retries: int = 3, delay: float = 1.0): + """Decorator for retrying failed operations""" + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + last_exception = None + for attempt in range(max_retries): + try: + return func(*args, **kwargs) + except Exception as e: + last_exception = e + logger.warning(f"Attempt {attempt + 1}/{max_retries} failed: {str(e)}") + if attempt < max_retries - 1: + time.sleep(delay * (attempt + 1)) # Exponential backoff + logger.error(f"All {max_retries} attempts failed. Last error: {str(last_exception)}") + raise last_exception + return wrapper + return decorator + +@dataclass +class SystemHealth: + """System health metrics""" + cpu_usage: float + memory_usage: float + network_latency: float + disk_usage: float + error_rate: float + last_check: datetime + +@dataclass +class QuantumBotInstance: + """Represents a Quantum Edge trading bot instance""" + bot_id: str + trading_system: TradingSystem + ml_model: MachineLearningModel + risk_manager: RiskManager + sentiment_analyzer: SentimentAnalyzer + trading_env: TradingEnvironment + config: Dict + status: str + last_update: datetime + performance_metrics: Dict + message_queue: queue.Queue + health_metrics: SystemHealth + error_count: int + recovery_attempts: int + last_error: Optional[Exception] = None + +class QuantumEdgeSystem: + def __init__(self, project_root: str, config_path: str): + """Initialize the Quantum Edge System""" + self.project_root = project_root + self.load_config(config_path) + self.bots: Dict[str, QuantumBotInstance] = {} + self.code_guardian = create_guardian(project_root) + self.system_monitor = SystemMonitor(project_root) + self.message_queue = queue.Queue() + self.running = True + self.thread_pool = ThreadPoolExecutor(max_workers=10) + self.error_threshold = self.config['monitoring']['alert_thresholds']['error_rate'] + self.recovery_threshold = 3 + + # Initialize system components + self._init_system_components() + self._start_management_threads() + self._init_dashboard() + self._setup_signal_handlers() + + def _setup_signal_handlers(self): + """Setup signal handlers for graceful shutdown""" + signal.signal(signal.SIGINT, self._handle_shutdown) + signal.signal(signal.SIGTERM, self._handle_shutdown) + + def _handle_shutdown(self, signum, frame): + """Handle system shutdown signals""" + logger.info(f"Received shutdown signal {signum}") + self.stop() + + @retry_on_failure(max_retries=3, delay=2.0) + def load_config(self, config_path: str): + """Load system configuration with retry""" + try: + with open(config_path, 'r') as f: + self.config = json.load(f) + self.validate_config() + except Exception as e: + logger.error(f"Error loading config: {str(e)}") + raise + + def validate_config(self): + """Validate system configuration with detailed checks""" + required_sections = ['trading', 'ml_model', 'risk_management', 'sentiment_analysis'] + for section in required_sections: + if section not in self.config: + raise ValueError(f"Missing required config section: {section}") + + # Validate section-specific requirements + if section == 'trading': + self._validate_trading_config() + elif section == 'ml_model': + self._validate_ml_config() + elif section == 'risk_management': + self._validate_risk_config() + elif section == 'sentiment_analysis': + self._validate_sentiment_config() + + def _validate_trading_config(self): + """Validate trading configuration""" + trading_config = self.config['trading'] + required_fields = ['exchange', 'markets', 'timeframes'] + for field in required_fields: + if field not in trading_config: + raise ValueError(f"Missing required trading config field: {field}") + + if not trading_config['markets']: + raise ValueError("No trading markets specified") + + if not trading_config['timeframes']: + raise ValueError("No timeframes specified") + + def _validate_ml_config(self): + """Validate ML configuration""" + ml_config = self.config['ml_model'] + if 'default_type' not in ml_config: + raise ValueError("ML model default type not specified") + + if ml_config['default_type'] not in ['lstm', 'reinforcement']: + raise ValueError(f"Invalid ML model type: {ml_config['default_type']}") + + def _validate_risk_config(self): + """Validate risk management configuration""" + risk_config = self.config['risk_management'] + required_sections = ['position_sizing', 'risk_limits', 'stop_loss'] + for section in required_sections: + if section not in risk_config: + raise ValueError(f"Missing required risk config section: {section}") + + def _validate_sentiment_config(self): + """Validate sentiment analysis configuration""" + sentiment_config = self.config['sentiment_analysis'] + if 'providers' not in sentiment_config: + raise ValueError("Sentiment analysis providers not specified") + + def _init_system_components(self): + """Initialize system-wide components with error handling""" + try: + self.global_risk_manager = RiskManager(self.config['risk_management']) + self.global_sentiment_analyzer = SentimentAnalyzer(self.config['sentiment_analysis']) + self.performance_tracker = self._init_performance_tracker() + self.health_metrics = SystemHealth( + cpu_usage=0.0, + memory_usage=0.0, + network_latency=0.0, + disk_usage=0.0, + error_rate=0.0, + last_check=datetime.now() + ) + except Exception as e: + logger.error(f"Error initializing system components: {str(e)}") + raise + + def _init_performance_tracker(self): + """Initialize system-wide performance tracking with enhanced metrics""" + return { + 'system_metrics': {}, + 'bot_metrics': {}, + 'risk_metrics': {}, + 'sentiment_metrics': {}, + 'ml_metrics': {}, + 'error_metrics': { + 'total_errors': 0, + 'error_types': {}, + 'recovery_success_rate': 1.0 + }, + 'performance_metrics': { + 'average_latency': 0.0, + 'throughput': 0.0, + 'resource_utilization': {} + } + } + + def _start_management_threads(self): + """Start system management threads with enhanced monitoring""" + self.threads = { + 'monitor': threading.Thread(target=self._monitor_system), + 'message_handler': threading.Thread(target=self._handle_messages), + 'code_repair': threading.Thread(target=self._continuous_code_repair), + 'performance_tracker': threading.Thread(target=self._track_performance), + 'risk_monitor': threading.Thread(target=self._monitor_risk), + 'sentiment_monitor': threading.Thread(target=self._monitor_sentiment), + 'health_checker': threading.Thread(target=self._check_system_health) + } + + for thread_name, thread in self.threads.items(): + thread.daemon = True + thread.name = f"quantum_edge_{thread_name}" + thread.start() + logger.info(f"Started thread: {thread_name}") + + def _check_system_health(self): + """Continuously check system health""" + while self.running: + try: + health_metrics = { + 'cpu_usage': self.system_monitor.get_cpu_usage(), + 'memory_usage': self.system_monitor.get_memory_usage(), + 'network_latency': self.system_monitor.get_network_latency(), + 'disk_usage': self.system_monitor.get_disk_usage(), + 'error_rate': self._calculate_error_rate() + } + + self.health_metrics = SystemHealth( + **health_metrics, + last_check=datetime.now() + ) + + if self._is_system_unhealthy(): + self._handle_system_health_issue() + + time.sleep(60) + + except Exception as e: + logger.error(f"Error checking system health: {str(e)}") + time.sleep(300) + + def _calculate_error_rate(self) -> float: + """Calculate system-wide error rate""" + total_errors = sum(bot.error_count for bot in self.bots.values()) + total_operations = sum(bot.performance_metrics.get('total_operations', 0) + for bot in self.bots.values()) + return total_errors / total_operations if total_operations > 0 else 0.0 + + def _is_system_unhealthy(self) -> bool: + """Determine if system is unhealthy""" + thresholds = self.config['monitoring']['alert_thresholds'] + return ( + self.health_metrics.cpu_usage > thresholds['cpu_usage'] or + self.health_metrics.memory_usage > thresholds['memory_usage'] or + self.health_metrics.network_latency > thresholds['api_latency'] or + self.health_metrics.error_rate > thresholds['error_rate'] + ) + + def _handle_system_health_issue(self): + """Handle system health issues""" + logger.warning("System health issues detected") + + # Reduce system load + self._optimize_system_performance() + + # Notify all bots + self.broadcast_message({ + 'type': 'system_alert', + 'action': 'reduce_load', + 'timestamp': datetime.now().isoformat() + }) + + # Log health metrics + logger.warning(f"Current health metrics: {self.health_metrics}") + + @retry_on_failure(max_retries=3, delay=2.0) + def create_quantum_bot(self, config: Dict) -> str: + """Create a new Quantum Edge bot instance with enhanced error handling""" + try: + bot_id = f"quantum_bot_{len(self.bots) + 1}" + + # Create bot-specific config + bot_config = self._create_bot_config(config) + config_path = os.path.join(self.project_root, 'config', f'{bot_id}_config.json') + + # Save config with retry + self._save_bot_config(config_path, bot_config) + + # Initialize bot components with parallel execution + components = self._initialize_bot_components(bot_config) + + # Create bot instance with health monitoring + bot = QuantumBotInstance( + bot_id=bot_id, + trading_system=components['trading_system'], + ml_model=components['ml_model'], + risk_manager=components['risk_manager'], + sentiment_analyzer=components['sentiment_analyzer'], + trading_env=components['trading_env'], + config=bot_config, + status='initialized', + last_update=datetime.now(), + performance_metrics={}, + message_queue=queue.Queue(), + health_metrics=SystemHealth( + cpu_usage=0.0, + memory_usage=0.0, + network_latency=0.0, + disk_usage=0.0, + error_rate=0.0, + last_check=datetime.now() + ), + error_count=0, + recovery_attempts=0 + ) + + self.bots[bot_id] = bot + logger.info(f"Created new Quantum Edge bot instance: {bot_id}") + + return bot_id + + except Exception as e: + logger.error(f"Error creating Quantum Edge bot: {str(e)}") + raise + + def _save_bot_config(self, config_path: str, config: Dict): + """Save bot configuration with retry""" + try: + with open(config_path, 'w') as f: + json.dump(config, f, indent=2) + except Exception as e: + logger.error(f"Error saving bot config: {str(e)}") + raise + + def _initialize_bot_components(self, config: Dict) -> Dict: + """Initialize bot components in parallel""" + components = {} + futures = { + 'trading_system': self.thread_pool.submit( + create_trading_system, config['trading'] + ), + 'ml_model': self.thread_pool.submit( + MachineLearningModel, config['ml_model'] + ), + 'risk_manager': self.thread_pool.submit( + RiskManager, config['risk_management'] + ), + 'sentiment_analyzer': self.thread_pool.submit( + SentimentAnalyzer, config['sentiment_analysis'] + ), + 'trading_env': self.thread_pool.submit( + TradingEnvironment, config['trading'] + ) + } + + for name, future in futures.items(): + try: + components[name] = future.result() + except Exception as e: + logger.error(f"Error initializing {name}: {str(e)}") + raise + + return components + + def start_bot(self, bot_id: str): + """Start a Quantum Edge bot with enhanced error handling""" + if bot_id in self.bots: + try: + bot = self.bots[bot_id] + + # Initialize components with retry + self._initialize_bot_components_with_retry(bot) + + # Start bot with health monitoring + bot.status = 'running' + bot.last_update = datetime.now() + + logger.info(f"Started Quantum Edge bot: {bot_id}") + + # Send start message to bot + self._send_message_to_bot(bot_id, { + 'type': 'command', + 'action': 'start', + 'timestamp': datetime.now().isoformat() + }) + + except Exception as e: + logger.error(f"Error starting Quantum Edge bot {bot_id}: {str(e)}") + self._handle_bot_error(bot_id, e) + + def _initialize_bot_components_with_retry(self, bot: QuantumBotInstance): + """Initialize bot components with retry mechanism""" + try: + bot.ml_model.initialize() + bot.trading_env.reset() + bot.trading_system.start() + except Exception as e: + logger.error(f"Error initializing bot components: {str(e)}") + bot.error_count += 1 + bot.last_error = e + raise + + def _handle_bot_error(self, bot_id: str, error: Exception): + """Handle bot errors with recovery mechanism""" + bot = self.bots[bot_id] + bot.error_count += 1 + bot.last_error = error + + if bot.error_count >= self.recovery_threshold: + logger.warning(f"Bot {bot_id} exceeded error threshold, attempting recovery") + self._attempt_bot_recovery(bot_id) + else: + bot.status = 'error' + logger.error(f"Bot {bot_id} encountered error: {str(error)}") + + def _attempt_bot_recovery(self, bot_id: str): + """Attempt to recover a failed bot""" + bot = self.bots[bot_id] + try: + # Reset bot state + bot.error_count = 0 + bot.recovery_attempts += 1 + + # Reinitialize components + self._initialize_bot_components_with_retry(bot) + + # Restart bot + bot.status = 'running' + logger.info(f"Successfully recovered bot {bot_id}") + + except Exception as e: + logger.error(f"Failed to recover bot {bot_id}: {str(e)}") + bot.status = 'failed' + self._handle_critical_bot_failure(bot_id) + + def _handle_critical_bot_failure(self, bot_id: str): + """Handle critical bot failures""" + logger.error(f"Critical failure for bot {bot_id}") + + # Notify system + self.message_queue.put({ + 'type': 'critical_error', + 'bot_id': bot_id, + 'timestamp': datetime.now().isoformat() + }) + + # Update system metrics + self.performance_tracker['error_metrics']['total_errors'] += 1 + error_type = type(self.bots[bot_id].last_error).__name__ + self.performance_tracker['error_metrics']['error_types'][error_type] = \ + self.performance_tracker['error_metrics']['error_types'].get(error_type, 0) + 1 + + def stop(self): + """Stop the Quantum Edge System with graceful shutdown""" + logger.info("Initiating system shutdown") + self.running = False + + # Stop all bots gracefully + for bot_id in self.bots: + self.stop_bot(bot_id) + + # Stop components + self.code_guardian.stop() + self.system_monitor.stop() + + # Shutdown thread pool + self.thread_pool.shutdown(wait=True) + + # Wait for threads + for thread_name, thread in self.threads.items(): + if thread.is_alive(): + logger.info(f"Waiting for thread {thread_name} to finish") + thread.join(timeout=30) + if thread.is_alive(): + logger.warning(f"Thread {thread_name} did not terminate gracefully") + + logger.info("Quantum Edge System stopped") + +def create_quantum_edge_system(project_root: str, config_path: str) -> QuantumEdgeSystem: + """Create and initialize a Quantum Edge System""" + return QuantumEdgeSystem(project_root, config_path) + +if __name__ == "__main__": + # Example usage with enhanced error handling + config_path = "config/quantum_edge_config.json" + system = None + + try: + system = create_quantum_edge_system(".", config_path) + + # Create test bots with different strategies + configs = [ + { + "trading": { + "initial_capital": 100000, + "strategy": "trend_following", + "markets": ["BTC/USD", "ETH/USD"] + }, + "ml_model": { + "type": "lstm", + "features": ["price", "volume", "sentiment"] + } + }, + { + "trading": { + "initial_capital": 50000, + "strategy": "mean_reversion", + "markets": ["SOL/USD", "ADA/USD"] + }, + "ml_model": { + "type": "reinforcement", + "features": ["technical_indicators", "order_flow"] + } + } + ] + + # Create and start bots + bot_ids = [] + for config in configs: + bot_id = system.create_quantum_bot(config) + bot_ids.append(bot_id) + system.start_bot(bot_id) + + # Monitor system + while True: + status = system.get_system_status() + print(f"System Status: {json.dumps(status, indent=2)}") + time.sleep(300) # Update every 5 minutes + + except KeyboardInterrupt: + print("Shutting down Quantum Edge System...") + if system: + system.stop() + except Exception as e: + print(f"Critical error: {str(e)}") + if system: + system.stop() + raise \ No newline at end of file diff --git a/requirements 2.0.2.txt b/requirements 2.0.2.txt new file mode 100644 index 0000000..5606445 --- /dev/null +++ b/requirements 2.0.2.txt @@ -0,0 +1,69 @@ +# Core dependencies +numpy==1.24.3 +pandas==2.0.3 +scipy==1.10.1 +scikit-learn==1.3.0 + +# Deep Learning +torch==2.0.1 +tensorflow==2.13.0 +keras==2.13.1 +transformers==4.31.0 + +# Reinforcement Learning +gym==0.26.2 +stable-baselines3==2.0.0 + +# Trading & Financial +ccxt==4.0.0 +ta==0.10.2 +yfinance==0.2.28 +pandas-ta==0.3.14b0 + +# Data Processing & Analysis +statsmodels==0.14.0 +pyfolio==0.9.2 +empyrical==0.5.5 + +# Sentiment Analysis +textblob==0.17.1 +vaderSentiment==3.3.2 +newsapi-python==0.2.7 +tweepy==4.14.0 +praw==7.7.1 + +# Web Dashboard +dash==2.11.1 +dash-bootstrap-components==1.4.1 +plotly==5.15.0 + +# System Monitoring +psutil==5.9.5 +py-cpuinfo==9.0.0 + +# Code Analysis +pylint==2.17.5 +astroid==2.15.6 +radon==6.0.1 + +# Utilities +python-dotenv==1.0.0 +requests==2.31.0 +websockets==11.0.3 +aiohttp==3.8.5 +schedule==1.2.0 + +# Testing +pytest==7.4.0 +pytest-asyncio==0.21.1 +pytest-cov==4.1.0 + +# Documentation +sphinx==7.1.2 +sphinx-rtd-theme==1.2.2 + +# Development Tools +black==23.7.0 +isort==5.12.0 +mypy==1.5.1 +pre-commit==3.3.3 \ No newline at end of file diff --git a/requirements 2.0.txt b/requirements 2.0.txt new file mode 100644 index 0000000..bbbb949 --- /dev/null +++ b/requirements 2.0.txt @@ -0,0 +1,18 @@ +numpy>=1.21.0 +pandas>=1.3.0 +ccxt>=2.0.0 +scikit-learn>=0.24.2 +tensorflow>=2.6.0 +stable-baselines3>=1.5.0 +gym>=0.21.0 +ta-lib>=0.4.24 +textblob>=0.15.3 +tweepy>=4.10.0 +newsapi-python>=0.2.6 +yfinance>=0.1.63 +schedule>=1.1.0 +joblib>=1.0.2 +python-dotenv>=0.19.0 +flask>=2.0.1 +plotly>=5.3.1 +dash>=2.0.0 \ No newline at end of file diff --git a/risk_management 2.0.py b/risk_management 2.0.py new file mode 100644 index 0000000..6260dd3 --- /dev/null +++ b/risk_management 2.0.py @@ -0,0 +1,249 @@ +import numpy as np +import pandas as pd +from typing import Dict, Tuple, Optional +import logging +from dataclasses import dataclass +from datetime import datetime + +logger = logging.getLogger(__name__) + +@dataclass +class RiskMetrics: + """Data class to store risk metrics""" + daily_drawdown: float + max_drawdown: float + sharpe_ratio: float + sortino_ratio: float + win_rate: float + profit_factor: float + avg_win: float + avg_loss: float + max_consecutive_losses: int + max_consecutive_wins: int + +class RiskManager: + def __init__(self, config: Dict): + self.config = config + self.initial_capital = config['initial_capital'] + self.current_capital = self.initial_capital + self.risk_per_trade = config['risk_per_trade'] + self.max_daily_loss = config['max_daily_loss'] + self.max_drawdown = config['max_drawdown'] + self.max_positions = config['max_positions'] + self.leverage = config['leverage'] + self.stop_loss_pct = config['stop_loss_pct'] + self.take_profit_pct = config['take_profit_pct'] + + # Performance tracking + self.trades_history = [] + self.daily_pnl = [] + self.positions = {} + self.risk_metrics = None + + def calculate_position_size(self, + price: float, + stop_loss: float, + account_balance: float) -> Tuple[float, float]: + """ + Calculate position size based on risk parameters + """ + # Calculate risk amount in base currency + risk_amount = account_balance * self.risk_per_trade + + # Calculate position size based on stop loss + price_distance = abs(price - stop_loss) + position_size = risk_amount / price_distance + + # Apply leverage + position_size *= self.leverage + + # Calculate required margin + required_margin = (position_size * price) / self.leverage + + # Ensure we don't exceed maximum position size + max_position = account_balance * self.leverage / price + position_size = min(position_size, max_position) + + return position_size, required_margin + + def validate_trade(self, + symbol: str, + position_size: float, + price: float, + stop_loss: float, + take_profit: float) -> bool: + """ + Validate if a trade meets risk management criteria + """ + # Check if we have too many open positions + if len(self.positions) >= self.max_positions: + logger.warning("Maximum number of positions reached") + return False + + # Check if symbol is already in a position + if symbol in self.positions: + logger.warning(f"Position already exists for {symbol}") + return False + + # Calculate potential loss + potential_loss = position_size * abs(price - stop_loss) + + # Check if potential loss exceeds daily limit + if potential_loss > self.max_daily_loss: + logger.warning("Trade exceeds maximum daily loss limit") + return False + + # Check if stop loss is too far + stop_loss_distance = abs(price - stop_loss) / price + if stop_loss_distance > self.stop_loss_pct: + logger.warning("Stop loss distance exceeds maximum allowed") + return False + + # Check if take profit is reasonable + take_profit_distance = abs(take_profit - price) / price + if take_profit_distance > self.take_profit_pct: + logger.warning("Take profit distance exceeds maximum allowed") + return False + + return True + + def update_position(self, + symbol: str, + entry_price: float, + current_price: float, + position_size: float, + position_type: str) -> Optional[float]: + """ + Update position and check for stop loss or take profit + """ + if symbol not in self.positions: + self.positions[symbol] = { + 'entry_price': entry_price, + 'current_price': current_price, + 'position_size': position_size, + 'position_type': position_type, + 'entry_time': datetime.now() + } + return None + + position = self.positions[symbol] + pnl = 0 + + # Calculate unrealized PnL + if position_type == 'long': + pnl = (current_price - entry_price) * position_size + else: + pnl = (entry_price - current_price) * position_size + + # Check stop loss + if position_type == 'long': + if current_price <= entry_price * (1 - self.stop_loss_pct): + pnl = -position_size * entry_price * self.stop_loss_pct + del self.positions[symbol] + return pnl + else: + if current_price >= entry_price * (1 + self.stop_loss_pct): + pnl = -position_size * entry_price * self.stop_loss_pct + del self.positions[symbol] + return pnl + + # Check take profit + if position_type == 'long': + if current_price >= entry_price * (1 + self.take_profit_pct): + pnl = position_size * entry_price * self.take_profit_pct + del self.positions[symbol] + return pnl + else: + if current_price <= entry_price * (1 - self.take_profit_pct): + pnl = position_size * entry_price * self.take_profit_pct + del self.positions[symbol] + return pnl + + # Update current price + position['current_price'] = current_price + return None + + def calculate_risk_metrics(self) -> RiskMetrics: + """ + Calculate various risk metrics + """ + if not self.trades_history: + return None + + # Convert trades history to DataFrame + df = pd.DataFrame(self.trades_history) + + # Calculate daily returns + daily_returns = df.groupby(df['exit_time'].dt.date)['pnl'].sum() + + # Calculate drawdown + cumulative_returns = (1 + daily_returns).cumprod() + rolling_max = cumulative_returns.expanding().max() + drawdowns = (cumulative_returns - rolling_max) / rolling_max + + # Calculate metrics + daily_drawdown = drawdowns.min() + max_drawdown = drawdowns.min() + + # Calculate Sharpe ratio + risk_free_rate = 0.02 # 2% annual risk-free rate + excess_returns = daily_returns - risk_free_rate/252 + sharpe_ratio = np.sqrt(252) * excess_returns.mean() / excess_returns.std() + + # Calculate Sortino ratio + downside_returns = excess_returns[excess_returns < 0] + sortino_ratio = np.sqrt(252) * excess_returns.mean() / downside_returns.std() + + # Calculate win rate and profit factor + winning_trades = df[df['pnl'] > 0] + losing_trades = df[df['pnl'] < 0] + win_rate = len(winning_trades) / len(df) + profit_factor = abs(winning_trades['pnl'].sum() / losing_trades['pnl'].sum()) + + # Calculate average win and loss + avg_win = winning_trades['pnl'].mean() + avg_loss = losing_trades['pnl'].mean() + + # Calculate consecutive wins and losses + df['consecutive'] = (df['pnl'] > 0).astype(int) + max_consecutive_wins = df['consecutive'].groupby((df['consecutive'] != df['consecutive'].shift()).cumsum()).sum().max() + max_consecutive_losses = df['consecutive'].groupby((df['consecutive'] != df['consecutive'].shift()).cumsum()).sum().min() + + self.risk_metrics = RiskMetrics( + daily_drawdown=daily_drawdown, + max_drawdown=max_drawdown, + sharpe_ratio=sharpe_ratio, + sortino_ratio=sortino_ratio, + win_rate=win_rate, + profit_factor=profit_factor, + avg_win=avg_win, + avg_loss=avg_loss, + max_consecutive_losses=max_consecutive_losses, + max_consecutive_wins=max_consecutive_wins + ) + + return self.risk_metrics + + def should_stop_trading(self) -> bool: + """ + Check if trading should be stopped based on risk metrics + """ + if not self.risk_metrics: + return False + + # Stop if maximum drawdown is exceeded + if self.risk_metrics.max_drawdown < -self.max_drawdown: + logger.warning("Maximum drawdown exceeded. Stopping trading.") + return True + + # Stop if win rate is too low + if self.risk_metrics.win_rate < self.config['min_win_rate']: + logger.warning("Win rate below minimum threshold. Stopping trading.") + return True + + # Stop if profit factor is too low + if self.risk_metrics.profit_factor < self.config['min_profit_factor']: + logger.warning("Profit factor below minimum threshold. Stopping trading.") + return True + + return False \ No newline at end of file diff --git a/run_analysis 2.0.py b/run_analysis 2.0.py new file mode 100644 index 0000000..4004881 --- /dev/null +++ b/run_analysis 2.0.py @@ -0,0 +1,112 @@ +import os +import sys +import logging +from datetime import datetime, timedelta +from src.backtesting import Backtester +from src.dashboard import run_dashboard +import threading +import webbrowser +import time + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('analysis.log'), + logging.StreamHandler(sys.stdout) + ] +) + +logger = logging.getLogger(__name__) + +def run_backtests(): + """Run all backtest scenarios""" + # Create results directory if it doesn't exist + results_dir = 'backtest_results' + os.makedirs(results_dir, exist_ok=True) + + # Load configuration + config_path = os.path.join(os.path.dirname(__file__), 'config', 'config.json') + + # Create backtester + backtester = Backtester(config_path) + + # Define test scenarios + scenarios = [ + { + 'name': 'BTC/USDT 1h - Last 30 days', + 'symbol': 'BTC/USDT', + 'timeframe': '1h', + 'days': 30 + }, + { + 'name': 'ETH/USDT 4h - Last 60 days', + 'symbol': 'ETH/USDT', + 'timeframe': '4h', + 'days': 60 + }, + { + 'name': 'BTC/USDT 1d - Last 90 days', + 'symbol': 'BTC/USDT', + 'timeframe': '1d', + 'days': 90 + }, + { + 'name': 'ETH/USDT 1d - Last 90 days', + 'symbol': 'ETH/USDT', + 'timeframe': '1d', + 'days': 90 + } + ] + + # Run each scenario + for scenario in scenarios: + logger.info(f"\nRunning scenario: {scenario['name']}") + + # Calculate date range + end_date = datetime.now() + start_date = end_date - timedelta(days=scenario['days']) + + # Run backtest + results = backtester.run_backtest( + symbol=scenario['symbol'], + timeframe=scenario['timeframe'], + start_date=start_date, + end_date=end_date, + initial_capital=50.0 + ) + + if results: + # Save results + filename = f"backtest_results_{scenario['symbol'].replace('/', '_')}_{scenario['timeframe']}.json" + filepath = os.path.join(results_dir, filename) + backtester.save_results(filepath) + logger.info(f"Results saved to {filepath}") + else: + logger.error(f"Backtest failed for scenario: {scenario['name']}") + +def open_browser(): + """Open browser after a short delay""" + time.sleep(3) # Wait for the server to start + webbrowser.open('http://localhost:8050') + +def main(): + """Run backtests and launch dashboard""" + try: + # Run backtests + logger.info("Starting backtests...") + run_backtests() + logger.info("Backtests completed successfully") + + # Launch dashboard + logger.info("Launching dashboard...") + threading.Thread(target=open_browser).start() + run_dashboard() + + except Exception as e: + logger.error(f"Error during analysis: {str(e)}") + raise + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/run_backtest 2.0.py b/run_backtest 2.0.py new file mode 100644 index 0000000..e17e073 --- /dev/null +++ b/run_backtest 2.0.py @@ -0,0 +1,84 @@ +import os +import sys +from datetime import datetime, timedelta +import logging +from src.backtesting import Backtester + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('backtest.log'), + logging.StreamHandler(sys.stdout) + ] +) + +logger = logging.getLogger(__name__) + +def run_backtest_scenarios(): + # Load configuration + config_path = os.path.join(os.path.dirname(__file__), 'config', 'config.json') + + # Create backtester + backtester = Backtester(config_path) + + # Define test scenarios + scenarios = [ + { + 'name': 'BTC/USDT 1h - Last 30 days', + 'symbol': 'BTC/USDT', + 'timeframe': '1h', + 'days': 30 + }, + { + 'name': 'ETH/USDT 4h - Last 60 days', + 'symbol': 'ETH/USDT', + 'timeframe': '4h', + 'days': 60 + }, + { + 'name': 'BTC/USDT 1d - Last 90 days', + 'symbol': 'BTC/USDT', + 'timeframe': '1d', + 'days': 90 + } + ] + + # Run each scenario + for scenario in scenarios: + logger.info(f"\nRunning scenario: {scenario['name']}") + + # Calculate date range + end_date = datetime.now() + start_date = end_date - timedelta(days=scenario['days']) + + # Run backtest + results = backtester.run_backtest( + symbol=scenario['symbol'], + timeframe=scenario['timeframe'], + start_date=start_date, + end_date=end_date, + initial_capital=50.0 + ) + + if results: + # Print performance metrics + metrics = results['performance_metrics'] + print(f"\nResults for {scenario['name']}:") + print(f"Total Trades: {metrics['total_trades']}") + print(f"Win Rate: {metrics['win_rate']:.2%}") + print(f"Total Return: {metrics['total_return']:.2%}") + print(f"Annual Return: {metrics['annual_return']:.2%}") + print(f"Sharpe Ratio: {metrics['sharpe_ratio']:.2f}") + print(f"Max Drawdown: {metrics['max_drawdown']:.2%}") + + # Save results + filename = f"backtest_results_{scenario['symbol'].replace('/', '_')}_{scenario['timeframe']}.json" + backtester.save_results(filename) + logger.info(f"Results saved to {filename}") + else: + logger.error(f"Backtest failed for scenario: {scenario['name']}") + +if __name__ == "__main__": + run_backtest_scenarios() \ No newline at end of file diff --git a/sentiment_analysis 2.0.py b/sentiment_analysis 2.0.py new file mode 100644 index 0000000..7327580 --- /dev/null +++ b/sentiment_analysis 2.0.py @@ -0,0 +1,267 @@ +import numpy as np +import pandas as pd +from typing import Dict, List, Optional +import logging +from datetime import datetime, timedelta +import requests +from textblob import TextBlob +import tweepy +from newsapi import NewsApiClient +import yfinance as yf +from concurrent.futures import ThreadPoolExecutor +import json +import os + +logger = logging.getLogger(__name__) + +class SentimentAnalyzer: + def __init__(self, config: Dict): + self.config = config + self.news_api = NewsApiClient(api_key=config['news_api_key']) + self.twitter_auth = tweepy.OAuthHandler( + config['twitter_api_key'], + config['twitter_api_secret'] + ) + self.twitter_auth.set_access_token( + config['twitter_access_token'], + config['twitter_access_token_secret'] + ) + self.twitter_api = tweepy.API(self.twitter_auth) + + # Initialize sentiment cache + self.sentiment_cache = {} + self.cache_duration = timedelta(hours=1) + + def analyze_text(self, text: str) -> float: + """ + Analyze sentiment of a single text using TextBlob + """ + try: + analysis = TextBlob(text) + # Normalize sentiment score to [-1, 1] + return analysis.sentiment.polarity + except Exception as e: + logger.error(f"Error analyzing text: {str(e)}") + return 0.0 + + def get_news_sentiment(self, symbol: str) -> Optional[float]: + """ + Get sentiment from news articles + """ + try: + # Check cache first + cache_key = f"news_{symbol}" + if cache_key in self.sentiment_cache: + cached_data = self.sentiment_cache[cache_key] + if datetime.now() - cached_data['timestamp'] < self.cache_duration: + return cached_data['sentiment'] + + # Get news articles + news = self.news_api.get_everything( + q=symbol, + language='en', + from_param=(datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d'), + sort_by='relevancy' + ) + + if not news['articles']: + return None + + # Analyze sentiment of each article + sentiments = [] + for article in news['articles']: + title_sentiment = self.analyze_text(article['title']) + if article['description']: + desc_sentiment = self.analyze_text(article['description']) + sentiments.append((title_sentiment + desc_sentiment) / 2) + else: + sentiments.append(title_sentiment) + + # Calculate weighted average sentiment + avg_sentiment = np.mean(sentiments) + + # Cache the result + self.sentiment_cache[cache_key] = { + 'sentiment': avg_sentiment, + 'timestamp': datetime.now() + } + + return avg_sentiment + + except Exception as e: + logger.error(f"Error getting news sentiment: {str(e)}") + return None + + def get_twitter_sentiment(self, symbol: str) -> Optional[float]: + """ + Get sentiment from Twitter + """ + try: + # Check cache first + cache_key = f"twitter_{symbol}" + if cache_key in self.sentiment_cache: + cached_data = self.sentiment_cache[cache_key] + if datetime.now() - cached_data['timestamp'] < self.cache_duration: + return cached_data['sentiment'] + + # Get tweets + tweets = self.twitter_api.search_tweets( + q=f"${symbol}", + lang="en", + count=100 + ) + + if not tweets: + return None + + # Analyze sentiment of each tweet + sentiments = [] + for tweet in tweets: + sentiment = self.analyze_text(tweet.text) + sentiments.append(sentiment) + + # Calculate weighted average sentiment + avg_sentiment = np.mean(sentiments) + + # Cache the result + self.sentiment_cache[cache_key] = { + 'sentiment': avg_sentiment, + 'timestamp': datetime.now() + } + + return avg_sentiment + + except Exception as e: + logger.error(f"Error getting Twitter sentiment: {str(e)}") + return None + + def get_market_sentiment(self, symbol: str) -> Optional[float]: + """ + Get market sentiment indicators + """ + try: + # Check cache first + cache_key = f"market_{symbol}" + if cache_key in self.sentiment_cache: + cached_data = self.sentiment_cache[cache_key] + if datetime.now() - cached_data['timestamp'] < self.cache_duration: + return cached_data['sentiment'] + + # Get market data + ticker = yf.Ticker(symbol) + info = ticker.info + + # Calculate various sentiment indicators + sentiment_indicators = [] + + # RSI sentiment + if 'RSI' in info: + rsi = info['RSI'] + rsi_sentiment = (rsi - 50) / 50 # Normalize to [-1, 1] + sentiment_indicators.append(rsi_sentiment) + + # Volume sentiment + if 'volume' in info and 'averageVolume' in info: + volume_ratio = info['volume'] / info['averageVolume'] + volume_sentiment = (volume_ratio - 1) / volume_ratio # Normalize to [-1, 1] + sentiment_indicators.append(volume_sentiment) + + # Price momentum sentiment + if 'regularMarketChangePercent' in info: + momentum_sentiment = info['regularMarketChangePercent'] / 100 + sentiment_indicators.append(momentum_sentiment) + + if not sentiment_indicators: + return None + + # Calculate weighted average sentiment + avg_sentiment = np.mean(sentiment_indicators) + + # Cache the result + self.sentiment_cache[cache_key] = { + 'sentiment': avg_sentiment, + 'timestamp': datetime.now() + } + + return avg_sentiment + + except Exception as e: + logger.error(f"Error getting market sentiment: {str(e)}") + return None + + def get_combined_sentiment(self, symbol: str) -> Optional[float]: + """ + Get combined sentiment from all sources + """ + try: + # Check cache first + cache_key = f"combined_{symbol}" + if cache_key in self.sentiment_cache: + cached_data = self.sentiment_cache[cache_key] + if datetime.now() - cached_data['timestamp'] < self.cache_duration: + return cached_data['sentiment'] + + # Get sentiment from all sources + sentiments = [] + weights = [] + + # News sentiment + news_sentiment = self.get_news_sentiment(symbol) + if news_sentiment is not None: + sentiments.append(news_sentiment) + weights.append(self.config['sentiment_weights']['news']) + + # Twitter sentiment + twitter_sentiment = self.get_twitter_sentiment(symbol) + if twitter_sentiment is not None: + sentiments.append(twitter_sentiment) + weights.append(self.config['sentiment_weights']['twitter']) + + # Market sentiment + market_sentiment = self.get_market_sentiment(symbol) + if market_sentiment is not None: + sentiments.append(market_sentiment) + weights.append(self.config['sentiment_weights']['market']) + + if not sentiments: + return None + + # Calculate weighted average sentiment + avg_sentiment = np.average(sentiments, weights=weights) + + # Cache the result + self.sentiment_cache[cache_key] = { + 'sentiment': avg_sentiment, + 'timestamp': datetime.now() + } + + return avg_sentiment + + except Exception as e: + logger.error(f"Error getting combined sentiment: {str(e)}") + return None + + def clear_cache(self): + """ + Clear the sentiment cache + """ + self.sentiment_cache.clear() + + def get_sentiment_signal(self, symbol: str) -> int: + """ + Convert sentiment to trading signal + """ + sentiment = self.get_combined_sentiment(symbol) + if sentiment is None: + return 0 + + # Define sentiment thresholds + positive_threshold = self.config['sentiment_thresholds']['positive'] + negative_threshold = self.config['sentiment_thresholds']['negative'] + + if sentiment > positive_threshold: + return 1 # Buy signal + elif sentiment < negative_threshold: + return -1 # Sell signal + else: + return 0 # Neutral signal \ No newline at end of file diff --git a/system_monitor 2.0.py b/system_monitor 2.0.py new file mode 100644 index 0000000..d0e0501 --- /dev/null +++ b/system_monitor 2.0.py @@ -0,0 +1,204 @@ +import logging +import time +import threading +from typing import Dict, Any, Optional +from datetime import datetime +import functools +import traceback +from .code_guardian import CodeGuardian, create_guardian + +logger = logging.getLogger(__name__) + +class SystemMonitor: + def __init__(self, project_root: str): + self.guardian = create_guardian(project_root) + self.component_status: Dict[str, Dict[str, Any]] = {} + self.performance_data: Dict[str, Dict[str, float]] = {} + self.alerts: Dict[str, Dict[str, Any]] = {} + self.running = True + + # Start monitoring thread + self.monitor_thread = threading.Thread(target=self._monitor_system) + self.monitor_thread.daemon = True + self.monitor_thread.start() + + def monitor_component(self, component_name: str): + """Decorator to monitor component performance and errors""" + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + start_time = time.time() + try: + result = func(*args, **kwargs) + execution_time = time.time() - start_time + + # Update performance metrics + self.guardian.monitor_performance(component_name, execution_time) + + # Update component status + self.component_status[component_name] = { + 'status': 'healthy', + 'last_execution': datetime.now().isoformat(), + 'execution_time': execution_time, + 'error': None + } + + return result + + except Exception as e: + error_info = { + 'type': type(e).__name__, + 'message': str(e), + 'traceback': traceback.format_exc() + } + + # Update component status + self.component_status[component_name] = { + 'status': 'error', + 'last_execution': datetime.now().isoformat(), + 'execution_time': time.time() - start_time, + 'error': error_info + } + + # Create alert + self._create_alert( + component_name, + f"Error in {component_name}: {str(e)}", + 'error', + error_info + ) + + logger.error(f"Error in {component_name}: {str(e)}") + raise + + return wrapper + return decorator + + def _create_alert(self, + component: str, + message: str, + level: str, + details: Optional[Dict] = None): + """Create a new alert""" + alert_id = f"{component}_{datetime.now().timestamp()}" + self.alerts[alert_id] = { + 'component': component, + 'message': message, + 'level': level, + 'timestamp': datetime.now().isoformat(), + 'details': details, + 'acknowledged': False + } + + def acknowledge_alert(self, alert_id: str): + """Acknowledge an alert""" + if alert_id in self.alerts: + self.alerts[alert_id]['acknowledged'] = True + + def get_system_status(self) -> Dict[str, Any]: + """Get overall system status""" + return { + 'components': self.component_status, + 'alerts': { + 'total': len(self.alerts), + 'unacknowledged': len([a for a in self.alerts.values() if not a['acknowledged']]), + 'by_level': self._count_alerts_by_level() + }, + 'code_health': self.guardian.get_status_report(), + 'performance': self._get_performance_summary() + } + + def _count_alerts_by_level(self) -> Dict[str, int]: + """Count alerts by level""" + counts = {'error': 0, 'warning': 0, 'info': 0} + for alert in self.alerts.values(): + if alert['level'] in counts: + counts[alert['level']] += 1 + return counts + + def _get_performance_summary(self) -> Dict[str, Dict[str, float]]: + """Get performance summary for all components""" + summary = {} + for component, metrics in self.guardian.performance_metrics.items(): + if metrics: + summary[component] = { + 'avg_execution_time': sum(metrics) / len(metrics), + 'max_execution_time': max(metrics), + 'min_execution_time': min(metrics), + 'total_executions': len(metrics) + } + return summary + + def _monitor_system(self): + """Continuous system monitoring""" + while self.running: + try: + # Check component health + for component, status in self.component_status.items(): + if status['status'] == 'error': + self._create_alert( + component, + f"Component {component} is in error state", + 'error', + status['error'] + ) + + # Check for performance degradation + if component in self.guardian.performance_metrics: + metrics = self.guardian.performance_metrics[component] + if len(metrics) > 10: + recent_avg = sum(metrics[-10:]) / 10 + overall_avg = sum(metrics) / len(metrics) + + if recent_avg > overall_avg * 1.5: # 50% slower + self._create_alert( + component, + f"Performance degradation detected in {component}", + 'warning', + { + 'recent_avg': recent_avg, + 'overall_avg': overall_avg + } + ) + + # Sleep for a while + time.sleep(60) # Check every minute + + except Exception as e: + logger.error(f"Error in system monitoring: {str(e)}") + time.sleep(300) # Wait longer if there's an error + + def stop(self): + """Stop the system monitor""" + self.running = False + self.guardian.stop() + if self.monitor_thread.is_alive(): + self.monitor_thread.join() + +# Example usage +def example_usage(): + # Create system monitor + monitor = SystemMonitor(".") + + # Example component with monitoring + @monitor.monitor_component("example_component") + def example_function(x: int) -> int: + time.sleep(1) # Simulate work + return x * 2 + + try: + # Run component + for i in range(5): + result = example_function(i) + print(f"Result: {result}") + + # Get system status + status = monitor.get_system_status() + print("\nSystem Status:") + print(json.dumps(status, indent=2)) + + finally: + monitor.stop() + +if __name__ == "__main__": + example_usage() \ No newline at end of file diff --git a/technical_analysis 2.0.py b/technical_analysis 2.0.py new file mode 100644 index 0000000..a8b5f99 --- /dev/null +++ b/technical_analysis 2.0.py @@ -0,0 +1,293 @@ +import numpy as np +import pandas as pd +import talib +from typing import Dict, List, Tuple, Optional +import logging + +logger = logging.getLogger(__name__) + +class TechnicalAnalyzer: + def __init__(self, config: Dict): + self.config = config + self.indicators = {} + self.patterns = {} + + def add_indicators(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Add technical indicators to the dataframe + """ + df = df.copy() + + # Trend Indicators + df['sma_20'] = talib.SMA(df['close'], timeperiod=20) + df['sma_50'] = talib.SMA(df['close'], timeperiod=50) + df['sma_200'] = talib.SMA(df['close'], timeperiod=200) + df['ema_20'] = talib.EMA(df['close'], timeperiod=20) + + # Volatility Indicators + df['upperband'], df['middleband'], df['lowerband'] = talib.BBANDS( + df['close'], + timeperiod=self.config['indicators']['bollinger_bands']['period'], + nbdevup=self.config['indicators']['bollinger_bands']['std_dev'], + nbdevdn=self.config['indicators']['bollinger_bands']['std_dev'] + ) + df['atr'] = talib.ATR( + df['high'], + df['low'], + df['close'], + timeperiod=self.config['indicators']['atr']['period'] + ) + + # Momentum Indicators + df['rsi'] = talib.RSI( + df['close'], + timeperiod=self.config['indicators']['rsi']['period'] + ) + df['macd'], df['macdsignal'], df['macdhist'] = talib.MACD( + df['close'], + fastperiod=self.config['indicators']['macd']['fast_period'], + slowperiod=self.config['indicators']['macd']['slow_period'], + signalperiod=self.config['indicators']['macd']['signal_period'] + ) + + # Volume Indicators + df['obv'] = talib.OBV(df['close'], df['volume']) + + # Additional Indicators + df['adx'] = talib.ADX(df['high'], df['low'], df['close'], timeperiod=14) + df['cci'] = talib.CCI(df['high'], df['low'], df['close'], timeperiod=14) + df['stoch_k'], df['stoch_d'] = talib.STOCH( + df['high'], + df['low'], + df['close'], + fastk_period=14, + slowk_period=3, + slowd_period=3 + ) + + # Store indicators for reference + self.indicators = { + 'trend': ['sma_20', 'sma_50', 'sma_200', 'ema_20'], + 'volatility': ['upperband', 'middleband', 'lowerband', 'atr'], + 'momentum': ['rsi', 'macd', 'macdsignal', 'macdhist'], + 'volume': ['obv'], + 'additional': ['adx', 'cci', 'stoch_k', 'stoch_d'] + } + + return df + + def detect_patterns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Detect candlestick patterns and chart patterns + """ + df = df.copy() + + # Candlestick Patterns + if self.config['patterns']['candlestick']: + df['doji'] = talib.CDLDOJI(df['open'], df['high'], df['low'], df['close']) + df['hammer'] = talib.CDLHAMMER(df['open'], df['high'], df['low'], df['close']) + df['engulfing'] = talib.CDLENGULFING(df['open'], df['high'], df['low'], df['close']) + df['morning_star'] = talib.CDLMORNINGSTAR(df['open'], df['high'], df['low'], df['close']) + df['evening_star'] = talib.CDLEVENINGSTAR(df['open'], df['high'], df['low'], df['close']) + + # Chart Patterns + if self.config['patterns']['chart']: + df['head_and_shoulders'] = self._detect_head_and_shoulders(df) + df['double_top'] = self._detect_double_top(df) + df['double_bottom'] = self._detect_double_bottom(df) + df['triangle'] = self._detect_triangle(df) + + return df + + def _detect_head_and_shoulders(self, df: pd.DataFrame) -> pd.Series: + """ + Detect head and shoulders pattern + """ + pattern = pd.Series(0, index=df.index) + + for i in range(20, len(df) - 20): + # Find potential left shoulder + left_shoulder = df['high'].iloc[i-20:i].max() + left_shoulder_idx = df['high'].iloc[i-20:i].idxmax() + + # Find potential head + head = df['high'].iloc[i-10:i+10].max() + head_idx = df['high'].iloc[i-10:i+10].idxmax() + + # Find potential right shoulder + right_shoulder = df['high'].iloc[i:i+20].max() + right_shoulder_idx = df['high'].iloc[i:i+20].idxmax() + + # Find neckline + neckline = min(df['low'].iloc[left_shoulder_idx:right_shoulder_idx]) + + # Check pattern conditions + if (left_shoulder < head and right_shoulder < head and + abs(left_shoulder - right_shoulder) / head < 0.1): + pattern.iloc[i] = 1 + + return pattern + + def _detect_double_top(self, df: pd.DataFrame) -> pd.Series: + """ + Detect double top pattern + """ + pattern = pd.Series(0, index=df.index) + + for i in range(20, len(df) - 20): + # Find potential first peak + first_peak = df['high'].iloc[i-20:i].max() + first_peak_idx = df['high'].iloc[i-20:i].idxmax() + + # Find potential second peak + second_peak = df['high'].iloc[i:i+20].max() + second_peak_idx = df['high'].iloc[i:i+20].idxmax() + + # Find valley between peaks + valley = df['low'].iloc[first_peak_idx:second_peak_idx].min() + + # Check pattern conditions + if (abs(first_peak - second_peak) / first_peak < 0.02 and + (first_peak - valley) / first_peak > 0.02): + pattern.iloc[i] = 1 + + return pattern + + def _detect_double_bottom(self, df: pd.DataFrame) -> pd.Series: + """ + Detect double bottom pattern + """ + pattern = pd.Series(0, index=df.index) + + for i in range(20, len(df) - 20): + # Find potential first bottom + first_bottom = df['low'].iloc[i-20:i].min() + first_bottom_idx = df['low'].iloc[i-20:i].idxmin() + + # Find potential second bottom + second_bottom = df['low'].iloc[i:i+20].min() + second_bottom_idx = df['low'].iloc[i:i+20].idxmin() + + # Find peak between bottoms + peak = df['high'].iloc[first_bottom_idx:second_bottom_idx].max() + + # Check pattern conditions + if (abs(first_bottom - second_bottom) / first_bottom < 0.02 and + (peak - first_bottom) / first_bottom > 0.02): + pattern.iloc[i] = 1 + + return pattern + + def _detect_triangle(self, df: pd.DataFrame) -> pd.Series: + """ + Detect triangle patterns (ascending, descending, symmetrical) + """ + pattern = pd.Series(0, index=df.index) + + for i in range(20, len(df) - 20): + # Get highs and lows for the period + highs = df['high'].iloc[i-20:i] + lows = df['low'].iloc[i-20:i] + + # Calculate trend lines + high_slope = np.polyfit(range(len(highs)), highs, 1)[0] + low_slope = np.polyfit(range(len(lows)), lows, 1)[0] + + # Classify triangle type + if abs(high_slope) < 0.001 and low_slope > 0.001: + pattern.iloc[i] = 1 # Ascending triangle + elif high_slope < -0.001 and abs(low_slope) < 0.001: + pattern.iloc[i] = 2 # Descending triangle + elif abs(high_slope + low_slope) < 0.001: + pattern.iloc[i] = 3 # Symmetrical triangle + + return pattern + + def generate_signals(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Generate trading signals based on technical indicators and patterns + """ + df = df.copy() + + # Initialize signal column + df['signal'] = 0 + + # RSI signals + df.loc[df['rsi'] < self.config['indicators']['rsi']['oversold'], 'signal'] += 1 + df.loc[df['rsi'] > self.config['indicators']['rsi']['overbought'], 'signal'] -= 1 + + # MACD signals + df.loc[df['macd'] > df['macdsignal'], 'signal'] += 1 + df.loc[df['macd'] < df['macdsignal'], 'signal'] -= 1 + + # Bollinger Bands signals + df.loc[df['close'] < df['lowerband'], 'signal'] += 1 + df.loc[df['close'] > df['upperband'], 'signal'] -= 1 + + # Trend signals + df.loc[df['close'] > df['sma_20'], 'signal'] += 1 + df.loc[df['close'] < df['sma_20'], 'signal'] -= 1 + + # Pattern signals + if 'head_and_shoulders' in df.columns: + df.loc[df['head_and_shoulders'] == 1, 'signal'] -= 1 + if 'double_top' in df.columns: + df.loc[df['double_top'] == 1, 'signal'] -= 1 + if 'double_bottom' in df.columns: + df.loc[df['double_bottom'] == 1, 'signal'] += 1 + if 'triangle' in df.columns: + df.loc[df['triangle'] == 1, 'signal'] += 1 # Ascending + df.loc[df['triangle'] == 2, 'signal'] -= 1 # Descending + + # Normalize signals to -1, 0, 1 + df['signal'] = df['signal'].apply(lambda x: 1 if x > 2 else (-1 if x < -2 else 0)) + + return df + + def calculate_support_resistance(self, df: pd.DataFrame, window: int = 20) -> Tuple[pd.Series, pd.Series]: + """ + Calculate support and resistance levels + """ + support = df['low'].rolling(window=window).min() + resistance = df['high'].rolling(window=window).max() + + return support, resistance + + def calculate_volatility(self, df: pd.DataFrame) -> pd.Series: + """ + Calculate various volatility measures + """ + # ATR-based volatility + atr_volatility = df['atr'] / df['close'] + + # Bollinger Band width + bb_width = (df['upperband'] - df['lowerband']) / df['middleband'] + + # Historical volatility + returns = df['close'].pct_change() + hist_volatility = returns.rolling(window=20).std() + + return pd.DataFrame({ + 'atr_volatility': atr_volatility, + 'bb_width': bb_width, + 'hist_volatility': hist_volatility + }) + + def get_market_regime(self, df: pd.DataFrame) -> pd.Series: + """ + Determine market regime (trending, ranging, volatile) + """ + regime = pd.Series('unknown', index=df.index) + + # Calculate ADX for trend strength + adx = df['adx'] + + # Calculate volatility + volatility = self.calculate_volatility(df)['atr_volatility'] + + # Determine regime + regime.loc[adx > 25] = 'trending' + regime.loc[(adx <= 25) & (volatility > volatility.rolling(window=20).mean())] = 'volatile' + regime.loc[(adx <= 25) & (volatility <= volatility.rolling(window=20).mean())] = 'ranging' + + return regime \ No newline at end of file diff --git a/trading_strategy2.0.py b/trading_strategy2.0.py new file mode 100644 index 0000000..7fbbc9b --- /dev/null +++ b/trading_strategy2.0.py @@ -0,0 +1,303 @@ +import numpy as np +import pandas as pd +from typing import Dict, List, Optional, Tuple +import logging +from datetime import datetime +from dataclasses import dataclass +import json +import os + +from .technical_analysis import TechnicalAnalyzer +from .machine_learning import MachineLearningModel +from .risk_management import RiskManager +from .sentiment_analysis import SentimentAnalyzer + +logger = logging.getLogger(__name__) + +@dataclass +class TradeSignal: + """Data class to store trade signals""" + symbol: str + action: str # 'buy', 'sell', or 'hold' + confidence: float + price: float + stop_loss: float + take_profit: float + position_size: float + timestamp: datetime + technical_score: float + ml_score: float + sentiment_score: float + risk_score: float + +class TradingStrategy: + def __init__(self, config: Dict): + self.config = config + self.technical_analyzer = TechnicalAnalyzer(config) + self.ml_model = MachineLearningModel(config) + self.risk_manager = RiskManager(config) + self.sentiment_analyzer = SentimentAnalyzer(config) + + # Initialize state + self.active_trades = {} + self.trade_history = [] + self.performance_metrics = {} + + def analyze_market(self, symbol: str, data: pd.DataFrame) -> TradeSignal: + """ + Analyze market conditions and generate trading signals + """ + try: + # Technical analysis + technical_signals = self.technical_analyzer.generate_signals(data) + technical_score = technical_signals['signal'] + + # Machine learning prediction + ml_predictions = self.ml_model.predict(data) + ml_score = ml_predictions[-1] if ml_predictions is not None else 0 + + # Sentiment analysis + sentiment_score = self.sentiment_analyzer.get_combined_sentiment(symbol) + if sentiment_score is None: + sentiment_score = 0 + + # Risk assessment + risk_score = self.risk_manager.calculate_risk_metrics() + + # Combine signals + combined_score = ( + technical_score * self.config['signal_weights']['technical'] + + ml_score * self.config['signal_weights']['ml'] + + sentiment_score * self.config['signal_weights']['sentiment'] + + risk_score * self.config['signal_weights']['risk'] + ) + + # Generate trading signal + current_price = data['close'].iloc[-1] + + # Calculate stop loss and take profit levels + stop_loss = self._calculate_stop_loss(current_price, combined_score) + take_profit = self._calculate_take_profit(current_price, combined_score) + + # Calculate position size + position_size, required_margin = self.risk_manager.calculate_position_size( + current_price, + stop_loss, + self.risk_manager.current_capital + ) + + # Determine action + if combined_score > self.config['signal_thresholds']['buy']: + action = 'buy' + elif combined_score < self.config['signal_thresholds']['sell']: + action = 'sell' + else: + action = 'hold' + + # Create trade signal + signal = TradeSignal( + symbol=symbol, + action=action, + confidence=abs(combined_score), + price=current_price, + stop_loss=stop_loss, + take_profit=take_profit, + position_size=position_size, + timestamp=datetime.now(), + technical_score=technical_score, + ml_score=ml_score, + sentiment_score=sentiment_score, + risk_score=risk_score + ) + + return signal + + except Exception as e: + logger.error(f"Error analyzing market: {str(e)}") + return None + + def execute_trade(self, signal: TradeSignal) -> bool: + """ + Execute a trade based on the signal + """ + try: + # Validate trade + if not self.risk_manager.validate_trade( + signal.symbol, + signal.position_size, + signal.price, + signal.stop_loss, + signal.take_profit + ): + return False + + # Execute trade + if signal.action in ['buy', 'sell']: + # Update position + pnl = self.risk_manager.update_position( + signal.symbol, + signal.price, + signal.price, + signal.position_size, + signal.action + ) + + if pnl is not None: + # Record trade + self.trade_history.append({ + 'symbol': signal.symbol, + 'action': signal.action, + 'entry_price': signal.price, + 'exit_price': signal.price, + 'position_size': signal.position_size, + 'pnl': pnl, + 'entry_time': signal.timestamp, + 'exit_time': datetime.now() + }) + + # Update performance metrics + self._update_performance_metrics() + + return True + + return False + + except Exception as e: + logger.error(f"Error executing trade: {str(e)}") + return False + + def update_positions(self, current_prices: Dict[str, float]): + """ + Update all open positions with current prices + """ + try: + for symbol, price in current_prices.items(): + if symbol in self.risk_manager.positions: + position = self.risk_manager.positions[symbol] + pnl = self.risk_manager.update_position( + symbol, + position['entry_price'], + price, + position['position_size'], + position['position_type'] + ) + + if pnl is not None: + # Record trade + self.trade_history.append({ + 'symbol': symbol, + 'action': 'close', + 'entry_price': position['entry_price'], + 'exit_price': price, + 'position_size': position['position_size'], + 'pnl': pnl, + 'entry_time': position['entry_time'], + 'exit_time': datetime.now() + }) + + # Update performance metrics + self._update_performance_metrics() + + except Exception as e: + logger.error(f"Error updating positions: {str(e)}") + + def _calculate_stop_loss(self, price: float, signal: float) -> float: + """ + Calculate stop loss level based on signal strength + """ + # Adjust stop loss distance based on signal strength + base_stop_loss = self.config['stop_loss_pct'] + signal_factor = abs(signal) + stop_loss_distance = base_stop_loss * (1 + signal_factor) + + if signal > 0: # Buy signal + return price * (1 - stop_loss_distance) + else: # Sell signal + return price * (1 + stop_loss_distance) + + def _calculate_take_profit(self, price: float, signal: float) -> float: + """ + Calculate take profit level based on signal strength + """ + # Adjust take profit distance based on signal strength + base_take_profit = self.config['take_profit_pct'] + signal_factor = abs(signal) + take_profit_distance = base_take_profit * (1 + signal_factor) + + if signal > 0: # Buy signal + return price * (1 + take_profit_distance) + else: # Sell signal + return price * (1 - take_profit_distance) + + def _update_performance_metrics(self): + """ + Update performance metrics based on trade history + """ + if not self.trade_history: + return + + # Convert trade history to DataFrame + df = pd.DataFrame(self.trade_history) + + # Calculate metrics + self.performance_metrics = { + 'total_trades': len(df), + 'winning_trades': len(df[df['pnl'] > 0]), + 'losing_trades': len(df[df['pnl'] < 0]), + 'win_rate': len(df[df['pnl'] > 0]) / len(df), + 'total_pnl': df['pnl'].sum(), + 'avg_pnl': df['pnl'].mean(), + 'max_drawdown': self.risk_manager.risk_metrics.max_drawdown if self.risk_manager.risk_metrics else 0, + 'sharpe_ratio': self.risk_manager.risk_metrics.sharpe_ratio if self.risk_manager.risk_metrics else 0, + 'profit_factor': self.risk_manager.risk_metrics.profit_factor if self.risk_manager.risk_metrics else 0 + } + + def should_stop_trading(self) -> bool: + """ + Check if trading should be stopped based on risk metrics + """ + return self.risk_manager.should_stop_trading() + + def save_state(self, filepath: str): + """ + Save trading strategy state + """ + try: + state = { + 'active_trades': self.active_trades, + 'trade_history': self.trade_history, + 'performance_metrics': self.performance_metrics, + 'risk_metrics': self.risk_manager.risk_metrics.__dict__ if self.risk_manager.risk_metrics else None + } + + with open(filepath, 'w') as f: + json.dump(state, f, default=str) + + logger.info(f"Trading strategy state saved to {filepath}") + return True + + except Exception as e: + logger.error(f"Error saving state: {str(e)}") + return False + + def load_state(self, filepath: str): + """ + Load trading strategy state + """ + try: + with open(filepath, 'r') as f: + state = json.load(f) + + self.active_trades = state['active_trades'] + self.trade_history = state['trade_history'] + self.performance_metrics = state['performance_metrics'] + + if state['risk_metrics']: + self.risk_manager.risk_metrics = RiskMetrics(**state['risk_metrics']) + + logger.info(f"Trading strategy state loaded from {filepath}") + return True + + except Exception as e: + logger.error(f"Error loading state: {str(e)}") + return False \ No newline at end of file diff --git a/trading_system 2.0.2.py b/trading_system 2.0.2.py new file mode 100644 index 0000000..c417fcc --- /dev/null +++ b/trading_system 2.0.2.py @@ -0,0 +1,242 @@ +import numpy as np +import pandas as pd +from datetime import datetime, timedelta +import logging +from typing import Dict, List, Optional, Tuple +from dataclasses import dataclass +import json +import os +from .system_monitor import SystemMonitor + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('logs/trading_system.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +@dataclass +class Trade: + symbol: str + direction: str + entry_price: float + stop_loss: float + take_profit: float + position_size: float + entry_time: datetime + exit_price: Optional[float] = None + exit_time: Optional[datetime] = None + pnl: Optional[float] = None + status: str = 'open' + +class TradingSystem: + def __init__(self, config_path: str): + # Load configuration + with open(config_path, 'r') as f: + self.config = json.load(f) + + # Initialize system monitor + self.monitor = SystemMonitor(os.path.dirname(os.path.dirname(__file__))) + + # Initialize trading parameters + self.initial_capital = self.config['trading']['initial_capital'] + self.current_capital = self.initial_capital + self.performance_history = [] + self.active_trades: List[Trade] = [] + + # Initialize strategy parameters + self.strategy_params = self.config['strategy'] + self.risk_params = self.config['risk_management'] + + # Initialize performance metrics + self.metrics = { + 'win_rate': 0.0, + 'profit_factor': 0.0, + 'max_drawdown': 0.0, + 'sharpe_ratio': 0.0, + 'total_trades': 0, + 'winning_trades': 0, + 'losing_trades': 0 + } + + @SystemMonitor.monitor_component("strategy_execution") + def execute_strategy(self, market_data: pd.DataFrame) -> Optional[Dict]: + """Execute trading strategy""" + try: + # Generate trading signals + signal = self._generate_signals(market_data) + + if signal: + # Validate trade + if self._validate_trade(signal): + # Execute trade + trade = self._execute_trade(signal) + return {'status': 'success', 'trade': trade} + + return None + + except Exception as e: + logger.error(f"Error executing strategy: {str(e)}") + return {'status': 'error', 'message': str(e)} + + @SystemMonitor.monitor_component("risk_management") + def _validate_trade(self, signal: Dict) -> bool: + """Validate trade against risk parameters""" + try: + # Check if we have too many open trades + if len(self.active_trades) >= self.risk_params['max_positions']: + return False + + # Check if we have enough capital + required_margin = self._calculate_margin(signal) + if required_margin > self.current_capital * self.risk_params['max_position_size']: + return False + + # Check if we're within daily loss limit + if self._check_daily_loss_limit(): + return False + + return True + + except Exception as e: + logger.error(f"Error validating trade: {str(e)}") + return False + + @SystemMonitor.monitor_component("trade_execution") + def _execute_trade(self, signal: Dict) -> Optional[Trade]: + """Execute a trade""" + try: + # Calculate position size + position_size = self._calculate_position_size(signal) + + # Create trade object + trade = Trade( + symbol=signal['symbol'], + direction=signal['direction'], + entry_price=signal['price'], + stop_loss=signal['stop_loss'], + take_profit=signal['take_profit'], + position_size=position_size, + entry_time=datetime.now(), + exit_price=None, + exit_time=None, + pnl=None, + status='open' + ) + + # Add to active trades + self.active_trades.append(trade) + + return trade + + except Exception as e: + logger.error(f"Error executing trade: {str(e)}") + return None + + @SystemMonitor.monitor_component("performance_monitoring") + def update_performance(self): + """Update performance metrics""" + try: + if not self.performance_history: + return + + # Calculate basic metrics + total_trades = len(self.performance_history) + winning_trades = len([t for t in self.performance_history if t['pnl'] > 0]) + + self.metrics.update({ + 'total_trades': total_trades, + 'winning_trades': winning_trades, + 'losing_trades': total_trades - winning_trades, + 'win_rate': winning_trades / total_trades if total_trades > 0 else 0 + }) + + # Calculate advanced metrics + self._calculate_advanced_metrics() + + # Check if we need to adjust strategy + self._check_strategy_adjustment() + + except Exception as e: + logger.error(f"Error updating performance: {str(e)}") + + @SystemMonitor.monitor_component("strategy_adjustment") + def _check_strategy_adjustment(self): + """Check if strategy needs adjustment""" + try: + # Check win rate + if self.metrics['win_rate'] < self.strategy_params['min_win_rate']: + self._adjust_strategy('defensive') + elif self.metrics['win_rate'] > self.strategy_params['target_win_rate']: + self._adjust_strategy('aggressive') + + # Check drawdown + if self.metrics['max_drawdown'] > self.risk_params['max_drawdown']: + self._adjust_strategy('risk_reduction') + + except Exception as e: + logger.error(f"Error checking strategy adjustment: {str(e)}") + + def _adjust_strategy(self, mode: str): + """Adjust strategy parameters""" + if mode == 'defensive': + self.strategy_params['position_size'] *= 0.8 + self.strategy_params['stop_loss_multiplier'] *= 0.9 + + elif mode == 'aggressive': + self.strategy_params['position_size'] *= 1.2 + self.strategy_params['take_profit_multiplier'] *= 1.1 + + elif mode == 'risk_reduction': + self.strategy_params['position_size'] *= 0.7 + self.strategy_params['max_positions'] = max(1, self.strategy_params['max_positions'] - 1) + + def get_status(self) -> Dict: + """Get current system status""" + return { + 'capital': self.current_capital, + 'active_trades': len(self.active_trades), + 'metrics': self.metrics, + 'system_health': self.monitor.get_system_status() + } + + def stop(self): + """Stop the trading system""" + self.monitor.stop() + +def create_trading_system(config_path: str) -> TradingSystem: + """Create and initialize a trading system""" + return TradingSystem(config_path) + +if __name__ == "__main__": + # Example usage + config_path = os.path.join(os.path.dirname(__file__), '..', 'config', 'config.json') + trading_system = create_trading_system(config_path) + + try: + # Simulate some trading + market_data = pd.DataFrame({ + 'timestamp': pd.date_range(start='2024-01-01', periods=100, freq='H'), + 'open': np.random.randn(100).cumsum() + 100, + 'high': np.random.randn(100).cumsum() + 102, + 'low': np.random.randn(100).cumsum() + 98, + 'close': np.random.randn(100).cumsum() + 100, + 'volume': np.random.randint(1000, 10000, 100) + }) + + for i in range(len(market_data)): + result = trading_system.execute_strategy(market_data.iloc[:i+1]) + if result and result['status'] == 'success': + print(f"Executed trade: {result['trade']}") + + # Get final status + status = trading_system.get_status() + print("\nFinal Status:") + print(json.dumps(status, indent=2, default=str)) + + finally: + trading_system.stop() \ No newline at end of file diff --git a/trading_system 2.0.py b/trading_system 2.0.py new file mode 100644 index 0000000..5a68e1b --- /dev/null +++ b/trading_system 2.0.py @@ -0,0 +1,318 @@ +import numpy as np +import pandas as pd +from datetime import datetime, timedelta +import logging +from typing import Dict, List, Optional, Tuple +from dataclasses import dataclass +import json +import os + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('logs/trading_system.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + +@dataclass +class Trade: + symbol: str + direction: str + entry_price: float + stop_loss: float + take_profit: float + position_size: float + entry_time: datetime + exit_price: Optional[float] = None + exit_time: Optional[datetime] = None + pnl: Optional[float] = None + status: str = 'open' + +class TradingSystem: + def __init__(self, initial_capital: float = 50.0): + self.initial_capital = initial_capital + self.current_capital = initial_capital + self.performance_history: List[Dict] = [] + self.active_trades: Dict[str, Trade] = {} + self.trade_history: List[Trade] = [] + self.strategy_parameters = self._get_initial_parameters() + self.risk_metrics = self._initialize_risk_metrics() + self.last_recalibration = datetime.now() + + # Load configuration + self._load_config() + + def _load_config(self): + """Load configuration from config file""" + try: + with open('config/config.json', 'r') as f: + self.config = json.load(f) + except FileNotFoundError: + logger.warning("Config file not found. Using default parameters.") + self.config = self._get_default_config() + + def _get_default_config(self) -> Dict: + """Get default configuration parameters""" + return { + 'risk_per_trade': 0.01, # 1% risk per trade + 'max_positions': 2, + 'min_win_rate': 0.4, + 'recalibration_window': 20, + 'max_drawdown': 0.1, # 10% maximum drawdown + 'leverage': 1, # No leverage initially + 'position_sizing': { + 'method': 'fixed_fractional', + 'fraction': 0.01 # 1% of capital per trade + } + } + + def _get_initial_parameters(self) -> Dict: + """Get initial strategy parameters""" + return { + 'rsi_period': 14, + 'rsi_overbought': 70, + 'rsi_oversold': 30, + 'bb_period': 20, + 'bb_std': 2, + 'macd_fast': 12, + 'macd_slow': 26, + 'macd_signal': 9, + 'atr_period': 14, + 'atr_multiplier': 2 + } + + def _initialize_risk_metrics(self) -> Dict: + """Initialize risk metrics tracking""" + return { + 'total_trades': 0, + 'winning_trades': 0, + 'losing_trades': 0, + 'win_rate': 0.0, + 'profit_factor': 0.0, + 'max_drawdown': 0.0, + 'current_drawdown': 0.0, + 'avg_trade': 0.0, + 'largest_win': 0.0, + 'largest_loss': 0.0 + } + + def monitor_performance(self, window_size: int = 20) -> bool: + """ + Monitor recent performance and determine if recalibration is needed + Returns True if recalibration is needed + """ + if len(self.performance_history) < window_size: + return False + + recent_performance = self.performance_history[-window_size:] + win_rate = sum(1 for trade in recent_performance if trade['pnl'] > 0) / window_size + + # Check various performance metrics + needs_recalibration = False + + # Win rate check + if win_rate < self.config['min_win_rate']: + logger.warning(f"Win rate {win_rate:.2%} below threshold {self.config['min_win_rate']:.2%}") + needs_recalibration = True + + # Drawdown check + current_drawdown = self._calculate_drawdown() + if current_drawdown > self.config['max_drawdown']: + logger.warning(f"Current drawdown {current_drawdown:.2%} exceeds maximum {self.config['max_drawdown']:.2%}") + needs_recalibration = True + + # Profit factor check + profit_factor = self._calculate_profit_factor(recent_performance) + if profit_factor < 1.0: + logger.warning(f"Profit factor {profit_factor:.2f} below 1.0") + needs_recalibration = True + + return needs_recalibration + + def recalibrate_strategy(self, market_data: pd.DataFrame): + """ + Adjust strategy parameters based on recent market conditions + """ + logger.info("Starting strategy recalibration") + + # Analyze market conditions + volatility = self._calculate_volatility(market_data) + trend_strength = self._calculate_trend_strength(market_data) + + # Adjust parameters based on market conditions + new_parameters = self.strategy_parameters.copy() + + # Adjust RSI levels based on volatility + if volatility > 0.02: # High volatility + new_parameters['rsi_overbought'] = 75 + new_parameters['rsi_oversold'] = 25 + else: # Low volatility + new_parameters['rsi_overbought'] = 70 + new_parameters['rsi_oversold'] = 30 + + # Adjust ATR multiplier based on trend strength + if trend_strength > 0.7: # Strong trend + new_parameters['atr_multiplier'] = 2.5 + else: # Weak trend + new_parameters['atr_multiplier'] = 2.0 + + # Update parameters + self.strategy_parameters = new_parameters + self.last_recalibration = datetime.now() + + logger.info("Strategy recalibration completed") + logger.info(f"New parameters: {new_parameters}") + + def calculate_position_size(self, entry_price: float, stop_loss: float) -> float: + """ + Calculate position size based on risk management rules + """ + risk_amount = self.current_capital * self.config['risk_per_trade'] + risk_per_unit = abs(entry_price - stop_loss) + + if risk_per_unit == 0: + logger.warning("Risk per unit is zero. Cannot calculate position size.") + return 0 + + position_size = risk_amount / risk_per_unit + + # Apply leverage if configured + if self.config['leverage'] > 1: + position_size *= self.config['leverage'] + + # Ensure position size doesn't exceed maximum allowed + max_position = self.current_capital * self.config['position_sizing']['fraction'] + position_size = min(position_size, max_position) + + return position_size + + def _calculate_volatility(self, data: pd.DataFrame) -> float: + """Calculate market volatility""" + returns = data['close'].pct_change() + return returns.std() + + def _calculate_trend_strength(self, data: pd.DataFrame) -> float: + """Calculate trend strength using ADX""" + # Implementation would go here + return 0.5 # Placeholder + + def _calculate_drawdown(self) -> float: + """Calculate current drawdown""" + if not self.performance_history: + return 0.0 + + peak = max(self.performance_history, key=lambda x: x['equity'])['equity'] + current = self.performance_history[-1]['equity'] + return (peak - current) / peak + + def _calculate_profit_factor(self, trades: List[Dict]) -> float: + """Calculate profit factor from recent trades""" + gross_profit = sum(t['pnl'] for t in trades if t['pnl'] > 0) + gross_loss = abs(sum(t['pnl'] for t in trades if t['pnl'] < 0)) + + if gross_loss == 0: + return float('inf') + + return gross_profit / gross_loss + + def update_risk_metrics(self, trade: Trade): + """Update risk metrics after a trade""" + self.risk_metrics['total_trades'] += 1 + + if trade.pnl and trade.pnl > 0: + self.risk_metrics['winning_trades'] += 1 + self.risk_metrics['largest_win'] = max( + self.risk_metrics['largest_win'], + trade.pnl + ) + elif trade.pnl and trade.pnl < 0: + self.risk_metrics['losing_trades'] += 1 + self.risk_metrics['largest_loss'] = min( + self.risk_metrics['largest_loss'], + trade.pnl + ) + + # Update win rate + if self.risk_metrics['total_trades'] > 0: + self.risk_metrics['win_rate'] = ( + self.risk_metrics['winning_trades'] / + self.risk_metrics['total_trades'] + ) + + # Update average trade + if trade.pnl: + self.risk_metrics['avg_trade'] = ( + (self.risk_metrics['avg_trade'] * (self.risk_metrics['total_trades'] - 1) + + trade.pnl) / self.risk_metrics['total_trades'] + ) + + def save_state(self): + """Save current system state""" + state = { + 'current_capital': self.current_capital, + 'strategy_parameters': self.strategy_parameters, + 'risk_metrics': self.risk_metrics, + 'last_recalibration': self.last_recalibration.isoformat(), + 'active_trades': { + symbol: { + 'direction': trade.direction, + 'entry_price': trade.entry_price, + 'stop_loss': trade.stop_loss, + 'take_profit': trade.take_profit, + 'position_size': trade.position_size, + 'entry_time': trade.entry_time.isoformat() + } + for symbol, trade in self.active_trades.items() + } + } + + try: + with open('data/system_state.json', 'w') as f: + json.dump(state, f, indent=4) + except Exception as e: + logger.error(f"Error saving system state: {str(e)}") + + def load_state(self): + """Load system state from file""" + try: + with open('data/system_state.json', 'r') as f: + state = json.load(f) + + self.current_capital = state['current_capital'] + self.strategy_parameters = state['strategy_parameters'] + self.risk_metrics = state['risk_metrics'] + self.last_recalibration = datetime.fromisoformat(state['last_recalibration']) + + # Reconstruct active trades + self.active_trades = {} + for symbol, trade_data in state['active_trades'].items(): + self.active_trades[symbol] = Trade( + symbol=symbol, + direction=trade_data['direction'], + entry_price=trade_data['entry_price'], + stop_loss=trade_data['stop_loss'], + take_profit=trade_data['take_profit'], + position_size=trade_data['position_size'], + entry_time=datetime.fromisoformat(trade_data['entry_time']) + ) + except FileNotFoundError: + logger.info("No saved state found. Starting fresh.") + except Exception as e: + logger.error(f"Error loading system state: {str(e)}") + + def get_system_status(self) -> Dict: + """Get current system status""" + return { + 'current_capital': self.current_capital, + 'total_trades': self.risk_metrics['total_trades'], + 'win_rate': self.risk_metrics['win_rate'], + 'profit_factor': self.risk_metrics['profit_factor'], + 'current_drawdown': self.risk_metrics['current_drawdown'], + 'active_trades': len(self.active_trades), + 'last_recalibration': self.last_recalibration.isoformat(), + 'strategy_parameters': self.strategy_parameters + } \ No newline at end of file diff --git a/visualization 2.0.py b/visualization 2.0.py new file mode 100644 index 0000000..df97be0 --- /dev/null +++ b/visualization 2.0.py @@ -0,0 +1,169 @@ +import pandas as pd +import plotly.graph_objects as go +from plotly.subplots import make_subplots +from typing import Dict, List +import json +import os + +def plot_backtest_results(results_file: str, save_path: str = None): + """ + Create interactive plots for backtest results + """ + # Load results + with open(results_file, 'r') as f: + results = json.load(f) + + # Convert data to DataFrames + trades_df = pd.DataFrame(results['trades']) + equity_df = pd.DataFrame(results['equity_curve']) + + # Create figure with secondary y-axis + fig = make_subplots( + rows=2, cols=1, + shared_xaxes=True, + vertical_spacing=0.03, + subplot_titles=('Price and Trades', 'Equity Curve'), + row_heights=[0.7, 0.3] + ) + + # Add price line + fig.add_trace( + go.Scatter( + x=trades_df['timestamp'], + y=trades_df['price'], + name='Price', + line=dict(color='blue') + ), + row=1, col=1 + ) + + # Add buy trades + buy_trades = trades_df[trades_df['action'] == 'buy'] + fig.add_trace( + go.Scatter( + x=buy_trades['timestamp'], + y=buy_trades['price'], + mode='markers', + name='Buy', + marker=dict(color='green', size=10) + ), + row=1, col=1 + ) + + # Add sell trades + sell_trades = trades_df[trades_df['action'] == 'sell'] + fig.add_trace( + go.Scatter( + x=sell_trades['timestamp'], + y=sell_trades['price'], + mode='markers', + name='Sell', + marker=dict(color='red', size=10) + ), + row=1, col=1 + ) + + # Add equity curve + fig.add_trace( + go.Scatter( + x=equity_df['timestamp'], + y=equity_df['equity'], + name='Equity', + line=dict(color='purple') + ), + row=2, col=1 + ) + + # Update layout + fig.update_layout( + title='Backtest Results', + xaxis_title='Date', + yaxis_title='Price', + yaxis2_title='Equity', + showlegend=True, + height=800 + ) + + # Save plot if path is provided + if save_path: + fig.write_html(save_path) + print(f"Plot saved to {save_path}") + + return fig + +def plot_performance_metrics(results_files: List[str], save_path: str = None): + """ + Create comparison plot of performance metrics across different scenarios + """ + metrics_data = [] + + for file in results_files: + with open(file, 'r') as f: + results = json.load(f) + metrics = results['performance_metrics'] + + # Extract scenario name from filename + scenario_name = os.path.basename(file).replace('backtest_results_', '').replace('.json', '') + + metrics_data.append({ + 'Scenario': scenario_name, + 'Total Return': metrics['total_return'], + 'Annual Return': metrics['annual_return'], + 'Sharpe Ratio': metrics['sharpe_ratio'], + 'Max Drawdown': metrics['max_drawdown'], + 'Win Rate': metrics['win_rate'] + }) + + # Create DataFrame + df = pd.DataFrame(metrics_data) + + # Create figure + fig = go.Figure() + + # Add bars for each metric + metrics = ['Total Return', 'Annual Return', 'Sharpe Ratio', 'Max Drawdown', 'Win Rate'] + for metric in metrics: + fig.add_trace( + go.Bar( + name=metric, + x=df['Scenario'], + y=df[metric] + ) + ) + + # Update layout + fig.update_layout( + title='Performance Metrics Comparison', + xaxis_title='Scenario', + yaxis_title='Value', + barmode='group', + height=600 + ) + + # Save plot if path is provided + if save_path: + fig.write_html(save_path) + print(f"Plot saved to {save_path}") + + return fig + +def main(): + # Example usage + results_dir = 'backtest_results' + results_files = [ + os.path.join(results_dir, f) for f in os.listdir(results_dir) + if f.startswith('backtest_results_') and f.endswith('.json') + ] + + # Create plots for each scenario + for file in results_files: + scenario_name = os.path.basename(file).replace('.json', '') + plot_path = os.path.join(results_dir, f'{scenario_name}_plot.html') + plot_backtest_results(file, plot_path) + + # Create comparison plot + comparison_path = os.path.join(results_dir, 'performance_comparison.html') + plot_performance_metrics(results_files, comparison_path) + +if __name__ == "__main__": + main() \ No newline at end of file