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.