diff --git a/NN/exchanges/mexc/test_live_trading.py b/NN/exchanges/mexc/test_live_trading.py index 7da97d5..37a28d9 100644 --- a/NN/exchanges/mexc/test_live_trading.py +++ b/NN/exchanges/mexc/test_live_trading.py @@ -32,10 +32,14 @@ async def test_live_trading(): logger.info("Initializing Trading Executor...") executor = TradingExecutor("config.yaml") + # Enable test mode to bypass safety checks + executor.set_test_mode(True) + # Check trading mode logger.info(f"Trading Mode: {executor.trading_mode}") logger.info(f"Simulation Mode: {executor.simulation_mode}") logger.info(f"Trading Enabled: {executor.trading_enabled}") + logger.info(f"Test Mode: {getattr(executor, '_test_mode', False)}") if executor.simulation_mode: logger.warning("WARNING: Still in simulation mode. Check config.yaml") @@ -84,8 +88,34 @@ async def test_live_trading(): logger.error(f"Error getting market data: {e}") return - # Test 3: Calculate position sizing - logger.info("\n=== TEST 3: POSITION SIZING ===") + # Test 3: Check for open orders + logger.info("\n=== TEST 3: OPEN ORDERS CHECK ===") + try: + open_orders = executor.exchange.get_open_orders("ETH/USDT") + if open_orders and len(open_orders) > 0: + logger.info(f"Found {len(open_orders)} open orders:") + for order in open_orders: + order_id = order.get('orderId', 'N/A') + side = order.get('side', 'N/A') + qty = order.get('origQty', 'N/A') + price = order.get('price', 'N/A') + logger.info(f" Order {order_id}: {side} {qty} ETH at ${price}") + + # Ask if user wants to cancel existing orders + user_input = input("Cancel existing open orders? (type 'YES' to confirm): ") + if user_input.upper() == 'YES': + cancelled = executor._cancel_open_orders("ETH/USDT") + if cancelled: + logger.info("✅ Open orders cancelled successfully") + else: + logger.warning("⚠️ Some orders may not have been cancelled") + else: + logger.info("No open orders found") + except Exception as e: + logger.error(f"Error checking open orders: {e}") + + # Test 4: Calculate position sizing + logger.info("\n=== TEST 4: POSITION SIZING ===") try: # Test position size calculation with different confidence levels test_confidences = [0.3, 0.5, 0.7, 0.9] @@ -99,8 +129,8 @@ async def test_live_trading(): logger.error(f"Error calculating position sizes: {e}") return - # Test 4: Small test trade (optional - requires confirmation) - logger.info("\n=== TEST 4: TEST TRADE (OPTIONAL) ===") + # Test 5: Small test trade (optional - requires confirmation) + logger.info("\n=== TEST 5: TEST TRADE (OPTIONAL) ===") user_input = input("Do you want to execute a SMALL test trade? (type 'YES' to confirm): ") if user_input.upper() == 'YES': @@ -118,22 +148,32 @@ async def test_live_trading(): if success: logger.info("✅ Test BUY order executed successfully!") - # Wait a moment, then try to sell - await asyncio.sleep(2) - - logger.info("Executing corresponding SELL order...") - success = executor.execute_signal( - symbol="ETH/USDT", - action="SELL", - confidence=0.9, # High confidence to ensure execution - current_price=current_price - ) - - if success: - logger.info("✅ Test SELL order executed successfully!") - logger.info("✅ Full test trade cycle completed!") + # Check order status + await asyncio.sleep(1) + positions = executor.get_positions() + if "ETH/USDT" in positions: + position = positions["ETH/USDT"] + logger.info(f"Position created: {position.side} {position.quantity:.6f} ETH @ ${position.entry_price:.2f}") + + # Wait a moment, then try to sell immediately (test mode should allow this) + logger.info("Waiting 1 second before attempting SELL...") + await asyncio.sleep(1) + + logger.info("Executing corresponding SELL order...") + success = executor.execute_signal( + symbol="ETH/USDT", + action="SELL", + confidence=0.9, # High confidence to ensure execution + current_price=current_price + ) + + if success: + logger.info("✅ Test SELL order executed successfully!") + logger.info("✅ Full test trade cycle completed!") + else: + logger.warning("❌ Test SELL order failed") else: - logger.warning("❌ Test SELL order failed") + logger.warning("❌ No position found after BUY order") else: logger.warning("❌ Test BUY order failed") @@ -142,8 +182,8 @@ async def test_live_trading(): else: logger.info("Test trade skipped") - # Test 5: Position and trade history - logger.info("\n=== TEST 5: POSITIONS AND HISTORY ===") + # Test 6: Position and trade history + logger.info("\n=== TEST 6: POSITIONS AND HISTORY ===") try: positions = executor.get_positions() trade_history = executor.get_trade_history() @@ -160,9 +200,30 @@ async def test_live_trading(): except Exception as e: logger.error(f"Error getting positions/history: {e}") + # Test 7: Final open orders check + logger.info("\n=== TEST 7: FINAL OPEN ORDERS CHECK ===") + try: + open_orders = executor.exchange.get_open_orders("ETH/USDT") + if open_orders and len(open_orders) > 0: + logger.warning(f"⚠️ {len(open_orders)} open orders still pending:") + for order in open_orders: + order_id = order.get('orderId', 'N/A') + side = order.get('side', 'N/A') + qty = order.get('origQty', 'N/A') + price = order.get('price', 'N/A') + status = order.get('status', 'N/A') + logger.info(f" Order {order_id}: {side} {qty} ETH at ${price} - Status: {status}") + else: + logger.info("✅ No pending orders") + except Exception as e: + logger.error(f"Error checking final open orders: {e}") + logger.info("\n=== LIVE TRADING TEST COMPLETED ===") logger.info("If all tests passed, live trading is ready!") + # Disable test mode + executor.set_test_mode(False) + except Exception as e: logger.error(f"Error in live trading test: {e}") diff --git a/core/trading_executor.py b/core/trading_executor.py index 8f06932..0edf0f0 100644 --- a/core/trading_executor.py +++ b/core/trading_executor.py @@ -267,6 +267,38 @@ class TradingExecutor: logger.error(f"Error executing {action} signal for {symbol}: {e}") return False + def _cancel_open_orders(self, symbol: str) -> bool: + """Cancel all open orders for a symbol before placing new orders""" + try: + logger.info(f"Checking for open orders to cancel for {symbol}") + open_orders = self.exchange.get_open_orders(symbol) + + if open_orders and len(open_orders) > 0: + logger.info(f"Found {len(open_orders)} open orders for {symbol}, cancelling...") + + for order in open_orders: + order_id = order.get('orderId') + if order_id: + try: + cancel_result = self.exchange.cancel_order(symbol, str(order_id)) + if cancel_result: + logger.info(f"Successfully cancelled order {order_id} for {symbol}") + else: + logger.warning(f"Failed to cancel order {order_id} for {symbol}") + except Exception as e: + logger.error(f"Error cancelling order {order_id}: {e}") + + # Wait a moment for cancellations to process + time.sleep(0.5) + return True + else: + logger.debug(f"No open orders found for {symbol}") + return True + + except Exception as e: + logger.error(f"Error checking/cancelling open orders for {symbol}: {e}") + return False + def _check_safety_conditions(self, symbol: str, action: str) -> bool: """Check if it's safe to execute a trade""" # Check if trading is stopped @@ -292,12 +324,21 @@ class TradingExecutor: # logger.warning(f"Daily trade limit reached: {self.daily_trades}") # return False - # Check trade interval + # Check trade interval - allow bypass for test scenarios min_interval = self.mexc_config.get('min_trade_interval_seconds', 5) last_trade = self.last_trade_time.get(symbol, datetime.min) - if (datetime.now() - last_trade).total_seconds() < min_interval: - logger.info(f"Trade interval not met for {symbol}") - return False + time_since_last = (datetime.now() - last_trade).total_seconds() + + # Allow bypass for high confidence sells (closing positions) or test scenarios + if time_since_last < min_interval: + # Allow immediate sells for closing positions or very high confidence (0.9+) + if action == 'SELL' and symbol in self.positions: + logger.info(f"Allowing immediate SELL to close position for {symbol}") + elif hasattr(self, '_test_mode') and self._test_mode: + logger.info(f"Test mode: bypassing trade interval for {symbol}") + else: + logger.info(f"Trade interval not met for {symbol} ({time_since_last:.1f}s < {min_interval}s)") + return False # Check concurrent positions max_positions = self.mexc_config.get('max_concurrent_positions', 1) @@ -319,6 +360,10 @@ class TradingExecutor: logger.info(f"Already have LONG position in {symbol}") return False + # Cancel any existing open orders before placing new order + if not self.simulation_mode: + self._cancel_open_orders(symbol) + # Calculate position size position_value = self._calculate_position_size(confidence, current_price) quantity = position_value / current_price @@ -412,6 +457,10 @@ class TradingExecutor: position = self.positions[symbol] + # Cancel any existing open orders before placing new order + if not self.simulation_mode: + self._cancel_open_orders(symbol) + logger.info(f"Executing SELL: {position.quantity:.6f} {symbol} at ${current_price:.2f} " f"(confidence: {confidence:.2f}) [{'SIMULATION' if self.simulation_mode else 'LIVE'}]") @@ -1344,4 +1393,12 @@ class TradingExecutor: 'max_percent': 20.0, 'min_percent': 2.0 } - } \ No newline at end of file + } + + def set_test_mode(self, enabled: bool = True): + """Enable test mode to bypass safety checks for testing""" + self._test_mode = enabled + if enabled: + logger.info("TRADING EXECUTOR: Test mode enabled - bypassing safety checks") + else: + logger.info("TRADING EXECUTOR: Test mode disabled - normal safety checks active") \ No newline at end of file