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

gravity

Местный знаток
Попробуйте брать остаток от деления на 100.
И код решения покажите в Спойлере.
Кажется так.
PHP:
Expand Collapse Copy
void OnStart()  // Событие Start – это специальное событие для активизации скрипта после его загрузки. Это событие обрабатывается функцией OnStart.
  {             // Должна иметь тип void, параметров не имеет:
//---
   int i;                  // объявляем целый тип числа и присваиваем ему имя i

for(i=1; i<=1000; i++)     // объявляем оператор цикла for (выражение1;выражение2;выражение3)
                           // i=1, пока i больше или равно 1000 - будет выполнятся тело цикла фор заключенное в {},
                           // i++ означает что прибавляем единицу к i=1 после каждой итерации(повторения действия)
   {
   if(i%2==1 || i%100==44) Print(i);
   }
  }
//+------------------------------------------------------------------+
 

BorisSedov

Активный участник
Следующая задача немного ближе к рынку.
Напишите скрипт который вычисляет среднюю цену за всю историю на графике. Но нужно соблюдать два условия.
  • Учитываются только закрытые бары.
  • Учитываем только бары у которых цена закрытия больше чем цена открытия.
Бары не подходящие по условиям не учитываем в расчетах (игнорируем).
Результат вычисления вывести при помощи функции Print.
 

BorisSedov

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

C++:
Expand Collapse Copy
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
int i,n=0;
double price=0;

for(i=Bars-1; i>0; i--)
   {
   if(Close[i]>Open[i])
      {
      price+=Close[i];
      n++;
      }
   }

if(n>0) price/=n;

Print(DoubleToStr(price,Digits));
}
//+------------------------------------------------------------------+
 

gravity

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

1) Почему объявленным переменным присваиваем значение=0?
2) Вот эта строчка price+=Close. Как я понимаю, означает что price=price+Close
В первом случае price станет равным цене закрытия. А дальше, почему цены закрытия плюсовать между собой?
3) Во втором if, пока бары не закончились в истории, price/=n;
Тоесть price=price/n
Например для 5го бара будет(при условии, что они оба соответствуют условию в If) Close[4]+Close[5] = (Close[4]+Close[5])/5
4)
А принт начнет работать только тогда, когда окажется что в последнем if не будет соблюдено условие (n>0)?

Лучше как для первоклашки, разложи всё по полочкам, если время есть:rolleyes::)
 
Последнее редактирование:

gravity

Местный знаток
4) А принт начнет работать только тогда, когда окажется что в последнем if не будет соблюдено условие (n>0)?

Лучше как для первоклашки, разложи всё по полочкам, если время есть:rolleyes::)
4й вопрос снимается, так и есть.335075

Кажется и остальное понял.
Получается плюсуюем цены закрытия баров подходящих по условию и делим на их количество. В итоге получаем среднюю цену закрытия этих баров.
В самом конце будет вычеслена средняя цена закрытия всех баров в истории подходящих условиям и так как условие последнего if (n>0) , не будет саблюдено. Print напечатает нам результат в журнал.

Открытым остался 1-й вопрос.
 
Последнее редактирование:

Ugar

Гуру форума
1) Почему объявленным переменным присваиваем значение=0?
При объявлении переменной компьютер выделяет для неё кусочек памаяти. Но в ячейках может что то храниться, мусор от прошлых выполненных задач. Соответственно если после объявления нет чёткого присвоения, переменную надо инициализировать.
Например
int a;
a=x+y;
Здесь нормально. Какой бы мусор не был в переменной, после выполнения присвоения a=x+y; в ней то что надо.

А вот так нельзя.
int a;
a++;
Объявили переменную, в ней мусор, потом наращиваем этот мусор на 1. Обязательно надо перед наращиванием инициализировать. Так нормально
int a=0;
a++;
 

BorisSedov

Активный участник
При объявлении переменной компьютер выделяет для неё кусочек памяти.
Верно сказано.

Почему так происходит?
Объявляя переменную, мы придумываем для нее имя. Это имя, считайте адресом, как адрес e-mail, только вместо писем, по этому адресу хранятся данные (10111001) в памяти. Если при объявлении мы не присвоили значение переменной, то эти данные остаются такими же, которые были до объявления переменной (10111001). А если присвоили переменной значение 0, то данные по этому адресу обнуляются (00000000). А придумано это для ускорения работы MQL4 программ, так как на записывание нулей тратится какое-то время. Таким образом, объявляя переменную, мы сами решаем, нужно нам обнулить её или нет.

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

Прокомментирую работу скрипта для лучшего понимания.

C++:
Expand Collapse Copy
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
int i,n=0; // Объявлены переменные, i и n, переменной n сразу же присвоено значение 0.
double price=0; // Объявлена переменная для вычисления средней цены, ей также присвоено значение 0.

for(i=Bars-1; i>0; i--)// Сразу присвоено значение Bars-1 переменной i. После этого проверено условие что i>0,
   {                   // если это так, то выполняется один раз все, что написано внутри тела цикла с 13 по 17 строку включительно.
   if(Close[i]>Open[i]) // Это условие (Close[i]>Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                 // Как только условие (i>0) не будет выполнено, сразу же выполнение цикла прерывается, и начинается выполнение программы от 19 строки включительно.
      price+=Close[i];  // В этом условии проверяется что Close[i]>Open[i], если это так, то выполняется тело условия с 15 по 16 строку включительно.
      n++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих цен.
      }                 // После 17 строки, независимо от условия 13 строки, сначала уменьшается значение i на 1 (i--), а далее проверяется снова условие что i>0,
   }                    // Если это условие (условие цикла) соблюдается, то цикл повторяется.

if(n>0) price/=n; // У нас же может быть график на котором нет подходящих цен, по этому количество n может быть равно 0, а делить на 0 нельзя.
                  // Деление на 0 приведет к ошибке в программе. Чтобы не делить на 0, мы перед деление сначала проверяем что n>0, а только после этого делим.

Print(DoubleToStr(price,Digits)); // Выводится результат. Этот результат выводится всегда, даже если не отработает цикл - будет просто 0.00000 в этом случае.
}
//+------------------------------------------------------------------+
 
Последнее редактирование:

Ugar

Гуру форума
Любая программа выполнятся также, как мы читаем текст в книге, слово за словом, строка за строкой.
Это не совсем так. Читаем мы всегда по порядку, а программа выполняет операторы в порядке приоритета.
2+2*2=6, а не 8.
Кроме того. В новом языке не уверен, но в старом метаквоты утверждали что в операторе if при выполнении равных по приоритету, порядок как написано не гарантировался.
Например в if(a==b && b>c && d<e) неизвестно в каком порядке будут выполняться сравнения, не факт что как написано.
 

BorisSedov

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

BorisSedov

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

DomovenokBrest

♔♕♖♗♘♙
Для закрепления материала, предлагаю решить новую задачу.
Нужно написать скрипт который определяет каких баров на графике больше,
с ценой закрытия которая больше чем цена открытия
или
с ценой закрытия которая меньше чем цена открытия.
Результат вывести словом Up – если баров закрытых вверх больше, или Down – если баров закрытых вниз больше.
Если Вы не против, присоединюсь к Вам. Я изучал язык разбирая программы сторонних программистов. Замечаю у себя массу пробелов в знаниях теории. Значит нужно вернуться назад и восполнить пробел.
Код:
Expand Collapse Copy
void OnStart()
// Нужно написать скрипт который определяет каких баров на графике больше,
// с ценой закрытия которая больше чем цена открытия
// или
// с ценой закрытия которая меньше чем цена открытия.
// Результат вывести словом Up – если баров закрытых вверх больше, или Down – если баров закрытых вниз больше.
// Рассматриваем только закрытые бары.
{
int i, n=0, m=0;        // Объявлены переменные, i и n и m, переменной n и m сразу же присвоено значение 0.

for(i=Bars-1; i>0; i--) // Сразу присвоено значение Bars-1 переменной i. После этого проверено условие что i>0,
   {                    // если это так, то выполняется один раз все, что написано внутри тела цикла.
   if(Close[i]>Open[i]) // Это условие (Close[i]>Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                
      n++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }                
 
   if(Close[i]<Open[i]) // Это условие (Close[i]<Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                
      m++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }  
   }                  
if (n>m)               // если баров с условием (Close[i]>Open[i]) больше, чем баров с условием (Close[i]<Open[i]), то
Print("Up");           // Выводится результат.
if (n<m)               // если баров с условием (Close[i]>Open[i]) меньше, чем баров с условием (Close[i]<Open[i]), то
Print("Down");         // Выводится результат.

}
 
Последнее редактирование:

BorisSedov

Активный участник
Если Вы не против, присоединюсь к Вам. Я изучал язык разбирая программы сторонних программистов. Замечаю у себя массу пробелов в знаниях теории. Значит нужно вернуться назад и восполнить пробел.
Мы будем только рады вашему участию в этой теме. :)
Задача решена правильно.

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

Ugar

Гуру форума
Если Вы не против, присоединюсь к Вам. Я изучал язык разбирая программы сторонних программистов. Замечаю у себя массу пробелов в знаниях теории. Значит нужно вернуться назад и восполнить пробел.
Код:
Expand Collapse Copy
void OnStart()
// Нужно написать скрипт который определяет каких баров на графике больше,
// с ценой закрытия которая больше чем цена открытия
// или
// с ценой закрытия которая меньше чем цена открытия.
// Результат вывести словом Up – если баров закрытых вверх больше, или Down – если баров закрытых вниз больше.
// Рассматриваем только закрытые бары.
{
int i, n=0, m=0;        // Объявлены переменные, i и n и m, переменной n и m сразу же присвоено значение 0.

for(i=Bars-1; i>0; i--) // Сразу присвоено значение Bars-1 переменной i. После этого проверено условие что i>0,
   {                    // если это так, то выполняется один раз все, что написано внутри тела цикла.
   if(Close[i]>Open[i]) // Это условие (Close[i]>Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {               
      n++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }               

   if(Close[i]<Open[i]) // Это условие (Close[i]<Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {               
      m++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      } 
   }                 
if (n>m)               // если баров с условием (Close[i]>Open[i]) больше, чем баров с условием (Close[i]<Open[i]), то
Print("Up");           // Выводится результат.
if (n<m)               // если баров с условием (Close[i]>Open[i]) меньше, чем баров с условием (Close[i]<Open[i]), то
Print("Down");         // Выводится результат.

}
При сравнении цен не учтены погрешности double.
 

DomovenokBrest

♔♕♖♗♘♙
Мы будем только рады вашему участию в этой теме. :)
Задача решена правильно.

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


С поправками вводных

Код:
Expand Collapse Copy
void OnStart()
// Нужно написать скрипт который определяет каких баров на графике больше,
// с ценой закрытия которая больше чем цена открытия
// или
// с ценой закрытия которая меньше чем цена открытия.
// Результат вывести словом Up – если баров закрытых вверх больше, или Down – если баров закрытых вниз больше.
// Рассматриваем только закрытые бары.
// Какой получится результат, в случае, если баров закрытых вверх или вниз будет поровну? 
// При сравнении цен учесть погрешности double. 
{
int i;
double n=0.0, m=0.0;        // Объявлены переменные, i и n и m, переменной n и m сразу же присвоено значение 0.

for(i=Bars-1; i>0; i--) // Сразу присвоено значение Bars-1 переменной i. После этого проверено условие что i>0,
   {                    // если это так, то выполняется один раз все, что написано внутри тела цикла.
   if(Close[i]>Open[i]) // Это условие (Close[i]>Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                
      n++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }                
 
   if(Close[i]<Open[i]) // Это условие (Close[i]<Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                
      m++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }  
   }                  
if (n>m)               // если баров с условием (Close[i]>Open[i]) больше, чем баров с условием (Close[i]<Open[i]), то
Print("Up");           // Выводится результат.
if (n<m)               // если баров с условием (Close[i]>Open[i]) меньше, чем баров с условием (Close[i]<Open[i]), то
Print("Down");         // Выводится результат.
if (n==m)               // если баров с условием (Close[i]>Open[i]) равно  барам с условием (Close[i]<Open[i]), то
Print("Even");         // Выводится результат.

}
 

BorisSedov

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

BorisSedov

Активный участник
С поправками вводных
Переменные n и m должны оставаться типа int, мы же просто считаем количество, а количество это целое.
Комментировать код так подробно не обязательно.
А в целом все отлично.
 

DomovenokBrest

♔♕♖♗♘♙
Переменные n и m должны оставаться типа int, мы же просто считаем количество, а количество это целое.
Комментировать код так подробно не обязательно.
А в целом все отлично.
Да, а запостил, просмотрел пост, увидел и у себя поправил. Плюс вывел разницу большей переменной. Всегда ведь интересно кого на рынке больше :)

Код:
Expand Collapse Copy
void OnStart()
// Нужно написать скрипт который определяет каких баров на графике больше,
// с ценой закрытия которая больше чем цена открытия
// или
// с ценой закрытия которая меньше чем цена открытия.
// Результат вывести словом Up – если баров закрытых вверх больше, или Down – если баров закрытых вниз больше.
// Рассматриваем только закрытые бары.
// Какой получится результат, в случае, если баров закрытых вверх или вниз будет поровну?
// При сравнении цен учесть погрешности double.
{
int i, a=0;
int n=0.0, m=0.0;        // Объявлены переменные, i, a, n, m, переменной a, n и m сразу же присвоено значение 0.

for(i=Bars-1; i>0; i--) // Сразу присвоено значение Bars-1 переменной i. После этого проверено условие что i>0,
   {                    // если это так, то выполняется один раз все, что написано внутри тела цикла.
   if(Close[i]>Open[i]) // Это условие (Close[i]>Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                 
      n++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }                 
  
   if(Close[i]<Open[i]) // Это условие (Close[i]<Open[i]) расположено как раз в теле цикла, и оно выполняется только если выше будет соблюдаться условие i>0,
      {                 
      m++;              // В теле условия суммируются все подходящие цены закрытия и подсчитывается количество подходящих баров.
      }   
   }                   
if (n>m)               // если баров с условием (Close[i]>Open[i]) больше, чем баров с условием (Close[i]<Open[i]), то
      {
       a=n-m;
       Print("Up","-", a);  // Выводится результат.
      }               

if (n<m)               // если баров с условием (Close[i]>Open[i]) меньше, чем баров с условием (Close[i]<Open[i]), то
      {
       a=m-n;
       Print("Down","-", a);  // Выводится результат.
      }   

if (n==m)               // если баров с условием (Close[i]>Open[i]) равно  барам с условием (Close[i]<Open[i]), то
Print("Even","-",n,"-", m);  // Выводится результат.

}
 

BorisSedov

Активный участник
Исследование завершено.
Что мы имеем?
На графике 100 000 баров, скрипт проверяет расхождения при сравнении с нормализацией цен, и без нормализации.
В результате не было выявлено не одного случая с ошибками связанными с типом double при сравнении.
Практика также показывает, что при сравнении цен Open[], High[], Low[], Close[] в неизменном виде, нормализацию делать не обязательно. Цены в этих массивах уже нормализованы. Но если цену изменить, прибавив или отняв какое то количество пунктов, то в этом случае обязательно нужно делать нормализацию чтобы исключить возможные ошибки.

C++:
Expand Collapse Copy
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
int i,total,n=0;

total=Bars;

for(i=total-1; i>0; i--)
   {
   if((Open[i]!=Close[i] && NormalizeDouble(Open[i],Digits)==NormalizeDouble(Close[i],Digits)) ||
      (High[i]!=Close[i] && NormalizeDouble(High[i],Digits)==NormalizeDouble(Close[i],Digits)) ||
      (Low[i]!=Close[i] && NormalizeDouble(Low[i],Digits)==NormalizeDouble(Close[i],Digits)) ||
      (High[i]!=Open[i] && NormalizeDouble(High[i],Digits)==NormalizeDouble(Open[i],Digits)) ||
      (Low[i]!=Open[i] && NormalizeDouble(Low[i],Digits)==NormalizeDouble(Open[i],Digits))) n++;
   }

Print("Количество баров: ",total);
Print("Количество ошибок: ",n);
}
//+------------------------------------------------------------------+
 
Последнее редактирование:
Верх