Скачать MetaTrader 5

Оптимизация быстродеятельности эксперта. Подскажите, что можно усовершенствовать на рабочем примере.

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Они уже зарабатывают на своих сигналах. Опубликуй и ты свой!
Forex Trader
114255
Forex Trader 2006.05.03 16:45 
Ниже приведен пример простенького эксперта который имеет достаточно прмитивный вход, прыгающий трейлинг стоп и модуль для четкого подтягивания стопа на любой уровень по достижению профитности. Вот хотелось бы поинтересоватся, можно ли этот код сделать еще более совершенным (в плане быстродействия)? Может у когото из вас есть свои нюансы или некие специфические азы в написании экспертов. Жду предложений.

#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);
} 
Forex Trader
114255
Forex Trader 2006.05.03 17:16  
Этого эксперта можно ускорить.
Например, заголовок цикла
   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. А оно надо? Похоже, что нет, лишняя работа

Forex Trader
114255
Forex Trader 2006.05.03 17:33  
Хорошо. Вы верно подметили на счет повторного вызова функций. Но что даст то что мы на один тик выиграем то что не будем проверять CheckForCloseByTS и CheckForCloseByPips?. Это легко можно изменить написав перед CheckForOpen(). Но что мы выиграем?.. Минус один лишний вход в эти функции после открытия позиций?. Поставить задержку в вызове функций в 5 минут тоже результата недаст. Потому что нам нужно мониторить каждый тик для подтягивания стопа... Сделать функцию которая бы оценивала сколько там еще до уровня подтягивания стопа и на основе этих данных оценить на сколько трейлингу упасть в спячку для проверки?.. Ну впринципе можно и попробовать. Даст ли это результат. И сколько мы выиграем?... Незнаю...
Forex Trader
114255
Forex Trader 2006.05.03 17:48  
Да, легко изменить. Только тогда лишний раз будет вызываться уже CheckForOpen
Forex Trader
114255
Forex Trader 2006.05.03 18:02  
Merab, почитайте, пожалуйста, вот здесь: "Проблемы с памятью"
Возможно это не совсем в тему про Ваш советник, но всё равно Вам может быть полезно. Вы наверное просто идёте по пути научного тыка, который формулируется следующим образом:"А давай как я возьму десяток параметров и найду в n-мерном пространстве глобальный максимум загнав тестер сразу на оптимизацию по всем параметрам с мелким шагом, чтобы чего не пропустить. Наверняка что-то получится?" Действительно что-то получится. Правда если Вам нужен только ТАКОЙ способ решения, то сразу скажу, что никакие двуядерные супер-пупергигагерцовые системы Вашу задачу не решат поскольку технические средства не могут соревноваться с геометрической прогрессией (и могу сказать для справки - и НИКОГДА не смогут!). И дело тут совершенно не в том во сколько раз MQL4 медленнее, чем C++. Даже если разработчикам МТ4 удастся ускорить работу тестера в 10 раз это Вам в лучшем случае сможет сэкономить лишь считанные проценты (и не более того!) времени до того самого момента когда Вы станете миллионером ;o)! Я же со своей стороны могу Вам лишь предложить то, чем сам пользуюсь постоянно:

solandr:
Я например по своему опыту провожу оптимизацию каждого параметра по отдельности используя метод последовательных приближений (для информации один прогон в тестере моего эксперта занимает 3мин на P4 2,4ГГц – период М1(все тики) за 1,5 года). То есть делю диапазон значений например на 20 интервалов, далее в области максимума делю пару прилегающих к максимуму интервалов из предыдущей оптимизации ещё на 20 интервалов и делаю ещё один такой же шаг. Обычно 3-4 таких итерации оказывается вполне достаточно. Таким образом мы получаем в итоге результат по точности сопоставимый с прогоном сразу по 8000 интервалам с самым мелким шагом (20 в 3 степени). При этом мы имеем экономию в 8000-3*20=7940 итераций. То есть в идеале тратим время в 133 раза меньше, чем при тупом прогоне сразу на мелком шаге. При этом нужно отметить, что если у нас имеется ограниченное количество самого времени, за которое мы хотим получить результат (например мы можем подождать результат до вечера рабочего дня), то мы можем взять в 133 раза более длительный период для тестирования (например вместо 1 недели можно будет посчитать по 133 неделям) и в итоге мы будем иметь результат который будет хоть чего-то стоить, потратив на это тоже самое количество расчётного времени! А результаты быстрых прогонов численностью в 2,7 млн. штук, которых человек в состоянии дождаться, у меня вызывают серьёзные сомнения в плане применимости полученных результатов.
Конечно же мне можно возразить в плане того, что при просчёте всех мелких интервалов можно получить какой-то новый максимум, который будет упущен при расчёте по методике последовательных приближений, описанной выше. Но на это можно сказать, что в таком случае можно поймать лишь максимум, отражающий особенности выборки, и которых не будет в будущем! То есть при оптимизации должны выбираться параметры, изменение которых в небольших пределах, вызывает небольшое изменение в конечном результате. Ну а если у вас на мелком шаге окажется супер-пупер максимум, который мы можем не отследить на более крупном шаге, то можно быть точно уверенным, что данный максимум отражает ТОЛЬКО особенности конкретной выборки и его лучше не принимать во внимание вообще.
Forex Trader
114255
Forex Trader 2006.05.03 19:22  
Провёл я испытания.
Запустил представленного эксперта как есть на оптимизацию (чтобы вывод в логи не мешался).
36 прогонов за 4 минуты 2 секунды. На 1 прогон - 6.7 секунды

Устранил по собственному совету все лишние вызовы функций.
Те же 36 прогонов за 3 минуты 7 секунд. 1 прогон 5.2 секунды

Дополнительно вставил элементарнейшую проверку на наличие денег
2 минуты 55 секунд или 4.9 секунды на прогон

А вы говорите, что это даст.
Forex Trader
114255
Forex Trader 2006.05.03 19:43  
Каким это образом у вас проверка на наличи денег повышает скорость работы?.. А вообще немоглибы вы выложить весь код?
Forex Trader
114255
Forex Trader 2006.05.04 10:27  
Каким это образом у вас проверка на наличи денег повышает скорость работы?.. А вообще немоглибы вы выложить весь код?

Просто не вызывается функция 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);
} 
//+------------------------------------------------------------------+
Forex Trader
114255
Forex Trader 2006.05.04 10:59  
2 Slawa
ИМХО : код еще можно намного ускорить - сама функция

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);
   }
}



топ "тормозного искусства" :). Незачем на каждом тике пересчитывать значения мувингов на предыдущих барах, а это происходит, если нет открытых ордеров. Код лень писать - ИМХО - и так очевидно: эти значения не изменяются - считаем один раз, заносим в массив и используем. Причем, пересчет нужен только по последнему бару, один раз на момент открытия этого бара, все остальные элементы массива просто смещаем на один.

Удачи и попутных трендов.

Forex Trader
114255
Forex Trader 2006.05.04 12:55  
2 Slawa
ИМХО : код еще можно намного ускорить - сама функция

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);
   }
}



топ "тормозного искусства" :). Незачем на каждом тике пересчитывать значения мувингов на предыдущих барах, а это происходит, если нет открытых ордеров. Код лень писать - ИМХО - и так очевидно: эти значения не изменяются - считаем один раз, заносим в массив и используем. Причем, пересчет нужен только по последнему бару, один раз на момент открытия этого бара, все остальные элементы массива просто смещаем на один.

Удачи и попутных трендов.

======А можете показать в вашем исполнении (выложить здесь полный код эксперта с вашим виденыем)уже ускоренный варянт,там где мои тормоза Вы смогли снять?Буду очень признателен!!!
Forex Trader
114255
Forex Trader 2006.05.04 13:13  
А можете показать в вашем исполнении (выложить здесь полный код эксперта с вашим виденыем)уже ускоренный варянт,там где мои тормоза Вы смогли снять?Буду очень признателен!!!

Так это и есть Ваш эксперт. Я в нём сделал только те изменения, о которых говорил раньше. Из самодеятельности я просто добавил один break (похоже, Вы его просто забыли, в функции CheckForCloseByTS первый break).

Добавил переменные symbol, total, type, money. Поиском по тексту эти переменные ищите.

Переписал функцию start - при визуальном сравнении Вашего и моего текста сразу увидите.

Возможна проблема с тем, что открывающие фигурные скобки я ставил в новой строке.
12
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий