Смотри, как бесплатно скачать роботов
Ищи нас в Telegram!
Ставь лайки и следи за новостями
Интересный скрипт?
Поставь на него ссылку - пусть другие тоже оценят
Понравился скрипт?
Оцени его работу в терминале MetaTrader 5
Советники

Советник по времени с трейлингстопом. - эксперт для MetaTrader 4

Просмотров:
5166
Рейтинг:
(9)
Опубликован:
2020.02.28 15:17
Нужен робот или индикатор на основе этого кода? Закажите его на бирже фрилансеров Перейти на биржу

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

Ограничения выбора типов ордеров:

1.      Можно выбрать только один тип рыночного ордера, либо Buy, либо Sell. И с выбранным рыночным ордером нельзя выбрать отложенные ордера.

2.      Отложенные и лимитные ордера можно выбирать в любом сочетании.

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

Для рыночного ордера используется трейлингстоп. Stoploss модифицируется на расстояние, не больше значения Трейлингстоп от текущей цены Bid, для ордеров Buy, и от цены Ask, для ордеров Sell в первом советнике, и уменьшает Трейлингстоп при приближении к ТейкПрофит по формуле во втором советнике.

Во втором советнике для TakeProfit так же используется трейлинг. При приближении текущей цены к уровню TakeProfit, Тейкпрофит модифицируется на расстояние TralingProfit.

 

Алгоритм работы.

 

При инициализации.

 

1.      Присваиваем время начала работы переменной tx=TimeCurrent();

2.      Смотрим правильность назначения времени. Если время изменялось в настройках, (не равно указанному в настройках) оно не должно быть меньше текущего времени начала работы советника. Если меньше текущего выводим сообщение об ошибке.
if(Open_Time != D'03.01.2019 13:00:00' && Open_Time < tx)

{  Work = false;

      Alert("Время открытия меньше текущего. Эксперт не работает.");

     }

3.      Проверяем что бы время жизни отложенных ордеров было больше 11 минут. МТ4 выдает ошибку, если разница между временем открытия и закрытия ордера менее 11 минут.

if(time_op < 11)

     {      Work = false;

      Alert("Время жизни отложенных ордеров должно быть более 11 минут. Эксперт не работает.");

     }

4.      Если время не менялось, то присваиваем Времени открытия ордеров значение на 120 секунд больше Времени начала работы советника.
if(Open_Time== D'03.01.2019 13:00:00')
{Open_Time = tx+120;}
Это нужно для проверки работы советника в тестере и в Маркете.

5.      Проверяем корректность ограничения открытия типов ордеров, и выводим сообщения, если что не так.

if(Open_Sell==True && Open_Buy==True) // если оба раночных

     {

      Work = false;

      Alert("Одновременное открытие рыночных ордеров Sell и Buy не разрешено. Эксперт не работает.");

     }

 

   if((Open_Sell==True && (Open_Sell_Limit==True || Open_Sell_Stop==True ||Open_Buy_Limit==True  || Open_Buy_Stop==True))

      || (Open_Buy==True && (Open_Sell_Limit==True || Open_Sell_Stop==True ||Open_Buy_Limit==True  || Open_Buy_Stop==True))) // если раночный с отложенным

     {

      Work = false;

      Alert("Одновременное открытие рыночного ордера и отложенного или лимитного не разрешено. Эксперт не работает.");

     }

5. Проверяем открытые в терминале ордера на наш инструмент и номер Магик. Проверяем путем пересчета всех ордеров и отсеивая по признаку равенства нашего инструмента и номера Магик ордера и нашего Магик.

Ордеров с нашим Магик быть не должно.

Наличие ордеров с нашим Магик на работу данных советников не влияет, но по старой памяти сделал. Функция  Countinit();

6.      Присваиваем значения неизменяемым по ходу работы переменным:

Symb=Symbol();

   point = 1/Point; // чтобы не делить на Point

   Close_Time = Open_Time + 60*time_op; // Время закрытия отложенных, лимитных неоткрытых ордеров expiration. Равно времени открытия ордеров плюс время жизни ордера.

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

Время закрытия ордеров по ходу работы не меняется, и если отложенные ордера не станут рыночными, они сами удалятся.

 

На этом инициализация заканчивается.

 

Начинаем работу на Тике. Функция OnTick

 

1. Если у нас критическая ошибка, выводим один раз сообщение про ошибку, на следующем тике сообщение уже не выводим.

if(Work==false) // Критическая ошибка

     {

      if(AlertWork==false)   // Если Алерта еще не было

        {  Alert("Критическая ошибка. Эксперт не работает."); AlertWork=true; }

      return;

     }                            

  1. Далее смотрим, не завершена ли работа. Если наш рыночный ордер закрылся, то работа советника завершается. Выводим сообщение о завершении работы и какую мы прибыль или убыток получили. Сообщение выводится один раз.

if(End==true) // Работа завершена

     {

      if(AlertEnd==false)   // Если Алерта еще не было

        {  Alert("Работа эксперта завершена. Прибыль/убыток = ",OrderProfit()); AlertEnd=true; }

      return;

     }           

  1. Смотрим жив ли наш рыночный ордер. В конце этой стандартной функции OnTick идет подсчет ордеров и поиск нашего ордера, с нашим Магик. Функция Count(); функция подсчета присваивает переменной Ticket тикет нашего ордера и переменной total количество найденный наших ордеров и если количество наших ордеров = 1 и тип найденного ордера рыночный, т.е. равен 0 или 1, то смотрим ответ OrderSelect нашего ордера по номеру тикета. Если ответ положительный, смотрим время закрытия нашего ордера, если оно равно нулю, ордер не закрыт, значит нам надо проверить нужно ли модифицировать ордер, по условиям трейлингстопа в функции ModifyTral();

if(Total==1 && (Or==0 || Or==1))  // если рыночный ордер был выставлен и жив

     {

     if(OrderSelect(Ticket, SELECT_BY_TICKET)==true)

        {

         if(OrderCloseTime()==0)              // Если наш рыночный ордер не закрыт

           {             ModifyTral();

            return;

           }

А если время закрытия нашего ордера не равно нулю, значит наш рыночный ордер был закрыт. Присваиваем флагу закрытия значение Истина, End=true, и выводим сообщение что ордер закрылся и заодно значение свопа и комиссии. Общую прибыль выводим на следующем тике, в сообщении о завершении работы.

И если конечно OrderSelect вдруг выдал ошибку, то выводим сообщение об этом с номером ошибки.

if(OrderCloseTime()!=0)              // Если наш рыночный ордер закрылся

           {

            End=true;

            Alert("Наш рыночный ордер закрылся. Работа Советника завершена ",

            " Своп = ", OrderSwap(), " Комиссия = ", OrderCommission());

            return;

           }

        }

      else

         Alert("OrderSelect() нашего рыночного ордера вернул ошибку - ",GetLastError());

     }

 

Далее смотрим время выставления ордеров в минутах. Почему в минутах? Потому что время между тиками часто бывает более 1 секунды и поймать равенство в секундах часто невозможно. Можно конечно использовать условие: Если время выставления ордера стало меньше текущего времени. Будет точнее и может быть и вернее. Если в минуту выставления ордеров не будет ни одного тика, ордера не выставятся. Но такое в торговую сессию бывает редко, или почти не бывает. Так же смотрим, что ордера еще не были выставлены, флаг OpnOr==false, что бы ни выставлять их повторно, ведь минуту равенство по времени будет истинным. Ордера выставляются в функции OpenOrder();

if((Open_Time)/60 == TimeCurrent()/60 && OpnOr==false)

     {

      Alert("Время выставления ордеров -  ") ;

      OpenOrder();

      OpnOr=true;

     }

Далее, если флаг открытия ордеров положительный, OpnOr=true;, считаем наши ордера, и если видим, что появился один наш рыночный ордер, удаляем оставшиеся отложенные ордера.

Считаем в функции Count(); Удаляем в функции DeleteOrder();

if(OpnOr==true)

     {     Count();// функция подсчета рыночных ордеров с нашим магик

    if (Total==1)

    DeleteOrder(); 

     }

И уходим на ожидание нового тика.

   return;

На этом работа функции OnTick заканчивается.

 

Алгоритм работы функций.

 

Функция подсчета ордеров с нашим Магик Countinit()

 

Обычная функция подсчета ордеров. Объявляем переменную Totalin=0;

В функции for(int cin=0; cin<OrdersTotal(); cin++) делаем итерации от нуля, до количества всех ордеров в терминале.

На каждой итерации сперва смотрим, какой ответ даст функция OrderSelect, при выборе ордера по номеру в терминале. В терминале ордера нумеруются от нуля до последнего и выбираем только среди открытых отложенных или рыночных ордеров. Закрытые и удаленные ордера мы не берем.

if(sel=OrderSelect(cin,SELECT_BY_POS,MODE_TRADES))

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

if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)

            Totalin++;

Далее смотрим, Если Totalin>0, т.е. до начала работы есть ордера по нашему инструменту и с нашим магик, то выдаем сообщение что не работаем и присваиваем флагу работы значение Ложь.

Если ордеров по нашему инструменту и с нашим магик нет, то работаем.

Work=true;

   return(Totalin);

Функция возвращает количество найденных ордеров, переменную Totalin

 

 

Функция подсчета рыночных ордеров Count()

 

Функция подсчета ордеров по условию нашего инструмента, нашего Магик и типа рыночного ордера.

 

После работы функции и появления рыночного ордера, мы должны иметь в глобальных переменных тикет, тип, цену открытия, уровень стоплосс, уровень тейкпрофит, лотность ордера.

Что бы не было ошибок вначале присваиваем этим переменным нулевые значения, а типу ордера значение -1.

Переменной количества наших рыночных ордеров Total=0; тоже присваваем значение ноль.

Обновляем значения в терминале. RefreshRates();

 

Далее в функции цикла по номерам всех рыночных и отложенных ордеров в терминале,

for(cnt=0; cnt<OrdersTotal(); cnt++)

выбираем ордер по номеру

if(sel=OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))

 и смотрим условия равенства нашему инструменту, нашему номеру магик и что бы тип ордера был Buy или Sell.

if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic && (OrderType()== 1 ||  OrderType() ==0))

Если все условия истинны, увеличиваем переменную Total на единицу и переменной Ticket = OrderTicket(); присваиваем номер тикета найденного ордера.

Выводим сообщение, что мы нашли рыночный наш ордер выводом сообщения с переменными для контроля ситуации.

Alert("Total ",Total," OrdersTotal() ", OrdersTotal(),"Тикет = ",OrderTicket(), " OrderType() ", OrderType(),Tip," cnt ", cnt);

 

После окончания цикла и выхода из него, смотрим, если количество наших рыночных ордеров более одного, выводим сообщение об ошибке, присваиваем флагу состояния работы значение Ложь и заканчиваем работу.

if(Total>1) // Не более одного рыночного ордера c нашим Магик при работе эксперта

     {

      Alert("Ордеров с нашим магик больше одного = ",Total," Поменяйте магик или удалите ордера. Эксперт не работает.");

      Comment("Ощибка во время работы, количество ордеров с нашим Магик = ",Total);

      Work=false;

      return(Total);                             // Выход из Count()

     }

Если количество наших рыночных ордеров стало 1, то сперва выбираем наш ордер по номеру тикета. sel=OrderSelect(Ticket, SELECT_BY_TICKET);

Почему нам это нужно.

В цикле подсчета наших рыночных ордеров, после итерации, в которой нашелся наш рыночный ордер, и мы присвоили переменной Ticket тикет нашего рыночного ордера, начнется следующая итерация (необязательно итерация в которой найдется наш рыночный ордер будет последней), и функция выбора ордера OrderSelect выберет следующий ордер, с другим тикетом, и терминал МТ4 запомнит последний выбор. Терминал помнит значения последнего выбранного ордера функцией OrderSelect.

После выбора ордера выводим сообщение с номером Тикета, типа ордера, ценой Bid на момент открытия ордера и ценой открытия ордера и присваиваем нашим глобальным переменным значения ордера.

 

Alert("Наш Тикет = ", Ticket,OrderTicket(),"Тип = ", Tip,OrderType(),"Bid",Bid,"Цена открытия",OrderOpenPrice());

 

      Tip   =OrderType();                    // Тип выбранного орд.

      Symb= Symbol();                        //Инструмент выбранного ордера;

      Price =OrderOpenPrice();               // Цена открытия выбранн. орд.

      //   ClosePrice = OrderClosePrice();

      SL    =OrderStopLoss();                // SL выбранного орд.

      TP    =OrderTakeProfit();              // TP выбранного орд.

      Lot   =OrderLots();                    // Количество лотов

      Alert("Наш Ордер Тикет = ", Ticket,"Тип = ", Tip,OrderType(),"Ask",Ask,"Цена открытия",OrderOpenPrice());

 

Далее, если Тип ордера Buy переменной Or присваиваем значение 0 и если Sell  значение 1.

if(Tip==OP_BUY)

         Or=0;

      if(Tip==OP_SELL)

         Or=1;

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

Переменную Or используем как флаг появления рыночного ордера в функции OnTick.

 

Далее сравниваем полученный тикет, с тикетами наших открытых ордеров. При этом, если вспомнить об ограничениях по типам открываемых ордеров, если открывался рыночный ордер Buy или Sell мы уже знаем, какой ордер рыночный, а вот про отложенные мы не знаем, какой станет рыночным, а хотелось бы знать.

После того, как отложенный ордер становится рыночным, его тикет не меняется. Этим и воспользуемся. При открытии ордеров мы запоминаем их тикеты в переменных Ticket0, Ticket1, Ticket2, Ticket3, Ticket4, Ticket5. Первые две переменные это тикеты рыночных ордеров, их сравнивать не имеет смысла.

При нахождении равенства тикетов, выводим сообщение, какой ордер стал рыночным.

  if(Ticket == Ticket2)

        {  Alert("Рыночным Ордером стал ордер BuyLimit, Тралим его");}

      if(Ticket == Ticket3)

        { Alert("Рыночным Ордером стал ордер SellLimit, Тралим его");}

      if(Ticket == Ticket4)

        { Alert("Рыночным Ордером стал ордер BuyStop, Тралим его");}

      if(Ticket == Ticket5)

        { Alert("Рыночным Ордером стал ордер SellStop, Тралим его");}

      Work=true;                                  // для верности флаг работы Истина

      return(Total);                             // Выход из Count()

 

А вот если рыночного ордера не нашли, Total==0, для верности присваиваем переменным ордера нулевые значения,  типу ордера -1, и продолжаем работать.

Возможно это излишне, но мне так спокойнее. К тому же операция присваивания одна из самых быстрых.

На этом функция подсчета рыночных ордеров закончена.

 

 

Функция модификации рыночного ордера по условиям Трейлингстоп ModifyTral()

 

Модификацию ордера проводим в цикле while по условию (true).

Цикл while(true), это цикл, условием выхода из которого является команда break;

Логика такая, выходим из цикла после удачной модификации или критической ошибки, в остальных случаях повторяем попытку.

Перед началом каждой итерации цикла присваиваем переменной TS значение Tral_Stop;

Присваиваем переменной Min_Dist значение Минимально допустимого уровня стоп-лосса/тейк-профита в пунктах.

Сравниваем значение TS и Min_Dist и если значение нашего трейлингстопа меньше минимальной дистанции присваиваем переменной TS значение минимально допустимого уровня стоп-лосса/тейк-профита в пунктах.

double TS=Tral_Stop;                // Исходное значение

      double Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);//Миним. дист

      if(TS<Min_Dist)                     // Если меньше допуст.

         TS=Min_Dist;                      // Новое значение TS

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

 

Присваиваем флагу модификации Modify=false; значение Ложь перед сравнением уровней цены плюс или минус трейлингстоп и стоплосс.

 

Для того что бы не городить огород из операторов if и для каждого типа ордера написать свой план модификации используем оператор switch(Tip)

Для Типа ордера 0, case 0 : т.е. Buy действия следующие:

Если уровень СтопЛосс меньше (ниже) значения текущей цены Bid минус Трейлингстоп в пунктах умноженный на значение Point, т.е. цена поднялась выше цены открытия ордера, то уровень СтопЛосс делаем на уровне цены Bid минус Трейлингстоп умноженный на значение Point то модифицируем ордер, т.е. присваиваем переменной SL новое значение, а флагу модификации Modify=true; значение Истина и выходим из оператора switch по команде break;, но не из цикла  while. Так же переменной Text ="Buy "; присваиваем соответствующее значение, для сообщения.

 

             if(NormalizeDouble(SL,Digits)<  // Если ниже желаем.

               NormalizeDouble(Bid-TS*Point,Digits))

              {

               SL=Bid-TS*Point;           // то модифицируем его

               Text="Buy ";        // Текст для Buy

               Modify=true;               // Назначен к модифи.

              }

            break;                        // Выход из switch

Для Типа ордера 1, case 1 : т.е. Sell действия следующие:

Если уровень СтопЛосс больше (выше) значения текущей цены Ask плюс Трейлингстоп в пунктах умноженный на значение Point, т.е. цена опустилась ниже цены открытия ордера, то уровень СтопЛосс делаем на уровне цены Ask плюс Трейлингстоп умноженный на значение Point модифицируем ордер, т.е. присваиваем переменной SL новое значение, а флагу модификации Modify=true; значение Истина и выходим из оператора switch, так как он заканчивается, но не из цикла  while.

Сравниваем мы нормализованные значения.

 

if(NormalizeDouble(SL,Digits)>  // Если выше желаем.

               NormalizeDouble(Ask+TS*Point,Digits)

               || NormalizeDouble(SL,Digits)==0)//или равно нулю

              {

               SL=Ask+TS*Point;           // то модифицируем его

               Text="Sell ";              // Текст для Sell

               Modify=true;               // Назначен к модификации.

              }

Далее, если флаг модификации Ложь, выходим из цикла while, и за циклом возвращаем значение флага модификации return(Modify);.

 

if(Modify==false)                   // Если его не модифи

         break;                           // Выход из while

Иначе флаг модификации Истина, и мы приступаем к модификации ордера.

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

Выводим сперва так же сообщение о начале модификации

 

       TP    =OrderTakeProfit();    // TP выбранного орд.

      Price =OrderOpenPrice();     // Цена выбранн. орд.

      Ticket=OrderTicket();        // Номер выбранн. орд.

 

      Alert("Модификация ", Text,Ticket,". Ждём ответ..");

      Ans=OrderModify(Ticket,Price,SL,TP,0);//Модифицируем его!

 

Если получаем ответ результата модификации Истина выводим сообщение со значением переменной Text, Тикетом ордера. И выходим из цикла while, а далее выходим из функции, возвращая значение флага модификации.

 

if(Ans==true)                       // Получилось :)

        {

         Alert("Ордер ",Text,Ticket," модифицирован:)");

         break;                           // Из цикла модифи.

        }

Иначе результат модификации Ложь, делаем обработку ошибок в функции Fun_Error и если ошибка не критическая, функция Fun_Error возвращает 1, уходим на следующую итерацию цикла модификации, Иначе ошибка критическая и выходим из цикла через команду break;.и выходим их функции, возвращая значение флага модификации.

       if(Fun_Error(GetLastError())==1) // Обработка ошибок

         continue;                           // Повторная попытка

      break;                              // Из цикла модификации.

     }                                    // Конец цикла модификации.

return(Modify);

 

Функция обработки ошибок.

 

Функция обработки ошибок служит для вывода сообщений с кодом ошибки и разделения критических и исправляемых ошибок.

Делаем это в операторе switch(Error). Если ошибка, по нашему разумению исправляемая, возвращаем 1, если критическая возвращаем 0. В качестве решений обычно подождать секунды 3 или обновить значения данных в терминале.

Хотелось отметить, нет цен, ждем новый тик когда функция RefreshRates() даст ответ Истина, т.е. цены обновятся, и делаем это в цикле через 1 миллисекунду. Это что бы не выходить из из цикла модификации, а сразу модифицировать ордер. Иначе на новом тике мы сперва начнем функцию OnTick и только потом опять вызовем функцию модификации.

case 136:

         Alert("Нет цен. Ждём новый тик..");

         while(RefreshRates()==false)           // До нового тика

            Sleep(1);                           // Задержка в цикле

         return(1);                             // Выход из функции

 

Если уж ошибка совсем критическая присваиваем флагу работы значение Ложь

case  5:

         Alert("Старая версия терминала.");

         Work=false;                            // Больше не работать

         return(0);                             // Выход из функции

      case 64:

         Alert("Счет заблокирован.");

         Work=false;                            // Больше не работать

         return(0);                             // Выход из функции

 

Если кода ошибка в нашем списке нет, выводим просто сообщение с кодом ошибки.

default:

         Alert("Возникла ошибка ",Error); // Другие варианты

         return(0);   

 

Наборы кодов ошибок собраны и для модификации и для открытия и для удаления ордеров.

 

Функция проверки минимальной дистанции.

 

Все очень просто, присваиваем переменной Min_Dist значение минимальной дистанции по нашему инструменту.

Если введенный параметр меньше минимальной дистанции, присваиваем параметру значение минимальной дистанции, выводим сообщение и возвращаем значение параметра.

double Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// Миним. дистанция

   if(Parametr<Min_Dist) // Если меньше допуст.

     {

      Parametr=Min_Dist;                        // Установим допуст.

      Alert("Увеличена дистанция стоп-приказа или цены открытия отложенных ордеров.");

     }

   return(Parametr);                            // Возврат значения

 

Функция открытия ордеров.

Функция открытия ордеров начинает свою работу после наступления времени открытия ордеров.

Функция открывает каждый тип ордера в зависимости от флага открытия типа ордера if(Open_Buy), если Истина, то в скобки оператора if, Иначе за скобки оператора if, в цикле while(true), до тех пор пока не откроет.

Сначала думал сделать отдельную функцию расчета цен, и одну с циклом открытия и обработки ошибок, но решил не делать так потому что для каждого типа ордера цены считаются по своему, так же есть проблема с Алертом об открытии ордера с указанием родительского типа. Для вывода правильного Алерта надо будет делать отдельно функцию или делать перебор в switch или через оператор if. В общем кардинального уменьшения кода не увидел.

 

Функция OrderSend возвращает тикет ордера, присвоенный ему торговым сервером и является индивидуальным для каждого ордера на торговом сервере, этим и воспользуемся.

Тикеты для каждого ордера запоминаем в отдельных переменных Ticket0 для типа Buy, Ticket1 для типа Sell, Ticket2 для типа BuyLimit , Ticket3 для типа SellLimit, Ticket4 для типа BuyStop, Ticket5 для типа SellStop.

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

 

if(Ticket0==0) // Открытых орд. нет

После обновления данных в терминале, для каждого типа ордера считаем СтопЛосс, ТейкПрофит, и цены открытия ордеров для отложенных типов, для рыночных цены не считаем. Параметры СтопЛосс и ТейкПрофит переназначаем через функцию проверки минимальной дистанции New_Stop, что бы не было ошибок при открытии ордера по применению уровней ниже Минимально допустимых уровней стоп-лосса/тейк-профита в пунктах.

 

             RefreshRates();                        // Обновление данных

            SL=Bid - New_Stop(StopLoss)*Point;     // Вычисление SL откр.

            TP=Bid + New_Stop(TakeProfit)*Point;   // Вычисление TP откр.

 

Выводим сообщение Alert("Попытка открыть Buy Ожидание ответа..");

Ticket0=OrderSend(Symb,OP_BUY,Lots,Ask,slippage,SL,TP,"QstrBuy",Magic,0,Blue);//Открытие Buy

            if(Ticket0>0) // Если получилось :)

              {

               Alert(Symbol()," ТФ ",Period(),"Открыт ордер Buy по цене ",Ask,"Ticket0 = ",Ticket0);

               Or=0;

               break;

              }

Если все получилось присваиваем переменной Or = 0 для ордеров типа Buy, Or=1 для типа Sell, Or=2 для типа BuyLimit , Or=3 для типа SellLimit, Or=4 для типа BuyStop, Or=5 для типа SellStop. В общем ненужная операция, но по ней видно, какой последний тип ордера был открыт. И выходим из индивидуального цикла открытия ордера while(true) через break;

Иначе делаем работу над ошибками, так же как функции модификации ордера.

 

Функция удаления ордеров

 

Функция удаления ордеров вызывается сразу после появления рыночного ордера в функции подсчета рыночных ордеров Count(). После появления ордера мы имеет переменную Ticket не равную нулю и точно знаем, что эта переменная равна какой то нашей переменной Ticket0-5.

Проверяем, для каждого отложенного типа ордера. Если тикет найденного функцией Count() рыночного ордера не равен нашему тикету0-5 из функции открытия ордеров и этот тикет0-5 не равен нулю, т.е. ордер данного типа был открыт приступаем к удалению не ставшего рыночным открытого отложенного ордера.

if(Ticket!=Ticket2 && Ticket2!=0)

Удаление ордера сделано так же как в функции открытия ордеров, через цикл удаления while(true).

Выводим сообщение, что пытаемся удалить ордер с указанием типа ордера, непосредственно перед удалением.

      Alert("Попытка удалить ордер BuyLimin ",Ticket2,". Ожидание ответа..");

         Ans=OrderDelete(Ticket2);             // Удаление ордера

Если ответ Ans Истина, то выводим сообщение об удалении ордера и выходим из цикла удаления ордера и переходим к проверке следующего типа ордера.

            if(Ans==true)                             // Получилось :)

           {

            Alert("Удалён ордер BuyLimin ",Ticket2);

            break;                                 // Выход из цикла удаления

Иначе делаем работу над ошибками либо удачно удаляя ордер, либо, если ошибка критическая выходим из цикла удаления ордера и переходим к следующему типу.

          if(Fun_Error(GetLastError())==1) // Обработка ошибок

            continue;                           // Повторная попытка

         break;                                 // Выход из while

    Sven Sven

    Простенький сеточник, вход рыночными ордерами и добавление объема в случае неудовлетворительного движения рынка. Возможно есть у кого пожелания или советы по усовершенствованию - пишите, будем обсуждать!

    Verification - RSI Verification - RSI

    Индикатор Relative Strength Index с расширенными параметрами.

    Average Day Range Average Day Range

    Индикатор рисует два квадрата: один от минимума вверх, а второй от максимума вниз. Высота квадрата равна ADR (5 дней).

    Библиотека для работы с COM-объектами. Библиотека для работы с COM-объектами.

    Эта библиотека даёт возможность работать с COM-объектами, предоставленными некоторыми приложениями. Например: Excel, Word, Mathcad, Matlab. А также объект ADODB для работы с базами данных через драйвер ODBC. Библиотека работает и в MT4 и в MT5.