瀏覽代碼

Enhance position information display in PositionsCommands by adding margin used details and refining market data updates in SimplePositionTracker. Ensure accurate extraction of margin and ROE from exchange position info, improving overall clarity in position management.

Carles Sentis 3 周之前
父節點
當前提交
699f7c0b34
共有 3 個文件被更改,包括 72 次插入17 次删除
  1. 3 2
      src/commands/info/positions.py
  2. 68 14
      src/monitoring/simple_position_tracker.py
  3. 1 1
      trading_bot.py

+ 3 - 2
src/commands/info/positions.py

@@ -177,6 +177,9 @@ class PositionsCommands(InfoCommandsBase):
                     # Display individual position value
                     # Display individual position value
                     positions_text += f"   🏦 Value: ${individual_position_value:,.2f}\n"
                     positions_text += f"   🏦 Value: ${individual_position_value:,.2f}\n"
                     
                     
+                    if margin_used > 0:
+                        positions_text += f"   💳 Margin: ${margin_used:,.2f}\n"
+
                     if mark_price > 0 and abs(mark_price - entry_price) > 1e-9:
                     if mark_price > 0 and abs(mark_price - entry_price) > 1e-9:
                         positions_text += f"   📈 Mark: {mark_price_str}\n"
                         positions_text += f"   📈 Mark: {mark_price_str}\n"
                     
                     
@@ -188,8 +191,6 @@ class PositionsCommands(InfoCommandsBase):
                     positions_text += f"   {roe_emoji} ROE: {roe_percentage:+.2f}%\n"
                     positions_text += f"   {roe_emoji} ROE: {roe_percentage:+.2f}%\n"
                     
                     
                     # Show exchange-provided risk data if available
                     # Show exchange-provided risk data if available
-                    if margin_used > 0:
-                        positions_text += f"   💳 Margin Used: ${margin_used:,.2f}\n"
                     if position_trade.get('liquidation_price') is not None and position_trade.get('liquidation_price') > 0:
                     if position_trade.get('liquidation_price') is not None and position_trade.get('liquidation_price') > 0:
                         liq_price_str = formatter.format_price_with_symbol(position_trade.get('liquidation_price'), base_asset)
                         liq_price_str = formatter.format_price_with_symbol(position_trade.get('liquidation_price'), base_asset)
                         positions_text += f"   ⚠️ Liquidation: {liq_price_str}\n"
                         positions_text += f"   ⚠️ Liquidation: {liq_price_str}\n"

+ 68 - 14
src/monitoring/simple_position_tracker.py

@@ -128,25 +128,41 @@ class SimplePositionTracker:
             
             
             if lifecycle_id:
             if lifecycle_id:
                 # Update to position_opened using existing manager
                 # Update to position_opened using existing manager
-                success = stats.update_trade_position_opened(
+                stats.update_trade_position_opened(
                     lifecycle_id=lifecycle_id,
                     lifecycle_id=lifecycle_id,
                     entry_price=entry_price,
                     entry_price=entry_price,
                     entry_amount=size,
                     entry_amount=size,
-                    exchange_fill_id=f"position_detected_{timestamp.isoformat()}",
+                    exchange_fill_id=f"position_detected_{timestamp.isoformat()}"
+                )
+
+                # Now, update the market data for the newly opened position
+                margin_used = None
+                if 'info' in exchange_pos and isinstance(exchange_pos['info'], dict):
+                    position_info = exchange_pos['info'].get('position', {})
+                    if position_info:
+                        margin_used = position_info.get('marginUsed')
+
+                stats.trade_manager.update_trade_market_data(
+                    lifecycle_id=lifecycle_id,
+                    current_position_size=size,
                     unrealized_pnl=exchange_pos.get('unrealizedPnl'),
                     unrealized_pnl=exchange_pos.get('unrealizedPnl'),
-                    roe_percentage=roe_percentage
+                    roe_percentage=roe_percentage,
+                    mark_price=exchange_pos.get('markPrice'),
+                    position_value=exchange_pos.get('positionValue'),
+                    margin_used=margin_used,
+                    leverage=exchange_pos.get('leverage'),
+                    liquidation_price=exchange_pos.get('liquidationPrice')
                 )
                 )
                 
                 
-                if success:
+                logger.info(f"🚀 NEW POSITION: {symbol} {side.upper()} {size} @ {entry_price}")
-                    logger.info(f"🚀 NEW POSITION: {symbol} {side.upper()} {size} @ {entry_price}")
+                
-                    
+                # Send notification
-                    # Send notification
+                await self._send_position_notification('opened', symbol, {
-                    await self._send_position_notification('opened', symbol, {
+                    'side': side,
-                        'side': side,
+                    'size': size,
-                        'size': size,
+                    'price': entry_price,
-                        'price': entry_price,
+                    'timestamp': timestamp
-                        'timestamp': timestamp
+                })
-                    })
         except Exception as e:
         except Exception as e:
             logger.error(f"❌ Error handling position opened for {symbol}: {e}")
             logger.error(f"❌ Error handling position opened for {symbol}: {e}")
     
     
@@ -159,7 +175,7 @@ class SimplePositionTracker:
             size = db_pos.get('current_position_size', 0)
             size = db_pos.get('current_position_size', 0)
             
             
             # Estimate exit price (could be improved with recent fills)
             # Estimate exit price (could be improved with recent fills)
-            market_data = self.trading_engine.get_market_data(symbol)
+            market_data = await self.trading_engine.get_market_data(symbol)
             exit_price = entry_price  # Fallback
             exit_price = entry_price  # Fallback
             if market_data and market_data.get('ticker'):
             if market_data and market_data.get('ticker'):
                 exit_price = float(market_data['ticker'].get('last', exit_price))
                 exit_price = float(market_data['ticker'].get('last', exit_price))
@@ -239,7 +255,45 @@ class SimplePositionTracker:
                 await self._handle_position_closed(symbol, db_pos, stats, timestamp)
                 await self._handle_position_closed(symbol, db_pos, stats, timestamp)
                 await self._handle_position_opened(symbol, exchange_pos, stats, timestamp)
                 await self._handle_position_opened(symbol, exchange_pos, stats, timestamp)
                 return
                 return
+
+            # If we are here, the side is the same. Now we can update market data for the existing trade.
+            lifecycle_id = db_pos['trade_lifecycle_id']
             
             
+            # Extract all relevant market data from the exchange position
+            unrealized_pnl = exchange_pos.get('unrealizedPnl')
+            leverage = exchange_pos.get('leverage')
+            liquidation_price = exchange_pos.get('liquidationPrice')
+            mark_price = exchange_pos.get('markPrice')
+            position_value = exchange_pos.get('contracts', 0) * exchange_pos.get('markPrice', 0) if mark_price else None
+
+            # Safely extract ROE and Margin from the 'info' dictionary
+            roe_percentage = None
+            margin_used = None
+            if 'info' in exchange_pos and isinstance(exchange_pos['info'], dict):
+                logger.info(f"Exchange position info for {symbol}: {exchange_pos['info']}") # Temporary logging
+                position_info = exchange_pos['info'].get('position', {})
+                if position_info:
+                    roe_raw = position_info.get('returnOnEquity')
+                    roe_percentage = float(roe_raw) * 100 if roe_raw is not None else None
+                    margin_used = position_info.get('marginUsed')
+
+            # Call the trade manager to update the database
+            success = stats.trade_manager.update_trade_market_data(
+                lifecycle_id=lifecycle_id,
+                current_position_size=exchange_size,
+                unrealized_pnl=unrealized_pnl,
+                roe_percentage=roe_percentage,
+                mark_price=mark_price,
+                position_value=position_value,
+                margin_used=margin_used,
+                leverage=leverage,
+                liquidation_price=liquidation_price
+            )
+
+            if success:
+                logger.debug(f"🔄 Synced market data for {symbol} (Lifecycle: {lifecycle_id[:8]})")
+
+
             # Check if size actually changed (with small tolerance)
             # Check if size actually changed (with small tolerance)
             if abs(exchange_size - db_size) < 1e-6:
             if abs(exchange_size - db_size) < 1e-6:
                 return  # No meaningful change
                 return  # No meaningful change

+ 1 - 1
trading_bot.py

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