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

eevviill2

Местный знаток
Правильно ли то что при смене настроек в индикаторе сбиваются глобальные переменные?
 

eevviill2

Местный знаток
Бывали ли у кого то случаи в мультивалютном советнике что Magic слетал?
(ордер открывался с 0 magic)
 
Последнее редактирование:

Ugar

Гуру форума
Спасибо. Поправил. Если не сложно - проверьте.

C++:
#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(OT == OP_SELL)           // Если тип операций для функции OrderType() выбран OP_SELL (продажа), то
              {                      
               RefreshRates();        // обновляем цену
               resalt = OrderClose(Ticket,OrderLots(),NormalizeDouble(MarketInfo(OrderSymbol(),MODE_ASK),(int)MarketInfo(OrderSymbol(),MODE_DIGITS)),slipp,clrNONE); // выбранный тип закрывается
              }
          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;
              }
          }
      }
}
return; после удаления ордера, вызовет выход из функции в котором этот оператор используется, в данном случае из OnStart(). Получается что если наткнётся на отложенный ордер, скрипт его удалит и прекратит работу. А там могут быть ещё не закрытые и не удалённые ордера.
В данном случае аргументы всех OrderDelete() одинаковые. Можно написать один раз для всех отложенных ордеров.
Код:
if(OT > OP_SELL)      // Если ордер отложенный, то
    {                       
    resalt = OrderDelete(Ticket,CLR_NONE);//Удалить
    }
Ну и наконец, нет никакой обработки ошибок, даже в журнал не пишет.
 

Ugar

Гуру форума
Правильно ли то что при смене настроек в индикаторе сбиваются глобальные переменные?
При инициализации должны инициализироваться переменные объявленные на глобальном уровне.
Но я, на всякий случай, дополнительно инициализирую их, например в OnInit(). Так надёжнее.
 
Последнее редактирование:

Ugar

Гуру форума
Бывали ли у кого то случаи в мультивалютном советнике что Magic слетал?
(ордер открывался с 0 magic)
Нет. Такого не должно быть. Разве что косяк языка. Но я много писал таких и никогда не сбивались маджики.
 

eevviill2

Местный знаток
При инициализации должны инициализироваться переменные объявленные на глобальном уровне.
Но я, на всякий случай, дополнительно инициализирую их, например в OnInit(). Так надёжнее.
В советниках не иницилиаризуются.
И это правильно.
 

eevviill2

Местный знаток
Нет. Такого не должно быть. Разве что косяк языка. Но я много писал таких и никогда не сбивались маджики.
У меня уже 2 раза было. На разных советниках MSY. Меджик прямо из настроек в OrderSend передаётся.
Смотрю что то советник не трейлит 3 из 7 ордеров. Навожу на ордер. Пишет "Placed by expert id0"
 

eevviill2

Местный знаток
У меня уже 2 раза было. На разных советниках MSY. Меджик прямо из настроек в OrderSend передаётся.
Смотрю что то советник не трейлит 3 из 7 ордеров. Навожу на ордер. Пишет "Placed by expert id0"
А недавно видел в каком то советнике
Код:
extern const int magic = 567;
думаю поможет ли.
 

DomovenokBrest

♔♕♖♗♘♙
return; после удаления ордера, вызовет выход из функции в котором этот оператор используется, в данном случае из OnStart(). Получается что если наткнётся на отложенный ордер, скрипт его удалит и прекратит работу. А там могут быть ещё не закрытые и не удалённые ордера.
В данном случае аргументы всех OrderDelete() одинаковые. Можно написать один раз для всех отложенных ордеров.
Код:
if(OT > OP_SELL)      // Если ордер отложенный, то
    {                      
    resalt = OrderDelete(Ticket,CLR_NONE);//Удалить
    }
Ну и наконец, нет никакой обработки ошибок, даже в журнал не пишет.
Поправил
C++:
#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 успешно выполнена");
              }
          }
      }
 

Ugar

Гуру форума
Поправил
C++:
#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 успешно выполнена");
              }
          }
      }
Цикл выполняется от последнего ордера к первому for(i = OrdersTotal()-1; i >= 0; i--). По этому if(!resalt) i--; приведёт не к повторению, а к пропуску следующего ордера.
 

Ugar

Гуру форума
Есть нюанс с объявлениями переменных, массивов, структур... У нас есть операторы и функции тело которых находится внутри фигурных скобок. Так вот если внутри пары фигурных скобок объявить переменную, она действует только в пределах этих скобок. Пример:
Код:
if(true)
      {
      int a=0;
      a++;
      Print(a);
      }
   if(true)
      {
      int a=0;
      a+=3;
      Print(a);
      }
Здесь переменные a в верхнем if и в нижнем это разные переменные. Они никак не связаны и не будут друг другу мешать. Но за пределами операторов if они не существуют.

Переменная объявленная вне функции или оператора с фигурными скобками будет действовать и внутри фигурных скобок.
Код:
int a=0;
if(true)
   {
   a++;
   Print(a);
   }
if(true)
   {
   a+=3;
   Print(a);
   }

Если объявить вне фигурных скобок и внутри фигурных скобок одинаковые переменные, компилятор сделает замечание, но внутри эти скобок будет действовать переменная объявленная внутри. Так лучше не делать.
Код:
   int a=0;
   if(true)
      {
      a++;
      Print(a);
      }
   if(true)
      {
      int a=0;
      a+=3;
      Print(a);
      }
Здесь в верхнем if деуствет переменная объявленная вне оператора if. Она бы и в нижнем if действовала, но там объявили свою.

Соответственно, если переменная объявлена вне всех функций, она действует внутри всех функций и операторов, такую ещё называют глобальной.
Код:
int a;
int OnInit()
  {
//---
   a=0;
//---
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
//---
   a=0;
  }
void OnTick()
  {
//---
   a++;
   Comment(a);
  }
Здесь переменная а объявлена на глобальном уровне, значит она действует внутри всех функций и операторов программы.
 
Последнее редактирование:

Ugar

Гуру форума
А недавно видел в каком то советнике
Код:
extern const int magic = 567;
думаю поможет ли.
В старом языке внешние переменные обозначались extern. В ходе выполнения программы можно было менять значение этой переменной. Если где то в коде есть magic=0; то да, значение могло смениться на 0. Тогда это косяк программиста.
Сейчас применяется input значение этой переменной менять нельзя.
 

Ugar

Гуру форума
Ссылки в функции. Если в аргументе функции между типом и именем переменной стоит & это ссылка.
Если по простому, аргументы передают в функцию какое то значение, а ссылка может передать не только в функцию, но и из неё. Например один из вариантов SymbolInfoInteger() может передавать результат по ссылке.
Возвращает true или false в зависимости от успешности выполнения функции. В случае успеха значение свойства помещается в приемную переменную, передаваемую по ссылке последним параметром.

bool SymbolInfoInteger(
string name, // символ
ENUM_SYMBOL_INFO_INTEGER prop_id, // идентификатор свойства
long& long_var // сюда примем значение свойства
);
Код:
long Spread;
if(SymbolInfoInteger(Symbol(),SYMBOL_SPREAD,Spread))Print("Текущий спред ",Spread);
else Print("Ошибка получения спреда ",_LastError);
Здесь функция SymbolInfoInteger() передала значение спреда по ссылке в переменную Spread.

По ссылке в функцию можно передать не только переменную, но и массив, структуру и массив структур.
 

BorisSedov

Активный участник
Я попробовал. Проверьте пожалуйста. Но Comment не выдает...
Очень хорошо. (y)
Пробуйте вносить в код небольшие изменения и затем тестировать, это позволит научиться проводить отладку.
 

Ugar

Гуру форума
Я попробовал. Проверьте пожалуйста. Но Comment не выдает...

C++:
#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 int    TakeProfit      = 300;      // Take Profit:
input int    StopLoss        = 100;      // Stop Loss:
input int    Magic           = 12345;    // Magic Number:
input int    Slippage        = 3;        // Slippage:
//+------------------------------------------------------------------+
int    slipp, del;
double point, lot;
//+------------------------------------------------------------------+
//| 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()
  {
//--- получим минимальное значение Stop level
   double minstoplevel=MarketInfo(Symbol(),MODE_STOPLEVEL);
   Print("Minimum Stop Level=",minstoplevel," points");
//--- вычисленные значения цен SL и TP должны быть нормализованы
   double stoploss=NormalizeDouble(Bid-minstoplevel*Point,Digits);
   double takeprofit=NormalizeDouble(Bid+minstoplevel*Point,Digits);
   double minlot = MarketInfo(Symbol(),MODE_MINLOT); // узнаем каков минимальный размер лота
   double maxlot = MarketInfo(Symbol(),MODE_MAXLOT); // узнаем каков максимальный размер лота
//---
if (OrdersCount(0,Magic)>=0) Comment (OrdersCount(0,Magic));
else
if (OrdersCount(0,Magic)<1)
{
     if (lot >= minlot && lot <= maxlot )
  {

//--- размещаем рыночный ордер на покупку 1 лота
if (OrdersTotal()<1 && Close[1] > Close[3]+Delta_N*Point)
     {
   int ticket=OrderSend(Symbol(),OP_BUY,lot,Ask,Slippage,StopLoss,TakeProfit,"My order BUY",Magic,0,clrGreen);
   if(ticket<0)
       {
      Print("OrderSend завершилась с ошибкой #",GetLastError());
       }
   else
      Print("Функция OrderSend успешно выполнена");
     }
//--- размещаем рыночный ордер на продажу 1 лота
if (OrdersTotal()<1 && Close[1] < Close[3]-Delta_N*Point)
     {
   int ticket=OrderSend(Symbol(),OP_SELL,lot,Bid,Slippage,StopLoss,TakeProfit,"My order BUY",Magic,0,clrGreen);
   if(ticket<0)
       {
      Print("OrderSend завершилась с ошибкой #",GetLastError());
       }
   else
      Print("Функция OrderSend успешно выполнена");
     }

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;
}
О, Вы уже используете пользовательские функцию 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 ордера
Comment("Buy Orders ",OrdersBuy,"\nBuy Orders ",OrdersSell);

В условиях открытия ордеров использовано OrdersTotal()<1. А OrdersTotal() возвращает количество ордеров независимо от типа, символа и маджика. А между тем уже есть посчитанные ордера с учётом символа и маджика функцией OrdersCount(). Стоит использовать эти данные, а не OrdersTotal().
 

DomovenokBrest

♔♕♖♗♘♙
О, Вы уже используете пользовательские функцию 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 ордера
Comment("Buy Orders ",OrdersBuy,"\nBuy Orders ",OrdersSell);

В условиях открытия ордеров использовано OrdersTotal()<1. А OrdersTotal() возвращает количество ордеров независимо от типа, символа и маджика. А между тем уже есть посчитанные ордера с учётом символа и маджика функцией OrdersCount(). Стоит использовать эти данные, а не OrdersTotal().
Спасибо. Функция действительно не моя. Написана нашим форумчанином strannik-ps. Мной не содрана. Пользуюсь функциями написанными Пашей с его же ведома и разрешения.
Особое спасибо за понятные разъяснения!
 

Ugar

Гуру форума
Спасибо. Функция действительно не моя. Написана нашим форумчанином strannik-ps. Мной не содрана. Пользуюсь функциями написанными Пашей с его же ведома и разрешения.
Особое спасибо за понятные разъяснения!
Если кто то выкладывает в общедоступном месте код в открытом виде, значит он не против что этот код будут изучать, брать от туда функции... Иначе он об этом напишет (это мало помогает) или выложит только компилированную программу.
 

gravity

Местный знаток
Следующая задача.
Напишите скрипт, который закрывает все открытые ордера на счете.
(перед запуском скрипта, желательно открыть несколько ордеров Бай и Селл)
PHP:
#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) Это вроде понятно, но все же.
Тут можно использовать switch, потому что значение типа ордера целое число (0-5)?
4) Ошибочно ли, если RefreshRates(); задать 1 раз в теле цикла if(OrderSelect()) ?
Или надо перед каждом case?

По коду Домовенка.
PHP:
#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();
2) Зачем в resalt нужно MarketInfo задавать тип int?
(itn)MarketInfo(OrderSymbol(),MODE_DIGITS))
3) Чтобы было повторение, надо так? Получится, что мы опять будем пытаться закрывать тот же ордер, пока он не закроется?
if(!resalt) i++;
 
Последнее редактирование:

DomovenokBrest

♔♕♖♗♘♙
Следующая задача.
Нужно написать советник, который подсчитывает и выводит (через 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++:
#property strict

//input int MagicNumber = 555;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{

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

}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//Comment(MagicNumber);

}
//+------------------------------------------------------------------+
Скажите, почему не открывает ордера в тестере сделки? Натолкните в направлении поиска ошибки пожалуйста. А то мозг зациклился.. :)
C++:
#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 или все же под спойлером?
 
Последнее редактирование:
Верх