|
@@ -235,6 +235,17 @@ class CopyTradingMonitor:
|
|
# Update our tracking
|
|
# Update our tracking
|
|
self.target_positions = new_positions
|
|
self.target_positions = new_positions
|
|
|
|
|
|
|
|
+ # Update our current positions for status display
|
|
|
|
+ try:
|
|
|
|
+ our_current_positions = await asyncio.to_thread(self.client.get_positions)
|
|
|
|
+ if our_current_positions:
|
|
|
|
+ self.our_positions = {pos['symbol']: pos for pos in our_current_positions}
|
|
|
|
+ else:
|
|
|
|
+ self.our_positions = {}
|
|
|
|
+ self.logger.debug(f"Updated our positions: {len(self.our_positions)} positions")
|
|
|
|
+ except Exception as e:
|
|
|
|
+ self.logger.error(f"Error updating our positions: {e}")
|
|
|
|
+
|
|
# Update last check timestamp (async version)
|
|
# Update last check timestamp (async version)
|
|
await self.state_manager.update_last_check_async()
|
|
await self.state_manager.update_last_check_async()
|
|
|
|
|
|
@@ -656,8 +667,8 @@ class CopyTradingMonitor:
|
|
symbol = f"{trade.coin}/USDC:USDC"
|
|
symbol = f"{trade.coin}/USDC:USDC"
|
|
positions = await asyncio.to_thread(self.client.get_positions, symbol=symbol)
|
|
positions = await asyncio.to_thread(self.client.get_positions, symbol=symbol)
|
|
if not positions:
|
|
if not positions:
|
|
- self.logger.warning(f"⚠️ No position found for {trade.coin} to close")
|
|
|
|
- return False
|
|
|
|
|
|
+ self.logger.info(f"✅ No positions found for {trade.coin} - already closed or never opened")
|
|
|
|
+ return True # We're already in the desired state (no position)
|
|
|
|
|
|
# Find the position to close
|
|
# Find the position to close
|
|
position_to_close = None
|
|
position_to_close = None
|
|
@@ -667,8 +678,8 @@ class CopyTradingMonitor:
|
|
break
|
|
break
|
|
|
|
|
|
if not position_to_close:
|
|
if not position_to_close:
|
|
- self.logger.warning(f"⚠️ No open position found for {trade.coin}")
|
|
|
|
- return False
|
|
|
|
|
|
+ self.logger.info(f"✅ No open position found for {trade.coin} - already closed or never opened")
|
|
|
|
+ return True # We're already in the desired state (no position)
|
|
|
|
|
|
# Determine the opposite side to close the position
|
|
# Determine the opposite side to close the position
|
|
current_side = 'long' if float(position_to_close.get('contracts', 0)) > 0 else 'short'
|
|
current_side = 'long' if float(position_to_close.get('contracts', 0)) > 0 else 'short'
|
|
@@ -688,9 +699,32 @@ class CopyTradingMonitor:
|
|
return False
|
|
return False
|
|
|
|
|
|
elif 'reduce' in trade.action:
|
|
elif 'reduce' in trade.action:
|
|
- # Reduce existing position
|
|
|
|
- reduce_side = 'sell' if 'long' in trade.action else 'buy'
|
|
|
|
|
|
+ # Reduce existing position - first check if we have the position
|
|
symbol = f"{trade.coin}/USDC:USDC"
|
|
symbol = f"{trade.coin}/USDC:USDC"
|
|
|
|
+ positions = await asyncio.to_thread(self.client.get_positions, symbol=symbol)
|
|
|
|
+
|
|
|
|
+ # Check if we have a position to reduce
|
|
|
|
+ position_to_reduce = None
|
|
|
|
+ if positions:
|
|
|
|
+ for pos in positions:
|
|
|
|
+ if pos.get('symbol') == symbol and float(pos.get('contracts', 0)) != 0:
|
|
|
|
+ position_to_reduce = pos
|
|
|
|
+ break
|
|
|
|
+
|
|
|
|
+ if not position_to_reduce:
|
|
|
|
+ self.logger.info(f"✅ No position found for {trade.coin} to reduce - already closed or never opened")
|
|
|
|
+ return True # We're already in the desired state (no/small position)
|
|
|
|
+
|
|
|
|
+ # Get current position size and validate reduction amount
|
|
|
|
+ current_size = abs(float(position_to_reduce.get('contracts', 0)))
|
|
|
|
+ if token_amount >= current_size:
|
|
|
|
+ self.logger.info(f"📉 Reduction amount ({token_amount:.6f}) >= position size ({current_size:.6f}) - treating as close")
|
|
|
|
+ # This is effectively a close, use the exact position size
|
|
|
|
+ token_amount = current_size
|
|
|
|
+
|
|
|
|
+ reduce_side = 'sell' if 'long' in trade.action else 'buy'
|
|
|
|
+ self.logger.info(f"📉 Reducing position: {reduce_side} {token_amount:.6f} {trade.coin} (current size: {current_size:.6f})")
|
|
|
|
+
|
|
result, error = await asyncio.to_thread(
|
|
result, error = await asyncio.to_thread(
|
|
self.client.place_market_order,
|
|
self.client.place_market_order,
|
|
symbol=symbol,
|
|
symbol=symbol,
|