Помогите исправить ошибки invalid takeprofit и 4107

 

Суть советника в том чтобы выставить сетку ордеров на байстоп и селлстоп, когда срабатывает хоть один ордер то если открыло на бай то снизу ставится отложенный селлстоп с удвоенным лотом (типичный мартигейл), а сверху убирается ордер если он больше лота открытого ордера и открывается стандартным лотом (у меня это 0.01). На селл то же самое только наоборот. Ну и блок который следит за целостностью сетки.

Ошибки:

1. Бывает так что не выставляет снизу\сверху ордер с удвоенным лотом. Проходит 2 ячейки сетки и только тогда открывает.

Не открывает ордер с удвоенным лотомНа следуйщей ячейке сетки выставляет ордер нормально

2. Не могу исправить ошибки в советнике:

USDJPY,M30: OrderSend error 4107. Вроде бы все цена нормализуются, но ошибка постоянно вылазит как в тестере так и на реале.

USDJPY,M30: invalid takeprofit for OrderSend function. Про эту ошибку вообще не знаю как исправить. Где то в программе ошибка но все работает.

USDJPY,H4: invalid takeprofit for OrderSend function

3. Эта ошибка наверно скорее из-за не скачанной истории в терминале но бывает так что в тестере советник слетает и закрывает - открывает ордера тогда как должен просто закрыть ордер с меньшим лотом и открыть с двойным лотом. А он зацикливается и закрывает даже тот ордер что и с лотом больше.

Код:

#property copyright "Slash"
#property link      "http://www.metaquotes.net"
extern double lot = 0.01;
extern double shag = 0.35;


int search_open_buy (string simbal, double cena){
   for (int b=OrdersTotal(); b>=0; b--){
   OrderSelect(b,SELECT_BY_POS,MODE_TRADES);
      if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true){
         if (OrderSymbol() == simbal){
            if (OrderType() == 0){return(1);}}}}}

int search_open_sell (string simbal, double cena){
   for (int b=OrdersTotal(); b>=0; b--){
   OrderSelect(b,SELECT_BY_POS,MODE_TRADES);
      if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true){
         if (OrderSymbol() == simbal){
            if (OrderType() == 1){return(1);}}}}}

int search_order (string simvol, double open_price){
   for (int h=OrdersTotal(); h >= 0; h--){
      if (OrderSelect(h,SELECT_BY_POS,MODE_TRADES)) {
         if (OrderSymbol() == simvol){
            if (OrderOpenPrice() == open_price){return(1);}}}}
   return(0);}


//+---------------------------------------------------------------------------------------------------------------------+
//|                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                 |
//+---------------------------------------------------------------------------------------------------------------------+
int start() {
   //+------------------------------------------------------------------+
   string para = Symbol();
   double open_prise;
   double open_lotik;
   int open_tipok;
   double Cena[38] = {91, 91.35, 91.7, 92.05, 92.4, 92.75, 93.1, 93.45, 93.8, 94.15, 94.5, 94.85, 95.2, 95.55, 95.9, 96.25, 
96.6, 96.95, 97.3, 97.65, 98, 98.35, 98.7, 99.05, 99.4, 99.75, 100.1, 100.45, 100.8, 101.15, 101.5, 101.85, 102.2, 102.55, 102.9, 103.25, 103.6, 103.95};
   for (int i=0; i <= 38; i++){

      if (search_order (para, Cena[i]) == 0){
         if (Ask > Cena[i]){open_sellstop (para, lot, Cena[i], Cena[i]+shag, Cena[i]-shag);}
         if (Ask < Cena[i]){open_buystop (para, lot, Cena[i], Cena[i]-shag, Cena[i]+shag);}
      }

      if (search_open_buy (para, Cena[i]) == 1) {

         open_prise = OrderOpenPrice();
         open_lotik = OrderLots();
         open_tipok = OrderType();

         if (search_order (para, open_prise-shag) == 1){
            if(OrderLots() <= open_lotik){
            close_order(OrderTicket());
            open_sellstop (para, open_lotik*2, open_prise-shag, open_prise, open_prise-shag*2);
            }
         }
         if (search_order (para, open_prise+shag) == 1){
            if(OrderLots() != lot){
            close_order(OrderTicket());
            open_buystop (para, lot, open_prise+shag, open_prise, open_prise+shag*2);
            }
         }
      }

      if (search_open_sell (para, Cena[i]) == 1) {
      open_prise = OrderOpenPrice();
      open_lotik = OrderLots();
      open_tipok = OrderType();

         if (search_order (para, open_prise+shag) == 1){
            if(OrderLots() <= open_lotik){
            close_order(OrderTicket());
            open_buystop (para, open_lotik*2, open_prise+shag, open_prise, open_prise+shag*2);
            }
         }
         if (search_order (para, open_prise-shag) == 1){
            if(OrderLots() != lot){
            close_order(OrderTicket());
            open_sellstop (para, lot, open_prise-shag, open_prise, open_prise-shag*2);
            }
         }
      }
   }
   //----
   return;
}
//+------------------------------------------------------------------+

void open_sellstop (string simvol, double lot, double cena, double SL, double TP){
   double norm_lot = NormalizeDouble(lot,2);
   double norm_cena = NormalizeDouble(cena,Digits);
   double norm_SL = NormalizeDouble(SL,Digits);
   double norm_TP = NormalizeDouble(TP,Digits);
   
   OrderSend(simvol, OP_SELLSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE);
   Sleep(1000*3);
}

void open_buystop (string simvol, double lot, double cena, double SL, double TP){
   double norm_lot = NormalizeDouble(lot,2);
   double norm_cena = NormalizeDouble(cena,Digits);
   double norm_SL = NormalizeDouble(SL,Digits);
   double norm_TP = NormalizeDouble(TP,Digits);

   OrderSend(simvol, OP_BUYSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE);
   Sleep(1000*3);
}

void close_order (int tick){
   OrderDelete(tick);
   Sleep(1000*3);
}
 
int search_open_buy (string simbal, double cena){
   for (int b=OrdersTotal(); b>=0; b--){
   OrderSelect(b,SELECT_BY_POS,MODE_TRADES);
      if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true){
         if (OrderSymbol() == simbal){
            if (OrderType() == 0){return(1);}}}}}

Первое что бросилось в глаза for (int b=OrdersTotal(); b>=0; b--) не правильнее b=OrdersTotal()-1 ???

Второе- зачем дважды OrderSelect(b,SELECT_BY_POS,MODE_TRADES) ???

Третье - зачем в пользовательской функции параметр double cena ??? Если он нигде не используется.

Дальше желания смотреть нет в виду явной кривости кода.

У Кима есть функция где реализовано авто изминение тп при значении меньше минимального посмотрите здесь, может что-то найдете интерестное для себя.

 
ALXIMIKS:

Первое что бросилось в глаза for (int b=OrdersTotal(); b>=0; b--) не правильнее b=OrdersTotal()-1 ???

Второе- зачем дважды OrderSelect(b,SELECT_BY_POS,MODE_TRADES) ???

Третье - зачем в пользовательской функции параметр double cena ??? Если он нигде не используется.

Дальше желания смотреть нет в виду явной кривости кода.

У Кима есть функция где реализовано авто изминение тп при значении меньше минимального посмотрите здесь, может что-то найдете интерестное для себя.


Ок, исправил) Ошибку конечно это не исправило но буду думать дальше. Недавно тока начал учить MQL4 поэтому такой корявый код.
 

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

if (OrderSend(simvol, OP_BUYSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE) <= 0)
   Print("Error N", GetLastError(), ", norm_lot = ", norm_lot, ", norm_cena = ", norm_cena, ", norm_SL = ", norm_SL, ", norm_TP = ", norm_TP);
 
Scriptong:

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


Ошибка 4107 из за цены равной 0

Оказывается все было дело из-за нулевой цены. Спасибо за подсказку) Прям камень с души.


Получается что я с массивом перепутал. Я специально ввел не 39 а 38 так как отсчет в массиве начинается с нуля, но все равно ошибка выходила с нулевой ценой. Поиграл с массивом и for и в итоге начав цикл не с 0 а с 1, то ошибка ушла полностью ^_^

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

Открывает 2 ордера по одной цене

#property copyright "Slash"
#property link      "http://www.metaquotes.net"
extern double lot = 0.01;
extern double shag = 0.35;


int search_open_buy (string simbal){
   for (int b=OrdersTotal(); b>=0; b--){
      if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true){
         if (OrderSymbol() == simbal){
            if (OrderType() == 0){return(1);}}}}}

int search_open_sell (string simbal){
   for (int b=OrdersTotal(); b>=0; b--){
      if (OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true){
         if (OrderSymbol() == simbal){
            if (OrderType() == 1){return(1);}}}}}

int search_order (string simvol, double open_price){
   for (int h=OrdersTotal(); h >= 0; h--){
      if (OrderSelect(h,SELECT_BY_POS,MODE_TRADES)) {
         if (OrderSymbol() == simvol){
            if (OrderOpenPrice() == open_price){return(1);}}}}
   return(0);}


//+---------------------------------------------------------------------------------------------------------------------+
//|                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                 |
//+---------------------------------------------------------------------------------------------------------------------+
int start() {
   //+------------------------------------------------------------------+
   string para = Symbol();
   double Cena[37] = {91, 91.35, 91.7, 92.05, 92.4, 92.75, 93.1, 93.45, 93.8, 94.15, 94.5, 94.85, 95.2, 95.55, 95.9, 96.25, 96.6, 96.95, 
97.3, 97.65, 98, 98.35, 98.7, 99.05, 99.4, 99.75, 100.1, 100.45, 100.8, 101.15, 101.5, 101.85, 102.2, 102.55, 102.9, 103.25, 103.6, 103.95};
   
   double open_prise;
   double open_lotik;
   int open_tipok;
   
   for (int i=1; i <= 36; i++){

      if (search_order (para, Cena[i]) == 0){
         if (Ask > Cena[i]){open_sellstop (para, lot, Cena[i], Cena[i]+shag, Cena[i]-shag);}
         if (Ask < Cena[i]){open_buystop (para, lot, Cena[i], Cena[i]-shag, Cena[i]+shag);}
      }

      if (search_open_buy (para) == 1) {

         open_prise = OrderOpenPrice();
         open_lotik = OrderLots();
         open_tipok = OrderType();

         if (search_order (para, open_prise-shag) == 1){
            if(OrderLots() <= open_lotik){
            close_order(OrderTicket());
            open_sellstop (para, open_lotik*2, open_prise-shag, open_prise, open_prise-shag*2);
            }
         }
         if (search_order (para, open_prise+shag) == 1){
            if(OrderLots() != lot){
            close_order(OrderTicket());
            open_buystop (para, lot, open_prise+shag, open_prise, open_prise+shag*2);
            }
         }
      }

      if (search_open_sell (para) == 1) {
      open_prise = OrderOpenPrice();
      open_lotik = OrderLots();
      open_tipok = OrderType();

         if (search_order (para, open_prise+shag) == 1){
            if(OrderLots() <= open_lotik){
            close_order(OrderTicket());
            open_buystop (para, open_lotik*2, open_prise+shag, open_prise, open_prise+shag*2);
            }
         }
         if (search_order (para, open_prise-shag) == 1){
            if(OrderLots() != lot){
            close_order(OrderTicket());
            open_sellstop (para, lot, open_prise-shag, open_prise, open_prise-shag*2);
            }
         }
      }
   }
   //----
   return;
}
//+------------------------------------------------------------------+

void open_sellstop (string simvol, double lot, double cena, double SL, double TP){
   double norm_lot = NormalizeDouble(lot,2);
   double norm_cena = NormalizeDouble(cena,Digits);
   double norm_SL = NormalizeDouble(SL,Digits);
   double norm_TP = NormalizeDouble(TP,Digits);
   
   OrderSend(simvol, OP_SELLSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE);
   
   if (OrderSend(simvol, OP_SELLSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE) <= 0)
   Print("Error N", GetLastError(), ", norm_lot = ", norm_lot, ", norm_cena = ", norm_cena, ", norm_SL = ", norm_SL, ", norm_TP = ", norm_TP);
   Sleep(1000*3);
}

void open_buystop (string simvol, double lot, double cena, double SL, double TP){
   double norm_lot = NormalizeDouble(lot,2);
   double norm_cena = NormalizeDouble(cena,Digits);
   double norm_SL = NormalizeDouble(SL,Digits);
   double norm_TP = NormalizeDouble(TP,Digits);

   OrderSend(simvol, OP_BUYSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE);
   
   if (OrderSend(simvol, OP_BUYSTOP, norm_lot, norm_cena, 3, norm_SL, norm_TP, "My order #"+DoubleToStr(NormalizeDouble(cena,Digits),Digits), 0, CLR_NONE) <= 0)
   Print("Error N", GetLastError(), ", norm_lot = ", norm_lot, ", norm_cena = ", norm_cena, ", norm_SL = ", norm_SL, ", norm_TP = ", norm_TP);
   
   Sleep(1000*3);
}

void close_order (int tick){
   OrderDelete(tick);
   if (OrderDelete(tick)<=0)
   Print("Error N: ", GetLastError(), " | Order N: ", tick);
   Sleep(1000*3);
}
 
Slashkin:

После того как сетка открылась очистил журнал и оказалось что открывает по 2 ордера по одной цене.

Определение наличия ордера в функции search_order происходит некорректно. Нельзя напрямую сравнивать вещественные числа. Потому ордер и не находится (цены не равны). По своему опыту, сравнение лучше производить отдельно. Например, такой функцией:

bool IsValuesEquals(double first, double second)
{
   return (MathAbs(first - second) < Point / 10);
}

С правой стороны неравенства точность сравнения можно (и нужно) изменять в зависимости от поставленной задачи. При сравнении цен приведенный критерий вполне подойдет.

 

Сравнивать нужно на "меньше какой-либо величины" (Delta), проскальзывания например...

//+----------------------------------------------------------------------------+
int search_order (string simvol, double open_price){
   for (int h=OrdersTotal()-1; h >= 0; h--){
      if (OrderSelect(h,SELECT_BY_POS,MODE_TRADES)) {
         if (OrderSymbol() == simvol) {
            if (MathAbs(OrderOpenPrice()-open_price)<Delta*Point) return(1);
            }
         }
      }
   return(0);
}
//+----------------------------------------------------------------------------+
 
Scriptong:

Определение наличия ордера в функции search_order происходит некорректно. Нельзя напрямую сравнивать вещественные числа. Потому ордер и не находится (цены не равны). По своему опыту, сравнение лучше производить отдельно. Например, такой функцией:

С правой стороны неравенства точность сравнения можно (и нужно) изменять в зависимости от поставленной задачи. При сравнении цен приведенный критерий вполне подойдет.

Можно третьим параметром передать максимальное расхождение, с которым и сравнивать

 
Кстати на счет проскальзывания хорошая идея. Как то не подумал об этом. Сделал вот такой вариант:
int search_order (string simvol, double open_price){
   for (int h=OrdersTotal()-1; h >= 0; h--){
      if (OrderSelect(h,SELECT_BY_POS,MODE_TRADES)) {
         if (OrderSymbol() == simvol){
         
            double op = NormalizeDouble(OrderOpenPrice(), Digits);
            double io = NormalizeDouble(open_price, Digits);
            if (MathAbs(op - io) < 0.35){return(1);}
            
          }}}
   return(0);}

но все равно в сетке по 2 ордера по одной и той же цене открывает. Дальше тестера не запускаю потому что дальше так же по 2 ордера будет открывать.
 

В общем по поводу открытия двух ордеров по одной цене на тестере я не знаю как убрать а на реале работает нормально. Наверно тестер не учитывает Sleep.

А вот ошибку открытия удвоенного ордера через ячейку исправил, только я не пошел путем который советовали, я тупо взял нормализовал числа и сравнил их. На тестере все норм работает, на реале пока тоже *тьфутьфутьфу*. Вот код блока который я исправил:

int search_order (string simvol, double open_price){
   for (int h=OrdersTotal()-1; h >= 0; h--){
      if (OrderSelect(h,SELECT_BY_POS,MODE_TRADES)) {
         if (OrderSymbol() == simvol){
         
            double op = NormalizeDouble(OrderOpenPrice(), Digits);
            double io = NormalizeDouble(open_price, Digits);

            if (io == op){return(1);}
          }
      }
   }
   return(0);
}

Советник теперь работает но в нем не проработано проверки на гэп, недавно был гэп по паре доллар йена и открыв ордер по цене ниже отложенного ордера советник по алгоритму открыл выше ордер на бай стоп и соответственно он был открыт и получился лок. Но такое бывает не так часто так что убытки быстро покрываются.

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