Изучаем язык программирования MQL4

Ugar

Гуру форума
PHP:
Expand Collapse Copy
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
//Следующая задача.
//Напишите скрипт, который закрывает все открытые ордера на счете.
//(перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)

{
  int i,type;
  bool result;

  for(i=OrdersTotal()-1; i>=0; i--)  //                 
  {
    if(OrderSelect (i,SELECT_BY_POS,MODE_TRADES)) //выбираем ордер для работы
    {
    type = OrderType(); // записываем тип ордера

    result = false;     //

    RefreshRates();     // обновляем цену
      switch(type)      // выполняем тот case, который соответствует типу ордера(type)
      {
         //закрываем ордера на покупку
         case OP_BUY       : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), MODE_DIGITS, Red );
                          break;

         //закрываем ордера на подажу
         case OP_SELL      : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), MODE_DIGITS, Red );
                          break;

         //удаляем отложенные ордера
         case OP_BUYLIMIT  :
         case OP_BUYSTOP   :
         case OP_SELLLIMIT :
         case OP_SELLSTOP  : result = OrderDelete( OrderTicket() );
       }
      // если в OrderClose или OrderDlete произошла ошибка и закрытие или удаление ордера не произошло...
      if(result == false)
      {
         // ... то выдаем алерт...
         Alert("Ордер " , OrderTicket() , " не закрыт. Ошибка: " , GetLastError() );
         // ... и делаем задержку на 3000мс = 3 сек.
         Sleep(3000);
      }
    }
  }

  return;

}
//+------------------------------------------------------------------+
Взял готовый скрипт и пытался в нем разобраться. От себя только: добавил if перед Ордерселект, и приписал Рефрешратес.

1) Будет ли ошибкой, если объявить глобально?
result = false;
Нет. Можно объявлять где угодно, главное что бы она существовала там где нужна.
2) Зачем нужна эта задержка
Sleep(3000);
Спать 3 секунды. Программа останавливает работу на это время. Обычно делают после ошибки. Например если цен нет или со связью проблемы, поспали пока не нормализуется обстановка.
3) Это вроде понятно, но все же.
Тут можно использовать switch, потому что значение типа ордера целое число (0-5)?
Можно. switch работает быстрее чем куча if. Но обычно это делают только если много пунктов переключения. В данном случае всего 6, выигрыша в скорости не будет. По этому как удобнее.
4) Ошибочно ли, если RefreshRates(); задать 1 раз в теле цикла if(OrderSelect()) ?
Или надо перед каждом case?
Если после выбора ордера обновлять цены, то в случае отложенных ордеров, обновление будет выполняться бесполезно, ведь для удаления отложек цены не нужны.
По коду Домовенка.
PHP:
Expand Collapse Copy
#property strict


int slipp;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Следующая задача.
// Напишите скрипт, который закрывает все открытые ордера на счете.
// (перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)
{
bool   resalt;
int    OT, Ticket, i;
for(i = OrdersTotal()-1; i >= 0; i--) // Переменной i присваиваем значение OrdersTotal()-1. После этого проверено условие что i>=0,
      {                               // если это так, то выполняется один раз все, что написано внутри тела цикла
        if(OrderSelect(i, SELECT_BY_POS))
          {
          OT = OrderType();           //Переменной OT присваиваем значение OrderType()
          Ticket = OrderTicket();     //Переменной Ticket присваиваем значение OrderTicket()
          if(OT == OP_BUY)            // Если тип операций для функции OrderType() выбран OP_BUY (покупка), то
              {
               RefreshRates();        // обновляем цену
               resalt = OrderClose(Ticket,OrderLots(),NormalizeDouble(MarketInfo(OrderSymbol(),MODE_BID),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)),slipp,clrNONE);// выбранный тип закрывается
               if(!resalt) i--;       // Если по к.л. ошибке ордер не закрылся, просто повторяем операция закрытия еще раз
               else Alert("Closed BUY, OrderTicket ",OrderTicket(),",  Lots  ",OrderLots(),",  Close price  ",MarketInfo(OrderSymbol(),MODE_BID));
              }
          if(OT == OP_SELL)           // Если тип операций для функции OrderType() выбран OP_SELL (продажа), то
              {               
               RefreshRates();        // обновляем цену
               resalt = OrderClose(Ticket,OrderLots(),NormalizeDouble(MarketInfo(OrderSymbol(),MODE_ASK),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)),slipp,clrNONE);// выбранный тип закрывается
               if(!resalt) i--; // Если по к.л. ошибке ордер не закрылся, просто повторяем операция закрытия еще раз
               else Alert("Closed Sell, OrderTicket ",OrderTicket(),",  Lots  ",OrderLots(),",  Close price  ",MarketInfo(OrderSymbol(),MODE_ASK));
              }
// return; после удаления ордера, вызовет выход из функции в котором этот оператор используется,
// в данном случае из OnStart(). Получается что если наткнётся на отложенный ордер, скрипт его удалит и прекратит работу.
// А там могут быть ещё не закрытые и не удалённые ордера.
// В данном случае аргументы всех OrderDelete() одинаковые. Можно написать один раз для всех отложенных ордеров.
         /* if(OT == OP_BUYLIMIT)       // Если тип операций для функции OrderType() выбран OP_BUYLIMIT, то
              {                       // выбранный тип удаляется
               resalt = OrderDelete(Ticket,CLR_NONE); return;
              }
          if(OT == OP_SELLLIMIT)      // Если тип операций для функции OrderType() выбран OP_SELLLIMIT, то
              {                       // выбранный тип удаляется
               resalt = OrderDelete(Ticket,CLR_NONE); return;              }
          if(OT == OP_BUYSTOP)        // Если тип операций для функции OrderType() выбран OP_BUYSTOP, то
              {                       // выбранный тип удаляется
               resalt = OrderDelete(Ticket,CLR_NONE); return;
              }
          if(OT == OP_SELLSTOP)       // Если тип операций для функции OrderType() выбран OP_SELLSTOP, то
              {                       // выбранный тип удаляется
               resalt = OrderDelete(Ticket,CLR_NONE); return;
              }*/
          if(OT > OP_SELL)            // Если ордер отложенный, то
              {               
               resalt = OrderDelete(Ticket,CLR_NONE);//Удалить
               if(!resalt) i--;       // Если по какой либо ошибке ордер не закрылся, просто повторяем операция закрытия еще раз
               else Alert("Closed Buy/Sell: Limit or Stop orders, OrderTicket ",OrderTicket(),",  Lots  ",OrderLots());
              }
      
          if(Ticket>0)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
          }
      }
1) Равнозначна ли запись, при присвоении значения Ticket и при записи сразу в параметры OrderClose как в скрипте выше?
Ticket = OrderTicket();
OrderTicket() функция. Если нам нужен тикет один раз, то нет смысла её вызывать что бы загнать в переменную. Сразу вызвать там где нужен тикет. А если тикет в коде используется многократно, стоит один раз вызвать записав в переменную, а потом эту переменную использовать везде где нужен тикет. В данном случае тикет используется 2 раза, в закрытии или удалении и алерте. Особой разницы нет.
2) Зачем в resalt нужно MarketInfo задавать тип int?
(itn)MarketInfo(OrderSymbol(),MODE_DIGITS))
Второй аргумент NormalizeDouble целочисленный, а MarketInfo возвращает дробное значение, надо преобразовать. Иначе компилятор сделает замечание.
double NormalizeDouble(
double value, // нормализуемое число
int digits // кол-во знаков после запятой
);
double MarketInfo(
string symbol, // символ инструмента
int type // тип информации
);
3) Чтобы было повторение, надо так? Получится, что мы опять будем пытаться закрывать тот же ордер, пока он не закроется?
if(!resalt) i++;
Правильно.
Код:
Expand Collapse Copy
        if(Ticket>0)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
А вот это что такое, я не знаю.
 

Ugar

Гуру форума
Скажите, почему не открывает ордера в тестере сделки? Натолкните в направлении поиска ошибки пожалуйста. А то мозг зациклился.. :)
C++:
Expand Collapse Copy
#property strict

// Следующая задача.
// Нужно написать советник, который подсчитывает и выводит (через Comment)
// количество открытых ордеров соответствующих инструменту своего графика.
// Пример: советник запущен на графике EURUSD, подсчитываем только ордера EURUSD,
// а другие игнорируем. Если открытых ордеров нет, то советник открывает один ордер.
// Направление открытия (buy/sell) советник определяет следующим образом:
// если Close[1] > Close[3]+N*Point, то открывается ордер Buy, а если Close[1] < Close[3]-N*Point,
// то открывается ордер Sell. Значение переменной N (в пунктах), а также MagicNumber, StopLoss и TakeProfit
// нужно вывести во входные параметры (input).
// Советник нужно протестировать в тестере стратегий.

//+------------------------------------------------------------------+
input double    Lots            = 0.01;     // Lots:
input int       Delta_N         = 25;       // Delta:
input double    TakeProfit      = 300;      // Take Profit:
input double    StopLoss        = 100;      // Stop Loss:
input int       Magic           = 12345;    // Magic Number:
input int       Slippage        = 3;        // Slippage:
//+------------------------------------------------------------------+
int    slipp, del, ticket;
double point, lot, SL, TP;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//----Определение пяти значного брокера
   point = _Point;
   if(_Digits == 3 || _Digits == 5)
      {
       point = 10.0 * point;
       slipp = Slippage * 10;
       }
//---
    lot          = Lots;
    del          = Delta_N; 
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  int OT=0;

//--- получим минимальное значение Stop level
   double minstoplevel=MarketInfo(Symbol(),MODE_STOPLEVEL);
   Print("Minimum Stop Level=",minstoplevel," points");
//--- вычисленные значения цен SL и TP должны быть нормализованы
//  double stoploss=NormalizeDouble(Bid-minstoplevel*Point,Digits);
  // if (StopLoss<stoploss) StopLoss=stoploss;
  // double takeprofit=NormalizeDouble(Bid+minstoplevel*Point,Digits);
  // if (TakeProfit<takeprofit) TakeProfit=takeprofit;
   double minlot = MarketInfo(Symbol(),MODE_MINLOT); // узнаем каков минимальный размер лота
   Print("Minimal lot=",minlot," lots");
   double maxlot = MarketInfo(Symbol(),MODE_MAXLOT); // узнаем каков максимальный размер лота
   Print("Maximal lot=",maxlot," lots");
//---
// функциz OrdersCount()написана правильно, а вот использована нет.
// Что бы правильно использовать функцию, не обязательно знать как она устроена. Важно знать что она делает, что возвращает, какие аргументы.
// Первый аргумент у неё тип ордера. Вы указали 0, а это OP_BUY. Соответственно, она только Buy и считает.
// Нужно понимать что функция это программа, которая выполняется компьютером. На это уходят ресурсы компьютера.
// А переменная это кусочек памяти, для обращения к ней ресурсов практически не надо.
/*if (OrdersCount(0,Magic)>=0) Comment (OrdersCount(0,Magic));
else
if (OrdersCount(0,Magic)<1)*/
// Вы тут трижды вызвали функцию. А можно было один раз вызвать, результат загнать в переменную,
// потом обращаться к ней сколько угодно раз. К экономии ресурсов надо привыкать с самого начала.
int OrdersBuy=OrdersCount(OP_BUY,Magic);  //Посчитали Buy ордера
int OrdersSell=OrdersCount(OP_SELL,Magic);//Посчитали Sell ордера
OT = OrdersBuy+OrdersSell; // Сумировали ордера BUY и SELL
Comment("Buy Orders ",OrdersBuy,"\nSell Orders ",OrdersSell);

// В условиях открытия ордеров использовано OrdersTotal()<1. А OrdersTotal() возвращает количество ордеров
// независимо от типа, символа и маджика. А между тем уже есть посчитанные ордера с учётом символа и маджика функцией OrdersCount().
// Стоит использовать эти данные, а не OrdersTotal().
for(int i=0;i<OT;i++)
{
{
     if (lot >= minlot && lot <= maxlot )
  {

//--- размещаем рыночный ордер на покупку 1 лота
// if (OrdersTotal()<1 && Close[1] > Close[3]+Delta_N*Point)
if (OT==0 && Close[i+1] > Close[i+3]+Delta_N*Point)
     {
   ticket=OrderSend(Symbol(),OP_BUY,lot,Ask,Slippage,0,0,"My order BUY",Magic,0,clrGreen);
   if(ticket<0)
         {
           SL = NormalizeDouble(Ask - StopLoss*Point,Digits);
           TP = NormalizeDouble(Ask + TakeProfit*Point,Digits);
        
           if (OrderSelect(ticket,SELECT_BY_TICKET))
               if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed) == true)
                   Print ("Ошибка модификации ордера на продажу");
        
         }  else Print("Ошибка открытия ордера на продажу");
  
     }
//--- размещаем рыночный ордер на продажу 1 лота
if (OT==0 && Close[i+1] < Close[i+3]-Delta_N*Point)
     {
   ticket=OrderSend(Symbol(),OP_SELL,lot,Bid,Slippage,0,0,"My order BUY",Magic,0,clrGreen);
   if(ticket<0)
       {
           SL = NormalizeDouble(Bid + StopLoss*Point,Digits);
           TP = NormalizeDouble(Bid - TakeProfit*Point,Digits);
        
           if (OrderSelect(ticket,SELECT_BY_TICKET))
               if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed) == true)
                   Print ("Ошибка модификации ордера на продажу");
        
         }  else Print("Ошибка открытия ордера на продажу");
     }

//else {return;}
    }
   }
  }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                    Подсчет ордеров по символу                    |
//+------------------------------------------------------------------+
int OrdersCount(int type, int MagicNum)
{
  int orders = 0;
   for(int i = OrdersTotal()-1; i >= 0; i--)
      {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
        if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNum)
          {
          if(OrderType() == type)orders++;
           }
       }
   }
  return orders;
}

И вопрос. Может удобнее прикреплять код файлом в mq4 или все же под спойлером?
for(int i=0;i<OT;i++)
Это зачем? ОТ в данном случае количество открытых ордеров Buy + Sell. Вначале их 0. Цикл будет выполняться когда i<OT , то есть меньше 0. А его начальное значение 0 и может быть только больше, так как i++. То есть цикл не будет выполняться пока не будет открыт хотя бы один ордер.
На будущее, название переменных лучше придумывать такие что бы из названия было приблизительно понятно зачем она. Я бы назвал сумму открытых ордеров, например OrdersSum.
 

gravity

Местный знаток
Второй аргумент NormalizeDouble целочисленный, а MarketInfo возвращает дробное значение, надо преобразовать. Иначе компилятор сделает замечание.

Только заметил, что в том скрипте, который выложил я, отсутствует нормализация. Это как влияет на работу?
PHP:
Expand Collapse Copy
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
//Следующая задача.
//Напишите скрипт, который закрывает все открытые ордера на счете.
//(перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)

{
  int i,type;
  bool result;

  for(i=OrdersTotal()-1; i>=0; i--)  //                 
  {
    if(OrderSelect (i,SELECT_BY_POS,MODE_TRADES)) //выбираем ордер для работы
    {
    type = OrderType(); // записываем тип ордера

    result = false;     //

    RefreshRates();     // обновляем цену
      switch(type)      // выполняем тот case, который соответствует типу ордера(type)
      {
         //закрываем ордера на покупку
         case OP_BUY       : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), MODE_DIGITS, Red );
                          break;
 
         //закрываем ордера на подажу
         case OP_SELL      : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), MODE_DIGITS, Red );
                          break;

         //удаляем отложенные ордера
         case OP_BUYLIMIT  :
         case OP_BUYSTOP   :
         case OP_SELLLIMIT :
         case OP_SELLSTOP  : result = OrderDelete( OrderTicket() );
       }
      // если в OrderClose или OrderDlete произошла ошибка и закрытие или удаление ордера не произошло...
      if(result == false)
      {
         // ... то выдаем алерт...
         Alert("Ордер " , OrderTicket() , " не закрыт. Ошибка: " , GetLastError() );
         // ... и делаем задержку на 3000мс = 3 сек.
         Sleep(3000);
      }
    }
  }

  return;

}
//+------------------------------------------------------------------+
case OP_BUY : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), MODE_DIGITS, Red );

А в OrderClose вообще не должно быть параметра MODE_DIGITS, он тут записан вместо проскальзывания. Похоже по нормальному надо тут нормализацию тоже сделать,как в варианте Домовенка,да?
Код:
Expand Collapse Copy
        if(Ticket>0)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
А вот это что такое, я не знаю.
А тут наверно можно написать if(resalt==false).
 
Последнее редактирование:

Ugar

Гуру форума
Массивы одномерные. Они похожи на переменные. Их то же объявляют перед использованием. Выглядят они так же как переменная, но после имени идёт квадратные скобки. Они так же имеют тип int, double, string...
Отличаются от переменных тем что в них может храниться не одно значение, а много. Количество значений соответствует количеству ячеек в массиве. При объявлении можно сразу указать сколько ячеек нужно в квадратных скобках. Это будет статический массив с заданным размером. Но в процессе работы его можно менять, увеличивая или уменьшая размер массива.
Если при объявлении массива размер не указан, значит он динамический. Сразу после объявления количество ячеек в нём =0. Перед использованием, надо изменить размер массива что бы нём были ячейки.
Если при объявлении
Например объявляем:
double dArray[];//Динамический массив.
int iArray[48];//Статический массив с 48 ячейкам.
Что бы использовать ячейку нужно указать её индекс (номер). Индексы нумеруются от 0 до размер -1. То есть при использовании iArray[48] указываем индексы 0-47.
При объявлении статического массива можно сразу присвоить значения ячейкам в фигурных скобках через запятую в порядке следования ячеек. Например:
int fibo[10]={0,1,1,2,3,5,8,13,21,34};
string OrderTypeStr[6]={"Buy","Sell","BuyLimit","SellLimit","BuyStop","SellStop"};

Присвоение ячейке значений, как и использование в вычислениях так же как и с переменной, только надо указать индекс ячейки
a[8]=33*2/3;
y=a[3]+2;
Но при присвоении значений ячейкам массива нельзя использовать арифметические операции их двух символов.
a[8]++;//Так нельзя
a[8]=a[8]+1;//Придётся так
Profit[8]+=OrderProfit();//Так нельзя
Profit[8]=Profit[8]+OrderProfit();//Придётся так
 
Последнее редактирование:

DomovenokBrest

♔♕♖♗♘♙
Только заметил, что в том скрипте, который выложил я, отсутствует нормализация. Это как влияет на работу?

case OP_BUY : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), MODE_DIGITS, Red );

А в OrderClose вообще не должно быть параметра MODE_DIGITS, он тут записан вместо проскальзывания. Похоже по нормальному надо тут нормализацию тоже сделать,как в варианте Домовенка,да?

А тут наверно можно написать if(resalt==false).
Так ведь так же пойдет?
C++:
Expand Collapse Copy
          if(OT == OP_SELL || OT == OP_BUY || OT > OP_SELL)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
 

gravity

Местный знаток
Так ведь так же пойдет?
C++:
Expand Collapse Copy
          if(OT == OP_SELL || OT == OP_BUY || OT > OP_SELL)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
Попробую я ответить) OT = OrderType();
А типы ордеров от 0-6.
Поэтому наверно можно if(OT>=0) Всмысле, короче будет.
 

DomovenokBrest

♔♕♖♗♘♙
Для меня очень много сразу информации. Не успевает уложиться в ячейки мозга ))
Нужно или время, что бы все разложилось по полочкам, или забивать инфу практикой...
 

MrGreen86

Гуру форума
Если после выбора ордера обновлять цены, то в случае отложенных ордеров, обновление будет выполняться бесполезно, ведь для удаления отложек цены не нужны.
нужны, многие брокеры все еще промышляют фриз левелом, это нужно учитывать.
2) Зачем в resalt нужно MarketInfo задавать тип int?
(itn)MarketInfo(OrderSymbol(),MODE_DIGITS))
вообще сейчас используется набор функций SymbolInfo
SymbolInfoInteget
SymbolInfoDouble
SymbolInfoString
Рекомендую использовать именно их. MarketInfo это старый упрощенный вариант.
Далее будет проще перейти на МТ5, так как в нем используется именно SymbolInfo
 

MrGreen86

Гуру форума
Так ведь так же пойдет?
C++:
Expand Collapse Copy
          if(OT == OP_SELL || OT == OP_BUY || OT > OP_SELL)
              {
               Print("OrderClose завершилась с ошибкой #",GetLastError());
              }
          else
               Print("Функция OrderClose успешно выполнена");
              }
а в чем смысл этой конструкции?

если ( ордер селл или ордер бай или ордер больше селл)
пишем что есть ошибка
если нет
пишем успех

вот только у вас первое условие выполняется в любом случае.
OrderType() имеет значение от 0 до 6. для всего этого есть предопределенные константы OP_BUY OP_SELL и так далее. Теперь рассмотрим ваше условие через эту призму:
if(OT ==1 || OT == 0 || OT > 1)
как видите ваше условие включает все возможные варианты значения OT )

достоверно определить закрылся ордер или нет можно по его параметру времени закрытия
OrderCloseTime().
у открытых ордеров этот параметр всегда равен 0. у закрытых >0
 

Ugar

Гуру форума
нужны, многие брокеры все еще промышляют фриз левелом, это нужно учитывать.
Давно замораживателей не встречал. Можно пример такого брокера? Хочется посмотреть на этого динозавра.
В таком случае, надо не только обновить цену, но и проверить её на заморозку перед удалением отложки.
 
Последнее редактирование:

gravity

Местный знаток
а в чем смысл этой конструкции?

если ( ордер селл или ордер бай или ордер больше селл)
пишем что есть ошибка
если нет
пишем успех

вот только у вас первое условие выполняется в любом случае.
OrderType() имеет значение от 0 до 6. для всего этого есть предопределенные константы OP_BUY OP_SELL и так далее. Теперь рассмотрим ваше условие через эту призму:
if(OT ==1 || OT == 0 || OT > 1)
как видите ваше условие включает все возможные варианты значения OT )

достоверно определить закрылся ордер или нет можно по его параметру времени закрытия
OrderCloseTime().
у открытых ордеров этот параметр всегда равен 0. у закрытых >0
А точно, условие в If выполняется всегда. И возвращает оно только значения от 0 до 6. А OrderType(); в случае ошибки , (-1) получается не возвращает, как в некоторых. Значит и подсказка неверна.
 

MrGreen86

Гуру форума
А точно, условие в If выполняется всегда. И возвращает оно только значения от 0 до 6. А в случае ошибки (-1) получается не возвращает, как в некоторых. Значит и подсказка неверна.
что-то мне никогда не приходило в голову что оно вернет если не было использовано OrderSelect. т.е. при ошибочном вызове.
как оказалось возвращает 0.
еще один камень в трупик MQ, это грубейшая ошибка с их стороны. Так как OP_BUY это 0, и ошибка тоже 0.
 

Ugar

Гуру форума
что-то мне никогда не приходило в голову что оно вернет если не было использовано OrderSelect. т.е. при ошибочном вызове.
как оказалось возвращает 0.
еще один камень в трупик MQ, это грубейшая ошибка с их стороны. Так как OP_BUY это 0, и ошибка тоже 0.
В данном случае это грубейшая ошибка со стороны программиста. В справочнике же написано:
Ордер должен быть предварительно выбран с помощью функции OrderSelect().
 

gravity

Местный знаток
Следующая задача.
Нужно написать советник, который подсчитывает и выводит (через Comment) количество открытых ордеров соответствующих инструменту своего графика. Пример: советник запущен на графике EURUSD, подсчитываем только ордера EURUSD, а другие игнорируем. Если открытых ордеров нет, то советник открывает один ордер. Направление открытия (buy/sell) советник определяет следующим образом: если Close[1] > Close[3]+N*Point, то открывается ордер Buy, а если Close[1] < Close[3]-N*Point, то открывается ордер Sell. Значение переменной N (в пунктах), а также MagicNumber, StopLoss и TakeProfit нужно вывести во входные параметры (input).
Советник нужно протестировать в тестере стратегий.
C-подобный:
Expand Collapse Copy
#property strict

//Следующая задача.
//Нужно написать советник, который подсчитывает и выводит (через Comment)
//количество открытых ордеров соответствующих инструменту своего графика.
//Пример: советник запущен на графике EURUSD, подсчитываем только ордера EURUSD, а другие игнорируем.
//Если открытых ордеров нет, то советник открывает один ордер.
//Направление открытия (buy/sell) советник определяет следующим образом:
//если Close[1] > Close[3]+N*Point, то открывается ордер Buy,
//а если Close[1] < Close[3]-N*Point, то открывается ордер Sell.
//Значение переменной N (в пунктах), а также MagicNumber, StopLoss и TakeProfit нужно вывести во входные параметры (input).
//Советник нужно протестировать в тестере стратегий.

//+------------------------------------------------------------------+

input double Lots        = 0.01;
input int    N           = 8;
input int    TakeProfit  = 30;
input int    StopLoss    = 10;
input int    MagicNumber = 555;
input int    Slippage    = 5;

//+------------------------------------------------------------------+
int    ticket;
double SL, TP, point;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(Digits == 3 || Digits == 5)
   {
      point = Point*10;
   }

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//+------------------------------------------------------------------+
//| Условия открытия для первого ордера                            |
//+------------------------------------------------------------------+

  if(CountTrades() == 0)                                                          // если ордеров еще нет, то ...
  {
     if(Close[1] > Close[3]+N*point)                                              // при соблюдении условия...
     {
        SL     = NormalizeDouble(Ask - StopLoss*point,Digits);                    // считаем стоп стоп-лосс(BUY)
        TP     = NormalizeDouble(Ask + TakeProfit*point,Digits);                  // считаем тейк профит(BUY)
        ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0, "1-й ордер", MagicNumber, 0, Blue);//открываем BAY
        if (ticket < 1)                                                           // если ордер не открылся, то возвращает (-1) и...
        {
           Print("Ошибка открытия ордера BUY");                                   //пишем в журнал об ошибке
         }
         else if (OrderSelect(ticket,SELECT_BY_TICKET))                           // если ордер есть(ticket>1), то...
              {
                  if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed))// == true)// модифицируем ордер с выставлением SL и TP
                    Print ("Ордер BUY успешно модифицирован");                    // пишем об успешной модификации
               }
               else                                                               // если OrderModify вернул false, то...
                  Print ("Ошибка модификации ордера BUY");                        // пишем об ошибке модификации
     }
     else if(Close[1] < Close[3]-N*point)                                         // при соблюдении условия...
          {
             TP     = NormalizeDouble(Bid - TakeProfit*point, Digits);            // считаем стоп стоп-лосс(SELL)
             SL     = NormalizeDouble(Bid + StopLoss*point,Digits);               // считаем тейк профит(SELL)
             ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, "1-й ордер", MagicNumber, 0, Red);//открываем SELL
             if (ticket < 1)                                                      // если ордер не открылся, то возвращает (-1) и...
        {
           Print("Ошибка открытия ордера SELL");                                  //пишем в журнал об ошибке
         }
         else if (OrderSelect(ticket,SELECT_BY_TICKET))                           // если ордер есть(ticket>1), то...
              {
                  if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed))//== true)// модифицируем ордер с выставлением SL и TP
                    Print ("Ордер SELL успешно модифицирован");                   // пишем об успешной модификации
               }
               else                                                               // если OrderModify вернул false, то...
                  Print ("Ошибка модификации ордера SELL");                       // пишем об ошибке модификации
         }
   }
   else                                                                           // если не выполняется условие (CountTrades() == 0), то...
      Comment("Количество открытых ордеров = " ,CountTrades());                   // выводим комментарий о количестве открытых ордеров
      
}

//+------------------------------------------------------------------+
//| Ф. считаем количество ордеров                                    |
//+------------------------------------------------------------------+

int CountTrades()                                                   
{
   int count = 0;
   for(int i= OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            if(OrderType() == OP_BUY || OrderType() == OP_SELL)
               count ++;
      }
   }

   return(count);

}
//+------------------------------------------------------------------+
Незнаю на сколько правильно, пользовался кодом Домовенка и подсматривал в других советниках.
Вот коммент у меня всегда будет 1, т.к. по условию, открываем ордера, только когда нет открытых ордеров.
И в строчке ,
if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed)) //== true)// модифицируем ордер
зачем проверка на true? Закомментил ее, она и так возвращает true, при успешной модификации.
 

MrGreen86

Гуру форума
И в строчке ,
if (OrderModify(ticket,OrderOpenPrice(),SL,TP,0,clrRed)) //== true)// модифицируем ордер
зачем проверка на true? Закомментил ее, она и так возвращает true, при успешной модификации.
это для новичков, у которых нет понимания что вместо логического выражения можно использовать булевую переменную или ответ.
 

gravity

Местный знаток
Следующая задача.
Напишите скрипт, который закрывает все открытые ордера на счете.
(перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)
Как то так...

C++:
Expand Collapse Copy
#property strict


int slipp;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Следующая задача.
// Напишите скрипт, который закрывает все открытые ордера на счете.
// (перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)
{
bool   resalt;
int    OT, Ticket, i;
for(i = OrdersTotal()-1; i >= 0; i--) // Переменной i присваиваем значение OrdersTotal()-1. После этого проверено условие что i>=0,
      {                               // если это так, то выполняется один раз все, что написано внутри тела цикла
        if(OrderSelect(i, SELECT_BY_POS))
          {
          OT = OrderType();           //Переменной OT присваиваем значение OrderType()
          Ticket = OrderTicket();     //Переменной Ticket присваиваем значение OrderTicket()
          if(OT == OP_BUY)            // Если тип операций для функции OrderType() выбран OP_BUY (покупка), то
              {                       // выбранный тип закрывается
               resalt = OrderClose(Ticket,OrderLots(),NormalizeDouble(MarketInfo(OrderSymbol(),MODE_BID),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)),slipp,clrNONE);
              }
          if(OT == OP_SELL)           // Если тип операций для функции OrderType() выбран OP_SELL (продажа), то
              {                       // выбранный тип закрывается
               resalt = OrderClose(Ticket,OrderLots(),NormalizeDouble(MarketInfo(OrderSymbol(),MODE_ASK),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)),slipp,clrNONE);
              }
          }
          else {return;}
      }
}
}
Так вот, разобрался.
1) Мое замечание неверное. Домовенок сделал верно.
2) Но с minstoplevel вместо стоп-лосса и тейк-профита, выдает ошибку 130 - слишком близкие стопы. Если не задавать стоп и тейк, то работает.(счет демо-стандарт, Альпари)
Похоже надо задавать стоп и тейк через модификацию ордера, потому что даже если явно их задать, например по 50пн, они все равно не выставляются. Хотя ошибки не возникает.
3) Для вычесленя стопа и тейка для Бай, надо использовать цены Ask. Забыл заменить.
335607
 
Последнее редактирование:

MrGreen86

Гуру форума
Так вот, разобрался.
1) Мое замечание неверное. Домовенок сделал верно.
2) Но с minstoplevel вместо стоп-лосса и тейк-профита, выдает ошибку 130 - слишком близкие стопы. Если не задавать стоп и тейк, то работает.(счет демо-стандарт, Альпари)
Похоже надо задавать стоп и тейк через модификацию ордера, потому что даже если явно их задать, например по 50пн, они все равно не выставляются. Хотя ошибки не возникает.
3) Для вычесленя стопа и тейка для Бай, надо использовать цены Ask. Забыл заменить.
Посмотреть вложение 335607
тут опять кривизна терминала MQ.
Дело в том что они не предусмотрели что стоп левел может быть динамическим.
Функций чтобы это проверить тоже не предоставили, т.е. советник из кода не может знать какой вариант применяется. Остается только догадываться и выносить это во входные параметры советников. Потому как у некоторых брокеров стоп левел действительно 0. У других он 0 потому что динамический.

Конкретно у Альпари как и у большинства брокеров стоп левел динамический.При этом опция MarketInfo(_Symbol,MODE_STOPLEVEL) вам вернет 0.
Нужно подстраиваться под брокера и спрашивать как у них считается стоп уровень. Например у альпари он всегда равен двум спредам.
double minstoplevel = ((Ask-Bid)*2) / _Point;
 

Ugar

Гуру форума
МТ4 довольно старый. Раньше всё было проще. Заморозка, стоплевел раньше были однозначными. Сейчас конкуренция среди брокеров. Каждый пытается привлечь к себе клиентов какими то ухищрениями. Сама платформа довольно гибкая в настройках. У многих брокеров опытные программисты, которые могут настроить платформу под нужды брокера. Я встречал плавающие стоплевелы и их значение можно было получать MarketInfo(). Но некоторые, альпари в том числе, решили что можно использовать спред в качестве стоплевел. Сейчас у альпари, на ECN счетах вообще нет стоплевела, то есть можно ставить стоп даже внутри спреда. То есть, Buy ордеру стоп лосс, можно поставить на Bid-1 пункт.
Кстати, в тестере и на счетах с исполнением по Instant стоп лосс и тейк профит можно задавать сразу при открытии в OrderSend.
На ECN счетах почти у всех брокеров исполнение по Market. А значит стоп лосс и тейк профит надо ставить модификацией ордера, после его открытия. В альпари было так же. Но, конкуренция же. Теперь на ECN счетах альпари исполнение хоть и по Market, но всё равно стопы и тейки можно задавать сразу при открытии.

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

MrGreen86

Гуру форума
Это косяки не метаквотов, а приспосабливание платформы программистами брокеров под свой регламент.
Была у меня дискуссия по поводу этого самого стоп левела с сотрудником MQ на их же форуме. Ошибку признали как и то что исправлять они ее не собирались. Ошибка древняя и была она еще со времен когда МТ4 был молод и полон сил, т.е. лет так 10 назад.

А вот по поводу плавающего стоп левела через MarketInfo я бы посмотрел, так как MQ утверждали что это невозможно. У какого брокера это есть?
 
  • Like
Реакции: Ugar
Верх