Эх сурвалжийг харах

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 4 өдөр өмнө
parent
commit
699f7c0b34

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

@@ -177,6 +177,9 @@ class PositionsCommands(InfoCommandsBase):
                     # Display individual position value
                     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:
                         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"
                     
                     # 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:
                         liq_price_str = formatter.format_price_with_symbol(position_trade.get('liquidation_price'), base_asset)
                         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:
                 # Update to position_opened using existing manager
-                success = stats.update_trade_position_opened(
+                stats.update_trade_position_opened(
                     lifecycle_id=lifecycle_id,
                     entry_price=entry_price,
                     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'),
-                    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}")
-                    
-                    # Send notification
-                    await self._send_position_notification('opened', symbol, {
-                        'side': side,
-                        'size': size,
-                        'price': entry_price,
-                        'timestamp': timestamp
-                    })
+                logger.info(f"🚀 NEW POSITION: {symbol} {side.upper()} {size} @ {entry_price}")
+                
+                # Send notification
+                await self._send_position_notification('opened', symbol, {
+                    'side': side,
+                    'size': size,
+                    'price': entry_price,
+                    'timestamp': timestamp
+                })
         except Exception as 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)
             
             # 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
             if market_data and market_data.get('ticker'):
                 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_opened(symbol, exchange_pos, stats, timestamp)
                 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)
             if abs(exchange_size - db_size) < 1e-6:
                 return  # No meaningful change

+ 1 - 1
trading_bot.py

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