Структура рулит. Учимся структурировать программы, изучаем возможности, ошибки, решения и т.п. - страница 7

 
Urain:

Предлагаю выложить основные модели проектирования:

1. Функциональная

2. Объектная

3. Событийная

...

дописывайте

4. Компонентная

--

Вообще на любую программу (включая замышляемую) можно смотреть под разными углами. // это понятно.

При первичном анализе проекта стараюсь в обязательном порядке рассмотреть как минимум 4 аспекта:

1. Структурный:  Физическая и логическая организация программного кода и компонентов программы.

2. Функциональный (не путать с функциональным подходом в разработке): Какие задачи решает программа (какой производит продукт), в чём её польза, что должна выдавать на выходе и т.п.

3. Коммуникативный:  Какой у программы должен быть юзер-интерфейс, с какими программами и как обменивается данными, протоколы обмена и тп...

4. Управленческий: Как программа управляется, какие необходимы настройки, степени свободы и т.п.

Все аспекты неразрывно взаимосвязаны, но взгляд под этими разными углами (+ ещё под какими-нибудь) позволяет не упустить важные тонкости, а на начальных стадиях просто не зевануть что-нибудь существенное с далеко идущими последствиями... )

 
MetaDriver:

...Вообще на любую программу (включая замышляемую) можно смотреть под разными углами. // это понятно...

Абсолютно согласен. Это общефилософский принцип - изучение явления с разных точек зрения...

А я в начале разработки пытаюсь ответить на вопрос "Что должна программа делать, а что не должна?". Первая часть вопроса попадает в рамки системы (тут МТС), вторая - не попадает, находится за пределами.

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

 
MetaDriver:

Для обмена мыслями / взаимообучения  предлагаю взять (высосать из пальца) более-менее смахивающую на практическую задачку, и всем колхозом её поструктурировать.

Например  хотя бы наметить  базовую структуру (точнее варианты таких структур) для такой задачки: 

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

Желательно либо сделать панель отключаемой (для оптимизации в тестере),  либо вынести всю "неграфическую" реализацию советника в подключаемый файл (.mqh), который может быть затем подключаем к графическому интерфейсу без изменений (дабы исключить) различия в работе "тестерной" и "графической" версий.

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

Поштурмуем задачку?

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

Как организовать универсальный базовый торговый класс - это отдельная интересная тема. Несколько лет практики в этом вопросе лично меня наконец-то привели к моей универсальной схеме. Она оказалось прозрачной и универсальной. Если интересно могу привести ее принципиальную блок-схему (ха-ха, все-таки рисовать блок-схемы небесполезное занятие). Но в любом случае, у каждого свой путь, и хорошее решение для одного не будет хорошим решением для другого.

 
C-4:

Если интересно могу привести ее принципиальную блок-схему (ха-ха, все-таки рисовать блок-схемы небесполезное занятие).

 
sergeev:
Наконец-то что-то прояснилось.... )
 
C-4:

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

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

1. Однозначно.

2. Ну почему же?  А как же кастомные события?  Вполне себе горизонтально и универсально.

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

3.  Поскольку я не согласен с п.2,  то этот вариант пока не копаю.

--

Есть вариант, который нахожу весьма симпатичным.  (Вариант с "отключаемой" панелью).  Сделать панель в виде индикатора.  Если эксперт в тестере - он панель просто не загружает. Дополнительный бонус - панель работает в другом потоке, оставляя больше ресурсов для эксперта.

Что до универсальности панели.  Не вижу принципиальных препятствий к тому, чтоб панель полностью конфигурировалась посредством  ini-файла. Т.е. там можно прописать абсолютно все данные необходимые для создания любой панели из ограниченного фиксированного набора визуальных компонентов + коды событий которые они должны генерировать при взаимодействии с юзером.

Как организовать универсальный базовый торговый класс - это отдельная интересная тема. Несколько лет практики в этом вопросе лично меня наконец-то привели к моей универсальной схеме. Она оказалось прозрачной и универсальной. Если интересно могу привести ее принципиальную блок-схему.  ....

А давай.  Мне даже очень интересно.  Да и практически полезно может быть.
 
MetaDriver:

1. Однозначно.

Нахр Зачем? Чрезмерная универсализация такое же зло, как преждевременная оптимизация.

А связывать блоки одного модуля через события... это медленно и неудобно.

 
MetaDriver:

А давай.  Мне даже очень интересно.  Да и практически полезно может быть.

Синяя рамка - сущности базового класса. Красная рамка сущности производного класса. Видно, что базовый класс навязывает потомку определение своей логики в четырех методах. Именно такой способ сводит описание любой стратегии к описанию всего четырех ситуаций:

1. Если все правила открытия длинной позиции соблюдены - то длинная позиция открывается в методе InitBuy()

2. Если все правила закрытия длинной позиции соблюдены - то длинная позиция закрывается в методе SupportBuy()

3. Если все правила открытия короткой позиции соблюдены - то короткая позиция открывается в методе InitSell()

4. Если все правила закрытия короткой позиции соблюдены - то короткая позиция закрывается в методе SupportSell()

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

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

Интересным моментом является  еще и способ работы с открытыми позициями. Базовый класс хранит отдельные списки длинных и коротких позиций. При наступлении нового события (например OnTick) класс начинает перебирать списки всех открытых позиций и предлагает по очереди обработать каждую из этих позиций методами SupportBuy SupportSell. Эти методы могут закрыть только ту позицию, которую предлагает им в данный момент базовый класс. Все прочие позиции доступны только для чтения. Таким образом, базовый класс навязывает своим потомкам идею  о том, что в текущий момент надо сосредоточиться только на одной единственной позиции. Когда я опробывал эту идею, оказалось, что логика даже самого сложного эксперта гораздо упростилась. К тому же она дает автоматическую поддержку понятия хеджа, т.к. эксперт держит информацию о своих длинных и коротких позициях.
 
TheXpert: ... Реализация торговой части зависит от стратегии, так что в рамках штурма гипотетической стратегии обсуждать нечего. Реализация стратегии как ни странно тоже зависит от стратегии :)
MetaDriver: ... А вот и не обязательно.  У меня так практически не зависит.  Вся торговая часть прописана в виде класса (CMarketDriver), который полностью реализует выставление ордеров, отслеживание позиций, реквоты и прочую хрень связанную с торговлей. По всем инструментам сразу. А стратегическая часть только подаёт ему на вход рекомендованные рыночные позиции по инструментам: т.е. заполняет массив структур формата {string Instrument; double Position} и запрашивает синхронизацию с сервером : MD.Synhronize(PositionArray).  И псё. Пока торгует только рыночными ордерами, но на подходе версия торгующая лимитниками выставляемыми внутрь спреда (для уменьшения торговых издержек). Для торговли тейкпрофиты/стоплоссы не использую, но MarketDriver может ставить защитные стопы на случай длительной потери связи с сервером (параметры стопов указываются один раз в настройках драйвера).   Кстати, очень удачное, практически беспроблемное структурное решение.  Для проверки стратегических идей в тестере вообще песня - никаких проблем с торговлей, всё внимание можно посвятить стратегии - вся торговля уже давно отлажена и инкапсулирована в торговом драйвере.

Как начнете основательно переводить исполнение в стратегии на лимитные ордера, сразу повылазит куча вопросов, как-то:

  • влияние ваших лимитников на цену, которая попадает в вашу стратегическую часть (анализатор/прогназатор/мозг).
  • синхронизация для мультивалютной стратегии
  • долговременное отсутствие исполнения при торговле по тренду (тралить? если да то как, или плюнуть и по рынку)
  • частичное исполнение
  • ...

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

MetaDriver: ... Для проверки стратегических идей в тестере вообще песня - никаких проблем с торговлей ...

Да, для лимитников действительно песня
 
GaryKa:

Как начнете основательно переводить исполнение в стратегии на лимитные ордера

Вот как раз пример того, о чем я говорил -- торговая часть зависит от стратегии.