|
@@ -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
|