Selaa lähdekoodia

Enhance order fill processing in OrderFillProcessor

- Reintroduced the check for recent fills when an order disappears, ensuring accurate status updates to 'filled' to prevent incorrect cancellation notifications.
- Improved the logic for matching recent fills with existing orders, enhancing reliability in order processing.
- Updated logging to provide clearer feedback on fill matches and order statuses.
Carles Sentis 1 päivä sitten
vanhempi
sitoutus
e667faf24c
2 muutettua tiedostoa jossa 22 lisäystä ja 55 poistoa
  1. 21 54
      src/monitoring/order_fill_processor.py
  2. 1 1
      trading_bot.py

+ 21 - 54
src/monitoring/order_fill_processor.py

@@ -73,11 +73,12 @@ class OrderFillProcessor:
                         # This is a quick check to see if a fill came through just before it disappeared
                         # and _check_external_trades hasn't processed it yet.
                         # This check is specific to this "disappeared orders" context.
-                        # fill_just_processed = await self._check_for_recent_fills_for_order(exchange_oid, order_in_db)
-                        # if fill_just_processed:
-                        #     logger.info(f"ℹ️ Order {exchange_oid} disappeared, but a recent fill was found. Assuming filled. Main fill processing will handle lifecycle.")
-                        #     # Potentially update order_in_db status here or rely on main fill processor
-                        #     continue # Skip to next disappeared_order_id
+                        fill_just_processed = await self._check_for_recent_fills_for_order(exchange_oid, order_in_db)
+                        if fill_just_processed:
+                            logger.info(f"ℹ️ Order {exchange_oid} disappeared, but a recent fill was found. Assuming filled. Main fill processing will handle lifecycle.")
+                            # Update order status to filled to prevent incorrect cancellation notifications
+                            stats.update_order_status(exchange_order_id=exchange_oid, new_status='filled')
+                            continue # Skip to next disappeared_order_id
 
                         # If no immediate fill found by the helper, proceed with external cancellation logic
                         logger.warning(f"⚠️ EXTERNAL CANCELLATION: Order {exchange_oid} with status '{last_status}' was likely cancelled externally on Hyperliquid")
@@ -188,63 +189,29 @@ class OrderFillProcessor:
 
     async def _check_for_recent_fills_for_order(self, exchange_oid, order_in_db):
         """Check for very recent fills that might match this order."""
-        # This method checks for fills that might have occurred *just before* an order disappeared,
-        # but *before* the main _check_external_trades might have run for the current cycle.
-        # It uses its own tracking of last_processed_trade_time or a default if not available.
         try:
             recent_fills = self.trading_engine.get_recent_fills()
             if not recent_fills:
                 return False
 
-            # This last_processed_trade_time is for the context of this specific helper,
-            # to avoid re-checking fills that the broader external trade monitor might have already seen.
-            # It attempts to use the global one if available.
-            # The key 'last_processed_trade_time' might be distinct from 'market_monitor_last_processed_trade_time'.
-            # For safety, let's ensure this is consistently named if it's meant to be the same.
-            # Given it's a helper within OrderFillProcessor, and external trades are separate,
-            # we will keep its independent loading logic for now.
-            # If MarketMonitor centralizes this timestamp, this should be updated.
-            
-            # Attempt to load the specific last_processed_trade_time if not already set on this instance
-            # This implies self.last_processed_trade_time is an attribute of OrderFillProcessor
-            if not hasattr(self, 'last_processed_trade_time_helper') or self.last_processed_trade_time_helper is None:
-                try:
-                    # Using a distinct metadata key for this helper to avoid conflict,
-                    # or assuming it should use the global one. For now, let's assume it tries to use the global.
-                    last_time_str = self.trading_engine.stats._get_metadata('market_monitor_last_processed_trade_time')
-                    if last_time_str:
-                        self.last_processed_trade_time_helper = datetime.fromisoformat(last_time_str).replace(tzinfo=timezone.utc)
-                    else:
-                        self.last_processed_trade_time_helper = datetime.now(timezone.utc) - timedelta(hours=1)
-                except Exception: 
-                     self.last_processed_trade_time_helper = datetime.now(timezone.utc) - timedelta(hours=1)
-
-
-            for fill in recent_fills:
+            # Check last 50 fills for the order ID to be thorough
+            for fill in recent_fills[-50:]:
                 try:
-                    trade_id = fill.get('id')
-                    timestamp_ms = fill.get('timestamp')
-                    symbol_from_fill = fill.get('symbol')
-                    side_from_fill = fill.get('side')
-                    amount_from_fill = float(fill.get('amount', 0))
-                    price_from_fill = float(fill.get('price', 0))
+                    exchange_order_id_from_fill = fill.get('info', {}).get('oid')
                     
-                    timestamp_dt = datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc) if timestamp_ms else datetime.now(timezone.utc)
-                    
-                    if timestamp_dt <= self.last_processed_trade_time_helper:
-                        continue
-                    
-                    if symbol_from_fill and side_from_fill and amount_from_fill > 0 and price_from_fill > 0:
-                        exchange_order_id_from_fill = fill.get('info', {}).get('oid')
+                    # Direct order ID match is the most reliable indicator
+                    if exchange_order_id_from_fill == exchange_oid:
+                        symbol_from_fill = fill.get('symbol')
+                        side_from_fill = fill.get('side')
+                        amount_from_fill = float(fill.get('amount', 0))
                         
-                        if exchange_order_id_from_fill == exchange_oid:
-                            if order_in_db.get('symbol') == symbol_from_fill and \
-                               order_in_db.get('side') == side_from_fill and \
-                               abs(float(order_in_db.get('amount_requested', 0)) - amount_from_fill) < 0.01 * amount_from_fill :
-                                logger.info(f"✅ Found recent matching fill {trade_id} for order {exchange_oid}. Not cancelling stop losses.")
-                                # This fill should be processed by the main external trade checker.
-                                # For the purpose of this helper, just confirming a fill exists is enough.
-                                return True
+                        # Verify this fill matches our order details
+                        if (symbol_from_fill == order_in_db.get('symbol') and 
+                            side_from_fill == order_in_db.get('side') and 
+                            amount_from_fill > 0):
+                            
+                            logger.info(f"✅ Found matching fill {fill.get('id')} for order {exchange_oid}. Order was filled, not cancelled.")
+                            return True
                 
                 except Exception as e:
                     logger.error(f"Error processing fill {fill.get('id','N/A')} in _check_for_recent_fills_for_order: {e}")

+ 1 - 1
trading_bot.py

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