MQL4: Советник модификации TP по условию / нужна проверка кода

 

Добрый день!

Я написал для себя небольшой советник, который модифицирует TP по заданному условию. Вроде - работает, но прошу знающих посмотреть код, может есть какие ошибки дилетанские?

Меня в первую очередь волнует, чтобы в случае ошибки модификации (вдруг не будет котировок в тот момент, или TP будет слишком близко к текущей цене), советник продолжал попытки модификации, именно для этого и введен блок return(-1)... 

PS. Расчет AC происходит для того, чтобы не запускать алгоритм каждый тик, а только каждый новый бар...

extern double checkline=0; // контрольная ближняя граница
extern double BE=0; // уровень безубыточности
extern int direction=0; //направление торговли: 1 - вверх (long), 2 - вниз (short)
extern int ticket=0; // номер ордера
int Slippage = 50; // проскальзывание в пп.
int Magic = 0001; // магический номер эксперта
string com = "Перевод в БУ"; // комментарий ордера
datetime last;
int ac;

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
 {
 if(last>=Time[0]) return;  // если время бара уже проверено то выходим сразу, т.е. ждем новый бар

//Модификация LONG (1)
if (direction==1 && Close[1]<checkline) //условие активации модификации ордера: направление вверх и закрытие прошлой свечи ниже контрольной линии
{
OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); // выбираем ордер по тикету
if (OrderTakeProfit()!=BE) // защита от повторной модификации
{
OrderModify(ticket,OrderOpenPrice(),OrderStopLoss(),BE,0,clrNONE); // модифицируем ордер
OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); 
if(OrderTakeProfit()!=BE) // если модификация не удалась, то возвращаемся для повторной модификации
    {
    Alert(Symbol(),"ошибка установки TP", GetLastError());
    return(-1);
    }
}
}
//Print(" direction=",direction," BE=",BE," ticket=",ticket," Close=",Close[1]," TP=",OrderTakeProfit());

//расчет AC
double ac_1 = 0; double ac_2 = 0; double ac_3 = 0;
ac_1 = iAC(NULL,0,1); ac_2 = iAC(NULL,0,2); ac_3 = iAC(NULL,0,3);
if ((ac_1>=0) && (ac_1>ac_2)) ac = 1; //AC - вверх (зеленый)
if ((ac_1>=0) && (ac_1<=ac_2)) ac = 2; //AC - вниз (красный)
if ((ac_1<0) && (ac_1>=ac_2)) ac = 1; //AC - вверх (зеленый)
if ((ac_1<0) && (ac_1<ac_2)) ac = 2; //AC - вниз (красный)

int ac2=0;
if ((ac_2>=0) && (ac_2>ac_3)) ac2 = 1; //AC - вверх (зеленый)
if ((ac_2>=0) && (ac_2<=ac_3)) ac2 = 2; //AC - вниз (красный)
if ((ac_2<0) && (ac_2>=ac_3)) ac2 = 1; //AC - вверх (зеленый)
if ((ac_2<0) && (ac_2<ac_3)) ac2 = 2; //AC - вниз (красный)

if (ac==1 || ac==2) last=Time[0]; // запомнили время бара для последующего тика
}  

   return(0);
  }
 

Ошибки:

  1. Не указано в названии темы, для какого языка вопрос.
  2. Используется старая и архаичная нотация int start() - так уже давно никто не пишет. Теперь нужно использовать функции int OnInit() и void OnTick().
  3. При оформлении желательно указывать "шапку" - с названием, с расширением.

 
Karputov Vladimir:

Ошибки:

  1. Не указано в названии темы, для какого языка вопрос.
  2. Используется старая и архаичная нотация int start() - так уже давно никто не пишет. Теперь нужно использовать функции int OnInit() и void OnTick().
  3. При оформлении желательно указывать "шапку" - с названием, с расширением.

Спасибо.

1. Поправил

2. Как это должно выглядеть и в чем проблема старого (моего) варианта? Эти новые функции я первый раз вижу :( Вроде старый вариант ведь работает?

3. Извините, не понял. 

 

Если пишите на старом коде (MQL4), то обязательно использовать

#property strict
 

Вот так будет красивше:

//+------------------------------------------------------------------+
//|                                                         Test.mq4 |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict
input double checkline=0; // контрольная ближняя граница
input double BE=0; // уровень безубыточности
input int direction=0; //направление торговли: 1 - вверх (long), 2 - вниз (short)
input int ticket=0; // номер ордера
int Slippage= 50; // проскальзывание в пп.
int Magic = 0001; // магический номер эксперта
string com="Перевод в БУ"; // комментарий ордера
datetime last;
int ac;
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(last>=Time[0]) return;  // если время бара уже проверено то выходим сразу, т.е. ждем новый бар
                              //Модификация LONG (1)
   if(direction==1 && Close[1]<checkline) //условие активации модификации ордера: направление вверх и закрытие прошлой свечи ниже контрольной линии
     {
      OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); // выбираем ордер по тикету
      if(OrderTakeProfit()!=BE) // защита от повторной модификации
        {
         OrderModify(ticket,OrderOpenPrice(),OrderStopLoss(),BE,0,clrNONE); // модифицируем ордер
         OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
         if(OrderTakeProfit()!=BE) // если модификация не удалась, то возвращаемся для повторной модификации
           {
            Alert(Symbol(),"ошибка установки TP",GetLastError());
            return;
           }
        }
     }
//Print(" direction=",direction," BE=",BE," ticket=",ticket," Close=",Close[1]," TP=",OrderTakeProfit());
//расчет AC
   double ac_1=0; double ac_2=0; double ac_3=0;
   ac_1=iAC(NULL,0,1); ac_2=iAC(NULL,0,2); ac_3=iAC(NULL,0,3);
   if((ac_1>=0) && (ac_1>ac_2)) ac=1; //AC - вверх (зеленый)
   if((ac_1>=0) &&(ac_1<=ac_2)) ac = 2; //AC - вниз (красный)
   if((ac_1<0) && (ac_1>=ac_2)) ac = 1; //AC - вверх (зеленый)
   if((ac_1<0) && (ac_1<ac_2)) ac=2; //AC - вниз (красный)

   int ac2=0;
   if((ac_2>=0) && (ac_2>ac_3)) ac2=1; //AC - вверх (зеленый)
   if((ac_2>=0) &&(ac_2<=ac_3)) ac2 = 2; //AC - вниз (красный)
   if((ac_2<0) && (ac_2>=ac_3)) ac2 = 1; //AC - вверх (зеленый)
   if((ac_2<0) && (ac_2<ac_3)) ac2=2; //AC - вниз (красный)

   if(ac==1 || ac==2) last=Time[0]; // запомнили время бара для последующего тика
   return;
  }
//+------------------------------------------------------------------+

И при этом, конечно есть сразу три предупреждения:

return value of 'OrderSelect' should be checked Test.mq4        25      7
return value of 'OrderModify' should be checked Test.mq4        28      10
return value of 'OrderSelect' should be checked Test.mq4        29      10
Вот теперь можно и код рассматривать...
Файлы:
Test.mq4  3 kb
 
Karputov Vladimir:

Вот так будет красивше:

И при этом, конечно есть сразу три предупреждения:

Вот теперь можно и код рассматривать...

Большое спасибо. Насчет шапки понял :) Это был тестовый пробный вариант, как-то не придал значения этому вопросу.

Принял Ваш вариант, еще раз спасибо. Значит, Ваш вариант рабочий? Т.е. будет ли он:

- модифицировать ордер при заданном условии (закрытие прошлого бара ниже checkline) 

- прекращать попытки модификации в случае успеха

- повторять попытки модификации в случае неудачи

 Т.е. я боюсь, чтобы не запустились какие-то замкнутые циклы, приводящие к бесконечным попыткам модификации/обращения к брокеру/загрузки торговой платформы MT4....

Конечно, я еще раз извиняюсь за дилетанские вопросы, мои знания поверхностны и 3-х летней давности... 

 
Ivan Molchanov:


Я не говорил, правильный код и не правильный. Просто привёл в более читаемый вариант. А вот по коду замечание: я бы ушёл от такого определения нового бара:

   if(ac==1 || ac==2) last=Time[0]; // запомнили время бара для последующего тика

Зачем привязываться к переменной "ac"? Новый бар он в Африке новый бар. При его определении нужно только сравнивать последнее сохранённое время (last) и время открытия бара.

 
Ivan Molchanov:

Большое спасибо. Насчет шапки понял :) Это был тестовый пробный вариант, как-то не придал значения этому вопросу.

Принял Ваш вариант, еще раз спасибо. Значит, Ваш вариант рабочий? Т.е. будет ли он:

- модифицировать ордер при заданном условии (закрытие прошлого бара ниже checkline) 

- прекращать попытки модификации в случае успеха

- повторять попытки модификации в случае неудачи

 Т.е. я боюсь, чтобы не запустились какие-то замкнутые циклы, приводящие к бесконечным попыткам модификации/обращения к брокеру/загрузки торговой платформы MT4....

Конечно, я еще раз извиняюсь за дилетанские вопросы, мои знания поверхностны и 3-х летней давности... 

Вот это что за фигня?

OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); // выбираем ордер по тикету

Сразу в глаза бросилось.

Если ордер выбираете по тикету, то для чего указываете режим MODE_TRADES ? Он игнорируется вообще при выборе по тикету и ордер в любом случае будет выбран если когда-либо существовал или существует в терминале. Чтобы узнать из какого списка он выбран, нужно проверить время его закрытия:

if(OrderCloseTime()==0) {// ордер выбран в списке рыночных позиций} 
else {// ордер выбран из списка закрытых}
Дальше не смотрел и не вникал.
 
Karputov Vladimir:

Я не говорил, правильный код и не правильный. Просто привёл в более читаемый вариант. А вот по коду замечание: я бы ушёл от такого определения нового бара:

Зачем привязываться к переменной "ac"? Новый бар он в Африке новый бар. При его определении нужно только сравнивать последнее сохранённое время (last) и время открытия бара.

Да, я понимаю всю корявость конструкции.

Будет ли так правильно:

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict
input double checkline=0; // контрольная ближняя граница
input double BE=0; // уровень безубыточности
input int direction=0; //направление торговли: 1 - вверх (long), 2 - вниз (short)
input int ticket=0; // номер ордера
int Slippage= 50; // проскальзывание в пп.
int Magic = 0001; // магический номер эксперта
string com="Перевод в БУ"; // комментарий ордера
datetime last;
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(last>=Time[0]) return;  // если время бара уже проверено то выходим сразу, т.е. ждем новый бар
                              //Модификация LONG (1)
   if(direction==1 && Close[1]<checkline) //условие активации модификации ордера: направление вверх и закрытие прошлой свечи ниже контрольной линии
     {
      OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); // выбираем ордер по тикету
      if(OrderTakeProfit()!=BE) // защита от повторной модификации
        {
         OrderModify(ticket,OrderOpenPrice(),OrderStopLoss(),BE,0,clrNONE); // модифицируем ордер
         OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
         if(OrderTakeProfit()!=BE) // если модификация не удалась, то возвращаемся для повторной модификации
           {
            Alert(Symbol(),"ошибка установки TP",GetLastError());
            return;
           }
        }
     }
   last=Time[0]; // запомнили время бара для последующего тика
   return;
  }
//+------------------------------------------------------------------+
 
Ivan Molchanov:

Да, я понимаю всю корявость конструкции.

Будет ли так правильно:

Нет, не правильно.

У вас ticket равен нулю. Вы его не выберите - это раз. Два - вы всегда собираетесь выбирать ордер с тикетом ticket ? Три - вы не правильно выбираете ордер по тикету.

 
Artyom Trishkin:

Нет, не правильно.

У вас ticket равен нулю. Вы его не выберите - это раз. Два - вы всегда собираетесь выбирать ордер с тикетом ticket ? Три - вы не правильно выбираете ордер по тикету.

Спасибо, но мой предыдущий ответ относился к изменению времени проверки бара... С тикетом я ничего тут не менял еще.

Но если говорить о тикете, то:

1. номер тикета я задаю при установке  советника (руками вбиваю), поэтому он выбирается без проблем, по крайней мере на демо это работало.

2. Да, мне необходимо менять только тот ордер, тикет которого я вбиваю.

3. Почему неправильно? Ордер выбирался и менялся. Но я не настаиваю, может Вы и правы, но тогда поясните, пожалуйста, в чем ошибка. 

Причина обращения: