Программирование на MQL II. Устойчивые программы
|

Программирование на MQL II. Устойчивые программы

   Начиная писать эту статью я задумался над целесообразностью продолжения разговоров о MQL II. Многие считают, что в связи со скорым появлением MQL4 – совершенно иного языка программирования для MetaTrader’а (смотри Forex Magazine Май 2004, №15, “Будущее инструментария трейдера”) не стоит больше уделять внимания такому “старью” как MQL II. Хотелось бы предотвратить появление у вас подобных мыслей, особенно у тех, кто только начинает или планирует изучать программирование в MetaTrader’е.


   Попробую отстоять своё мнение:


   · во-первых выход “четвёрки” планируют только летом и может случиться так, что в ожидании MQL4 придётся просидеть минимум месяц, то есть целый месяц без дела;
   · во-вторых, касается новичков, даже если вы не станете сейчас браться за изучение MQL II, а дождавшись выхода “четвёрки” примитесь сразу за MQL4, то уверяю вас, что изучение программирования как такового всё равно начнётся с одних и тех же этапов;
   · в-третьих MQL II прекрасный язык для того чтобы начинать программировать, ведь не даром в школах на информатике изучают простые языки типа Pascal, а не модные объектные языки, хотя последние во многом более эффективны;


   Надеюсь я вас убедил в том, что продолжить разговор о MQL II стоит, и мы переходим к рассмотрению вопросов, которые рано или поздно встают перед всеми программистами – как сделать программу более устойчивой к непредсказуемым ситуациям.


   Для кого-то эта тема покажется немного надуманной, что может быть проще: написал программу, отладил, запустил, работает. Так рассуждают те, кто думает, что программы пишутся только теми, кто их спользует.


   На самом деле, с ростом  популярности таких видов деятельности как работа на фондовых рынках, растёт и спрос на специалистов владеющих навыками написания программ для аналитических систем трейдеров.


   Теперь давайте сравним две ситуации: первая, когда человек написавший программу сам же её и использует, вотрая, когда трейдер не желающий по тем или иным причинам вникать в тонкости программирования изложил программисту суть своих замыслов, заплатил деньги и ждёт, что ему предоставят работающую программу.


   Что происходит, когда в программе возникает непредвиденное обстоятельство? Конечно в первом случае человек написавший программу понимает в чём дело и сразу же поправив код программы получает исправленную, правильно работающую с этим непредвиденным обстоятельством, программу. Во втором же случае трейдер скорее всего будет озабочен случившимся, ведь возможно это непредвиденное обстоятельство стоило ему некоторой суммы проигрыша. Он объяснит программисту в чём дело и будет ждать, когда тот исправит ошибку. Уходит время, а с ним, как говорится, и деньги. Не правда ли, неприятная ситуация как для программиста так и для трейдера?


   Откуда же могут взяться непредвиденные обстоятельства? Давайте обратим наше внимание на параметры пользовательских функций, индикаторов и экспертов. Каждый раз, когда в программе появляется ввод пользователем каких-то параметров, появляется и возможность получения непредвиденных обстоятельств. Работа программы так или иначе расчитана на некоторые предположения накладываемые на параметры. Рассмотрим примеры.


   Пусть в нашей программе требуется ввести начальную цену для каких-то вычислений. Мы даже не допускаем мысли, что кто-то из пользователей попробует ввести в поле цены валюты значение 999999999 или 0, ведь мы не видели ещё таких котировок ни на одной из валютных пар. Но так получилось, что пользователь при вводе ошибся или не прочитал тех инструкций, которые мы ему написали и в итоге программа вадаёт какие попало результаты. Мы как будто не причём, но и пользователь оказался разочарованным.


   Далее рассмотрим ещё один похожий пример. Обратимся к уже не раз упоминавшемуся на страницах журнала алгоритму построения сглаживающей кривой по методу медианного сглаживания (Forex Magazine Апрель 2004, №14, “Как найти ошибку”, Март 2004, №8, “Программирование на MQL II: Медианное сглаживание”)


   var: shift(0);
   array: values[5](0);
   var: ix(0), iy(0);
   var: is_sorted(true);
   SetLoopCount(0);
   for shift = 0 to bars-5 {
   // помещаем значения из массива Open
   // во временный массив, с которым мы и будем
   // дальше работать
   for ix = 0 to 4 {
   values [ix] = O[shift + ix];
   }
   // сортируем массив методом пузырька
   for ix = 0 to 4 {
   is_sorted = true;
   for iy = 0 to 3 {
   var: tmp(0);
   if(values[iy] > values[iy+1]) then {
   tmp = values[iy];
   values[iy] = values[iy+1];
   values[iy+1] = tmp;
   is_sorted = false;
   };
   };
   if(is_sorted) then {
   break;
   };
   };
   SetIndexValue(shift, values [2]);
   };


   Из второй строки видно, что нами используется массив values содержащий пять элементов. Из этого же следует, что сглаживание происходит медианой выбранной из пяти элементов. Имея опыт общения со сглаживающими кривыми скользящей средней (индикатор Moving Average) пользователи скорее всего привыкли, что могут произвольно менять промежуток сглаживания. Что если потребуется сделать индикатор, который умеет строить медианное сглаживание на промежутках отличных от 5. К сожалению MQL II не имеет возможности заводить массивы динамически меняющие свои размеры, поэтому как один из выходов из сложившейся ситуации можно использовать большой массив, который будет использоваться для размещения в нём сортируемых элементов. В следующем примере мы распределили под массив 20-ть ячеек.


   var: shift(0);
   array: values[20](0);
   var: ix(0), iy(0);
   var: is_sorted(true);
   SetLoopCount(0);
   for shift = 0 to bars-5 {
   // помещаем значения из массива Open
   // во временный массив, с которым мы и будем
   // дальше работать
   for ix = 0 to range – 1 {
   values [ix] = O[shift + ix];
   }
   // сортируем массив методом пузырька
   for ix = 0 to range – 1 {
   is_sorted = true;
   for iy = 0 to range – 2 {
   var: tmp(0);
   if(values[iy] > values[iy+1]) then {
   tmp = values[iy];
   values[iy] = values[iy+1];
   values[iy+1] = tmp;
   is_sorted = false;
   };
   };
   if(is_sorted) then {
   break;
   };
   };
   if(mod(range,2) != 0) then {
   SetIndexValue(shift, values [(range – 1)/2]);
   } else {
   SetIndexValue(shift, (values [(range/2)- 1]+values [(range/2)])/2);
   }
   };


   Видно, что кроме косметических изменений в программе при работе с сортируемым массивом, добавился один параметр – range, который даёт возможность пользователю выбирать промежуток медианного сглаживания. На рисунке 1 показан результат работы изменённого индикатора с параметром range принимающим значения 5, 6 и 7.


   Но массив тем не менее ограничен и существует опасность, что пользователь введёт значения нежелательные для нашей программы. Не известно как поведёт себя программа в случае, когда пользователю захочется установить значение параметра range = 50. Одна из неприятностей, которая может случиться, это когда программа как-то по-своему будет отрабатывать такую непредвиденную ситуацию, а пользователь будет введён в замешательство тем, что и на значении range = 30 и на значении range = 40 будет получать один и тот же график.


результат работы изменённого индикатора с параметром range принимающим значения 5, 6 и 7.


Рис.1


   Более логичного поведения программы в обоих случаях можно было бы достичь если бы мы в её начало вставили блок проверки параметров. В таком случае если параметры не удовлетворяют некоторым требованиям программы можно было бы предупредить пользователя об ошибке ввода с помощью функции Alert() и тут же указать на дозволенные значения. Ниже показан рабочий код, который отреагирует на неправильный ввод пользователя должным образом и, сообщив ему об этом, установит ближайшие допустимые значения переменной range.
   Примерно такую же обработку входных параметров можно было бы провести и в первой ситуации. Теперь-то пользователь будет предупреждён об ошибке ввода и не будет разочарован неожиданными результатами работы программы.


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


   Результатом статьи должно стать понимание того, что программа – это не только правильно изложенный алгоритм. Ещё она должна уметь корректно обработать различные неожиданные ситуации, и мастерство программиста лишь подчёркивается умением предвидеть и предупреждать подобные ситуации.


   input: range(5);


   var: shift(0);
   array: values[50](0);
   var: ix(0), iy(0);
   var: is_sorted(true);
   var: real_range(0);
   SetLoopCount(0);
   for shift = 0 to bars-1 {
   SetIndexValue(shift, 0);
   };
   real_range = range;


   for shift = 0 to bars-5 {
   // помещаем значения из массива Open
   // во временный массив, с которым мы и будем
   // дальше работать
   for ix = 0 to real_range – 1 {
   values [ix] = O[shift + ix];
   }
   // сортируем массив методом пузырька
   for ix = 0 to real_range – 1 {
   is_sorted = true;
   for iy = 0 to real_range – 2 {
   var: tmp(0);
   if(values[iy] > values[iy+1]) then {
   tmp = values[iy];
   values[iy] = values[iy+1];
   values[iy+1] = tmp;
   is_sorted = false;
   };
   };
   if(is_sorted) then {
   break;
   };
   };
   if(mod(real_range,2) != 0) then {
   SetIndexValue(shift, values [(real_range – 1)/2]);
   } else {
   SetIndexValue(shift,(values [(real_range/2)- 1]+values [(real_range/2)])/2);
   }
   };


Александр Иванов (AKA HORN)