Для сравнения языков 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.