Оптимизация быстродеятельности эксперта. Подскажите, что можно усовершенствовать на рабочем примере.
Например, заголовок цикла
for(int i=0;i<OrdersTotal();i++)
Сколько итераций, столько и обращений к функции OrdersTotal, плюс ещё 1 обращение
int total=OrdersTotal(); for(int i=0;i<total;i++)
2. То же самое касается вызова функции Symbol(). Заведите глобальную строковую переменную и присваивайте ей значение при инициализации эксперта
string symbol;
...
int init()
{
symbol=Symbol();
}
...
if(OrderSymbol()!=symbol) continue;
...
Самая главная проблема - в функции start
Вот отработает удачно функция CheckForOpen() и значение, возвращаемое функцией OrdersTotal() станет не 0, а 1. Сразу же вызовутся CheckForCloseByTS и CheckForCloseByPips. А оно надо? Похоже, что нет, лишняя работа
Возможно это не совсем в тему про Ваш советник, но всё равно Вам может быть полезно. Вы наверное просто идёте по пути научного тыка, который формулируется следующим образом:"А давай как я возьму десяток параметров и найду в n-мерном пространстве глобальный максимум загнав тестер сразу на оптимизацию по всем параметрам с мелким шагом, чтобы чего не пропустить. Наверняка что-то получится?" Действительно что-то получится. Правда если Вам нужен только ТАКОЙ способ решения, то сразу скажу, что никакие двуядерные супер-пупергигагерцовые системы Вашу задачу не решат поскольку технические средства не могут соревноваться с геометрической прогрессией (и могу сказать для справки - и НИКОГДА не смогут!). И дело тут совершенно не в том во сколько раз MQL4 медленнее, чем C++. Даже если разработчикам МТ4 удастся ускорить работу тестера в 10 раз это Вам в лучшем случае сможет сэкономить лишь считанные проценты (и не более того!) времени до того самого момента когда Вы станете миллионером ;o)! Я же со своей стороны могу Вам лишь предложить то, чем сам пользуюсь постоянно:
Я например по своему опыту провожу оптимизацию каждого параметра по отдельности используя метод последовательных приближений (для информации один прогон в тестере моего эксперта занимает 3мин на P4 2,4ГГц – период М1(все тики) за 1,5 года). То есть делю диапазон значений например на 20 интервалов, далее в области максимума делю пару прилегающих к максимуму интервалов из предыдущей оптимизации ещё на 20 интервалов и делаю ещё один такой же шаг. Обычно 3-4 таких итерации оказывается вполне достаточно. Таким образом мы получаем в итоге результат по точности сопоставимый с прогоном сразу по 8000 интервалам с самым мелким шагом (20 в 3 степени). При этом мы имеем экономию в 8000-3*20=7940 итераций. То есть в идеале тратим время в 133 раза меньше, чем при тупом прогоне сразу на мелком шаге. При этом нужно отметить, что если у нас имеется ограниченное количество самого времени, за которое мы хотим получить результат (например мы можем подождать результат до вечера рабочего дня), то мы можем взять в 133 раза более длительный период для тестирования (например вместо 1 недели можно будет посчитать по 133 неделям) и в итоге мы будем иметь результат который будет хоть чего-то стоить, потратив на это тоже самое количество расчётного времени! А результаты быстрых прогонов численностью в 2,7 млн. штук, которых человек в состоянии дождаться, у меня вызывают серьёзные сомнения в плане применимости полученных результатов.
Конечно же мне можно возразить в плане того, что при просчёте всех мелких интервалов можно получить какой-то новый максимум, который будет упущен при расчёте по методике последовательных приближений, описанной выше. Но на это можно сказать, что в таком случае можно поймать лишь максимум, отражающий особенности выборки, и которых не будет в будущем! То есть при оптимизации должны выбираться параметры, изменение которых в небольших пределах, вызывает небольшое изменение в конечном результате. Ну а если у вас на мелком шаге окажется супер-пупер максимум, который мы можем не отследить на более крупном шаге, то можно быть точно уверенным, что данный максимум отражает ТОЛЬКО особенности конкретной выборки и его лучше не принимать во внимание вообще.
Запустил представленного эксперта как есть на оптимизацию (чтобы вывод в логи не мешался).
36 прогонов за 4 минуты 2 секунды. На 1 прогон - 6.7 секунды
Устранил по собственному совету все лишние вызовы функций.
Те же 36 прогонов за 3 минуты 7 секунд. 1 прогон 5.2 секунды
Дополнительно вставил элементарнейшую проверку на наличие денег
2 минуты 55 секунд или 4.9 секунды на прогон
А вы говорите, что это даст.
Просто не вызывается функция CheckForOpen
код пожалуйста:
extern double SL = 58;
extern double TP = 310;
extern double MA_Type = 2;
extern double fast = 3;
extern double slow = 23;
extern double shiftfast = 0;
extern double shiftslow = 0;
extern double hour_work_from = 11;
extern double hour_work_to = 15;
extern double Lots = 1;
extern double TS_enabled = 0;
extern double TS_PipsZeroStop = 40;
extern double TS_PipsToMoveStop = 110;
extern double TS_PipsStop = 80;
extern double StopsEnabled = 2;
extern double Target1 = 180;
extern double Stop1 = 140;
extern double Target2 = 300;
extern double Stop2 = 245;
extern double Target3 = 80;
extern double Stop3 = 60;
double fast2 = 0;
double fast1 = 0;
double slow2 = 0;
double slow1 = 0;
double TS_value = 0;
int i = 0;
string symbol;
int init()
{
symbol=Symbol();
return(0);
}
int deinit() {
return(0);
}
void CheckForOpen() {
fast1=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,1+shiftfast);
fast2=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,2+shiftfast);
slow1=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,1+shiftfast);
slow2=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,2+shiftfast);
if ((fast1>slow1) && (fast2<slow2)) {
OrderSend(symbol,OP_BUY,Lots,Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Green);
}
else
{
if ((fast1<slow1) && (fast2>slow2))
OrderSend(symbol,OP_SELL,Lots,Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Green);
}
}
void CheckForCloseByTS() {
int total=OrdersTotal();
for(int i=0;i<total;i++) {
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()!=symbol) continue;
int type=OrderType();
if(type==OP_BUY) {
if ((Bid-OrderOpenPrice()) > (TS_PipsZeroStop*Point)) {
TS_value = 0;
if (OrderStopLoss() < OrderOpenPrice()) {
TS_value=OrderOpenPrice();
}
else {
if ((Bid - OrderStopLoss()) > (TS_PipsToMoveStop*Point)) {
TS_value = OrderStopLoss() + (TS_PipsStop*Point);
}
}
if (TS_value > 0) {
OrderModify(OrderTicket(),OrderOpenPrice(), TS_value, OrderTakeProfit(),0,Blue);
}
}
break;
}
if(type==OP_SELL) {
if ((OrderOpenPrice()-Ask) > (TS_PipsZeroStop*Point)) {
TS_value = 0;
if (OrderStopLoss() > OrderOpenPrice()) {
TS_value=OrderOpenPrice();
}
else {
if ((OrderStopLoss()-Ask) > (TS_PipsToMoveStop*Point)) {
TS_value = OrderStopLoss() - TS_PipsStop*Point;
}
}
if (TS_value > 0) {
OrderModify(OrderTicket(),OrderOpenPrice(), TS_value, OrderTakeProfit(),0,Green);
}
}
break;
}
}
}
void CheckForCloseByPips() {
int total=OrdersTotal();
for(int i=0;i<total;i++) {
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()!=symbol) continue;
int type=OrderType();
if(type==OP_BUY) {
if ((StopsEnabled > 0) && ((Bid-OrderOpenPrice()) > (Target1*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop1*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop1*Point), OrderTakeProfit(),0,Blue);
}
if ((StopsEnabled > 1) && ((Bid-OrderOpenPrice()) > (Target2*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop3*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop2*Point), OrderTakeProfit(),0,Blue);
}
if ((StopsEnabled > 2) && ((Bid-OrderOpenPrice()) > (Target3*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop3*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop3*Point), OrderTakeProfit(),0,Blue);
}
break;
}
if(type==OP_SELL) {
if ((StopsEnabled > 0) && ((OrderOpenPrice()-Ask) > (Target1*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop1*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop1*Point), OrderTakeProfit(),0,Blue);
}
if ((StopsEnabled > 1) && ((OrderOpenPrice()-Ask) > (Target2*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop2*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop2*Point), OrderTakeProfit(),0,Blue);
}
if ((StopsEnabled > 2) && ((OrderOpenPrice()-Ask) > (Target3*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop3*Point))) {
OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop3*Point), OrderTakeProfit(),0,Blue);
}
break;
}
}
}
int start() {
static bool money=true;
if (OrdersTotal() < 1)
{
int hour=Hour();
if ((hour >= hour_work_from) && (hour < hour_work_to) && money) {
CheckForOpen();
if(GetLastError()==134) money=false;
}
}
else
{
if (TS_enabled > 0) CheckForCloseByTS();
if (StopsEnabled > 0) CheckForCloseByPips();
}
return(0);
}
//+------------------------------------------------------------------+
ИМХО : код еще можно намного ускорить - сама функция
void CheckForOpen() {
fast1=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,1+shiftfast);
fast2=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,2+shiftfast);
slow1=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,1+shiftfast);
slow2=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,2+shiftfast);
if ((fast1>slow1) && (fast2<slow2)) {
OrderSend(symbol,OP_BUY,Lots,Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Green);
}
else
{
if ((fast1<slow1) && (fast2>slow2))
OrderSend(symbol,OP_SELL,Lots,Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Green);
}
}
топ "тормозного искусства" :). Незачем на каждом тике пересчитывать значения мувингов на предыдущих барах, а это происходит, если нет открытых ордеров. Код лень писать - ИМХО - и так очевидно: эти значения не изменяются - считаем один раз, заносим в массив и используем. Причем, пересчет нужен только по последнему бару, один раз на момент открытия этого бара, все остальные элементы массива просто смещаем на один.
Удачи и попутных трендов.
ИМХО : код еще можно намного ускорить - сама функция
void CheckForOpen() {
fast1=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,1+shiftfast);
fast2=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,2+shiftfast);
slow1=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,1+shiftfast);
slow2=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,2+shiftfast);
if ((fast1>slow1) && (fast2<slow2)) {
OrderSend(symbol,OP_BUY,Lots,Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Green);
}
else
{
if ((fast1<slow1) && (fast2>slow2))
OrderSend(symbol,OP_SELL,Lots,Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Green);
}
}
топ "тормозного искусства" :). Незачем на каждом тике пересчитывать значения мувингов на предыдущих барах, а это происходит, если нет открытых ордеров. Код лень писать - ИМХО - и так очевидно: эти значения не изменяются - считаем один раз, заносим в массив и используем. Причем, пересчет нужен только по последнему бару, один раз на момент открытия этого бара, все остальные элементы массива просто смещаем на один.
Удачи и попутных трендов.
Так это и есть Ваш эксперт. Я в нём сделал только те изменения, о которых говорил раньше. Из самодеятельности я просто добавил один break (похоже, Вы его просто забыли, в функции CheckForCloseByTS первый break).
Добавил переменные symbol, total, type, money. Поиском по тексту эти переменные ищите.
Переписал функцию start - при визуальном сравнении Вашего и моего текста сразу увидите.
Возможна проблема с тем, что открывающие фигурные скобки я ставил в новой строке.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
#property copyright "Buttler" #property link "fedakin@ukr.net" extern double SL = 58; extern double TP = 310; extern double MA_Type = 2; extern double fast = 3; extern double slow = 23; extern double shiftfast = 0; extern double shiftslow = 0; extern double hour_work_from = 11; extern double hour_work_to = 15; extern double Lots = 1; extern double TS_enabled = 0; extern double TS_PipsZeroStop = 40; extern double TS_PipsToMoveStop = 110; extern double TS_PipsStop = 80; extern double StopsEnabled = 2; extern double Target1 = 180; extern double Stop1 = 140; extern double Target2 = 300; extern double Stop2 = 245; extern double Target3 = 80; extern double Stop3 = 60; double fast2 = 0; double fast1 = 0; double slow2 = 0; double slow1 = 0; double TS_value = 0; int i = 0; int init() { return(0); } int deinit() { return(0); } void CheckForOpen() { fast1=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,1+shiftfast); fast2=iMA(NULL,0,fast,0,MA_Type,PRICE_CLOSE,2+shiftfast); slow1=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,1+shiftfast); slow2=iMA(NULL,0,slow,0,MA_Type,PRICE_CLOSE,2+shiftfast); if ((fast1>slow1) && (fast2<slow2)) { OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Green); } if ((fast1<slow1) && (fast2>slow2)) { OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Green); } } void CheckForCloseByTS() { for(int i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break; if(OrderSymbol()!=Symbol()) continue; if(OrderType()==OP_BUY) { if ((Bid-OrderOpenPrice()) > (TS_PipsZeroStop*Point)) { TS_value = 0; if (OrderStopLoss() < OrderOpenPrice()) { TS_value=OrderOpenPrice(); } else { if ((Bid - OrderStopLoss()) > (TS_PipsToMoveStop*Point)) { TS_value = OrderStopLoss() + (TS_PipsStop*Point); } } if (TS_value > 0) { OrderModify(OrderTicket(),OrderOpenPrice(), TS_value, OrderTakeProfit(),0,Blue); } } } if(OrderType()==OP_SELL) { if ((OrderOpenPrice()-Ask) > (TS_PipsZeroStop*Point)) { TS_value = 0; if (OrderStopLoss() > OrderOpenPrice()) { TS_value=OrderOpenPrice(); } else { if ((OrderStopLoss()-Ask) > (TS_PipsToMoveStop*Point)) { TS_value = OrderStopLoss() - TS_PipsStop*Point; } } if (TS_value > 0) { OrderModify(OrderTicket(),OrderOpenPrice(), TS_value, OrderTakeProfit(),0,Green); } } break; } } } void CheckForCloseByPips() { for(int i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break; if(OrderSymbol()!=Symbol()) continue; if(OrderType()==OP_BUY) { if ((StopsEnabled > 0) && ((Bid-OrderOpenPrice()) > (Target1*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop1*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop1*Point), OrderTakeProfit(),0,Blue); } if ((StopsEnabled > 1) && ((Bid-OrderOpenPrice()) > (Target2*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop3*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop2*Point), OrderTakeProfit(),0,Blue); } if ((StopsEnabled > 2) && ((Bid-OrderOpenPrice()) > (Target3*Point)) && ((OrderStopLoss() - OrderOpenPrice()) < (Stop3*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()+(Stop3*Point), OrderTakeProfit(),0,Blue); } break; } if(OrderType()==OP_SELL) { if ((StopsEnabled > 0) && ((OrderOpenPrice()-Ask) > (Target1*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop1*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop1*Point), OrderTakeProfit(),0,Blue); } if ((StopsEnabled > 1) && ((OrderOpenPrice()-Ask) > (Target2*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop2*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop2*Point), OrderTakeProfit(),0,Blue); } if ((StopsEnabled > 2) && ((OrderOpenPrice()-Ask) > (Target3*Point)) && ((OrderOpenPrice() - OrderStopLoss()) < (Stop3*Point))) { OrderModify(OrderTicket(),OrderOpenPrice(), OrderOpenPrice()-(Stop3*Point), OrderTakeProfit(),0,Blue); } break; } } } int start() { if ((OrdersTotal() < 1) && ((Hour() >= hour_work_from) && (Hour() < hour_work_to))) { CheckForOpen(); } if ((OrdersTotal() > 0) && (TS_enabled > 0)) { CheckForCloseByTS(); } if ((OrdersTotal() > 0) && (StopsEnabled > 0)) { CheckForCloseByPips(); } return(0); }