🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Scalping Strategy: How to Process Live Tick Data with SymbolInfoTick()

mql4 | Published on: 2025/12/8
The following content is generated by EasyQuant .

Problem Description

How do I get the price of every single tick to build a fast scalping strategy?

Solution

To capture the price of every single tick in MQL4 for a fast scalping strategy, you must utilize the OnTick() event handler combined with the SymbolInfoTick() function.

In high-frequency or fast scalping strategies, using the standard Bid and Ask variables is acceptable, but SymbolInfoTick() is superior because it populates an MqlTick structure. This ensures that the Bid, Ask, and Time values are synchronized from the exact same snapshot, preventing data mismatch during highly volatile moments.

Key Implementation Details

  1. Event Driven: The code must reside inside OnTick(). This function triggers every time the server sends a new price update.
  2. Atomic Data: Use MqlTick to get Bid and Ask simultaneously.
  3. Speed Optimization: To ensure you process "every" tick, your code inside OnTick must execute faster than the arrival of the next tick. Avoid Sleep(), heavy loops, or complex graphical object creation inside the main trading logic.

MQL4 Scalping Template

Here is a complete, optimized framework for a tick-based scalping strategy.

//+------------------------------------------------------------------+
//|                                            FastTickScalper.mq4   |
//|                        Copyright 2023, Quantitative AI Assistant |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI Assistant"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//--- Input Parameters
input double InpLots          = 0.1;   // Lot size
input int    InpStopLoss      = 10;    // Stop Loss in points
input int    InpTakeProfit    = 10;    // Take Profit in points
input int    InpMaxSpread     = 15;    // Max allowed spread in points
input int    InpSlippage      = 3;     // Max slippage in points
input int    InpMagicNum      = 12345; // Magic Number

//--- Global Variables for Tick Analysis
MqlTick currentTick;
double  lastTickBid = 0;
double  lastTickAsk = 0;
double  point;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Initialize point value for calculations
   point = Point;
   if(Digits == 3 || Digits == 5) point *= 10;
   
   // Initial data population
   if(!SymbolInfoTick(_Symbol, currentTick))
   {
      Print("Failed to get initial tick data");
      return(INIT_FAILED);
   }
   lastTickBid = currentTick.bid;
   lastTickAsk = currentTick.ask;

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. GET THE TICK DATA
   // We use SymbolInfoTick for atomic data access (Bid/Ask/Time sync)
   if(!SymbolInfoTick(_Symbol, currentTick))
   {
      // If we can't get the tick, we can't trade. Exit immediately.
      return; 
   }

   // 2. CHECK SPREAD (Crucial for Scalping)
   // Calculate spread in points
   int spread = (int)((currentTick.ask - currentTick.bid) / Point);
   
   // If spread is too high, do not execute logic
   if(spread > InpMaxSpread)
   {
      // Update history for next comparison and exit
      lastTickBid = currentTick.bid;
      lastTickAsk = currentTick.ask;
      return;
   }

   // 3. FAST SCALPING LOGIC
   // Example Logic: Detect a micro-momentum (Tick moves up/down)
   // NOTE: Replace this block with your specific algo logic
   
   bool signalBuy = false;
   bool signalSell = false;

   // Simple example: If Bid moved up significantly in one tick
   if(currentTick.bid > lastTickBid + point) 
   {
      signalBuy = true;
   }
   // Simple example: If Bid moved down significantly in one tick
   else if(currentTick.bid < lastTickBid - point)
   {
      signalSell = true;
   }

   // 4. EXECUTION
   // Only check orders if we have a signal to save CPU cycles
   if(signalBuy || signalSell)
   {
      // Check if we already have open positions to avoid over-trading
      if(OrdersTotal() == 0) 
      {
         if(signalBuy)
         {
            OpenTrade(OP_BUY, currentTick.ask);
         }
         else if(signalSell)
         {
            OpenTrade(OP_SELL, currentTick.bid);
         }
      }
   }

   // 5. STORE HISTORY
   // Store current tick as "last" for the next execution
   lastTickBid = currentTick.bid;
   lastTickAsk = currentTick.ask;
}

//+------------------------------------------------------------------+
//| Helper: Open Trade                                               |
//+------------------------------------------------------------------+
void OpenTrade(int type, double price)
{
   double sl = 0, tp = 0;
   
   // Calculate SL/TP based on direction
   if(type == OP_BUY)
   {
      if(InpStopLoss > 0) sl = price - InpStopLoss * point;
      if(InpTakeProfit > 0) tp = price + InpTakeProfit * point;
   }
   else if(type == OP_SELL)
   {
      if(InpStopLoss > 0) sl = price + InpStopLoss * point;
      if(InpTakeProfit > 0) tp = price - InpTakeProfit * point;
   }

   // Normalize prices
   sl = NormalizeDouble(sl, Digits);
   tp = NormalizeDouble(tp, Digits);
   price = NormalizeDouble(price, Digits);

   // Send Order
   int ticket = OrderSend(_Symbol, type, InpLots, price, InpSlippage, sl, tp, "FastScalper", InpMagicNum, 0, clrNONE);
   
   if(ticket < 0)
   {
      Print("OrderSend failed with error #", GetLastError());
   }
}

Code Explanation

  1. MqlTick currentTick: This structure is the core of the strategy. It holds time, bid, ask, last, and volume. Using this structure is faster and cleaner than calling MarketInfo() multiple times.
  2. SymbolInfoTick(_Symbol, currentTick): This function fills the structure with the very latest data from the market watch. It returns true if successful.
  3. Spread Filter: Scalping relies on tight spreads. The code calculates the spread immediately and exits OnTick if the spread exceeds InpMaxSpread. This prevents the EA from calculating logic during expensive market conditions.
  4. Logic Execution: The logic compares the currentTick against lastTickBid (stored from the previous execution). This allows you to analyze price velocity or direction tick-by-tick.
  5. Efficiency: The code checks OrdersTotal() only after a signal is generated. This saves processing time on ticks where no signal exists, which is the majority of the time.

Limitations of MQL4 for Tick Scalping

While the code above is optimized, you must be aware of the platform limitations:

  • Single Threading: MQL4 EAs run on a single thread. If your OnTick() logic takes 100ms to execute, but 3 ticks arrive during that 100ms, you will miss 2 ticks. The EA will only process the latest tick available when it finishes the previous calculation.
  • No Tick History: Unlike MQL5, MQL4 does not have a native CopyTicks function to retrieve history. You can only see the current tick. If you miss a tick because the CPU was busy, that data is lost to the EA.
  • Latency: Network latency (ping) is often higher than the time between ticks during news events. A VPS located near the broker's server is mandatory for tick scalping.

Q&A

Q: Can I backtest this tick strategy in MT4?
A: Yes, but with limitations. MT4 Strategy Tester generates ticks based on M1 OHLC data (interpolation), meaning the ticks are simulated, not real. For accurate tick scalping backtests, you must use "Tick Data Suite" or similar 3rd party tools to inject real tick history into MT4, or switch to MT5 which supports real tick data natively.

Q: How do I make the code run faster?
A: Remove any Print() or Comment() functions from the OnTick loop, as writing to the log/screen is slow. Ensure you are not calling heavy custom indicators (iCustom) on every tick; instead, code the indicator logic directly into the EA if possible.

Q: Why use SymbolInfoTick instead of Bid and Ask?
A: Bid and Ask are variables that are updated automatically, but SymbolInfoTick fills a structure that includes the time and volume of that specific tick update. It ensures that if you read the Bid and then the Ask, they belong to the exact same market snapshot.