import logging from typing import Dict, Optional from datetime import datetime, timedelta logger = logging.getLogger(__name__) class ExitStrategy: """Handles exit strategy with profit targets and time-based exits""" def __init__(self): self.min_profit_threshold = 0.0001 # 0.01% minimum profit self.max_position_duration = timedelta(hours=8) # 8 hours max self.profit_target_multiplier = 1.5 # Exit when profit is 1.5x the net funding rate def should_exit(self, position: Dict) -> tuple[bool, str]: """Determine if a position should be closed""" try: opened_at = datetime.fromisoformat(position['opened_at']) duration = datetime.now() - opened_at # Check max duration if duration > self.max_position_duration: return True, f"Max duration reached ({duration})" # Check profit target (if we have current P&L) if 'current_pnl' in position: net_rate = position.get('net_funding_rate', 0) target_profit = net_rate * self.profit_target_multiplier if position['current_pnl'] >= target_profit: return True, f"Profit target reached ({position['current_pnl']:.4%})" # For MVP, we'll also check if funding rates have converged # (This would require real-time funding rate monitoring) return False, "" except Exception as e: logger.error(f"Error checking exit conditions: {str(e)}") return False, "" async def calculate_exit_prices(self, exchange_manager, position: Dict) -> Optional[Dict]: """Calculate optimal exit prices""" try: symbol = position['symbol'] long_exchange = position['long_exchange'] short_exchange = position['short_exchange'] # Get current prices long_ticker = await exchange_manager.get_ticker(long_exchange, symbol) short_ticker = await exchange_manager.get_ticker(short_exchange, symbol) if not long_ticker or not short_ticker: return None # Use mid price for exit (similar to entry) long_exit_price = (long_ticker['bid'] + long_ticker['ask']) / 2 short_exit_price = (short_ticker['bid'] + short_ticker['ask']) / 2 return { 'long_exit_price': long_exit_price, 'short_exit_price': short_exit_price, } except Exception as e: logger.error(f"Error calculating exit prices: {str(e)}") return None