iCustom() в MQL5: нужна ли унификация функции? - страница 2

 

Вышеназванные задачи возникали уже десятилетия назад. И для их, в частности, решения были введены указатели на функции.

Неужели сложно выглядит:

- в теле советника везде вызов индикатора будет MyIndicator();

- а в ините MyIndicator = iCustom(...);

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

 
getch >>:
Указатели на переменные и на функции присутствуют даже в классическом Си. Неужели MQL5 примитивнее?!

Назовем это "надежнее" .

Mathemat >>:

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

Концептуально это сложнее, чем сейчас. Слишком много подводных камней.

 

Абстрагирование типов внешне всегда кажется сложнее и запутаннее. Зато нет никаких проблем, чтобы программным путем, без лишних выкрутасов, прямо получить внешние параметры индикатора. При этом inputStruct (или то, что ее могло бы заменить) должна передаваться по ссылке.

ОК, Ваше мнение я выслушал, спасибо.

2 getch: Ваше предложение никак не решает проблему получения неизвестных внешних параметров индикатора программным путем.

 
Mathemat >>:

Абстрагирование типов внешне всегда кажется сложнее и запутаннее. Зато нет никаких проблем, чтобы программным путем, без лишних выкрутасов, прямо получить внешние параметры индикатора. При этом inputStruct (или то, что ее могло бы заменить) должна передаваться по ссылке.

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


Допустим, при компиляции индикатора генерируется структура с параметрами и помещается в include файл с именем индикатора. Имхо, вполне нормальный и логичный путь.

1.(-) Этот файл нельзя будет изменять, т.к. проблемы совместимости и т.д.

2.(-) Компилятор должен будет переводить структуру в старый набор параметров, хотя бы из принципов совместимости.

3.(+) Можно плевать на порядок задания и значения по умолчанию (можно генерить).

4.(-) Существенное увеличение объема кода по сравнению со старой формой для выполнения той же задачи.

5.(-) Отсутствие исходников индикатора сразу делает невозможным его использование в коде.

6.(+?) Вместо многих параметров в функции надо будет задавать один -- структуру, но т.к. для каждого индикатора придется создавать свой тип -- сущность функции не поменяется

Уверен, что если копнуть еще глубже, минусов поприбавится, хотя, возможно, и плюсов.

 
TheXpert >>:

Никакого абстрагирования не будет. Для каждого индикатора -- своя структура, т.е. свой тип данных

Какая своя, Андрей? Она единая абсолютно для всех индюкаторов. Это структура, состоящая из строго трех полей. Тип каждого поля - динамический массив соответственно с элементами типа long, double, string (и в этом порядке). Для каждого типа данных (long, double, string) соответствующий массив уже реализован в библиотеке Include/Arrays.

Наверно, я что-то не то говорю?

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

 
Mathemat писал(а) >>

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

Вот именно из-за трёх массивов я и думал про CSV. Так удобнее - не надо думать про то, куда помещать параметр: при помощи перегруженной функции конвертим параметр в строку и добавляем к CSV.

А определять соответствие просто - как раньше делали для вызовов iCustom.

 
Mathemat >>:

Какая своя, Андрей? Она единая абсолютно для всех индюкаторов. Это структура, состоящая из строго трех полей. Тип каждого поля - динамический массив соответственно с элементами типа long, double, string (и в этом порядке). Для каждого типа данных (long, double, string) соответствующий массив уже реализован в библиотеке Include/Arrays.

Наверно, я что-то не то говорю?

Да, сорри, был невнимателен.

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

Это как раз несложно. Делаем не массивы, а три мапы -- строка-инт строка-дабл строка-строка.

Ключевой тип -- строка -- имя параметра. Ему соответствует значение. Парсить легко сопоставлять тоже, структура унифицирована.

Как Вам такой подход Mathemat, ?

 

Не очень понял, извини, Андрей.

Тут не все так просто, как хотелось бы. Наверно, дополнительно придется указывать и тип.

Вот, скажем, список input параметров (реальный зоопарк):


// логические

input bool _AggressiveTrade = true;

input bool _Verify = false;


// целочисленные простые

input int _OrdersMax = 4;

input int _TP = 320;

input int _SL = 150;

input long _Levels = 12;

input datetime _FinishTrading = 1526734321;


// это тоже целочисленные, но теперь видно, что без задания типа, оказывается, не обойтись, т.к. это enum

input ENUM_MA_METHOD _MAMethod = MODE_LWMA; // 3

input ENUM_TIMEFRAMES _TFBasic = PERIOD_M3; // тоже 3, но это уже другая тройка, чем предыдущий enum

input color _Basic = Blue; // это фактически тоже enum


// вещественные

input double _LotStandard = 0.15;

input double _Risk = 0.05;


// строковые

input string _SymbolAnalytic = "EURGBP";

input string _SymbolTrade = "USDJPY";


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

 
Mathemat >>:

Не очень понял, извини, Андрей.

Тут не все так просто, как хотелось бы. Наверно, дополнительно придется указывать и тип.

Как-то так:

class Params
{
public:    
   DoubleInputMap doubles;
   IntInputMap    integers;
   BoolInputMap   bools;
   StringInputMap strings;   
};

void OnTick()
{
   Params params;
   
   params.integers["FastMa"] = 5;
   params.integers["SlowMa"] = 25;
   params.strings["Description"] = "";
   params.bools["ShowSignal"] = true;
   
   hCustom = iCustom(_Symbol, 0, "CustomName", params);
}
Енумы -- это интегральные типы, поэтому их можно приводить к int
 
TheXpert >>:

Как-то так:

Енумы -- это интегральные типы, поэтому их можно приводить к int

Примерно понятно, спасибо, Андрей.

По поводу енумов: кастинг обоих енумов, MODE_LWMA и PERIOD_M3, к типу int приводит к одному числу, 3. А вот из тройки-то как восстановить нужный нам енум? Вот пример из моего кода.

Вот такая строка проходит нормально (MA_Method объявлен как ENUM_MA_METHOD):

MA_Method = (ENUM_MA_METHOD) 3;

а вот такая - нет, ругается компилятор:

MA_Method = 3;

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

Хотя и тут, наверно, можно сразу присваивать примерно так:

params.integers["MA_type"] = (ENUM_MA_Method)2;
Причина обращения: