Forráskód Böngészése

Increment bot version to 2.6.298 and add database reconciliation for missed position closures

- Updated BOT_VERSION to 2.6.298.
- Introduced a new method in PositionTracker to reconcile the database state with the exchange, ensuring missed position closures are detected and processed.
- Enhanced logging for missed closures, including detailed notifications about position status and PnL calculations.
Carles Sentis 23 órája
szülő
commit
844b20bde8
2 módosított fájl, 75 hozzáadás és 2 törlés
  1. 74 1
      src/monitoring/position_tracker.py
  2. 1 1
      trading_bot.py

+ 74 - 1
src/monitoring/position_tracker.py

@@ -81,15 +81,88 @@ class PositionTracker:
             previous_positions = self.current_positions.copy()
             await self._update_current_positions()
             
-            # Compare with previous positions
+            # Compare with previous positions (normal tracking)
             await self._process_position_changes(previous_positions, self.current_positions)
             
+            # IMPORTANT: Also reconcile with database state to catch missed positions
+            await self._reconcile_database_with_exchange()
+            
             # Update database with current market data for open positions
             await self._update_database_market_data()
             
         except Exception as e:
             logger.error(f"Error checking position changes: {e}")
             
+    async def _reconcile_database_with_exchange(self):
+        """Reconcile database state with exchange state to catch missed position closures"""
+        try:
+            # Lazy load TradingStats if needed
+            if self.trading_stats is None:
+                from ..stats.trading_stats import TradingStats
+                self.trading_stats = TradingStats()
+            
+            # Get open trades from database
+            open_trades = self.trading_stats.get_open_positions()
+            logger.debug(f"🔍 Reconciling: Database shows {len(open_trades)} open positions, Exchange shows {len(self.current_positions)}")
+            
+            for trade in open_trades:
+                try:
+                    symbol = trade.get('symbol', '')
+                    if not symbol:
+                        continue
+                        
+                    # Extract token from symbol (e.g., "BTC/USDC:USDC" -> "BTC")  
+                    token = symbol.split('/')[0] if '/' in symbol else symbol
+                    
+                    # Check if this database position exists on the exchange
+                    if token not in self.current_positions:
+                        # Position exists in database but NOT on exchange = it was closed and we missed it!
+                        logger.warning(f"🔍 Found missed position closure: {symbol} exists in database but not on exchange")
+                        
+                        # We need to simulate the position closure
+                        # Get current market price to calculate exit PnL
+                        market_data = self.hl_client.get_market_data(symbol)
+                        if not market_data:
+                            logger.error(f"Could not get market data for {symbol} to process missed closure")
+                            continue
+                            
+                        current_price = float(market_data.get('ticker', {}).get('last', 0))
+                        entry_price = float(trade.get('entry_price', 0))
+                        size = float(trade.get('amount', 0))
+                        side = trade.get('side', '').lower()
+                        
+                        # Calculate PnL
+                        if side == "long":
+                            pnl = (current_price - entry_price) * size
+                        else:
+                            pnl = (entry_price - current_price) * size
+                            
+                        # Close the position in database
+                        await self._save_position_stats(symbol, side, size, entry_price, current_price, pnl)
+                        
+                        # Send notification about missed closure
+                        pnl_emoji = "🟢" if pnl >= 0 else "🔴"
+                        message = (
+                            f"{pnl_emoji} Position Closed (Missed)\n"
+                            f"Token: {token}\n"
+                            f"Side: {side.title()}\n"
+                            f"Size: {size:.4f}\n"
+                            f"Entry: ${entry_price:.4f}\n"
+                            f"Exit: ${current_price:.4f}\n"
+                            f"PnL: ${pnl:.3f}\n"
+                            f"⚠️ Closed between monitoring cycles"
+                        )
+                        
+                        await self.notification_manager.send_generic_notification(message)
+                        logger.info(f"📊 Processed missed position closure: {symbol} side={side} PnL=${pnl:.3f}")
+                        
+                except Exception as e:
+                    logger.warning(f"Error processing missed closure for trade {trade.get('trade_lifecycle_id', 'unknown')}: {e}")
+                    continue
+                    
+        except Exception as e:
+            logger.error(f"Error reconciling database with exchange: {e}")
+            
     async def _update_database_market_data(self):
         """Update database with current market data for open positions"""
         try:

+ 1 - 1
trading_bot.py

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