Для сравнения языков MQL5 и QLUA мы написали несколько тестов, которые замеряют скорость выполнения базовых операций.
В тестах использовался компьютер с Windows 7 Professional 64 bit, MetaTrader 5 build 1340 и QUIK версии 7.2.0.45.
Результаты представлены в таблице, где все значения представлены в миллисекундах (чем меньше время, тем лучше):
Название MQL5 QLUA Преимущество MQL5 TestFloat 3 969 273 391 69 раз TestArrays 375 230 768 615 раз TestFibo 1 125 61 110 55 раз TestPiCalculated 2 328 183 812 79 раз TestQuickSort 2 031 211 279 104 раза TestAckermann 828 64 541 78 раз
Сравнения показывают, что MQL5 быстрее QLUA от 50 до 600 раз на базовых операциях любого языка программирования. Это достигается за счет того, что MQL5 является строго типизированным компилируемым языком в 32/64 бита в противоположность динамическому интерпретируемому QLUA.
Что это дает трейдеру? Возможность максимально быстро обсчитывать огромные массивы данных (а они в MetaTrader 5 практически не ограничены) и быстрее принимать решения.
Это всего лишь проверка базового функционала. Но за фасадом языков скрываются их API. И не у всех он простой. MQL5, будучи прикладным языком для торговой платформы, содержит в себе сотни специализированных функций по доступу/обработке рыночной информации и взаимодействию со всеми компонентами терминала.
Важно, что MQL5 не прицеплен сбоку к существующей системе, а сам является центральным звеном платформы. Все процессы в торговом терминале построены вокруг удовлетворения потребностей разработчиков торговых роботов. Это дает максимальную скорость доступа к внутренним данным платформы и прямой канал для торговых операций.
Ниже приведены примеры скриптов и результаты тестирования, чтобы каждый мог убедиться в результатах. Полные архивы скриптов можно скачать по ссылке https://c.mql5.com/36/9/mql5-vs-qlua-benchmarks.zip и проверить самостоятельно.
TestFloat — Скорость выполнения операций с вещественными числами
Код на 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; //--- //+------------------------------------------------------------------+ //| Функция OnStart | //+------------------------------------------------------------------+ int OnStart() { uint tick_count,res; //--- тест tick_count=GetTickCount(); TestFloat(); res=GetTickCount()-tick_count; Print("Test float time=",res," ms"); Print("Result=",f0); //--- возвращает время, затраченное на выполнение теста, в милисекундах return((int)res); } //+------------------------------------------------------------------+ //| Функция тестирования | //+------------------------------------------------------------------+ 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); } } //+------------------------------------------------------------------+
Код на 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 -- результы выполнения занесем сюда check=f0 message("TestFloat time=" ..res.." ms\n check="..tostring(check)); end function TestFloat() -- в цикле мы проходим до значение на 1 меньше, чем 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 -- запускаем скрипт Start()
TestArrays — Тестирование времени доступа к элементам массива
Код на 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]; //+------------------------------------------------------------------+ //| Функция OnStart | //+------------------------------------------------------------------+ int OnStart() { int i,k; uint tick_count,res; //--- тест 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); //--- возвращает время, затраченное на выполнение теста, в милисекундах return((int)res); } //+------------------------------------------------------------------+
Код на 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 -- контрольное число local check=0 for k=1,MAX_SIZE,1 do check=check+y[k] end message("Time = "..res.." ms\n check=".. check) end -- запускаем скрипт Start()
TestFibo — вычисление последовательности ряда Фибоначии
Код на 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]; //+------------------------------------------------------------------+ //| Функция OnStart | //+------------------------------------------------------------------+ void OnStart() { int i; uint res; //--- тест 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]); } //+------------------------------------------------------------------+ //| Функция тестирования | //+------------------------------------------------------------------+ long TestFibo(long n) { if(n<2) return(1); //--- return(TestFibo(n-2)+TestFibo(n-1)); } //+------------------------------------------------------------------+
Код на 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 -- запускаем скрипт Start()
TestPiCalculated - Вычисление 22 000 знаков числа Pi
Код на 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 //--- в эту строку поместим значение числа PI string str; int a[(MAX_SIZE/4+1)*14]; //+------------------------------------------------------------------+ //| Функция OnStart | //+------------------------------------------------------------------+ int OnStart() { uint tick_count,res; //--- тест tick_count=GetTickCount(); PiCalculate(MAX_SIZE); res=GetTickCount()-tick_count; Print("TestPiCalculated time=",res," ms"); Print("Pi=",StringSubstr(str,0,16)); //--- возвращает время, затраченное на выполнение теста, в милисекундах return((int)res); } //+------------------------------------------------------------------+ //| Функция тестирования | //+------------------------------------------------------------------+ 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®; } } //+------------------------------------------------------------------+
Код на LUA
-- TestPiCalculated -- сколько знаков числа Pi будем вычислять MAX_SIZE=22000 -- в эту строку поместим значение числа Pi str="" a={} function OnStart() start=os.clock() PiCalculate(MAX_SIZE) -- время вычисления числа Pi в миллисекундах res=(os.clock()-start)*1000 message("TestPiCalculated time=" .. res .." ms\n\n Pi="..string.sub(str,1,16)) -- выведем 16 знаков end function PiCalculate(digits) d = 0 c = (math.floor(digits/4)+1)*14 -- math.floor() -целочисленное деление на основе примера из справки 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) -целочисленное деление на основе примера из справки LUA end r=e+math.floor(d/f) -- math.floor(d/f) - это целочисленное деление на основе примера из справки 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 -- запускаем скрипт OnStart()
Тестирование времени быстрой сортировки массива
Код на MQL5
//+------------------------------------------------------------------+ //| TestQuickSort.mq5 | //| Copyright 2016, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2010, MetaQuotes Software Corp." #property link "http://www.mql5.com" //--- будем сортировать массив размером в 16 миллионов элементов #define MAX_SIZE 16000000 //--- int array[MAX_SIZE]; //+------------------------------------------------------------------+ //| Функция 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; } } //+------------------------------------------------------------------+ //| Функция быстрой сортировки | //+------------------------------------------------------------------+ 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); } //+------------------------------------------------------------------+
Код на LUA
-- TestQuickSort -- будем сортировать массив размером в 16 миллионов элементов 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 -- запускаем скрипт Start()
TestAckermann — тестирование рекурсии в функциях
Код на MQL5
//+------------------------------------------------------------------+ //| TestAckermann.mq5 | //| Copyright 2016, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2016, MetaQuotes Software Corp." #property link "http://www.mql5.com" //--- количество прогонов функции Аккермана в цикле #define MAX_SIZE 120000 //+------------------------------------------------------------------+ //| Функция OnStart | //+------------------------------------------------------------------+ void OnStart() { //--- контрольное число uint check=0; //--- время выполнения в миллисекундах uint res=0; //--- тест 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); //--- } //+------------------------------------------------------------------+ //| Функция тестирования | //+------------------------------------------------------------------+ 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)))); } //+------------------------------------------------------------------+
Код на LUA
-- TestAckermann MAX_SIZE=120000 function Start() local check=0 -- контрольное число 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 -- запускаем скрипт Start()
— Это был Неуловимый Джо, Гарри.
— А почему его зовут Неуловимым Джо, Билл?
— Потому что его никто ещё не поймал, Гарри.
— А почему его никто ещё не поймал, Билл?
— Потому что он нафиг никому не нужен, Гарри.
обгоните assembler.