Bladeren bron

Implement entry price estimation for orphaned positions - Added functionality to estimate entry prices for orphaned positions in both InfoCommands and MarketMonitor. This enhancement improves the accuracy of position management by providing fallback mechanisms for cases where the entry price is zero, including checks for recent fills, current market prices, and bid/ask averages. Enhanced logging for better traceability of the estimation process.

Carles Sentis 4 dagen geleden
bovenliggende
commit
e70404443d
2 gewijzigde bestanden met toevoegingen van 101 en 1 verwijderingen
  1. 51 1
      src/commands/info_commands.py
  2. 50 0
      src/monitoring/market_monitor.py

+ 51 - 1
src/commands/info_commands.py

@@ -130,6 +130,11 @@ class InfoCommands:
                     position_side = 'long' if contracts > 0 else 'short'
                     order_side = 'buy' if contracts > 0 else 'sell'
                     
+                    # 🔧 FIX: If entry price is 0, try to estimate it
+                    if entry_price <= 0:
+                        entry_price = await self._estimate_entry_price_for_orphaned_position(symbol, contracts)
+                        logger.info(f"🔄 Estimated entry price for orphaned {symbol}: ${entry_price:.4f}")
+                    
                     logger.info(f"🔄 Auto-syncing orphaned position: {symbol} {position_side} {abs(contracts)} @ ${entry_price}")
                     
                     # Create trade lifecycle for external position
@@ -1333,4 +1338,49 @@ Tap any button below for instant access to bot functions:
         ]
         reply_markup = InlineKeyboardMarkup(keyboard)
         
-        await context.bot.send_message(chat_id=chat_id, text=commands_text, parse_mode='HTML', reply_markup=reply_markup) 
+        await context.bot.send_message(chat_id=chat_id, text=commands_text, parse_mode='HTML', reply_markup=reply_markup)
+
+    async def _estimate_entry_price_for_orphaned_position(self, symbol: str, contracts: float) -> float:
+        """Estimate entry price for an orphaned position by checking recent fills and market data."""
+        try:
+            # Method 1: Check recent fills from the exchange
+            recent_fills = self.trading_engine.get_recent_fills()
+            if recent_fills:
+                # Look for recent fills for this symbol
+                symbol_fills = [fill for fill in recent_fills if fill.get('symbol') == symbol]
+                
+                if symbol_fills:
+                    # Get the most recent fill as entry price estimate
+                    latest_fill = symbol_fills[0]  # Assuming sorted by newest first
+                    fill_price = float(latest_fill.get('price', 0))
+                    
+                    if fill_price > 0:
+                        logger.info(f"💡 Found recent fill price for {symbol}: ${fill_price:.4f}")
+                        return fill_price
+            
+            # Method 2: Use current market price as fallback
+            market_data = self.trading_engine.get_market_data(symbol)
+            if market_data and market_data.get('ticker'):
+                current_price = float(market_data['ticker'].get('last', 0))
+                
+                if current_price > 0:
+                    logger.warning(f"⚠️ Using current market price as entry estimate for {symbol}: ${current_price:.4f}")
+                    return current_price
+            
+            # Method 3: Last resort - try bid/ask average
+            if market_data and market_data.get('ticker'):
+                bid = float(market_data['ticker'].get('bid', 0))
+                ask = float(market_data['ticker'].get('ask', 0))
+                
+                if bid > 0 and ask > 0:
+                    avg_price = (bid + ask) / 2
+                    logger.warning(f"⚠️ Using bid/ask average as entry estimate for {symbol}: ${avg_price:.4f}")
+                    return avg_price
+            
+            # Method 4: Absolute fallback - return a small positive value to avoid 0
+            logger.error(f"❌ Could not estimate entry price for {symbol}, using fallback value of $1.00")
+            return 1.0
+            
+        except Exception as e:
+            logger.error(f"❌ Error estimating entry price for {symbol}: {e}")
+            return 1.0  # Safe fallback 

+ 50 - 0
src/monitoring/market_monitor.py

@@ -1547,6 +1547,11 @@ class MarketMonitor:
                         order_side = 'buy' if contracts > 0 else 'sell'
                         token = symbol.split('/')[0] if '/' in symbol else symbol
                         
+                        # 🔧 FIX: If entry price is 0, try to estimate it
+                        if entry_price <= 0:
+                            entry_price = await self._estimate_entry_price_for_orphaned_position(symbol, contracts)
+                            logger.info(f"🔄 AUTO-SYNC: Estimated entry price for orphaned {symbol}: ${entry_price:.4f}")
+                        
                         logger.warning(f"🔄 AUTO-SYNC: Orphaned position detected - {symbol} {position_side} {abs(contracts)} @ ${entry_price}")
                         
                         # Create trade lifecycle for external position
@@ -1594,6 +1599,51 @@ class MarketMonitor:
         except Exception as e:
             logger.error(f"❌ Error in auto-sync orphaned positions: {e}", exc_info=True)
 
+    async def _estimate_entry_price_for_orphaned_position(self, symbol: str, contracts: float) -> float:
+        """Estimate entry price for an orphaned position by checking recent fills and market data."""
+        try:
+            # Method 1: Check recent fills from the exchange
+            recent_fills = self.trading_engine.get_recent_fills()
+            if recent_fills:
+                # Look for recent fills for this symbol
+                symbol_fills = [fill for fill in recent_fills if fill.get('symbol') == symbol]
+                
+                if symbol_fills:
+                    # Get the most recent fill as entry price estimate
+                    latest_fill = symbol_fills[0]  # Assuming sorted by newest first
+                    fill_price = float(latest_fill.get('price', 0))
+                    
+                    if fill_price > 0:
+                        logger.info(f"💡 AUTO-SYNC: Found recent fill price for {symbol}: ${fill_price:.4f}")
+                        return fill_price
+            
+            # Method 2: Use current market price as fallback
+            market_data = self.trading_engine.get_market_data(symbol)
+            if market_data and market_data.get('ticker'):
+                current_price = float(market_data['ticker'].get('last', 0))
+                
+                if current_price > 0:
+                    logger.warning(f"⚠️ AUTO-SYNC: Using current market price as entry estimate for {symbol}: ${current_price:.4f}")
+                    return current_price
+            
+            # Method 3: Last resort - try bid/ask average
+            if market_data and market_data.get('ticker'):
+                bid = float(market_data['ticker'].get('bid', 0))
+                ask = float(market_data['ticker'].get('ask', 0))
+                
+                if bid > 0 and ask > 0:
+                    avg_price = (bid + ask) / 2
+                    logger.warning(f"⚠️ AUTO-SYNC: Using bid/ask average as entry estimate for {symbol}: ${avg_price:.4f}")
+                    return avg_price
+            
+            # Method 4: Absolute fallback - return a small positive value to avoid 0
+            logger.error(f"❌ AUTO-SYNC: Could not estimate entry price for {symbol}, using fallback value of $1.00")
+            return 1.0
+            
+        except Exception as e:
+            logger.error(f"❌ AUTO-SYNC: Error estimating entry price for {symbol}: {e}")
+            return 1.0  # Safe fallback
+
     async def _handle_orphaned_position(self, symbol, contracts):
         """Handle the orphaned position."""
         try: