Przeglądaj źródła

Refactor external trade checking in PositionMonitor

- Updated the logic for checking external trades to improve internal tracking and prevent duplicate processing within a single cycle.
- Enhanced logging to provide clearer warnings when stats are unavailable or when fills have already been processed.
- Introduced a mechanism to track fills processed in the current cycle, ensuring accurate handling of external trades and improving overall reliability.
Carles Sentis 1 dzień temu
rodzic
commit
75d7a4ee51
2 zmienionych plików z 45 dodań i 7 usunięć
  1. 44 6
      src/monitoring/position_monitor.py
  2. 1 1
      trading_bot.py

+ 44 - 6
src/monitoring/position_monitor.py

@@ -441,15 +441,16 @@ class PositionMonitor:
             return False
     
     async def _check_external_trades(self):
-        """Check for trades made outside the Telegram bot and update stats."""
-        try:
-            stats = self.trading_engine.get_stats()
-            if not stats:
-                logger.warning("TradingStats not available in _check_external_trades. Skipping.")
-                return
+        """Check for external trades and update internal tracking."""
+        stats = self.trading_engine.stats
+        if not stats:
+            logger.warning("No stats manager available for external trade checking")
+            return
 
+        try:
             external_trades_processed = 0
             symbols_with_fills = set()
+            processed_fills_this_cycle = set()  # Track fills processed in this cycle
 
             recent_fills = self.trading_engine.get_recent_fills()
             if not recent_fills:
@@ -486,6 +487,11 @@ class PositionMonitor:
                         logger.debug(f"Skipping already processed fill: {trade_id}")
                         continue
                     
+                    # Check if this fill was already processed in this cycle
+                    if trade_id and trade_id in processed_fills_this_cycle:
+                        logger.debug(f"Skipping fill already processed in this cycle: {trade_id}")
+                        continue
+                    
                     fill_processed_this_iteration = False
                     
                     if not (symbol_from_fill and side_from_fill and amount_from_fill > 0 and price_from_fill > 0):
@@ -519,6 +525,10 @@ class PositionMonitor:
                                     full_symbol, side_from_fill, amount_from_fill, price_from_fill,
                                     'position_opened', timestamp_dt
                                 )
+                                
+                                # Mark fill as processed in this cycle
+                                if trade_id:
+                                    processed_fills_this_cycle.add(trade_id)
                             fill_processed_this_iteration = True
 
                     # Check if this is a bot order to increase an existing position
@@ -560,6 +570,10 @@ class PositionMonitor:
                                             
                                             logger.info(f"📈 Position INCREASED: {full_symbol} by {amount_from_fill} for lifecycle {existing_lc['trade_lifecycle_id'][:8]}...")
                                             symbols_with_fills.add(token)
+                                            
+                                            # Mark fill as processed in this cycle
+                                            if trade_id:
+                                                processed_fills_this_cycle.add(trade_id)
                                             fill_processed_this_iteration = True
 
                     # Check if this is a known bot order (SL/TP/exit)
@@ -630,6 +644,10 @@ class PositionMonitor:
                                 stats.migrate_trade_to_aggregated_stats(lc_id)
                                 if bot_order_db_id_to_update:
                                     stats.update_order_status(order_db_id=bot_order_db_id_to_update, new_status='filled', amount_filled_increment=amount_from_fill)
+                                
+                                # Mark fill as processed in this cycle
+                                if trade_id:
+                                    processed_fills_this_cycle.add(trade_id)
                                 fill_processed_this_iteration = True
 
                     # Check for external stop losses
@@ -661,6 +679,10 @@ class PositionMonitor:
                                     # Modify shared state carefully
                                     if exchange_order_id_from_fill in self.shared_state['external_stop_losses']:
                                         del self.shared_state['external_stop_losses'][exchange_order_id_from_fill]
+                                    
+                                    # Mark fill as processed in this cycle
+                                    if trade_id:
+                                        processed_fills_this_cycle.add(trade_id)
                                     fill_processed_this_iteration = True
                             else:
                                 logger.warning(f"⚠️ External SL (MM) {exchange_order_id_from_fill} for {full_symbol}, but no active lifecycle found.")
@@ -766,6 +788,10 @@ class PositionMonitor:
                                         full_symbol, side_from_fill, amount_from_fill, price_from_fill,
                                         action_type, timestamp_dt
                                     )
+                                    
+                                    # Mark fill as processed in this cycle
+                                    if trade_id:
+                                        processed_fills_this_cycle.add(trade_id)
                                     fill_processed_this_iteration = True
                         
                         elif action_type == 'position_closed' and existing_lc:
@@ -799,6 +825,10 @@ class PositionMonitor:
                                 )
                                 
                                 stats.migrate_trade_to_aggregated_stats(lc_id)
+                                
+                                # Mark fill as processed in this cycle
+                                if trade_id:
+                                    processed_fills_this_cycle.add(trade_id)
                                 fill_processed_this_iteration = True
                         
                         elif action_type in ['position_increased', 'position_decreased'] and existing_lc:
@@ -823,6 +853,10 @@ class PositionMonitor:
                             )
                             
                             symbols_with_fills.add(token)
+                            
+                            # Mark fill as processed in this cycle
+                            if trade_id:
+                                processed_fills_this_cycle.add(trade_id)
                             fill_processed_this_iteration = True
                             logger.info(f"📊 Position {action_type}: {full_symbol} new size: {new_size}")
 
@@ -849,6 +883,10 @@ class PositionMonitor:
                         )
                         logger.info(f"📋 Recorded trade via FALLBACK: {trade_id} (Unmatched External Fill)")
                         
+                        # Mark fill as processed in this cycle
+                        if trade_id:
+                            processed_fills_this_cycle.add(trade_id)
+                        
                         # No notification sent for unmatched external trades per user preference
                         fill_processed_this_iteration = True
 

+ 1 - 1
trading_bot.py

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