Скачать MetaTrader 5

Разработка эксперта средствами UML

18 ноября 2011, 17:05
Dennis Kirichenko
11
9 032

Ученые изучают то, что уже есть; инженеры создают то, чего никогда не было.

Альберт Эйнштейн

Введение

В своей статье «Simulink: в помощь разработчику эксперта» я предложил подход моделирования эксперта с помощью динамических систем. Однако такой подход отражает лишь один аспект работы проектировщика торговой системы – динамическое поведение ТС. В распоряжении специалистов есть средства, позволяющие расширить методологию разработчика ТС. В статье пойдет речь именно о том, как разработать эксперт с помощью универсального инструмента - графического языка UML.

Вообще UML, как графический язык, используется для визуального моделирования объектно-ориентированных программных систем. Но, как мне представляется, мы можем без колебаний применить его инструментарий и для разработки торговой системы. К тому же, язык MQL5 входит в семейство объектно-ориентированных языков, и это обстоятельство только облегчает нашу задачу.

Для моделирования я выбрал бесплатное для некоммерческих целей программное обеспечение Software Ideas Modeler.


1. Основы UML

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

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

Давайте очень кратко рассмотрим основы UML. Заинтересованному читателю я предлагаю самостоятельно освоить инструментарий UML, благо материала в свободном доступе для этого предостаточно.

Структура языка UML может быть отображена в виде диаграммы (рис. 1).

Рис. 1. Структура языка UML

Рис. 1. Структура языка UML

В состав строительных блоков входят: сущности (things - сами элементы модели), отношения (relationships - связывают сущности), диаграммы (diagrams - представления моделей UML).

UML-диаграммы позволяют визуализировать представления проектируемой системы с различных точек зрения.

В состав общих механизмов входят: спецификации (specifications - описание семантики), дополнения (adornments - подчеркивание важных характеристик модели), принятые деления (common divisions - абстракция и ее экземпляры, интерфейс и реализация), механизмы расширения (extensibility mechanisms - ограничения, стереотипы, помеченные значения).

Архитектура отвечает за высокоуровневое представление системы в ее окружении. Самое распространенное описание архитектуры – это «4+1 представление» (рис.2):

  • логическое представление (Logical view);
  • представление процессов (Process view);
  • представление реализации (Development view);
  • представление развертывания (Physical view);
  • представление прецедентов (Scenarios).

Рис. 2. 4+1 представление

Рис. 2. 4+1 представление


Следует также заметить, что язык UML имеет свою иерархию канонических диаграмм (рис.3). Версия 2.2 языка использует 14 видов UML-диаграмм.

Рис. 3. Канонические UML-диаграммы


Рис. 3. Канонические UML-диаграммы

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


2. UML-диаграммы


2.1 Диаграмма прецедентов

Как говорится, хорошее начало – половина дела. Обычно, но необязательно, аналитическую работу начинают с диаграммы прецедентов (use case diagram). Она характеризует работу системы с точки зрения пользователей.

При ее создании мы можем:

  • указать варианты использования ТС;
  • задать границы ТС;
  • определить экторов ТС;
  • обозначить отношения между экторами и вариантами ТС.

Прецеде́нт (англ. Use Case), также: вариант использования, сценарий использования - спецификация последовательностей действий (варианты последовательностей и ошибочные последовательности) в Унифицированном языке моделирования (UML), которые может осуществлять система, подсистема или класс, взаимодействуя с внешними акторами (англ. Actors).

А́ктор (англ. actor, в некоторых источниках — эктор или актёр) — множество логически связанных ролей в UML, исполняемых при взаимодействии с прецедентами или сущностями (система, подсистема или класс). Актором может быть человек или другая система, подсистема или класс, которые представляют нечто вне сущности.

Отношение (relationship) — семантическая связь между отдельными элементами модели.

Возможно, требовательный читатель заметит, что этот вид диаграммы носит достаточно общий характер, и скорее отражает концептуальную сущность ТС, нежели какую-то ее реализацию. Но в этом и суть – двигаться от общего к частному, от абстрактного к конкретному. Кто сказал, что мы не художники? Мы рисуем картину, начиная с общей идеи и эскиза. Сначала наносим на полотно штрихи. Добавляем краски. Вырисовываем детали…

Итак, в качестве примера давайте создадим диаграмму прецедентов (use case diagram) для некоторой торговой системы.

Экторами со стороны ввода я выбрал такие роли, как: Разработчик, Системный аналитик, Риск-менеджер и Администратор. Нужно отметить, что эти роли могут выполнять один или несколько человек. Какие действия совершает наша торговая система, и какие действия совершаются по отношению к ней?

Так, Разработчик может создавать и внедрять ТС. Кроме того, может участвовать в оптимизации ТС. Системный аналитик занимается оптимизацией работы ТС. Риск-менеджер поглощен управлением риском. Администратор следит за общей работой ТС. Со стороны выхода мы видим, что Пользователь извлекает прибыль вследствие функционирования ТС. Эта роль обобщена такими ролями, как Трейдер и Инвестор. А Управляющий также как и Администратор контролирует работу ТС.

На диаграмме присутствует блок «Торговая система». Он выражает границы ТС и отделяет ее от внешнего мира.

Теперь несколько слов об отношениях между экторами и вариантами использования, между самими экторами и самими прецедентами. Бóльшая часть отношений представлена ассоциациями, обозначенными сплошной линией. Это означает, что некоторый эктор инициирует некоторый вариант использования. Так, Риск-менеджер инициирует процесс управления риском и т.д. При этом, тех экторов, которые инициируют варианты, мы отнесем к главным, а тех, кто пользуется результатами совершаемого действия – к второстепенным. Так, второстепенным эктором может выступать Управляющий со стороны выхода. 

Ассоциация (англ. Association) — может указывать на то, что актер инициирует соответствующий вариант использования.

Обобщение (англ. Generalization, наследование) — моделирует соответствующую общность ролей.

Расширение (англ. Extend) — разновидность отношения зависимости между базовым вариантом использования и его специальным случаем.

Включение (англ. Include) — определяет взаимосвязь базового варианта использования с другим вариантом использования, функциональное поведение которого задействуется базовым не всегда, а только при выполнении дополнительных условий.

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

Рис. 4. Use-case диаграмма ТС

Рис. 4. Use-case диаграмма ТС

Прецеденты «Открывать позицию» и «Закрывать позицию» в свою очередь связаны отношением обобщения с прецедентом «Торговать». Последний прецедент является базовым для двух других. Так, он включает такой вариант использования, как «Управлять риском». И еще его поведение дополняет зависимый вариант «Получить прибыль».

Так как прибыль ТС образуется при условии, что цена продажи актива больше цены его покупки, я использовал именно отношение "extend" для указанных прецедентов. На диаграмме также приведена точка расширения, т.е. то конкретное условие, при котором задействуется вариант использования «Получить прибыль». Отношения зависимости отображены пунктирной линией со стрелкой с соответствующими стереотипами "include" и “extend”.

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

Нужно отметить, что для трейдера скорее больший интерес представляет ТС в узком смысле, нежели та, которая показана на рис. 4. Поэтому в дальнейшем предлагаю ориентироваться на сценарий «Торговать» с расширением «Получить прибыль».


2.2 Диаграмма классов

С помощью этой диаграммы - диаграммы классов (class diagram) - мы будем описывать структуру ТС. А именно, мы представим модель статической структуры торговой системы в терминологии классов объектно-ориентированного программирования. Таким образом, мы отразим программную логику ТС.

В UML диаграмма классов является типом диаграммы статической структуры. Она описывает структуру системы, показывая её классы, их атрибуты и операторы, а также взаимосвязи этих классов.

Что замечательного есть в этом типе диаграммы? Тот, кто немного знаком с языками объектно-ориентированного программирования, сразу заметит знакомое понятие «класс». Класс выступает в UML-диаграмме классов основным строительным блоком. Например, при генерации С++ кода блок UML-класса автоматически будет создан в виде некоторого классового шаблона. Останется только дописать реализацию каждого метода и свойства.

Давайте попробуем для примера что-нибудь спроектировать. Но прежде я бы хотел обратить внимание читателя на статью «Прототип торгового робота», в которой автор описывает преимущества использования прямой логики. На мой взгляд, весьма эффективен и производителен принцип вложенности – «макросы-функции-торговые модули».

Допустим, нам нужен некоторый торговый эксперт, который задействует возможности торговых классов стандартной библиотеки.

Создадим с помощью блока «Класс» модель класса в диаграмме классов. Я назвал ее CTradeExpert. Добавим некоторые атрибуты (в MQL5 это члены-данные класса) для нового класса. Пусть такими будут: Magic_No, e_trade, e_account, e_deal, e_symbol, e_pnt и вставим метод-конструктор класса CTradeExpert. Графически проделанная операция будет выглядеть, как показано на рис. 5.

Рис. 5. UML-модель класса CTradeExpert

Рис. 5. UML-модель класса CTradeExpert

Символ «-» перед атрибутом означает, что атрибут имеет право доступа в режиме «private», знак «#» - «protected», «+» - «public». Так, для атрибута Magic_No спецификатор доступа задан как private, для e_pnt – как public, а для других – как protected. Двоеточие, которое следует за именем атрибута, указывает на принадлежность к типу данных для атрибутов, а для методов – на тип возвращаемых данных. Так, атрибут Magic_No относится к типу int, e_trade – к CTrade и т.д.

Пока добавлять никакие методы и атрибуты не будем, а укажем, как связан наш класс CTradeExpert с классами стандартной библиотеки. Для этого добавим на диаграмму 6 блоков классов и назовем их следующим образом: CTrade, CAccountInfo, CDealInfo, CSymbolInfo, CObject. Модель класса CTradeExpert свяжем с 4-мя блоками торговых классов посредством отношения зависимости со стереотипом “use” (штрихпунктирная линия со стрелкой). 

Зависимость (dependency) - это семантическое отношение между двумя сущностями, при котором изменение одной из них, независимой, может повлиять на семантику другой, зависимой.

Стереотип в UML — описание поведения объекта.

Затем сами эти блоки свяжем с блоком CObject отношением обобщения (генерализации) с помощью линии с "незакрашенной" треугольной стрелкой на конце. Добавим еще комментарии к классам стандартной библиотеки. Теперь наша UML-диаграмма будет выглядеть так, как показано на рис.6.

Рис. 6. UML-диаграмма классов

Рис. 6. UML-диаграмма классов

Остается только сгенерировать программный код с помощью функции «Генерировать» на вкладке «Генератор» боковой панели (рис.7).

Рис. 7. Сгенирированный код

Рис. 7. Сгенерированный код

Из всех имеющихся наиболее подходит язык С++. На нем мы и получим код класса эксперта, а потом без труда переведем всё на язык MQL5.

Для указанной диаграммы сгенерированный программный код имеет следующий вид:

//
class CTradeExpert
{

private:
        int Magic_No;

protected:
        CTrade e_trade;

protected:
        CAccountInfo e_account;

protected:
        CDealInfo e_deal;

protected:
        CSymbolInfo e_symbol;

public:
        double e_pnt;

public:
        void CTradeExpert () 
    {

    }

};


//
class CObject
{
};

//
class CTrade : public CObject
{
};

//
class CDealInfo : public CObject
{
};

//
class CSymbolInfo : public CObject
{
};

//
class CAccountInfo : public CObject
{
};

Не правда ли очень знакомый синтаксис? Нужно лишь немного подправить тело класса. Для этого создадим в редакторе MetaEditor файл для нового класса TradeExpert.mqh. Скопируем в него сгенерированный ранее код. Удалим для читабельности повторяющийся спецификатор доступа protected для членов-данных класса CTradeExpert.

Удалим строки, связанные с объявлением классов стандартной библиотеки. После этого добавим инструкцию включения файлов #include для каждого используемого класса стандартной библиотеки, т.к. эти классы уже определены разработчиком. И добавим свои комментарии. В итоге получим примерно такой код:

//includes
#include <Trade\Trade.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\DealInfo.mqh>
#include <Trade\SymbolInfo.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTradeExpert
  {
private:
   int               Magic_No;   // магик эксперта

protected:
   CTrade            e_trade;    // объект для исполнения торговых приказов
   CAccountInfo      e_account;  // объект для получения свойств счета
   CDealInfo         e_deal;     // объект для получения свойств сделки
   CSymbolInfo       e_symbol;   // объект для получения свойств символа

public:
   double            e_pnt;      // значение в пп

public:
                     CTradeExpert()
     {
     }
  };
//+------------------------------------------------------------------+

Давайте в класс нашего эксперта добавим еще некоторые торговые функции-модули.

Такими могут стать: CheckSignal, OpenPosition, CheckPosition, ClosePosition и пр. Читатель, надеюсь, уже знаком с принципом "обслуживания состояний". Поэтому наш пробный класс CTradeExpert не покажется ему сложным. Я специально остановился на каком-то уже знакомом примере эксперта, чтобы легче воспринимались механизмы UML.

Итак, теперь модель класса будет выглядеть примерно так, как отображено на рис. 8.

Рис. 8. UML-модель класса CTradeExpert

Рис. 8. UML-модель класса CTradeExpert

Для обновленной модели класса также можно сгенерировать программный код с помощью уже описанного метода.


2.3 Диаграмма активности (деятельности)

С помощью этого типа UML-диаграммы мы сможем изучить поведение системы с использованием моделей потока данных и потока управления. Диаграмма активности отображает некоторый алгоритм, описывающий жизненный цикл объекта, состояния которого могут меняться.

Диаграмма активности отличается от блок-схемы, которая описывает лишь шаги алгоритма. Диаграмма активности имеет более широкую нотацию. Например, на ней можно указывать состояния объектов.

Диаграммы деятельности используются разработчиками для описания:

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

Предположим, что созданный ранее класс эксперта CTradeExpert мы будем использовать в файле советника Test_TradeExpert.mq5. Как мы помним, стандартный шаблон при создании советника в MetaEditor 5 предусматривает по умолчанию 3 функции-обработчика событий: OnInit, OnDeinit, OnTick. Остановимся на них.

Попробуем отобразить на диаграмме работу нашего эксперта в свете файла Test_TradeExpert.mq5. Тут нужно отметить, что эксперт, точнее его структура, достаточно примитивна. Пока мы только тренируемся. А для этого сойдет и простая структура эксперта.

Приступим к проектированию диаграммы для варианта использования нашего торгового советника, алгоритм которого представим в файле Test_TradeExpert.mq5.

Итак, все начинается с начального узла (рис. 9). От него маркер управления переходит к узлу вызова действия «Создать экземпляр эксперта». Выполнение этого действия инициирует поток объекта (синяя стрелка), изменяющий состояние узла объекта (myTE=создан), и управляющий поток к узлу вызова действия «Инициализировать советника». 

Поток управления (control flow) представляется в форме дуги (ребра) деятельности, которая связывает между собой два узла действия и по которой передаются только маркеры управления. 

Поток объектов (object flow) представляется в форме дуги (ребра) деятельности, по которой передаются только маркеры объектов или данных.

Узел действия (activity node) является абстрактным классом для отдельных точек в потоке деятельности, соединённых дугами (рёбрами).

Узел решения (decision node) является узлом управления, который выбирает между выходящими потоками.

Узел объекта (object node) представляют объекты, используемые в деятельности.

Дуга (ребро) деятельности (activity edge) является абстрактным классом для направленных соединений между двумя узлами действия.

Начальный узел (initial node) показывает, где начинается деятельность.

Конечный узел (final node) деятельности завершает все потоки деятельности.

Тот, в свою очередь, меняет состояние объекта myTE (myTE=инициализирован) и передает маркер управления узлу решения. Если эксперт инициализирован удачно, то поток управления направляется к узлу «Обрабатывать торговое событие NewTick». Если инициализация эксперта проходит неудачно, то маркер управления сначала попадает на узел объединения, после чего – на узел действия «Деинициализировать советника».

Маркеры — это абстрактные конструкции, которые вводятся для удобства описания динамического процесса выполнения статически определенного графа деятельности. Маркер может не содержать никакой дополнительной информации (пустой маркер) и тогда он называется маркером управления (control flow token) или же может содержать ссылку на объект или структуру данных, и тогда маркер называется маркером данных (data flow token).

Давайте рассмотрим первый поток управления, исходящий из узла решения. Он направлен в область с прерываемым выполнением действий, что обозначено отрисованным красной пунктирной линией прямоугольником со скругленны­ми углами и стереотипом “interruptible”. Когда поток управления находится в такой области, то он может внезапно прерваться. Если узел действия (оранжевый флажок), принимающий событие, «Выгрузить эксперт» активировать, то все потоки прервутся. Маркер управления переходит на прерывающее ребро (оранжевая зигзагообразная стрелка), а затем на узел соединения. После чего произойдет деинициализация советника. Потом маркер управления перейдёт в узел «Удалить глобальные переменные», после чего поток завершится в конечном узле деятельности.

Узел действия «Деинициализировать советника» также меняет состояние объекта myTE(myTE=деинициализирован) посредством объектного потока. А узел «Удалить глобальные переменные», в свою очередь, удаляет объект myTE (myTE=удален).

Рис. 9. Диаграмма активности для Test_TradeExpert.mq5

Рис. 9. Диаграмма активности для Test_TradeExpert.mq5

Допустим, что поток управления работает стабильно: выгрузка советника пока не происходит. Из узла «Обрабатывать торговое событие NewTick» поток переходит в другой блок – область расширения, стереотип которой задан как “iterative” (отрисованный пунктирной линией зелёный прямоугольник).

Эту область я назвал «Торговый блок», чтобы отразить основные характеристики и улучшить восприятие диаграммы. Характерная особенность блока – это цикличное выполнение операций для входящих объектов. Нам нужно всего 2 цикла – обработать направление long и short. На входе в блок и на выходе из блока находятся узлы расширения, включающие объекты торгового направления (long or short). 

Узел расширения (expansion node) - коллекция объектов, входящая в или выходящая из области расширения, исполняемой один раз для каждого объекта.

Узел действия, отправляющий сигнал (send signal action), представляет отправку сигнала.

Узел действия, принимающий событие (accept event action), ожидает получения события соответствующего типа.

Итак, каждое направление обрабатывается такими узлами, как: «Проверить сигнал» (узел отправки сигнала), «Получить сигнал» (узел приёма сигнала), «Открыть позицию» (узел отправки сигнала), «Проверить позицию» (узел отправки сигнала), «Закрыть позицию» (узел отправки сигнала). Еще нужно отметить, что объект направления (dir) может передаваться в объектном потоке между узлами действий, что отмечено сиреневыми стрелками. Работа в блоке будет продолжаться до тех пор, пока не произойдет выгрузка советника.


2.4 Диаграмма последовательности

С помощью этой диаграммы - диаграммы последовательностей (sequence diagram) - мы будем описывать последовательность, в которой взаимодействуют объекты. Очень важный аспект этого типа диаграммы – это время.

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

В верхней части располагаются объекты диаграммы, именно они и взаимодействуют. Объект имеет свою линию жизни в виде вертикальной пунктирной линии. Между собой объекты обмениваются сообщениями. Они представлены стрелками. Когда объект активен, он получает фокус управления. Графически такой фокус выражен узким прямоугольником на линии жизни.

Объект - это просто прямоугольник, внутри которого указаны подчеркнутые имя объекта и название класса (не обязательно), разделенные двоеточием.

Линия жизни объекта - это линия, которая изображает существование объекта на протяжении некоторого промежутка времени, и чем длиннее линия, тем дольше существует объект.

Фокус управления изображается в форме вытянутого узкого прямоугольника, верхняя сторона которого обозначает начало получения фокуса управления объекта (начало активности), а его нижняя сторона - окончание фокуса управления (окончание активности).

В UML каждое взаимодействие описывается совокупностью сообщений, которыми участвующие в нем объекты обмениваются между собой.

Давайте немного попрактикуемся.

Эктором выступит сам терминал. Он инициирует работу советника. Другими объектами, отмеченные стереотипом “event”, выступят события клиентского терминала: Init, Deinit, NewTick. Конечно, при желании можно расширить линейку событий. При старте советника на глобальном уровне создается объект – myTE, являющийся экземпляром класса CTradeExpert. Объект класса на диаграмме расположен чуть ниже относительно других, что указывает на его создании после выполнения функции конструктора.

Команда создания отмечена штрихпунктирной линией с открытой стрелкой с сообщением 1.1 CTradeExpert(). Штрих-пунктир линии со стрелкой указывает на тип “create” конструктора по умолчанию CTradeExpert(). После создания экземпляра класса CTradeExpert задействуется шаг 1.2 – фокус управления возвращается к терминалу. Синхронные сообщения для читабельности я обозначил в формате №.№, например 1.1, а асинхронные - №. Потом терминал обрабатывает событие Init функцией OnInit() на шаге 2.1, возврат фокуса идет на шаге 2.2. Сообщения типа “call” имеют вид линии с "закрашенной" треугольной стрелкой на конце.

Если событие Init вернет в терминал значение отличное от нуля, то значит, что имела место неудачная инициализация: задействуется шаг 3.1, приводящий к генерации и обработке события Deinit. На шаге 3.2 фокус управления возвращается к терминалу. Потом происходит удаление объекта класса CTradeExpert (шаг 4.1). Кстати, при создании диаграммы классов я не включил функцию деструктора в класс CTradeExpert. Это можно сделать позже. В этом и заключается одно из преимуществ конструирования диаграмм – процесс построения нескольких диаграмм идет итеративно. То, что не сделано сначала для одной диаграммы, можно сделать для другой, а позже внести изменения в первую.

Нужно отметить, что в MQL5-коде стандартного шаблона советника нет блока, обрабатывающего неудачную инициализацию. Его я указал для сохранения логики последовательности. В UML-диаграмме последовательностей при этом задействуется блок opt со сторожевым условием OnInit()!=0, что эквивалентно MQL5-конструкции if(OnInit()!=0) {}.

На шаге 4.2 управление передается в терминал.

Теперь терминал готов обрабатывать событие NewTick.

Обработку этого события в UML-диаграмме я заключил в блок loop, означающий бесконечный цикл. Т.е. советник будет обрабатывать это событие, пока мы его не отключим. Терминал обрабатывает событие NewTick с помощью функции OnTick (шаг 5). На шаге 6 фокус управления передается советнику myTE. Он с помощью 4-х рефлексивных сообщений реализует функции CheckSignal, OpenPosition, CheckPosition, ClosePosition. Рефлексивность обусловлена тем, что объект советника отсылает сообщения сам себе.

Кроме того, эти функции класса CTradeExpert заключены в блок цикла loop(2). Двойка означает, что цикл состоит из двух проходов. Почему из двух? Потому что обрабатываются 2 направления торговли – long и short (от шага 7-го до 10-го). На 11-ом шаге фокус передается в терминал.

Шаги №12 и 13 отвечают за деинициализацию и удаление объекта советника соответственно.

Рис. 10. SD-диаграмма для Test_TradeExpert.mq5

Рис. 10. SD-диаграмма для Test_TradeExpert.mq5

Итак, первичные навыки проектирования получены. С помощью созданных диаграмм работа разработчика весьма оптимизирована. Можем непосредственно заняться написанием кода для файла Test_TradeExpert.mq5. Конечно, можно обойтись и без диаграмм. Но когда у вас сложный эксперт, то наличие диаграмм сокращает вероятность возникновения ошибок и позволяет эффективно управлять разработкой ТС.

С помощью шаблона для советника создадим файл Test_TradeExpert.mq5.

На глобальном уровне создадим экземпляр класса CTradeExpert myTE.

Теперь будем заполнять тело функции OnTick().

Запишем функции класса следующим образом:

for(long dir=0;dir<2;dir++)

     {

      myTE.CheckSignal(dir);

      myTE.OpenPosition(dir);

      myTE.CheckPosition (dir);

      myTE.ClosePosition(dir);

     }

Примерно так будет обрабатываться событие NewTick. Конечно, еще нужно конкретизировать каждую из функций, которые будут, в том числе, использовать члены-данные класса. Но давайте оставим эту работу на будущее. Пока наша задача заключается в переносе логики UML-диаграмм в MQL5-код.


3. Разработка и представление эксперта на основе UML-диаграмм

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

Для начала создадим диаграмму прецедентов (use case diagram) для нашего советника. Она лишь в некоторой степени будет отличаться от той, которую рассматривали ранее. Я уделил внимание внутренней среде ТС, проигнорировав внешнюю (рис.11), т.к. в коде мы будем реализовывать только торговые задачи.

Рис. 11. Use-case диаграмма ТС

Рис. 11. Use-case диаграмма ТС

Теперь давайте определимся со структурой советника. Допустим, что мы будем использовать наработки Стандартной библиотеки, потому что она вполне соответствует заявленным задачам ТС. В последнее время она была существенно расширена. И прежде всего это касается классов торговых стратегий. Итак, перед нами стоит задача создать диаграмму классов. Она не будет простой, поэтому нужно запастись терпением.

Тут я хотел бы заметить, что мы рассматриваем Стандартную библиотеку, преследуя несколько целей. Во-первых, на ее основе мы попробуем создать торговый эксперт. А, во-вторых, что тоже немаловажно, мы попрактикуемся с диаграммами UML. В-третьих, наверное, разработчики не зря ее писали. Так что можно много полезного почерпнуть в ней, а заодно и разобраться с ее не совсем простой структурой.

Процедура преобразования кода в структуру UML-диаграммы называется обратной разработкой (обратный инжиниринг, реверс-инжиниринг). По сути, мы занимаемся этим вручную. Есть профессиональный софт, который позволяет сделать это автоматически (IBM Rational Rose, Visual Paradigm for UML, и т.д.). Но для практических целей я считаю, что нужно поработать, что называется, руками.

Давайте создадим с помощью блока «Класс» модель базового класса для реализации торговых стратегий CExpert. Посмотрим, какие еще используются классы и конструкции в теле класса CExpert. Во-первых, нужно отметить, что сам класс CExpert является потомком базового класса CExpertBase, который, в свою очередь, является потомком базового класса CObject.

На диаграмме создадим блоки для указанных классов и обозначим отношения между классами с помощью линии с "незакрашенной" треугольной стрелкой на конце (генерализация). Добавим комментарий к модели класса CExpert (желтый прямоугольник с загнутым уголком). Промежуточная структура классов выглядит теперь так – рис. 12. Саму диаграмму назовем Expert.

Рис. 12. Диаграмма Expert, начальный вид

Рис. 12. Диаграмма Expert, начальный вид

Посмотрим код в файле Expert.mqh. Там обнаружим, что класс CExpert, кроме всего прочего, задействует перечисления ENUM_TRADE_EVENTS и ENUM_TIMEFRAMES, одну из 8 предопределенных структур MqlDateTime. Также классом используются другие экземпляры классов, такие как: CExpertTrade, CExpertSignal, CExpertMoney, CExpertTrailing, CIndicators, CPositiontInfo, COrderInfo.

С учетом вышесказанного внесем некоторые изменения в диаграмму. Прежде всего, укажем, что классы CExpertSignal, CExpertMoney, CExpertTrailing являются потомками базового класса CExpertBase, а классы CPositiontInfo, COrderInfo – потомками базового класса CObject (для него я задал стереотип “metaclass”).

Обозначим отношения зависимости со стереотипом “use” между блоком класса CExpert и другими классами, не забывая про структуру MqlDateTime и перечисления. Изменим цветовой стиль блоков и получим следующую структуру – рис.13.

Рис. 13. Диаграмма Expert, начальный вид

Рис. 13. Диаграмма Expert, начальный вид


Однако и такая структура не будет полностью отражать всю полноту картины, т.к. есть еще ряд классов, которые опосредованно задействованы уже указанными классами. Что же это за классы? Во-первых, класс CExpertTrade является потомком класса CTrade. Последний является потомком класса CObject.

Класс CExpertTrade задействует перечисление ENUM_ORDER_TYPE_TIME, классы CSymbolInfo, CAccountInfo, которые также являются потомками класса CObject. Класс CTrade также использует экземпляры классов CSymbolInfo. Внесем изменения в диаграмму. Теперь наша диаграмма примет следующий вид – рис. 14.

Рис. 14. Диаграмма Expert, начальный вид

Рис. 14. Диаграмма Expert, начальный вид

Но и в этот раз диаграмма не будет полной. Например, если заглянуть в файл Стандартной библиотеки Trade.mqh, то можно увидеть, что класс CTrade использует несколько разных структур, перечислений и класс CSymbolInfo. Если их все отображать на одной диаграмме, то она станет достаточно насыщенной. А это затруднит ее восприятие.

Чтобы справиться с этой трудностью, я воспользовался таким элементом диаграммы, как Пакет. Он инкапсулирует близкие классы, перечисления, прочие пакеты и т.д. Связь пакета с элементами диаграммы я организовал через интерфейс. Так, диаграмму для пакета CTrade можно представить следующим образом – рис. 15.

Рис. 15. Диаграмма классов для пакета CTrade

Рис. 15. Диаграмма классов для пакета CTrade

На диаграмме пакета CTrade отображены связи зависимости класса CTrade с перечислениями и структурами.

Связь с базовым классом CObject и используемым классом CSymbolInfo реализована через интерфейс.

Возле интерфейсов есть пиктограмма связи с той диаграммой классов, где находится пакет CTrade в виде единственного элемента. Если кликнуть по любому из интерфейсов, то произойдет автоматический переход на исходную диаграмму (рис.16).

Рис. 16. Диаграмма Expert с интерфейсами

Рис. 16. Диаграмма Expert с интерфейсами

Интерфейсные связи я выделил оранжевым цветом. Пиктограмма диаграммы классов возле пакета CTrade указывает на возможность перехода в эту диаграмму. Таким способом – инкапсулированием – можно существенно улучшить читабельность и понимание диаграммы классов.

Итак, давайте пойдем дальше. Класс CObject использует в своем теле указатели на экземпляры своего же класса. Поэтому можно задать отношение зависимости для блока CObject со стереотипом “use” относительно самого себя.

Давайте рассмотрим блок модели класса CExpertBase. По первым строкам заголовочного файла ExpertBase.mqh можно сказать, что этот класс использует несколько экземпляров различных классов, а также перечисления. Поэтому резонно для модели класса и его связей создать пакет CExpertBase.

Итак, первым делом определим в диаграмме пакета модель класса CExpertBase. Через интерфейс покажем связь с базовым классом CObject, а также отношение использования с классами CSymbolInfo и CAccountInfo. Затем с помощью блоков классов и отношения зависимости укажем, что класс CExpertBase использует следующие классы: CiOpen, CiHigh, CiLow, CiSpread, CiTime, CiTickVolume, CiRealVolume.

Первые четыре класса являются потомками класса CPriceSeries, а вторые четыре – потомками класса CSeries. Причем сам класс CSeries имеет потомком класс CPriceSeries и является, в свою очередь, потомком класса CArrayObj. Отношения наследования уже применялись ранее, как мы помним. На диаграмме их обозначим отношением обобщения (генерализации).

Не забудем, что класс CExpertBase использует в своем теле такие перечисления, как: ENUM_TYPE_TREND, ENUM_USED_SERIES, ENUM_INIT_PHASE, ENUM_TIMEFRAMES. Последнее перечисление также используется потомками класса CPriceSeries и класса CSeries. Чтобы связи не потерялись, и диаграмма была понятной, произведем настройку стиля для каждого из элементов диаграммы. В итоге получим такую диаграмму (рис. 17).

Рис. 17. Диаграмма классов для пакета CExpertBase

Рис. 17. Диаграмма классов для пакета CExpertBase

Она, конечно же, не будет полной, придется еще немного над ней поработать. Оказывается, что та четверка классов, которая наследует класс CPriceSeries, также использует класс CDoubleBuffer. Кроме того, каждый класс из четверки использует по отдельности свой класс буфера, производный от класса CDoubleBuffer. Так, класс CiOpen использует класс COpenBuffer и т.д. Класс CDoubleBuffer сам имеет базовым классом класс CArrayDouble и использует перечисление ENUM_TIMEFRAMES.

Класс CArrayDouble наследует класс CArray, использует в своем теле указатели на экземпляры своего же класса и перечисление ENUM_DATATYPE. Класс COpenBuffer и остальные буферные классы ценовых рядов (CHighBuffer, CLowBuffer, CCloseBuffer) используют перечисление ENUM_TIMEFRAMES.

Те четыре класса, что наследуют класс CSeries, только используют каждый свой класс буфера (CSpreadBuffer, CTimeBuffer, CTickVolumeBuffer, CRealVolumeBuffer). Первый из классовых буферов CSpreadBuffer наследует класс CArrayInt, остальные – CArrayLong. Два последних класса используют указатели на экземпляры своего же класса, перечисление ENUM_DATATYPE и выступают потомками класса CArray, который, в свою очередь, является потомком класса CObject.

Класс CPriceSeries, также как и его потомки, использует класс CDoubleBuffer и перечисление ENUM_TIMEFRAMES.

Класс CSeries используют перечисления ENUM_SERIES_INFO_INTEGER, ENUM_TIMEFRAMES. Сам наследует класс CArrayObj. Последний наследует класс CArray, использует перечисление ENUM_POINTER_TYPE, указатели на экземпляры своего класса и класса CObject. В итоге получим диаграмму, представленную на рис.18.

Рис. 18. Расширенная диаграмма классов для пакета CExpertBase

Рис. 18. Расширенная диаграмма классов для пакета CExpertBase

А исходная диаграмма Expert для классов и пакетов CExpert, CExpertBase, CSymbolInfo, CAccountInfo и CObject с интерфейсами теперь будет выглядеть следующим образом (рис.19).

Рис. 19. Диаграмма Expert с интерфейсами

Рис. 19. Диаграмма Expert с интерфейсами

Я еще добавил перечисление ENUM_ORDER_TYPE, используемое классом CExpertTrade. Для читабельности выделил группу соединений разным цветом.

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

Итак, изучим класс CSymbolInfo. Если посмотреть на код файла SymbolInfo.mqh, то заметим, что базовый класс CSymbolInfo использует некоторые перечисления и структуры MQL5. Для него и его связей также уместно воспользоваться таким элементом UML-диаграммы как пакет (рис.20).

Рис. 20. Диаграмма пакета CSymbolInfo

Рис. 20. Диаграмма пакета CSymbolInfo

Наличие свободного места в диаграмме позволяет использовать в полной мере комментарии, чем я и воспользовался. На диаграмме отмечен также интерфейс связи с классом-предком CObject. Исходная диаграмма пакетов и классов Expert будет немного изменена. Я приведу ее обновленный вариант чуть позже, когда все классы и пакеты будут отражены на диаграмме.

Итак, идем дальше. Посмотрим на MQL5-код в файле AccountInfo.mqh. Как оказывается, класс CAccountInfo также использует несколько перечислений. Отразим их на диаграмме пакета, который создадим для этого класса и его связей с прочими сущностями (рис.21).

Рис. 21. Диаграмма пакета CAccountlInfo

Рис. 21. Диаграмма пакета CAccountlInfo

Теперь разберемся с классом CExpert. Для него тоже создадим пакет CExpert, который будет выглядеть так, как показано на рис.22. Продолжаем улучшать читабельность нашей основной диаграммы. Класс CExpert связан с несколькими другими классами, что обозначено интерфейсными оранжевыми линиями со стрелкой.

Рис. 22. Диаграмма пакета CExpert

Рис. 22. Диаграмма пакета CExpert


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

Класс CExpertSignal является потомком класса CExpertBase. Эта связь уже была указана на исходной диаграмме Expert. Кроме того, сам класс CExpertSignal использует класс CArrayObj, COrderInfo, CIndicators и экземпляры своего класса (рис.23). В частности, интерфейс связи с классом CArrayObj перебросит нас на диаграмму пакета CExpertBase, где раскрыта связь класса CArrayObj с прочими сущностями.

Рис. 23. Диаграмма пакета CExpertSignal

Рис. 23. Диаграмма пакета CExpertSignal

В целях некоторой экономии я не буду приводить все диаграммы – их можно будет посмотреть в прилагаемом файле Expert.simp. А лучше давайте посмотрим на нашу комплексную обновленную диаграмму пакетов и классов Expert (рис.24).

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

Рис. 24. Диаграмма пакетов и классов Expert

Рис. 24. Диаграмма пакетов и классов Expert

Итак, все, что можно было почерпнуть из имеющегося в Стандартной библиотеке кода для создания диаграмм, мы отразили. Осталось добавить некоторые свои блоки, которые конкретизируют торговые операции эксперта.

Самым первым блоком станет блок класса CmyExpert, который наследует от класса CExpert торговые «навыки». Это именно тот блок, ради которого мы так долго занимались реверс-инжинирингом. Он и будет реализовывать конкретную торговую стратегию. Затем нам еще понадобится конкретизировать виртуальные функции базовых классов экспертов.

Для этого создадим блоки классов CmyExpertSignal, CmyExpertMoney, CmyExpertTrailing и укажем, что они являются потомками соответствующих классов (рис.25).

Рис. 25. Расширенная диаграмма пакетов и классов Expert

Рис. 25. Расширенная диаграмма пакетов и классов Expert


Какие функции и данные должен включать каждый из классов - это уже дело разработчика. Здесь я стремлюсь отразить скорее общую схему, чем конкретную реализацию того или иного производного класса. Так, для каждого из производных классов можно создать свою отдельную диаграмму с подробным перечнем включаемых методов и свойств, как это было сделано, например, на рис.8.

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

Итак, детализируем работу эксперта в хронологическом порядке (рис.26).

Рис. 26. SD-диаграмма эксперта

Рис. 26. SD-диаграмма эксперта

Терминал выступает в качестве эктора. На глобальном уровне создает объект myTrader - экземпляр класса CmyExpert (шаг 1.1). Зеленым отмечены предопределенные события клиентского терминала (Init, Deinit, NewTick, Trade). Логика функционирования SD-диаграммы была описана ранее. Тут я бы хотел отметить некоторые специфические моменты. Когда тело эксперта нарастает, и кода становится все больше, то становится сложнее все это отобразить на диаграмме.

Для решения этой задачи используется блоковый подход. Набор некоторых общих функций оформляется в виде некоторого блока. Им, как правило, выступает другая SD-диаграмма. Говорят, что имеет место взаимодействие диаграмм (interaction use).

Так, в нашем случае я создал SD-диаграмму с именем OnInit для того, чтобы отразить логику обработки события терминала Init в отдельной диаграмме. Синтаксически она определена рамкой с ключевым словом ref (от англ. слова reference - ссылка) и задействуется тогда, когда маркер управления переходит от функции OnInit (шаг 2.1) к линии жизни события Init.

Кроме того, я задал для OnInit интерфейсный переход на свою SD-диаграмму. Т.е. если кликнуть 2 раза по рамке, то можно собственно открыть детализированную SD-диаграмму OnInit (рис. 27).

Рис. 27. SD-диаграмма OnInit

Рис. 27. SD-диаграмма OnInit

Переходы на другие SD-диаграммы очень удобно задействовать тогда, когда имеет место повторение некоторых действий.

Так, в диаграмме OnInit встречаются действия по деинициализации советника, обработку которых я поручил диаграмме myTrader_Deinit (рис. 28).

Рис. 28. SD-диаграмма myTrader_Deinit

Рис. 28. SD-диаграмма myTrader_Deinit

В общем, на данном этапе проектирования советника у меня вышло четыре SD-диаграммы. Естественно, при углубленной разработке возникнет потребность в дополнительных диаграммах. Так, я еще не обработал прочие события клиентского терминала (NewTick, Trade).


Выводы

В данной статье я предложил учитывать многоаспектность создания торгового советника с помощью графического языка UML, который используется для визуального моделирования объектно-ориентированных программных систем. Основным преимуществом такого подхода является визуализация работы проектировщика.

Как и в любом другом сложном явлении, у языка UML есть свои недостатки, которые разработчик должен осознавать (избыточность, неточная семантика и пр.).

Надеюсь, что описанная методика разработки советника вызовет интерес у читателя. Буду благодарен за замечания и конструктивную критику.


Расположение файлов:

#
          Файл                
            Путь               
Описание
 1  TradeExpert.mqh
  %MetaTrader%\MQL5\Include  Класс торгового советника
 2  Test_TradeExpert.mq5
  %MetaTrader%\MQL5\Experts  Торговый советник
 3  Expert.simp  %Documents%\UML projects  Проект UML-диаграмм
 4   SoftwareIdeasModeler.4.103.zip  %Program Files%\SoftwareIdeasModeler
  Дистрибутив Software Ideas Modeler


Используемая литература:

  1. Бесплатные курсы UML. Интернет-Университет Информационных Технологий
  2. Джим Арлоу, Айла Нейштадт. UML 2 и Унифицированный процесс. Практический объектно-ориентированный анализ и проектирование, Символ-Плюс, 2007. - 624 стр.
  3. Леоненков А.В. Объектно-ориентированный анализ и проектирование с использованием UML и IBM Rational Rose, Интернет-университетинформационных технологий, Бином. Лаборатория знаний, 2006. - 320 стр.
  4. Мартин Фаулер. UML. Основы. Краткое руководство по стандартному языку объектного моделирования, Символ-Плюс, 2011. - 192 стр.
  5. Пол Киммел. UML. Основы визуального анализа и проектирования, НТ Пресс, 2008. - 272 стр.
  6. Пол Киммел. UML. Универсальный язык программирования, НТ Пресс, 2008. - 272 стр.
  7. Ф. А. Новиков, Д. Ю. Иванов. Моделирование на UML, Профессиональная литература, Наука и техника, 2010. - 640 стр.
  8. Mark Priestly. Practical Object-Oriented Design With Uml, Mcgraw Hill Higher Education; 2nd edition, 2007. - 376 pp.
Прикрепленные файлы |
tradeexpert.mqh (3.47 KB)
expert.zip (82.35 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (11)
Nikolay Demko
Nikolay Demko | 19 ноя 2011 в 03:22

Что то не получается экспортировать проект в виде рисунка.

У шароварной версии этот функционал часом не отключен?

Dennis Kirichenko
Dennis Kirichenko | 19 ноя 2011 в 15:26
Urain:

Что то не получается экспортировать проект в виде рисунка.

У шароварной версии этот функционал часом не отключен?

Шароварная версия ничем не отличается от коммерческой :-)

Так что дерзайте, там всё очень просто...

Nikolay Demko
Nikolay Demko | 19 ноя 2011 в 16:23
denkir:

Шароварная версия ничем не отличается от коммерческой :-)

Так что дерзайте, там всё очень просто...

Получилось, первоначально не выставил размер, оставил умолчательную настройку относительный размер, после выставления размера всё получилось.
NTFS
NTFS | 7 апр 2013 в 14:41

День добрый!

Отличная и кропотливая работа. Правда создается впечатление, что часть этой работы сделана как будто за разработчиков MQL5. Ведь по сути изложена диаграмма стандартных классов MQL5.  Это я к тому, что было бы неплохо обнаружить в один прекрасный момент полную диаграмму классов MQL5 именно в формате UML, так, чтобы можно было просматривать ее в случае необходимости в одном из приложений.

Спасибо!!!! 

Serhiy Dotsenko
Serhiy Dotsenko | 2 мар 2015 в 12:02

для дальнейшего развития тематики...

 

 

Интервью с Гэ Сэньлинем (ATC 2011) Интервью с Гэ Сэньлинем (ATC 2011)

Советник Гэ Сэньлиня (yyy999) из Китая появился в первой десятке турнирной таблицы Automated Trading Championship 2011 в конце октября и с тех пор не покидал ее. Не часто участники из Поднебесной добиваются успехов на Чемпионате, ведь торговля на Форексе запрещена в этой стране. После неудачного выступления в прошлом году, Гэ Сэньлинь подготовил новый мультивалютный советник, который не закрывает убыточные позиции и использует наращивание позиции для выхода из минуса. Что ж, посмотрим, сможет ли этот эксперт подняться еще выше с такой рискованной стратегией.

Использование MetaTrader 5 как поставщика торговых сигналов для MetaTrader 4 Использование MetaTrader 5 как поставщика торговых сигналов для MetaTrader 4

В статье обсуждаются особенности использования MetaTrader 5 в качестве поставщика торговых сигналов для MetaTrader 4. Вы узнаете как создать простой поставщик торговых сигналов из MetaTrader 5 и как его подключить к нескольким терминалам MetaTrader 4. Также вы узнаете о том, как в реальном времени копировать сделки участников Automated Trading Championship на свой реальный счет в MetaTrader 4.

Лига Чемпионов ATC: Интервью с Борисом Одинцовым (ATC 2011) Лига Чемпионов ATC: Интервью с Борисом Одинцовым (ATC 2011)

Интервью с Борисом Одинцовым (bobsley) - последнее в рамках проекта "Лига Чемпионов ATC". Борис стал победителем Automated Trading Championship 2010 - первого Чемпионата с участием экспертов на новом языке MQL5. Тогда его советник в упорной борьбе сумел взобраться на самую вершину турнирной таблицы, заработав $77 000. В этом году Борис участвует с тем же советником, слегка изменив его настройки. Возможно, этот советник еще сможет повторить свой успех.

Прогнозирование временных рядов при помощи экспоненциального сглаживания (окончание) Прогнозирование временных рядов при помощи экспоненциального сглаживания (окончание)

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