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

Ugar

Гуру форума
Сложновато. Пытался.
Вот обрывки мыслей. Как все это правильно сложить, не знаю.
Может попроще задачу, ну или как эта решается?
Код:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
double info[][4];

   for(int i=0;i<OrdersHistoryTotal();i++)         // считаем все исторические ордера на счете
      {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) // если ордер не выбран, то...
            {
               Print("Ошибка при доступе к исторической базе (",GetLastError(),")"); // выводим сообщение об ошибке и...
               break;                                                                // прерываем подсчет ордеров                                                       
            }
         else
                  {
                     info[i][0]=OrderLots();
                     info[i][1]=AccountProfit() + OrderSwap() + OrderCommission();
                     info[i][2]=OrderClosePrice();
                     info[i][3]=OrderOpenPrice();
                  }
      }

Print("Лот = " info[i][0] ,"Профит = " info[i][1], "Цена закрытия = " info[i][2], "Цена открытия = " info[i][3])
В принципе, почти правильно. Но:
1. Перед использованием динамического массива, надо установить размер в 0 измерении, в данном случае он равен количеству исторических ордеров. ArrayResize
2. Желательно инициализировать массив, заполнив его нулями ArrayInitialize
3. Принт надо перенести внутрь цикла.
4. Создать 2 переменных. В одной считать суммарную прибыль, в другой количество только Buy, Sell ордеров. Так как только они могут иметь прибыль. Потом, уже вне цикла, с помощью данных в этих переменных, посчитать и напечатать среднюю прибыль.
 
Последнее редактирование:

gravity

Местный знаток
В принципе, почти правильно. Но:
1. Перед использованием динамического массива, надо установить размер в 0 измерении, в данном случае он равен количеству исторических ордеров. ArrayResize
2. Желательно инициализировать массив, заполнив его нулями ArrayInitialize
3. Принт надо перенести внутрь цикла.
4. Создать 2 переменных. В одной считать суммарную прибыль, в другой количество только Buy, Sell ордеров. Так как только они могут иметь прибыль. Потом, уже вне цикла, с помощью данных в этих переменных, посчитать и напечатать среднюю прибыль.
Вот что-то еще намудрил.
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()

double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл
int tip_ord = OrderType();      // тип ордера
    
double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   for(int i=0;i<total;i++)    // считаем все исторические ордера на счете
      {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) // если ордер не выбран, то...
            {
               Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
               break;                                                                  // прерываем подсчет ордеров                                                           
            }   
         else
                  {
                     info[i][0]=OrderLots();
                     info[i][1]=AccountProfit() + OrderSwap() + OrderCommission();
                     info[i][2]=OrderClosePrice();
                     info[i][3]=OrderOpenPrice();                   
                  }
                                  
                  if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)      // если ордер бай или селл, то...
                     {
                        sum_profit+= AccountProfit() + OrderSwap() + OrderCommission();  // суммируем профит
                        sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
                     }
                  Print("Лот = ", info[i][0] ,"Профит = ", info[i][1], "Цена закрытия = ", info[i][2], "Цена открытия = ", info[i][3])
                  
      }
      Print("Средняя прибыль по всем ордерам = ", sum_profit/sum_buy_sell ) // печатаем среднюю прибыль на 1 ордер

}
 
  • Like
Реакции: Ugar

Ugar

Гуру форума
Вот что-то еще намудрил.
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()

double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл
int tip_ord = OrderType();      // тип ордера
  
double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   for(int i=0;i<total;i++)    // считаем все исторические ордера на счете
      {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) // если ордер не выбран, то...
            {
               Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
               break;                                                                  // прерываем подсчет ордеров                                                         
            } 
         else
                  {
                     info[i][0]=OrderLots();
                     info[i][1]=AccountProfit() + OrderSwap() + OrderCommission();
                     info[i][2]=OrderClosePrice();
                     info[i][3]=OrderOpenPrice();                 
                  }
                                
                  if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)      // если ордер бай или селл, то...
                     {
                        sum_profit+= AccountProfit() + OrderSwap() + OrderCommission();  // суммируем профит
                        sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
                     }
                  Print("Лот = ", info[i][0] ,"Профит = ", info[i][1], "Цена закрытия = ", info[i][2], "Цена открытия = ", info[i][3])
                
      }
      Print("Средняя прибыль по всем ордерам = ", sum_profit/sum_buy_sell ) // печатаем среднюю прибыль на 1 ордер

}
Отлично. Не ошибка, но замечание
Нет смысла считать заново прибыль с учётом свопов и комиссий. Это уже посчитано и внесено в ячейку массива.
Код:
sum_profit+=info[i][1];
 
Последнее редактирование:

Ugar

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

Ugar

Гуру форума
Вот что-то еще намудрил.
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()

double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл
int tip_ord = OrderType();      // тип ордера
   
double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   for(int i=0;i<total;i++)    // считаем все исторические ордера на счете
      {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) // если ордер не выбран, то...
            {
               Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
               break;                                                                  // прерываем подсчет ордеров                                                          
            }  
         else
                  {
                     info[i][0]=OrderLots();
                     info[i][1]=AccountProfit() + OrderSwap() + OrderCommission();
                     info[i][2]=OrderClosePrice();
                     info[i][3]=OrderOpenPrice();                  
                  }
                                 
                  if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)      // если ордер бай или селл, то...
                     {
                        sum_profit+= AccountProfit() + OrderSwap() + OrderCommission();  // суммируем профит
                        sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
                     }
                  Print("Лот = ", info[i][0] ,"Профит = ", info[i][1], "Цена закрытия = ", info[i][2], "Цена открытия = ", info[i][3])
                 
      }
      Print("Средняя прибыль по всем ордерам = ", sum_profit/sum_buy_sell ) // печатаем среднюю прибыль на 1 ордер

}
Только сейчас заметеил
tip_ord = OrderType();
Тип ордера нужно определять для каждого ордера, а значит это должно быть внутри цикла, перебирающего ордера.
 

Ugar

Гуру форума
Здраствуйте Ugar
Вы можете мне помочь

Как выглядит функция для советника
которая закроет все ордера в безубыток от условия что появились открытые ордера и бай и селл.
Это как скрипт Close all но на строку больше
Либо описание неверное, либо не на строчку.
Судя по этому описанию не может быть что это всего на 1 строчку больше.
Вначале цикл считает суммарную прибыль всех ордеров и проверяет что бы были открыты Buy и Sell.
Вне цикла если прибыль положительная и есть открытые Buy и Sell, то запускаем закрытие всех ордеров. А это ещё один цикл в котором закрываются все ордера.
 

gravity

Местный знаток
Только сейчас заметеил
tip_ord = OrderType();
Тип ордера нужно определять для каждого ордера, а значит это должно быть внутри цикла, перебирающего ордера.
Получается эта строчка
int tip_ord = OrderType(); // тип ордера
должна быть {в теле цикла for}?

Сделал так, но выдает ошибки. И да, они и до этого были. Я даже не надеялся, что код может оказаться рабочим:D
336426

Отлично. Не ошибка, но замечание
Нет смысла считать заново прибыль с учётом свопов и комиссий. Это уже посчитано и внесено в ячейку массива.
Код:
sum_profit+=info[i][1];
Я хотел так сделать, но сомневался. Подумал что массив можно записать только в массив.
 

Вложения

  • урок9_Ugar_массивы.mq4
    6,4 КБ · Просмотры: 16

Ugar

Гуру форума
Получается эта строчка
int tip_ord = OrderType(); // тип ордера
должна быть {в теле цикла for}?

Сделал так, но выдает ошибки. И да, они и до этого были. Я даже не надеялся, что код может оказаться рабочим:D
Посмотреть вложение 336426


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

Ugar

Гуру форума
Как выглядит это условие?
У меня уже есть закрытие по проценту прибыли
Хочу добавить закрытие по безубытку как описано выше
void CloseAll()
{
int tot=OrdersTotal();
for(int i=tot-1; i>-1; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue; //проходим по всем открытым сделкам
if(OrderMagicNumber()!=magic) continue;
if(OrderType()>1)
{
int tick2=OrderTicket();
OrderDelete(OrderTicket());
Event("Удаляем отложку "+(string)tick2+". Ошибка "+Error(GetLastError())+". Время "+(string)Hour()+":"+(string)Minute());
}
if(OrderType()<2 && (key2==OrderType() || key3==1))
{
key2=1-key2;
double price=Ask;
if(OrderType()==OP_BUY) price=Bid;
int tick2=OrderTicket();
OrderClose(OrderTicket(),OrderLots(),price,50);
Event("Удаляем рыночный "+(string)tick2+". Ошибка "+Error(GetLastError())+". Время "+(string)Hour()+":"+(string)Minute());
}
OrderCount();
}
return;
}
В этой ветке уже разбирали эти вопросы. Повторяться нет смысла. Может кто то из тех кто обучался и понял подскажет?
 

gravity

Местный знаток
Очень важно научиться искать свои ошибки. На первый раз подскажу. В конце строчек принтов нет ;
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()
int tip_ord;
double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл
   
double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   for(int i=0;i<total;i++)     // считаем все исторические ордера на счете
   {
       if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)                       // если ордер не выбран, то...
       {
           Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
           break;                                                                  // прерываем подсчет ордеров                                                          
       }  
       else                                                                    // если ордер выбран успешно, то...
       {
           info[i][0]=OrderLots();                                             // сохраняем в масив размер лота выбранного ордера
           info[i][1]=OrderProfit() + OrderSwap() + OrderCommission();         // сохраняем в масив прибыль ордера с учетом свопа и комиссии
           info[i][2]=OrderClosePrice();                                       // сохраняем в масив цену закрытия ордера
           info[i][3]=OrderOpenPrice();                                        // сохраняем в масив цену открытия ордера            
     
           tip_ord = OrderType();                                              // записываем тип выбранного ордера
           string order;                                                       // создаём строковую перменую order
                               
           if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)   // если ордер бай или селл, то...
           {
              sum_profit+=info[i][1];                                          // суммируем профит
              sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
         
              if(tip_ord == OP_BUY)                                            // если тип ордера BUY, то...
              {
                 order = "BUY";                                                // присваиемам order = BUY
              }
              else order = "SELL";                                             // если иначе(не BUY), то присваиваем SELL
         
           Print                                                               // записывам в журнал:
               ("Оредр ", order," - ", sum_buy_sell," || ",                    // - тип и номер ордера
               "Лот = ", info[i][0]," || ",                                    // - лот ордера
               "Профит = ", info[i][1]," || ",                                 // - профит ордера
               "Цена закрытия = ", info[i][2]," || ",                          // - цену закрытия ордера
               "Цена открытия = ", info[i][3]);                                // - цену открытия ордера
            }

       }
                 
   }
Print("Средняя прибыль по всем ордерам = ", NormalizeDouble(sum_profit/sum_buy_sell, 2) ); // печатаем среднюю прибыль на 1 ордер

}
Немного дополнил код. Сейчас выводит ещё и тип ордера в журнале, задается номер.
Но почему-то иногда выводятся лот или прибыль с большим количеством знаков после запятой. Попробовал применить NormalizeDouble, но не помогло.

336469

Пару вопросов по массивам:
1) ArrayResize должен использоваться всегда, когда присутствует динамический массив[ ]?
2) ArrayInitialize это то же самое, что задавать изначально переменным значение=0,и тоже всегда должен присутствовать при использовании массива?
 

Ugar

Гуру форума
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()
int tip_ord;
double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл
  
double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   for(int i=0;i<total;i++)     // считаем все исторические ордера на счете
   {
       if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)                       // если ордер не выбран, то...
       {
           Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
           break;                                                                  // прерываем подсчет ордеров                                                         
       } 
       else                                                                    // если ордер выбран успешно, то...
       {
           info[i][0]=OrderLots();                                             // сохраняем в масив размер лота выбранного ордера
           info[i][1]=OrderProfit() + OrderSwap() + OrderCommission();         // сохраняем в масив прибыль ордера с учетом свопа и комиссии
           info[i][2]=OrderClosePrice();                                       // сохраняем в масив цену закрытия ордера
           info[i][3]=OrderOpenPrice();                                        // сохраняем в масив цену открытия ордера           
    
           tip_ord = OrderType();                                              // записываем тип выбранного ордера
           string order;                                                       // создаём строковую перменую order
                              
           if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)   // если ордер бай или селл, то...
           {
              sum_profit+=info[i][1];                                          // суммируем профит
              sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
        
              if(tip_ord == OP_BUY)                                            // если тип ордера BUY, то...
              {
                 order = "BUY";                                                // присваиемам order = BUY
              }
              else order = "SELL";                                             // если иначе(не BUY), то присваиваем SELL
        
           Print                                                               // записывам в журнал:
               ("Оредр ", order," - ", sum_buy_sell," || ",                    // - тип и номер ордера
               "Лот = ", info[i][0]," || ",                                    // - лот ордера
               "Профит = ", info[i][1]," || ",                                 // - профит ордера
               "Цена закрытия = ", info[i][2]," || ",                          // - цену закрытия ордера
               "Цена открытия = ", info[i][3]);                                // - цену открытия ордера
            }

       }
                
   }
Print("Средняя прибыль по всем ордерам = ", NormalizeDouble(sum_profit/sum_buy_sell, 2) ); // печатаем среднюю прибыль на 1 ордер

}
Немного дополнил код. Сейчас выводит ещё и тип ордера в журнале, задается номер.
Но почему-то иногда выводятся лот или прибыль с большим количеством знаков после запятой. Попробовал применить NormalizeDouble, но не помогло.

Посмотреть вложение 336469

Пару вопросов по массивам:
1) ArrayResize должен использоваться всегда, когда присутствует динамический массив[ ]?
2) ArrayInitialize это то же самое, что задавать изначально переменным значение=0,и тоже всегда должен присутствовать при использовании массива?
Погрешности вычисления и хранения дробных чисел обычное дело. Для преобразования дробного числа в текст, есть функция DoubleToString, Аргументы как у NormalizeDouble.
Любому массиву нужен размер. Статическому массиву он задаётся при объявлении. Динамическому он может задаваться автоматически, например если массив является буфером индикатора, или надо его задать ArrayResize().
Так же как и в переменных, если все ячейки заполняются присвоением и по другому не может быть, инициализировать не обязательно. В данном примере это можно было не делать, если при выполнении кода не будет ошибок. Всего предусмотреть сложно, по этому лучше инициализировать. Буфера индикаторов инициализировать не надо, они сами инициализируются.
 

MrGreen86

Гуру форума
сразу себе возьмите за правило считать ордера с конца. и запоминать номер последнего
C++:
int last_ticket = -1;
for(int i=OrdersTotal()-1;i>=0;i--) {
   if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES) continue;
   if(last_ticket==OrderTicket()) continue;
   last_ticket = OrderTicket();
}
почему с конца?
если в момент выполнения скрипта какой либо советник закроет ордер из списка или ордер закроется брокером, то вы рискуете пропустить один ордер из расчета.
Например ордеров 5, их номера 0 1 2 3 4.
Ваш цикл считает ордер 2, в этот момент закрылся ордер 0 1 или 2. Индексы ордеров выше сместились. А ваш скрипт после подсчета ордера 2 перейдет к ордеру 3. Но так как индексы сместились, то ордер 3 (по старому варианту) будет пропущен.
вот так более наглядно, одни и те же ордера выделены одним цветом.
сверху первый порядок, снизу второй порядок после закрытия ордера 2.
0 1 2 3 4 5
0 1 2 3 4

как видите ордер 3 стал ордером 2, и вы его успешно пропустили.

почему нужно проверять последний ордер?
если мы считаем с конца, то ситуация обратная. посчитали ордер номер 5, собираемся считать ордер номер 4. Но какой либо из ордеров 0-4 был закрыт. индексы смещаются и когда мы начинаем считать ордер 4, мы снова натыкаемся на тот же самый ордер, который ранее имел индекс 5.
Это не проблема если ваш советник только фиксирует наличие ордера, делает ему без убыток и тралл. Можно и не учитывать. ну проверит дважды условия трала, не страшно.
А вот когда вы считаете среднюю цену, что вы и делаете, это критично. Расчет будет ошибочным.

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

По массиву и ArrayResize. Старайтесь не забывать про третий параметр этой функции. Он резервирует место в памяти на будущее, если вдруг понадобиться больше места.
ArrayResize(info,total,100);
Так как постоянное использование просто ArrayResize(info,total) отнимает очень много ресурсов. В отдельных случаях это тормозит скорость тестирования советника в десятки раз.
В рамках вашего скрипта это роли не играет, так как у вас только один ArryaResize.
 

gravity

Местный знаток
сразу себе возьмите за правило считать ордера с конца. и запоминать номер последнего
C++:
int last_ticket = -1;
for(int i=OrdersTotal()-1;i>=0;i--) {
   if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES) continue;
   if(last_ticket==OrderTicket()) continue;
   last_ticket = OrderTicket();
}
почему с конца?
если в момент выполнения скрипта какой либо советник закроет ордер из списка или ордер закроется брокером, то вы рискуете пропустить один ордер из расчета.
Например ордеров 5, их номера 0 1 2 3 4.
Ваш цикл считает ордер 2, в этот момент закрылся ордер 0 1 или 2. Индексы ордеров выше сместились. А ваш скрипт после подсчета ордера 2 перейдет к ордеру 3. Но так как индексы сместились, то ордер 3 (по старому варианту) будет пропущен.
вот так более наглядно, одни и те же ордера выделены одним цветом.
сверху первый порядок, снизу второй порядок после закрытия ордера 2.
0 1 2 3 4 5
0 1 2 3 4

как видите ордер 3 стал ордером 2, и вы его успешно пропустили.

почему нужно проверять последний ордер?
если мы считаем с конца, то ситуация обратная. посчитали ордер номер 5, собираемся считать ордер номер 4. Но какой либо из ордеров 0-4 был закрыт. индексы смещаются и когда мы начинаем считать ордер 4, мы снова натыкаемся на тот же самый ордер, который ранее имел индекс 5.
Это не проблема если ваш советник только фиксирует наличие ордера, делает ему без убыток и тралл. Можно и не учитывать. ну проверит дважды условия трала, не страшно.
А вот когда вы считаете среднюю цену, что вы и делаете, это критично. Расчет будет ошибочным.

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

По массиву и ArrayResize. Старайтесь не забывать про третий параметр этой функции. Он резервирует место в памяти на будущее, если вдруг понадобиться больше места.
ArrayResize(info,total,100);
Так как постоянное использование просто ArrayResize(info,total) отнимает очень много ресурсов. В отдельных случаях это тормозит скорость тестирования советника в десятки раз.
В рамках вашего скрипта это роли не играет, так как у вас только один ArryaResize.

C внесением рекомендации. Добавил DoubleToString в принтах. Вывод тикета ордера.
C++:
#property strict

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
// Напишите скрипт, который запишет в двухмерный массив цены открытия, цены закрытия, лоты,
// прибыль в валюте депозита с учётом свопов и комиссий, всех исторических ордеров счёта.
// После этого, напечатает в лог всё что в массиве. Построчно. Каждый ордер в отдельной строке.
// В конце напечатает среднюю прибыль в валюте депозита по всем ордерам.
{
int total=OrdersHistoryTotal(); // присваиваем total значение OrdersHistoryTotal()
int tip_ord;
double sum_profit = 0;          // суммарный профит бай селл
int sum_buy_sell  = 0;          // сумма ордеров бай селл

double info[][4];               // инициализируем двухмерный динамический массив
ArrayResize(info,total);        // устанавливаем размер(total)в первом измерении массива info[][4];
ArrayInitialize(info,0);        // заполняем значения массива info[][4]; нулями

   //for(int i=0;i<total;i++)   // считаем все исторические ордера на счете, начиная с первого отложенного(открытого)
   for(int i=total-1;i>=0;i--)  // считаем все ист.ордера на счете, начиная с последнего отложенного(открытого)
   {
       if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)                       // если ордер не выбран, то...
       {
           Print("Ошибка при доступе к исторической базе (",GetLastError(),")");   // выводим сообщение об ошибке и...
           break;                                                                  // прерываем подсчет ордеров                                                       
       }
       else                                                                    // если ордер выбран успешно, то...
       {
      
           int last_ticket=-1;                                                 // создаем переменную со значением (-1)
           if(last_ticket==OrderTicket()) continue;                            // если что-то пошло ни так, переходим в начало цикла for
           last_ticket   = OrderTicket();                                      // записываем последний выбранный ордер
        
           info[i][0]=OrderLots();                                             // сохраняем в масив размер лота выбранного ордера
           info[i][1]=OrderProfit() + OrderSwap() + OrderCommission();         // сохраняем в масив прибыль ордера с учетом свопа и комиссии
           info[i][2]=OrderClosePrice();                                       // сохраняем в масив цену закрытия ордера
           info[i][3]=OrderOpenPrice();                                        // сохраняем в масив цену открытия ордера         
  
           tip_ord = OrderType();                                              // записываем тип выбранного ордера
           string order;                                                       // создаём строковую перменую order
                            
           if(tip_ord <=1)       //(tip_ord == OP_BUY || tip_ord == OP_SELL)   // если ордер бай или селл, то...
           {
              sum_profit+=info[i][1];                                          // суммируем профит
              sum_buy_sell++;                                                  // считаем общее количество ордеров бай, селл
          
              if(tip_ord == OP_BUY)                                            // если тип ордера BUY, то...
              {
                 order = "BUY";                                                // присваиемам order = BUY
              }
              else order = "SELL";                                             // если иначе(не BUY), то присваиваем SELL
      
           Print                                                               // записывам в журнал:
               ("Оредр ", order," - ", sum_buy_sell,                   " || ", // - тип и номер ордера
               "Лот = ", DoubleToString((info[i][0]),2),               " || ", // - лот ордера
               "Профит = ", DoubleToString((info[i][1]),2),            " || ", // - профит ордера
               "Цена закрытия = ", DoubleToString((info[i][2]),Digits)," || ", // - цену закрытия ордера
               "Цена открытия = ", DoubleToString((info[i][3]),Digits)," || ", // - цену открытия ордера
               "Тикет - ",last_ticket);                                        // - тикет ордера
           }

       }
              
   }
Print("Средняя прибыль по всем ордерам = ", DoubleToString(sum_profit/sum_buy_sell, 2) ); // печатаем среднюю прибыль на 1 ордер

}
Вопросы.
1) А в принте перенос строки никак не сделать?
Кроме как каждое значение выводить отдельным принтом.
2) И так и не понял, зачем в ArrayResize указывать 3й параметр, он что ускорит работу?
3) Если я скрываю историю счета, то почему то не выдает этот принт.
Print("Ошибка при доступе к исторической базе (",GetLastError(),")");
А вроде должен.
 
Последнее редактирование:

Ugar

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

Ugar

Гуру форума
По массиву и ArrayResize. Старайтесь не забывать про третий параметр этой функции. Он резервирует место в памяти на будущее, если вдруг понадобиться больше места.
ArrayResize(info,total,100);
Так как постоянное использование просто ArrayResize(info,total) отнимает очень много ресурсов. В отдельных случаях это тормозит скорость тестирования советника в десятки раз.
В рамках вашего скрипта это роли не играет, так как у вас только один ArryaResize.
А эту функцию уже исправили? Когда то столкнулся с проблемой что через несколько вызовов функция просто переставала менять размер. И глючила только если задан резерв. Убрал резерв и всё стало стабильно работать. С этим сталкивался давно, но как показывает практика, исправлений можно ждать годами и не дождаться.
 

gravity

Местный знаток
отлично.Тому кто поможет подарю советника с доходностью 100% в месяц
Вот, попытался.
Код:
#property strict

//Закрыть все ордера в безубыток от условия что появились открытые ордера и бай и селл.
//Это как скрипт Close all но на строку больше

//Вначале цикл считает суммарную прибыль всех ордеров и проверяет что бы были открыты Buy и Sell.
//Вне цикла если прибыль положительная и есть открытые Buy и Sell, то запускаем закрытие всех ордеров.
//А это ещё один цикл в котором закрываются все ордера.


//+------------------------------------------------------------------+
// Входные параметры советника                                       |
//+------------------------------------------------------------------+

input double  BU       = 1;     // Безубыток в валюте депозита
input int     Magic    = 777;   // Магик 
input int     Slippage = 3;     // Проскальзывание
//+------------------------------------------------------------------+
double ima1,ima2;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
 
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
{

//+------------------------------------------------------------------+
// Условия открытия ордеров для проверки работы Безубытка            |
//+------------------------------------------------------------------+

   ima1 = iMA ( Symbol(), 0, 89, 0, 1, 0,1 );  // 89
   ima2 = iMA ( Symbol(), 0, 233, 0, 1, 0,1 );  // 233
  
   if(ima1>ima2 && CountBay()<=1) // если 89>233 и оредров меньше 2х
   {
      int ticket = OrderSend(Symbol(), OP_BUY, 0.01, Ask, 0, 0, 0, "Покупка", Magic, 0, Blue);//открываем BAY
   }
   if(ima1<ima2 && CountSell()<5) // если 89<233 и ордеров меньше 5и
   {
      int ticket = OrderSend(Symbol(), OP_SELL, 0.05, Bid, 0, 0, 0, "Продажа", Magic, 0, Red);//открываем SELL
   }
  
//+------------------------------------------------------------------+
// Основная часть                                                    |
//+------------------------------------------------------------------+

      if (CountBay()!=0 && CountSell()!=0)  // если есть открытые ордера бай и селл...
      {

          if (CalculateProfit() >= BU)      // и общий профит ордеров >= безубытка, в валюте депозита то...
          {
             CloseAll();                    // закрываем все рыночные ордера
          }
    
      }
}

//+------------------------------------------------------------------+
// Считаем количество BUY                                            |
//+------------------------------------------------------------------+

int CountBay()
{
   int count = 0;
   for (int i = OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS))
         {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_BUY)
            count++;
         }
   } return(count);
}

//+------------------------------------------------------------------+
// Считаем количество SELL                                           |
//+------------------------------------------------------------------+

int CountSell()
{
   int count = 0;
   for (int i = OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS))
         {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_SELL)
            count++;
         }
   } return(count);
}

//+------------------------------------------------------------------+
// Суммарный профит ордеров BUY  и SELL                              |
//+------------------------------------------------------------------+

double CalculateProfit()
{
   double oProfit = 0;
   for (int i=OrdersTotal()-1; i>=0; i--)
   {
      if (OrderSelect(i, SELECT_BY_POS))
      {
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)
         {
            if (OrderType() == OP_BUY || OrderType() == OP_SELL)
            {
               oProfit += OrderProfit() + OrderSwap() + OrderCommission();  // суммируем профиты всех открытых ордеров
            }
         }
      }
   } return(oProfit);
}

//+------------------------------------------------------------------+
// Закрываем все рыночные ордера                                     |
//+------------------------------------------------------------------+

void CloseAll()
{
   for (int i = OrdersTotal()-1; i>=0; i--)
   {
      if (OrderSelect(i, SELECT_BY_POS))
      {
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)
         {
            if (OrderType() == OP_BUY)                                      // если бай, то закрываем по Бид
            {
               if(!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage))
                  Print ("Не удалось открыть ордер на покупку");
                  else Print ("Закрытие по БУ Бай");
            }
            if (OrderType() == OP_SELL)                                    // если селл, то закрываем по Аск
            {
               if(!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage))  // проверяем, выполнена ли функция закрытия ордеров
                  Print ("Не удалось открыть ордер на продажу");
                  else Print ("Закрытие по БУ Селл");
            }
         }
      }
   }
}

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

Thebuzzard

Интересующийся
Выдает ошибку при компиляции
Вы пишите на mql4 или 5 ?
 

Вложения

  • BUCLOSE.mq4
    10,8 КБ · Просмотры: 11
Верх