Вопрос к профессионалам: ООП и MQL4

 
Привет всем!

Мне довелось реализовывать на MQL4 стратегию, состоящую из нескольких взаимосвязанных индикаторов. Т.е. несколько индикаторов используются одновременно в индикаторах более высокого порядка, а последние, в свою очередь, используются в самой стратегии. В итоге столкнулся с проблемой структурирования кода. В ООП я бы сделал для каждого индикатора свой класс, загнал бы туда все методы и буферы, а связанные индикаторы реализовал бы через приемственность классов. Но в MQL4 ничего, похожего на ООП, я не встретил и сильно призадумался – как мне сделать код читабельным и масштабируемым.

Вот, что я имею… Индикаторы довольно сложны и требуют наличие достаточно большого числа буферов (>6). Чтобы окончательно не запутаться в коде, пришлось его подвергнуть жесткой фрагментации и вынести основную часть в отдельную библиотеку. Буферы и параметры индикаторов передаются в виде параметров функций, которые далее вызывают друг друга по цепочке, передавая уже только необходимые для каждой вложенной функции параметры.

Примерно так выглядит заголовок одного из индикаторов:

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1 Lime
#property indicator_color2 Aqua
#property indicator_color3 DimGray
#property indicator_color4 ForestGreen
#property indicator_color5 HotPink

#include <TendLib.mq4>

//---- input parameters
extern int RPeriod = 3;
extern int SPeriod = 15;
extern int LPeriod = 35;
extern double TSStep = 0.8;

//---- buffers
double FAMA_buf[];
double Rapid_buf[];
double Speed_buf[];
double ShortM_buf[];
double LSpeed_buf[];
double Lead_buf[];
double LongM_buf[];
double TS_buf[];
double Up_buf[];
double Down_buf[];

Примерно так выглядит его тело:

int pos, Start = Bars-IndicatorCounted()-1;

IndicatorBuffer(FAMA_buf,Symbol(),Period());
IndicatorBuffer(Rapid_buf,Symbol(),Period());
IndicatorBuffer(Speed_buf,Symbol(),Period());
IndicatorBuffer(LSpeed_buf,Symbol(),Period());
IndicatorBuffer(Lead_buf,Symbol(),Period());

iFAMAS(FAMA_buf,Rapid_buf,Symbol(),Period(),RPeriod,2,2,Start);
iTMI(Rapid_buf,Speed_buf,ShortM_buf,LSpeed_buf,Lead_buf,LongM_buf,TS_buf,
RPeriod,SPeriod,LPeriod,TSStep,Start);

for(pos=Start; pos>=0; pos--){
if(TS_buf[pos] > 0) Up_buf[pos] = ShortM_buf[pos]+0.2; else Up_buf[pos] = EMPTY_VALUE;
if(TS_buf[pos] < 0) Down_buf[pos] = ShortM_buf[pos]-0.2; else Down_buf[pos] = EMPTY_VALUE;
}

Структура индикатора стратегии выстраивается по аналогии. Представьте себе «кривизну» и нечитабельность кода этой стратегии, если она использует несколько индикаторов сразу! Получаем вот такой набор буферов :

double SignalBuyBuf[];
double SignalSellBuf[];
double TrendUpBuf[];
double TrendDownBuf[];
double PushUpBuf[];
double PushDownBuf[];

double IND_FAMA_buf[];
double IND_Rapid_buf[];

double TMI_Speed_buf[];
double TMI_ShortM_buf[];
double TMI_LSpeed_buf[];
double TMI_Lead_buf[];
double TMI_LongM_buf[];
double TMI_TS_buf[];

double Tends_Short_buf[];
double Tends_LTend_buf[];
double Tends_Lead_buf[];
double Tends_Long_buf[];

double TSI_WVol_buf[];
double TSI_VI_buf[];
double TSI_buf[];

И страшно представить, что будет с кодом, когда мне потребуется вызвать один из этих индикаторов одновременно с существующим, но на другом таймфрейме…

Возникает вопрос – можно ли как-то упростить такой код в MQL4? Может есть какое-то подобие namespace (изолированное пространство имен) или structure (группировка переменных в структуру). Я бы сделал "эмуляцию" ООП и жить стало бы значительно легче…

ЗЫ: Вариант перехода на MQL5 пока не рассматриваю, т.к. сама платформа еще мало распространена, а я планирую запустить стратегию реальную в работу в ближайшие месяцы. Что посоветуете?

ЗЫЫ: Вариант каскадного вызова через iCustom не катит, т.к. часто он у меня глючит (много параметров - сложно контролировать) и приходится вызывать один индикатор по нескольку раз, т.к. нужно считать сразу несколько линий -> лишняя нагрузка. К тому же мне все равно советник писать, а в советнике я бы не хотел использовать iCustom.

 
andreybs:
Мне довелось реализовывать на MQL4 стратегию, состоящую из нескольких взаимосвязанных индикаторов. Т.е. несколько индикаторов используются одновременно в индикаторах более высокого порядка, а последние, в свою очередь, используются в самой стратегии. В итоге столкнулся с проблемой структурирования кода. В ООП я бы сделал для каждого индикатора свой класс, загнал бы туда все методы и буферы, а связанные индикаторы реализовал бы через приемственность классов. Но в MQL4 ничего, похожего на ООП, я не встретил и сильно призадумался – как мне сделать код читабельным и масштабируемым.

Все описанные взаимодействия можно реализовать через вызовы функций. Разбейте код на функции и вызывайте в каком угодно порядке столько раз сколько надо и когда надо.

Главное правильно структурировать входные и выходные данные, но это не вопрос ООП, а логического мышления для определения нужной последовательности выполнения расчетов.

 
Andrei01:

Все описанные взаимодействия можно реализовать через вызовы функций. Разбейте код на функции и вызывайте в каком угодно порядке столько раз сколько надо и когда надо.

Главное правильно структурировать входные и выходные данные, но это не вопрос ООП, а логического мышления для определения нужной последовательности выполнения расчетов.


Ну при чем тут "логическое мышление"? Я же сказал, что реализовал все через функции. Но мне не нравится сам код. Не нравится в первую очередь из-за того, что приходится объявлять огромное кол-во массивов и передавать их в качестве параметров функции. Гораздо проще было бы все массивы засунуть в структуру и передать указатель на нее. Может знаете способ, как эмулировать структуру? Где то я встречал кусок кода на mql4 с точками типа "имя1.имя2". Может структуры в MQL4 все таки есть, но они просто не описаны в документации? Может есть "хитрости" использования перепроцессора (может он умеет что-то большее, чем тупая подмена меток на их значение)? Вот, что интересно узнать...
 
Структур и классов нет в MQL4. А точки в имени переменных допускаются.
 
andreybs:

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

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

Но не вижу какое это имеет отношение к структурированности кода.

 
andreybs:

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

структуры нужны для хранения данных РАЗНЫХ ТИПОВ, а данные одного типа можно хранить в многомерных массивах, да и смысл ООП несколько в другом - ООП освобождает программиста от рутинной задачи по подготовке(описанию) и инициализации переменных, этим должен "заведовать" вызываемый класс, ну и конечно такие прелести как наследование и полиморфизм - помогают не вникая в суть базового класса создать свой класс на его основе с измененными методами (ф-циями)

но, увы ООП не поддерживается в МТ4 

 
Andrei01:

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

Но не вижу какое это имеет отношение к структурированности кода.


Очень простое - передать 1 параметр-указатель вместо 12 :)

1. это и выглядит нагляднее
2. если потом нужно будет добавить/убрать параметр, то достаточно будет изменить только структуру, не правя во всех местах вызовы
3. клонировать структуру проще - это одна переменная, а не 12 (например, если нужно создать еще один экземпляр индикатора)

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

 
joo:
Структур и классов нет в MQL4. А точки в имени переменных допускаются.

Хм. Это уже что-то. А можно ли как то создать свой тип данных?
 
andreybs:

Хм. Это уже что-то. А можно ли как то создать свой тип данных?
Нет.
 
IgorM:

структуры нужны для хранения данных РАЗНЫХ ТИПОВ, а данные одного типа можно хранить в многомерных массивах, да и смысл ООП несколько в другом - ООП освобождает программиста от рутинной задачи по подготовке(описанию) и инициализации переменных, этим должен "заведовать" вызываемый класс, ну и конечно такие прелести как наследование и полиморфизм - помогают не вникая в суть базового класса создать свой класс на его основе с измененными методами (ф-циями)

но, увы ООП не поддерживается в МТ4


Ну, да, мне это и нужно. Я же писал - индикаторы 1-го и 2-го порядка. Стратегию можно считать 3-м порядком. Налицо наследование классов, если индикатор реализовать, как класс. Вот я и ищу обходные варианты, чтобы не было дублирования кода, но и чтобы читабельность не терялась.

 
joo:
Нет.

А перепроцессор может "играть" именами переменных (например, если создание группы переменных, т.е. куска кода засунуть в некий макрос) или он может только подставлять предварительно объявленные значения?