Quellcode durchsuchen

Update bot version and refactor monitoring components

- Incremented bot version to 2.6.284.
- Refactored MonitoringCoordinator to lazy-load DrawdownMonitor and RsiMonitor, avoiding circular imports and improving modularity.
- Updated PositionTracker, RiskManager, and PendingOrdersManager to retrieve positions using the new get_positions method, enhancing data handling consistency.
- Improved error handling and logging across various components for better traceability.
Carles Sentis vor 21 Stunden
Ursprung
Commit
9901b945c1

BIN
data/pending_orders.db


+ 1 - 1
src/bot/core.py

@@ -47,7 +47,7 @@ class TelegramTradingBot:
         self.trading_engine = TradingEngine()
         self.notification_manager = NotificationManager()
         self.monitoring_coordinator = MonitoringCoordinator(
-            self.trading_engine.hl_client, 
+            self.trading_engine.client, 
             self.notification_manager,
             Config
         )

+ 2 - 2
src/monitoring/__init__.py

@@ -7,7 +7,7 @@ from .pending_orders_manager import PendingOrdersManager
 from .risk_manager import RiskManager
 from .alarm_manager import AlarmManager
 from .drawdown_monitor import DrawdownMonitor
-from .rsi_monitor import RSIMonitor
+from .rsi_monitor import RsiMonitor
 
 __all__ = [
     'MonitoringCoordinator',
@@ -16,5 +16,5 @@ __all__ = [
     'RiskManager',
     'AlarmManager',
     'DrawdownMonitor',
-    'RSIMonitor'
+    'RsiMonitor'
 ] 

+ 49 - 11
src/monitoring/monitoring_coordinator.py

@@ -10,8 +10,7 @@ from .position_tracker import PositionTracker
 from .pending_orders_manager import PendingOrdersManager
 from .risk_manager import RiskManager
 from .alarm_manager import AlarmManager
-from .drawdown_monitor import DrawdownMonitor
-from .rsi_monitor import RSIMonitor
+# DrawdownMonitor and RsiMonitor will be lazy-loaded to avoid circular imports
 
 logger = logging.getLogger(__name__)
 
@@ -31,9 +30,14 @@ class MonitoringCoordinator:
         self.position_tracker = PositionTracker(hl_client, notification_manager)
         self.pending_orders_manager = PendingOrdersManager(hl_client, notification_manager)
         self.risk_manager = RiskManager(hl_client, notification_manager, config)
-        self.alarm_manager = AlarmManager(hl_client, notification_manager, config)
-        self.drawdown_monitor = DrawdownMonitor(hl_client, notification_manager, config)
-        self.rsi_monitor = RSIMonitor(hl_client, notification_manager, config)
+        self.alarm_manager = AlarmManager()  # AlarmManager only needs alarms_file (defaults to data/price_alarms.json)
+        
+        # DrawdownMonitor and RSIMonitor will be lazy-loaded to avoid circular imports
+        self.drawdown_monitor = None
+        self.rsi_monitor = None
+        self._hl_client = hl_client
+        self._notification_manager = notification_manager
+        self._config = config
         
     async def start(self):
         """Start all monitoring components"""
@@ -48,9 +52,16 @@ class MonitoringCoordinator:
             await self.position_tracker.start()
             await self.pending_orders_manager.start()
             await self.risk_manager.start()
-            await self.alarm_manager.start()
-            await self.drawdown_monitor.start()
-            await self.rsi_monitor.start()
+            # AlarmManager doesn't have start() method - it's always ready
+            
+            # Lazy-load optional monitors to avoid circular imports
+            self._init_optional_monitors()
+            
+            # Start optional monitors if they have async start methods
+            if hasattr(self.drawdown_monitor, 'start'):
+                await self.drawdown_monitor.start()
+            if hasattr(self.rsi_monitor, 'start'):
+                await self.rsi_monitor.start()
             
             logger.info("All monitoring components started successfully")
             
@@ -71,12 +82,39 @@ class MonitoringCoordinator:
         await self.position_tracker.stop()
         await self.pending_orders_manager.stop()
         await self.risk_manager.stop()
-        await self.alarm_manager.stop()
-        await self.drawdown_monitor.stop()
-        await self.rsi_monitor.stop()
+        # AlarmManager doesn't have stop() method - nothing to stop
+        
+        # Stop optional monitors if they exist and have stop methods
+        if self.drawdown_monitor and hasattr(self.drawdown_monitor, 'stop'):
+            await self.drawdown_monitor.stop()
+        if self.rsi_monitor and hasattr(self.rsi_monitor, 'stop'):
+            await self.rsi_monitor.stop()
         
         logger.info("Monitoring system stopped")
         
+    def _init_optional_monitors(self):
+        """Initialize optional monitors with lazy loading to avoid circular imports"""
+        try:
+            if self.drawdown_monitor is None:
+                # DrawdownMonitor needs a TradingStats instance
+                from ..stats.trading_stats import TradingStats
+                from .drawdown_monitor import DrawdownMonitor
+                stats = TradingStats()
+                self.drawdown_monitor = DrawdownMonitor(stats)
+                
+            if self.rsi_monitor is None:
+                # RsiMonitor class from rsi_monitor module
+                from .rsi_monitor import RsiMonitor
+                self.rsi_monitor = RsiMonitor(self._hl_client, self._notification_manager)
+                
+        except Exception as e:
+            logger.warning(f"Could not initialize optional monitors: {e}")
+            # Set to dummy objects that won't break the system
+            if self.drawdown_monitor is None:
+                self.drawdown_monitor = type('DummyMonitor', (), {'start': lambda: None, 'stop': lambda: None, 'is_running': False})()
+            if self.rsi_monitor is None:
+                self.rsi_monitor = type('DummyMonitor', (), {'start': lambda: None, 'stop': lambda: None, 'is_running': False})()
+        
     async def add_pending_stop_loss(self, symbol: str, stop_price: float, size: float, side: str, expires_hours: int = 24):
         """Add a pending stop loss order"""
         await self.pending_orders_manager.add_pending_stop_loss(symbol, stop_price, size, side, expires_hours)

+ 6 - 6
src/monitoring/pending_orders_manager.py

@@ -107,16 +107,16 @@ class PendingOrdersManager:
         """Check if any pending orders should be placed"""
         try:
             # Get current positions
-            user_state = await self.hl_client.get_user_state()
-            if not user_state or 'assetPositions' not in user_state:
+            positions = self.hl_client.get_positions()
+            if not positions:
                 return
                 
             current_positions = {}
-            for position in user_state['assetPositions']:
-                if position.get('position', {}).get('szi') != '0':
-                    symbol = position.get('position', {}).get('coin', '')
+            for position in positions:
+                size = float(position.get('szi', '0'))
+                if size != 0:
+                    symbol = position.get('coin', '')
                     if symbol:
-                        size = float(position.get('position', {}).get('szi', 0))
                         current_positions[symbol] = {
                             'size': size,
                             'side': 'long' if size > 0 else 'short'

+ 13 - 12
src/monitoring/position_tracker.py

@@ -67,22 +67,23 @@ class PositionTracker:
     async def _update_current_positions(self):
         """Update current positions from exchange"""
         try:
-            user_state = await self.hl_client.get_user_state()
-            if not user_state or 'assetPositions' not in user_state:
+            positions = self.hl_client.get_positions()
+            if not positions:
                 return
                 
             new_positions = {}
-            for position in user_state['assetPositions']:
-                if position.get('position', {}).get('szi') != '0':
-                    symbol = position.get('position', {}).get('coin', '')
+            for position in positions:
+                size = float(position.get('szi', '0'))
+                if size != 0:  # Only include open positions
+                    symbol = position.get('coin', '')
                     if symbol:
                         new_positions[symbol] = {
-                            'size': float(position.get('position', {}).get('szi', 0)),
-                            'entry_px': float(position.get('position', {}).get('entryPx', 0)),
-                            'unrealized_pnl': float(position.get('position', {}).get('unrealizedPnl', 0)),
-                            'margin_used': float(position.get('position', {}).get('marginUsed', 0)),
-                            'max_leverage': float(position.get('position', {}).get('maxLeverage', 1)),
-                            'return_on_equity': float(position.get('position', {}).get('returnOnEquity', 0))
+                            'size': size,
+                            'entry_px': float(position.get('entryPx', '0')),
+                            'unrealized_pnl': float(position.get('unrealizedPnl', '0')),
+                            'margin_used': float(position.get('marginUsed', '0')),
+                            'max_leverage': float(position.get('maxLeverage', '1')),
+                            'return_on_equity': float(position.get('returnOnEquity', '0'))
                         }
             
             self.current_positions = new_positions
@@ -133,7 +134,7 @@ class PositionTracker:
         """Handle position closed - save stats to database"""
         try:
             # Get current market price for PnL calculation
-            market_data = await self.hl_client.get_market_data(symbol)
+            market_data = self.hl_client.get_market_data(symbol)
             if not market_data:
                 logger.error(f"Could not get market data for {symbol}")
                 return

+ 16 - 18
src/monitoring/risk_manager.py

@@ -52,18 +52,17 @@ class RiskManager:
     async def _check_risk_thresholds(self):
         """Check if any positions need risk management"""
         try:
-            user_state = await self.hl_client.get_user_state()
-            if not user_state or 'assetPositions' not in user_state:
+            positions = self.hl_client.get_positions()
+            if not positions:
                 return
                 
             positions_to_close = []
             
-            for position in user_state['assetPositions']:
-                pos_data = position.get('position', {})
-                if pos_data.get('szi') != '0':
-                    symbol = pos_data.get('coin', '')
-                    roe = float(pos_data.get('returnOnEquity', 0))
-                    size = float(pos_data.get('szi', 0))
+            for position in positions:
+                size = float(position.get('szi', '0'))
+                if size != 0:
+                    symbol = position.get('coin', '')
+                    roe = float(position.get('returnOnEquity', '0'))
                     
                     # Check if ROE exceeds hard exit threshold
                     if roe <= self.hard_exit_roe:
@@ -71,7 +70,7 @@ class RiskManager:
                             'symbol': symbol,
                             'size': size,
                             'roe': roe,
-                            'unrealized_pnl': float(pos_data.get('unrealizedPnl', 0))
+                            'unrealized_pnl': float(position.get('unrealizedPnl', '0'))
                         })
                         
             # Close positions that exceed risk threshold
@@ -151,20 +150,19 @@ class RiskManager:
     async def get_risk_status(self) -> Dict:
         """Get current risk status"""
         try:
-            user_state = await self.hl_client.get_user_state()
-            if not user_state or 'assetPositions' not in user_state:
+            positions_data = self.hl_client.get_positions()
+            if not positions_data:
                 return {'positions': [], 'total_risk': 0}
                 
             positions = []
             total_unrealized_pnl = 0
             
-            for position in user_state['assetPositions']:
-                pos_data = position.get('position', {})
-                if pos_data.get('szi') != '0':
-                    symbol = pos_data.get('coin', '')
-                    roe = float(pos_data.get('returnOnEquity', 0))
-                    unrealized_pnl = float(pos_data.get('unrealizedPnl', 0))
-                    size = float(pos_data.get('szi', 0))
+            for position in positions_data:
+                size = float(position.get('szi', '0'))
+                if size != 0:
+                    symbol = position.get('coin', '')
+                    roe = float(position.get('returnOnEquity', '0'))
+                    unrealized_pnl = float(position.get('unrealizedPnl', '0'))
                     
                     total_unrealized_pnl += unrealized_pnl
                     

+ 1 - 1
trading_bot.py

@@ -14,7 +14,7 @@ from datetime import datetime
 from pathlib import Path
 
 # Bot version
-BOT_VERSION = "2.6.283"
+BOT_VERSION = "2.6.284"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))