La batalla por la velocidad: QLUA vs MQL5 - ¿Por qué MQL5 es de 50 a 600 veces más rápido?

MetaQuotes | 19 septiembre, 2019

Para comparar los lenguajes MQL5 y QLUA, hemos diseñado varias pruebas que miden la velocidad de ejecución de las operaciones básicas. En dichos tests, hemos utilizado una computadora con Windows 7 Professional 64 bit, MetaTrader 5 build 1340 y QUIK de versión 7.2.0.45.

Los resultados se muestran en un recuadro, donde los valores se representan en milisegundos (cuanto menor sea el tiempo, mejor será el resultado)

#
Nombre del script de prueba
MQL5, ms
 QLUA, ms
Ventaja de MQL5
1
 TestFloat 3 969 273 391 69 veces
2
 TestArrays 375 230 768 615 veces
3
 TestFibo 1 125 61 110 55 veces
4
 TestPiCalculated 2 328
183 812
 79 veces
5
 TestQuickSort 2 031
211 279
104 veces
 6  TestAckermann  828  64 541  78 veces

Las comparaciones muestran que MQL5 es de 50 a 600 veces más rápido que QLUA en las operaciones básicas de cualquier lenguaje de programación. Esto se logra gracias a que MQL5 es un lenguaje compilable rigurosamente tipado en 32/64 bits, en oposición a la interpretación dinámica de QLUA.

¿Y qué es lo que ofrece al tráder? La posibilidad de calcular a una velocidad máxima enormes matrices de datos (en MetaTrader 5 son prácticamente ilimitadas) y tomar decisiones a una mayor velocidad.

Y esto solo se refiere a la funcionalidad básica. Pero, tras las fachadas de los lenguajes, se ocultan sus API. Y no todos las tienen sencillas. Al tratarse de un lenguaje aplicado para una plataforma comercial, MQL5 contiene cientos de funciones especializadas de acceso/procesamiento de información de mercado e interacción con todos los componentes del terminal.

Lo importante es que MQL5 no se subordina al sistema existente, sino que constituye por sí mismo un eslabón principal de la plataforma. Todos los procesos en el terminal comercial se construyen para satisfacer las necesidades de los desarrolladores de robots comerciales. Esto proporciona una velocidad de acceso máxima a los datos internos de la plataforma, así como un canal para las operaciones comerciales.


TestFloat - Velocidad de ejecución de operaciones con números reales

Código en MQL5

//+------------------------------------------------------------------+
//|                                                    TestFloat.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 35000
//---
double f0=0;
double f1=123.456789;
double f2=98765.12345678998765432;
double f3=12345678943.98;
//---
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   uint tick_count,res;
//--- test
   tick_count=GetTickCount();
   TestFloat();
   res=GetTickCount()-tick_count;
   Print("Test float time=",res," ms");
   Print("Result=",f0);
//--- retorna el tiempo invertido en la ejecución del test, en milisegundos
   return((int)res);
  }
//+------------------------------------------------------------------+
//| Función de simulación                                            |
//+------------------------------------------------------------------+
void TestFloat()
  {
   for(int i=0;i<MAX_SIZE;i++)
      for(int j=0;j<MAX_SIZE;j++)
        {
         f0=f0+(f1/(i+1))-f2+(f3*i);
        }
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestFloat
f0=0.0  
f1=123.456789
f2=98765.12345678998765432
f3=12345678943.98
MAX_SIZE=35000
function Start()
   local t=os.clock()
   TestFloat()
   local res=(os.clock()-t)*1000
   -- introducimos aquí los resultados de la ejecución
   check=f0
   message("TestFloat time=" ..res.." ms\n  check="..tostring(check));
end

function TestFloat()
    -- iteramos en el ciclo hasta un valor 1 unidad menor que MAX_SIZE
        MAX_SIZE=MAX_SIZE-1
        for i=0, MAX_SIZE do
        for j=0, MAX_SIZE do
            f0=f0+(f1/(i+1))-f2+(f3*i);
        end
    end
end
-- iniciamos el script
Start()

TestArrays - Simulación del tiempo de acceso a los elementos de la matriz

Código en MQL5

//+------------------------------------------------------------------+
//|                                                   TestArrays.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 32000
//---
int x[MAX_SIZE],y[MAX_SIZE];
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   int  i,k;
   uint tick_count,res;
//--- test
   tick_count=GetTickCount();
   for(i=0;i<MAX_SIZE;i++)
      x[i]=i+1;

   for(k=0;k<MAX_SIZE;k++)
      for(i=MAX_SIZE-1; i>=0; i--)
         y[i]+=x[i];
   long check=0;
   for(i=0;i<MAX_SIZE;i++)
     {
      check+=y[i];
     }          
   res=GetTickCount()-tick_count;
   Print("TestArrays time=",res," ms");
      Print("check=",check);
//--- retorna el tiempo invertido en la ejecución del test, en milisegundos
   return((int)res);
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestArrays
function Start()
        MAX_SIZE=32000
    x={}
    y={}
    local start=os.clock()
    for i=1,MAX_SIZE,1 do
      x[i]=i
      y[i]=0
    end  
    y[MAX_SIZE]=0
    for k=1,MAX_SIZE,1 do
        for i=MAX_SIZE, 1,-1 do         
            y[i]=y[i]+x[i]
        end
    end
    local res=(os.clock()-start)*1000
    -- número de control
    local check=0
    for k=1,MAX_SIZE,1 do
        check=check+y[k]
    end
    message("Time = "..res.." ms\n  check=".. check)
end
-- iniciamos el script
Start()


TestFibo - cálculo de la secuencia de la serie de Fibonacci

Código en MQL5

//+------------------------------------------------------------------+
//|                                                     TestFibo.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 40
long fib[MAX_SIZE];
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   int  i;
   uint res;
//--- test
   res=GetTickCount();
   for(i=0;i<MAX_SIZE;i++)
      fib[i]=TestFibo(i);
   res=GetTickCount()-res;
   Print("TestFibo time=",res," ms");
   Print("Fibo[39]=",fib[39]);
  }
//+------------------------------------------------------------------+
//| Función de simulación                                            |
//+------------------------------------------------------------------+
long TestFibo(long n)
  {
   if(n<2) return(1);
//---
   return(TestFibo(n-2)+TestFibo(n-1));
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestFibo
MAX_SIZE=40
fib={}
function Start()
   start=os.clock()
   for i=0,MAX_SIZE-1 do
     fib[i]=TestFibo(i)
   end
   res=(os.clock()-start)*1000
   message("TestFibo time="..res.." ms\n Fibo[39]="..fib[39])
end

function TestFibo(n)
   if n<2 then
      return(1)
   else
      return(TestFibo(n-2)+TestFibo(n-1))
   end
end
-- iniciamos el script
Start()



TestPiCalculated -  Cálculo de 22 000 dígitos del número Pi

Código en MQL5

//+------------------------------------------------------------------+
//|                                             TestPiCalculated.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 22000
//--- en esta línea ubicamos el valor del número PI
string str;
int    a[(MAX_SIZE/4+1)*14];
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   uint tick_count,res;
//--- test
   tick_count=GetTickCount();
   PiCalculate(MAX_SIZE);
   res=GetTickCount()-tick_count;
   Print("TestPiCalculated time=",res," ms");
   Print("Pi=",StringSubstr(str,0,16));
//--- retorna el tiempo invertido en la ejecución del test, en milisegundos
   return((int)res);
  }
//+------------------------------------------------------------------+
//| Función de simulación                                            |
//+------------------------------------------------------------------+
void PiCalculate(const int digits)
  {
   int d = 0,e,b,g,r;
   int c = (digits/4+1)*14;
   int f = 10000;
//---
   for(int i=0;i<c;i++)
      a[i]=20000000;
//---
   while((b=c-=14)>0)
     {
      d=e=d%f;
      while(--b>0)
        {
         d = d * b + a[b];
         g = (b << 1) - 1;
         a[b]=(d%g)*f;
         d/=g;
        }
      r=e+d/f;
      if(r<1000)
        {
         if(r>99)
            str+="0";
         else
           {
            if(r>9)
               str+="00";
            else
               str+="000";
           }
        }
      str+=IntegerToString(r);
     }
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestPiCalculated
-- cuántos dígitos del número Pi vamos a calcular
MAX_SIZE=22000
-- en esta línea ubicamos el valor del número PI
str=""
a={}
function OnStart()
        start=os.clock()
        PiCalculate(MAX_SIZE)
        -- tiempo de cálculo del número Pi en milisegundos
        res=(os.clock()-start)*1000
        message("TestPiCalculated time=" .. res .." ms\n\n Pi="..string.sub(str,1,16)) -- mostramos 16 dígitos
end
function PiCalculate(digits)
        d = 0
        c = (math.floor(digits/4)+1)*14  -- math.floor() -división entera basada en el ejemplo de la guía LUA
        f = 10000

        for i=0,c do
                a[i]=20000000
        end
        c=c-14
        b=c
        while b>0 do
                e=d%f
                d=e
                while b-1>0 do
                        b=b-1
                        d = d * b + a[b]
                        g = (b * 2) - 1
                        a[b]=(d%g)*f  
            d=math.floor(d/g)  -- math.floor(d/g) -división entera basada en el ejemplo de la guía LUA
        end
        r=e+math.floor(d/f)  -- math.floor(d/f) - división entera basada en el ejemplo de la guía LUA
                if r<1000 then
                        if(r>99) then 
                                str=str .. "0"
                        else
                                if(r > 9) then
                                        str=str .. "00"
                                else
                                        str=str .. "000"
                                end
                        end
                end
                str=str .. string.format("%d",r)
                c=c-14
                b=c
        end
end
-- iniciamos el script
OnStart()


Simulación del tiempo de clasificación rápida de la matriz

Código en MQL5

//+------------------------------------------------------------------+
//|                                                TestQuickSort.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- clasificaremos una matriz con un tamaño de 16 millones de elementos
#define MAX_SIZE 16000000
//---
int array[MAX_SIZE];
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   uint tick_count,res;
   for(int i=0;i<MAX_SIZE;i++)
      array[i]=i%100;
   tick_count=GetTickCount();
   QuickSort(array,0,MAX_SIZE-1);
   res=GetTickCount()-tick_count;
   Print("TestQuickSort time=",res," ms");

   for(int i=1;i<MAX_SIZE;i++)
      if(array[i]<array[i-1])
        {
        Print("Array not sorted");
        break;
        }
  }
//+------------------------------------------------------------------+
//| Función de clasificación rápida                                  |
//+------------------------------------------------------------------+
void QuickSort(int &arr[],int left,int right)
  {
   int i=left;
   int j=right;
   int center=arr[(i+j)/2];
   int x;
//---
   while(i<=j)
     {
      while(arr[i]<center && i<right) i++;
      while(arr[j]>center && j>left) j--;
      if(i<=j)
        {
         x=arr[i];
         arr[i]=arr[j];
         arr[j]=x;
         i++;
         j--;
        }
     }
   if(left<j) QuickSort(arr,left,j);
   if(right>i) QuickSort(arr,i,right);
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestQuickSort
-- clasificaremos una matriz con un tamaño de 16 millones de elementos
MAX_SIZE=16000000
array={}
function Start()
    for i=0,MAX_SIZE-1 do
        array[i]=i%100
    end
    start=os.clock()
    QuickSort(array,0,MAX_SIZE-1)
    res=(os.clock()-t)*1000
    message("TestQuickSort time=" .. res .. " ms")
    for i=1,MAX_SIZE-1 do
        if array[i]<array[i-1] then
            message("Array not sorted");
            break;
        end
    end
end

function QuickSort(arr,left,right)
    i=left
    j=right
    center=arr[math.floor((i+j)/2)]
    while i<=j do
        while(arr[i]<center and i<right) do
            i=i+1
        end
        while(arr[j]>center and j>left) do
            j=j-1
        end
        if i<=j then
            x=arr[i]
            arr[i]=arr[j]
            arr[j]=x
            i=i+1
            j=j-1
        end
    end
    if left<j then 
        QuickSort(arr,left,j)
    end
    if right>i then 
        QuickSort(arr,i,right)
    end
end
-- iniciamos el script
Start()


TestAckermann - simulación de la recursión en las funciones

Código en MQL5

//+------------------------------------------------------------------+
//|                                                TestAckermann.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2016, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- número de pasadas en la función de Ackermann en el ciclo
#define MAX_SIZE 120000
//+------------------------------------------------------------------+
//| Función OnStart                                                  |
//+------------------------------------------------------------------+
void  OnStart()
  {
//--- número de control
   uint check=0;
//--- tiempo de ejecución en milisegundos
   uint res=0;
//--- test
   res=GetTickCount();
   for(int i=0;i<MAX_SIZE;i++)
      check+=Ackermann(1+i%3,1+i%5);
   res=GetTickCount()-res;
   Print("TestAckermann time=",res," ms");
   Print("check=",check);
//---
  }
//+------------------------------------------------------------------+
//| Función de simulación                                            |
//+------------------------------------------------------------------+
int Ackermann(int m,int n)
  {
   if(m==0) return(n+1);
   if(n==0) return(Ackermann(m-1,1));
//---
   return(Ackermann(m-1,Ackermann(m,(n-1))));
  }
//+------------------------------------------------------------------+

Código en LUA

-- TestAckermann
MAX_SIZE=120000
function Start()        
    local check=0 -- número de control
    local start=os.clock()
        for i=1,MAX_SIZE do
             check=check+Ackermann(1+i%3,1+i%5);                                                
        end 
    local finish=os.clock()
    local time=(finish-start)*1000
    message("TestAckermann time=".. time.." ms\n\n check="..check)
end

function Ackermann(m,n)
        if(m==0) then return(n+1) end
        if(n==0) then return(Ackermann(m-1,1)) end
        return(Ackermann(m-1,Ackermann(m,(n-1))))
end
-- iniciamos el script
Start()



Podrá descargar el directorio completo de scripts y comprobar los resultados por sí mismo.