Содержание
Здравствуйте! На прошлом уроке мы изучили важную и обязательную тему: Условные операторы. Без них я не представляю работу на языке MQL4. Сегодня мы разберемся, что такое цикл for, и зачем он нужен.
Если простым языком цикл — это последовательный перебор вводных параметров до момента его остановки, либо полного завершения. В уроке 1.4 Массивы мы разбирали массивы и говорили, что они могут содержать в себе огромное количество данный, чтобы вывести результат массива в принт приходилось его прописывать отдельно для каждого значения. С помощью цикла можно пробежаться по всему массиву сразу и выполнить необходимые вычисления.
Где используется цикл: пользовательские массивы, массивы тайм-сессии, когда вам нужно получить значения N свечей и вы перебором проходите по каждой. Ордера — невозможно работать с группой ордеров, не выявив их свойств через цикл, будь то поиск самого последнего ордера, самого прибыльного или максимально удаленного от цены. Подсчет прибыли или убытка за какой-либо период — цикл, количество ордеров в рынке по текущей паре — цикл, удаление графических объектов с графика или закрытие нескольких графиков — тоже цикл. Как видите, перебор значений часто используемая функция в программном коде. Рассмотрим оператор цикла for, который справится с этой задачей:
Оператор цикла for
Оператор состоит непосредственно из самого оператора (слова for) и трех выражений в круглых скобках, разделенных знаком точка с запятой.
0 |
for(int i=0;i<10;i++) |
Первое выражение инициализирует цикл целой переменной int i. В данном примере указано, что цикл начинается с нуля, i =0. Второе выражение является проверкой условия для завершения цикла, т.е. когда значение i дойдет до 10 — цикл будет прерван. Третье выражение является вычислением после каждой итерации, т.е. после того момента когда пройдут все строки тела цикла. Происходит арифметическая операция, которая прибавляет к текущему значению i единицу. Данный цикл будет повторяться 10 раз, потому что начинается он с нуля и будет повторяться, пока i не станет равной 10, т.е. полный цикл идет включая i=9. Если в теле цикла более одной переменной или функции, несколько строк, то его необходимо выделять фигурными скобками.
Проверим, как он работает на практике, добавим в тело цикла Print:
0 |
for(int i=0;i<10;i++) Print("i: ",i); |
Результатом будет 10 строчек принта в журнале со значениями переменной i.
Стоит заметить, что объявлять переменную i можно до оператора for, если в этом есть необходимость. Тут же после окончания цикла эта переменная больше не нужна, поэтому после него она просто сотрется из памяти. Переменную можно называть как угодно, просто уже исторически сложилось, что по умолчанию она равна i. Если я использую много циклов в коде, либо цикл в цикле, я использую разнообразные буквы: i, k, n, m и т.д., так проще и понятнее, чем давать им длинные названия.
Шаг, указываемый во третьем выражении может быть любым, давайте попробуем установить его равным двум, тогда результатом будут значения i: 0, 2, 4, 6, 8.
0 1 2 |
for(int i=0;i<10;i+=2) { Print("i: ",i); } |
Мы рассмотрели цикл for, в котором итерации идут в сторону увеличения объявленной переменной. Хорошо бы попробовать прогнать цикл в другую сторону. В следующем примере отсчет пойдет от 6 и будет идти пока i не станет равной 0, т.е. шесть раз. Шаг единица, i = i-1. Проверьте через принт.
0 1 2 |
for(int i=6;i>0;i--) { Print("i: ",i); } |
Теперь давайте выполним математическое действие в цикле, умножим переменную на 2 шесть раз подряд:
0 1 2 3 4 |
int a1 = 2; for(int i=0;i<5;i++) { a1 *= 2; } Print(a1); //результат 64 |
Мы объявили переменную a1 до цикла for, она была равна двум, после прохождения цикла ее значение изменилось на 64.
Теперь узнаем самую высокую точку High в цикле из 20 последних свечей, начиная с первой закрытой, заканчивая второе выражение после числа 20, чтобы получилось именно двадцать итераций:
0 1 2 3 4 |
double Highest = 0; for(int i=1;i<=20;i++) { if(High[i] > Highest) Highest = High[i]; } Print(Highest); |
Вначале мы задали переменную Highest типа double, чтобы в итоге она получила самую высокую точку high. Т.к. данные о ценах свечей хранятся в массивах-таймсессии, где 0 это еще открытая свеча, то цикл начинается с первой закрытой свечи и значение i выставляется в квадратных скобках массива, что в нашем случае как раз и будет номер свечей с первой по двадцатую. С помощью условного оператора if проверяется условие — если текущий high заданной свечи больше, чем уже сохраненное значение Highest, то оно переписывается на новое. В итоге через принт вы сможете увидеть результат.
Теперь посчитаем сколько на графике отдельно бычьих и медвежьих свечей:
0 1 2 3 4 5 |
int bear = 0, bull = 0; for(int i=1;i<=50;i++) { if(Open[i] > Close[i]) bear++; else bull++; } Print("Бычьих свечей: ",bull,", медвежьих свечей: ",bear); |
Следующий пример, тут мы узнаем сумму всех элементов массива. Создаем массив сразу со значениями и переменную, которая будет суммировать их вместе. Во втором выражении устанавливаем не число вручную, а функцию определения размера данного массива. Это удобно для статических массивов и необходимо при работе с динамическими.
0 1 2 3 4 5 |
int array[7] = { 1,5,4,9,2,3,8 }; int sum = 0; for(int i=0;i<ArraySize(array);i++) { sum += array[i]; } Print(sum); //результат 32 |
Операторы break, continue
Периодически во время цикла нужно пропустить дальнейший расчет, либо вообще прервать этот цикл. Для этого нужны эти два оператора. Break — прервать цикл, continue — перейти к следующей итерации.
Попробуем узнать средний размер 30 последних закрытых свечей, но создадим условие, по которому мы не будем использовать в расчете данные третьей и пятой свечи (допустим они очень большие и исказят результат расчета). Для того, чтобы узнать среднее значение нужна double переменная для того, чтобы суммировать данные всех свечей, а также счетчик количества свечей, которые участвовали в расчете (целое число int).
0 1 2 3 4 5 6 7 8 |
int cnt = 0; double average = 0; for(int i=1;i<=30;i++) { if(i == 3 || i == 5) continue; average += MathAbs(Open[i]-Close[i]); cnt = cnt+1; //Print("i: ",i); } Print("Средний размер ",cnt," свечей: ",DoubleToString(average/cnt/Point,1)); |
Когда условный оператор if показал истину по одному из двух условий, а именно то, что сейчас i равняется 3 или 5 — активируется оператор continue, который останавливает действие дальнейшего кода и осуществляет переход к следующей итерации. Для определения среднего значения нам все какая это свеча — бычья или медвежья, поэтому возводим результат в модуль. Далее в Print’e происходит перевод числового значения в текстовое, в котором сразу же выполняется деление суммарного значения размера свечей на их количество. Так как результат будет указан в единицах цены, то для перевода его в пункты мы умножим его на предопределенную переменную Point, которая означает размер пункта текущей валютной пары. В итоге мы пропустили 2 свечи и в принт выведется текст: «Средний размер 28 свечей: …».
Оператор continue очень часто используется при работе с ордерами, когда из расчета нужно исключить другие символы, кроме текущего, либо оставить только прибыльные ордера, конкретные магик номера и т.д.
С пропуском значений понятно, теперь нужно попробовать прервать цикл. Создадим массив с десятью значениями. Нам не важно их значение, главное узнать, когда сумма первых значений превысит 50. Тогда нужно прервать цикл и выдать в принт количество элементов, участвующих в расчете.
0 1 2 3 4 5 6 7 8 |
int cnt1 = 0; double sum1 = 0; int array1[10] = { 17,15,4,19,22,10,8,11,25,32 }; for(int i=0;i<ArraySize(array1);i++) { sum1 += array1[i]; cnt1++; if(sum1 >= 50) break; } Print("В расчете участвовало: ",cnt1," элементов массива."); //результат 4 |
После соблюдения условия, когда переменная для накопления суммы sum1 стала больше или равной 50 был применен оператор break, который остановил полностью выполнение всего цикла. За это время успело пройти четыре итерации.
Оператор break используется, когда по результату заданных условий вы нашли определенный торговый ордер и дальнейший расчет вам не нужен, либо если нужно остановить цикл, когда был достигнут ордер, который был открыт слишком давно.
Стоит заметить, что оператор цикла можно задавать без выражений, но тогда он будет выполняться бесконечно до того момента, пока терминал не зависнет, либо вы не закроете терминал. Если же вам нужно использовать такой цикл, то в нем обязательно нужно указывать функцию IsStopped() — проверка на принудительное завершение программного кода. В примере ниже мы добавим оператор break, чтобы избежать бесконечного прогона.
0 1 2 3 4 5 |
int x=0; for(;!IsStopped();) { x++; Print(x); if(x>1000) break; } |
Нельзя не сказать о том, что количество вложенный выражений в оператор может быть несколько, они указываются через запятую:
0 1 2 3 |
int k = 0, m = 0; for(k=0,m=10; m<10; k++,m--) { //Print("i=",i,", j=",j); } |
В основном такой метод примеряется при работе с двумерными массивами или когда вам нужно для подсчета использовать 2 переменные в выражениях.
Цикл можно помещать в тело другого цикла:
0 1 2 3 4 5 6 7 8 |
int cnt2 = 0, cnt3 = 0; for(int i=0;i<=9;i++) { cnt2++; for(int j=1;j<=20;j++) { cnt3++; } } Print("Количество итераций первого цикла: ",cnt2); //результат 10 Print("Количество итераций вообще: ",cnt3); //результат 200 |
Такой метод применяется при сложных расчетах, когда нужно сравнивать каждый отдельный ордер с другими из истории, некоторые графические объекты друг с другом и так далее.
Ну и напоследок сделаю пример, результат суммирования которого вы должны рассчитать вручную, чтобы закрепить теорию. Перед тем, как проверить его на графике, напишите ваш ответ для переменной cnt4 в комментарии к этому посту для самопроверки.
0 1 2 3 4 5 6 |
int cnt4 = 0; for(int i=1;i<=8;i++) { if(cnt4 == 4) continue; cnt4 = cnt4 + 1; if(i > 5) break; } Print("Результат: ",cnt4); |
Заключение
На этом все. В следующем уроке мы изучим два других оператора циклов, а также оператор-переключатель switch. Все примеры, как всегда, во вложении.
[download url=»http://www.davinci-fx.com/wp-content/uploads/2021/01/1.6-forbreakcontines.rar» title=»Скачать примеры урока»]