TradingTeaching Press · Dubai, UAE Trading is high-risk. Check local laws, your residency rules and your finances. Risk warning
🤖 Trading Automation

Debugging and Troubleshooting Trading Systems

Learn systematic approaches to debug and troubleshoot issues in your automated trading systems and Expert Advisors.

6 min read TradingTeaching Team

Even well-built trading systems encounter issues. This guide provides systematic approaches to identify and fix problems in your automated trading.

Common Issues Categories

Connection Problems

  • Broker server unavailable
  • Network timeouts
  • Authentication failures
  • WebRequest blocked

Logic Errors

  • Wrong signal generation
  • Incorrect position sizing
  • Missing trade conditions
  • Order type mismatches

Execution Issues

  • Order rejection
  • Slippage beyond limits
  • Partial fills
  • Wrong price execution

Resource Problems

  • Memory leaks
  • CPU overload
  • Disk space full
  • Handle exhaustion

MQL5 Debugging Techniques

Using Print Statements

// Basic logging
Print("Signal generated: ", signal, " at ", TimeCurrent());

// Detailed debug function
void Debug(string function, string message)
{
    Print("[DEBUG] ", function, ": ", message);
}

// Usage
void OnTick()
{
    Debug("OnTick", "New tick received");

    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    Debug("OnTick", "Bid price: " + DoubleToString(bid, _Digits));

    int signal = GenerateSignal();
    Debug("OnTick", "Signal value: " + IntegerToString(signal));
}

Conditional Debugging

input bool EnableDebug = true;
input int DebugLevel = 2;  // 1=Basic, 2=Detailed, 3=Verbose

void Log(int level, string message)
{
    if(!EnableDebug) return;
    if(level > DebugLevel) return;

    string prefix = "";
    switch(level)
    {
        case 1: prefix = "[INFO] "; break;
        case 2: prefix = "[DEBUG] "; break;
        case 3: prefix = "[TRACE] "; break;
    }

    Print(prefix, message);
}

// Usage
Log(1, "EA started");
Log(2, "Checking signal conditions");
Log(3, "MA Fast: " + DoubleToString(maFast, 5));

Error Code Handling

void HandleError(string operation)
{
    int error = GetLastError();

    if(error == 0) return;

    string errorMsg = "";

    switch(error)
    {
        case 10004: errorMsg = "Requote"; break;
        case 10006: errorMsg = "Request rejected"; break;
        case 10007: errorMsg = "Request canceled by trader"; break;
        case 10010: errorMsg = "Only position closing allowed"; break;
        case 10011: errorMsg = "Position closing only"; break;
        case 10012: errorMsg = "Invalid volume"; break;
        case 10013: errorMsg = "Invalid price"; break;
        case 10014: errorMsg = "Invalid stops"; break;
        case 10015: errorMsg = "Trade disabled"; break;
        case 10016: errorMsg = "Market closed"; break;
        case 10017: errorMsg = "Not enough money"; break;
        case 10018: errorMsg = "Price changed"; break;
        case 10019: errorMsg = "No quotes"; break;
        case 10020: errorMsg = "Invalid order expiration"; break;
        case 10021: errorMsg = "Order changed"; break;
        case 10022: errorMsg = "Too many requests"; break;
        default: errorMsg = "Unknown error: " + IntegerToString(error);
    }

    Print("[ERROR] ", operation, " failed: ", errorMsg);
    Alert(operation, " error: ", errorMsg);
}

// Usage
MqlTradeResult result;
if(!OrderSend(request, result))
{
    HandleError("OrderSend");
}

Variable State Tracking

void PrintTradeRequest(MqlTradeRequest& request)
{
    Print("=== Trade Request ===");
    Print("Action: ", EnumToString((ENUM_TRADE_REQUEST_ACTIONS)request.action));
    Print("Symbol: ", request.symbol);
    Print("Volume: ", request.volume);
    Print("Type: ", EnumToString((ENUM_ORDER_TYPE)request.type));
    Print("Price: ", request.price);
    Print("SL: ", request.sl);
    Print("TP: ", request.tp);
    Print("Deviation: ", request.deviation);
    Print("Magic: ", request.magic);
    Print("====================");
}

void PrintTradeResult(MqlTradeResult& result)
{
    Print("=== Trade Result ===");
    Print("Retcode: ", result.retcode);
    Print("Deal: ", result.deal);
    Print("Order: ", result.order);
    Print("Volume: ", result.volume);
    Print("Price: ", result.price);
    Print("Comment: ", result.comment);
    Print("====================");
}

Python Debugging

Logging Setup

import logging
from datetime import datetime

def setup_logger(name, log_file, level=logging.DEBUG):
    """Setup logger with file and console handlers"""

    logger = logging.getLogger(name)
    logger.setLevel(level)

    # File handler
    fh = logging.FileHandler(log_file)
    fh.setLevel(logging.DEBUG)

    # Console handler
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)

    # Format
    formatter = logging.Formatter(
        '%(asctime)s | %(name)s | %(levelname)s | %(message)s'
    )
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)

    logger.addHandler(fh)
    logger.addHandler(ch)

    return logger

# Usage
logger = setup_logger('trading_bot', 'logs/trading.log')

logger.debug("Detailed debug info")
logger.info("General info")
logger.warning("Warning message")
logger.error("Error occurred")
logger.critical("Critical failure")

Exception Handling

import traceback

class TradingBot:
    def __init__(self):
        self.logger = setup_logger('bot', 'bot.log')

    def execute_trade(self, symbol, direction, volume):
        """Execute trade with comprehensive error handling"""
        try:
            self.logger.info(f"Executing {direction} {volume} {symbol}")

            # Validate inputs
            if volume <= 0:
                raise ValueError(f"Invalid volume: {volume}")

            if direction not in ['buy', 'sell']:
                raise ValueError(f"Invalid direction: {direction}")

            # Execute
            result = self.broker.place_order(symbol, direction, volume)

            self.logger.info(f"Trade executed: {result}")
            return result

        except ValueError as e:
            self.logger.error(f"Validation error: {e}")
            raise

        except ConnectionError as e:
            self.logger.error(f"Connection error: {e}")
            self.logger.info("Attempting reconnection...")
            self.reconnect()

        except Exception as e:
            self.logger.critical(f"Unexpected error: {e}")
            self.logger.debug(traceback.format_exc())
            raise

Debug Context Manager

import time

class DebugTimer:
    """Context manager for timing code blocks"""

    def __init__(self, name, logger):
        self.name = name
        self.logger = logger

    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, *args):
        elapsed = time.time() - self.start
        self.logger.debug(f"{self.name} took {elapsed:.4f}s")

# Usage
with DebugTimer("Signal calculation", logger):
    signal = calculate_signal(data)

with DebugTimer("Order execution", logger):
    result = place_order(signal)

Common Issues and Solutions

Issue: EA Not Opening Trades

Symptoms: Signal generated but no trades

Debug Steps:

void DiagnoseNoTrades()
{
    Print("=== Diagnosing No Trades ===");

    // Check AutoTrading
    if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
    {
        Print("AutoTrading is DISABLED in terminal");
        return;
    }

    // Check EA permissions
    if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
    {
        Print("EA trading is NOT allowed");
        return;
    }

    // Check account
    if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
    {
        Print("Account trading is DISABLED");
        return;
    }

    // Check market
    if(!SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE))
    {
        Print("Symbol trading is DISABLED");
        return;
    }

    // Check spread
    double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    Print("Current spread: ", spread);

    // Check balance
    double balance = AccountInfoDouble(ACCOUNT_BALANCE);
    double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
    Print("Balance: ", balance, " Free margin: ", freeMargin);

    Print("All basic checks passed");
}

Issue: Orders Being Rejected

void DiagnoseOrderRejection(MqlTradeResult& result)
{
    Print("=== Order Rejection Diagnosis ===");
    Print("Retcode: ", result.retcode);

    switch(result.retcode)
    {
        case 10016:
            Print("Market is closed");
            Print("Check trading hours for ", _Symbol);
            break;

        case 10017:
            Print("Insufficient funds");
            Print("Required margin: Check position size");
            Print("Free margin: ", AccountInfoDouble(ACCOUNT_MARGIN_FREE));
            break;

        case 10014:
            Print("Invalid stops");
            Print("Check minimum stop distance");
            double stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
            Print("Minimum stop distance: ", stopLevel);
            break;

        case 10012:
            Print("Invalid volume");
            double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
            double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
            double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
            Print("Min lot: ", minLot, " Max: ", maxLot, " Step: ", lotStep);
            break;
    }
}

Issue: Unexpected Position Sizes

`mql5 void ValidateLotSize(double requestedLots) { double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

Print("Requested lots: ", requestedLots); Print("Min: ", minLot, " Max: ", maxLot, " Step: ", lotStep);

// Check minimum if(requestedLots < minLot) { Print("WARNING: Lots below minimum, will be adjusted to ", minLot); }

// Check step double normalized = MathFloor(requestedLots / lotStep) * lotStep; if(normalized != requestedLots) { Print("WARNING: Lots not aligned to step, will be ", normalized); }

// Check margin double margin; if(OrderCalcMargin(ORDER_TYPE_BUY, _Symbol, requestedLots, SymbolInfoDouble(_Symbol, SYMBOL_ASK), margin)) { Print("Required margin: ", margin); Print("Free margin: ", AccountInfoDouble(ACCOUNT_MARGIN_FREE));

if(margin > AccountInfoDouble(ACCOUNT_MARGIN_FREE)) { Print("ERROR: Insufficient margin for this lot size"); } } } `

Testing Strategies

Unit Testing EA Functions

void RunTests()
{
    Print("=== Running EA Tests ===");

    TestCalculateLotSize();
    TestSignalGeneration();
    TestStopLossCalculation();

    Print("=== Tests Complete ===");
}

void TestCalculateLotSize()
{
    Print("Testing CalculateLotSize...");

    // Test case 1: Normal calculation
    double lots = CalculateLotSize(1.0, 50);  // 1% risk, 50 pip SL
    if(lots > 0 && lots <= SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX))
    {
        Print("  Test 1 PASSED: lots = ", lots);
    }
    else
    {
        Print("  Test 1 FAILED: lots = ", lots);
    }

    // Test case 2: Zero stop loss
    lots = CalculateLotSize(1.0, 0);
    if(lots == 0)
    {
        Print("  Test 2 PASSED: Zero SL handled");
    }
    else
    {
        Print("  Test 2 FAILED: Zero SL not handled");
    }
}

Backtesting Verification

`mql5 // Add to OnTester() for backtest verification double OnTester() { // Get statistics double profit = TesterStatistics(STAT_PROFIT); double trades = TesterStatistics(STAT_TRADES); double winRate = TesterStatistics(STAT_PROFIT_TRADES) / TesterStatistics(STAT_TRADES) * 100; double drawdown = TesterStatistics(STAT_EQUITY_DD_RELATIVE);

Print("=== Backtest Summary ==="); Print("Total Trades: ", trades); Print("Net Profit: ", profit); Print("Win Rate: ", winRate, "%"); Print("Max Drawdown: ", drawdown, "%");

// Validate results if(trades < 100) { Print("WARNING: Too few trades for reliable statistics"); }

if(drawdown > 30) { Print("WARNING: Excessive drawdown"); }

return profit; } ``

Debugging Checklist

Before Each Trading Session

  • [ ] Check AutoTrading is enabled
  • [ ] Verify broker connection
  • [ ] Confirm account permissions
  • [ ] Check symbol is tradable
  • [ ] Review spread conditions
  • [ ] Verify sufficient margin
  • [ ] Check EA parameters
  • [ ] Review journal for errors

When Issues Occur

  1. Check MT5 Journal and Experts tabs
  2. Review log files
  3. Verify market conditions
  4. Test with minimal lot size
  5. Check network connectivity
  6. Review recent changes
  7. Test on demo account

Key Takeaways

  • Implement comprehensive logging from the start
  • Use conditional debugging to control output
  • Handle all error codes explicitly
  • Create diagnostic functions for common issues
  • Test EA functions independently
  • Keep a debugging checklist
  • Document all issues and solutions
  • Test changes on demo before live

What's Next?

Learn about strategy optimization techniques to improve your trading system performance.


This article is for educational purposes only and does not constitute financial advice.

Risk warning. This is education only, not financial, investment, tax or legal advice, and not a recommendation to buy or sell anything. Trading forex, CFDs, stocks, commodities, futures, options and crypto is high-risk; with leverage you can lose more than you deposit, and most retail traders lose money. Before you trade or invest in any form, check the local laws where you are and the rules of your country of residence, and consider your own financial situation; if in doubt, ask a licensed adviser. Past and tested results, and all examples, are for illustration only and do not guarantee future results.

Get the strategy right before you automate it

An automated system is only as good as the rules behind it. The book series covers building and testing those rules before a line of code is written.

Explore the books