Изменение входных параметров индикатора на ходу

 
Хочу написать универсальный модуль, который бы можно было в несколько нажатий подключить к любому индикатору.

Модуль бы позволял менять входные целочисленные (int) параметры индикатора на ходу. По нажатию на TAB происходил бы соответствующий выбор входного параметра. Колесико мыши (что-то события такого в MQL не нашел) - его изменние на ±1.

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

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

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

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

 
Meat:

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

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

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

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

 
kbw74614:
Ну совсем уж универсальный подход не обязателен. Имел в виду, что берем исходник большинства индикаторов и минимальным количеством копи-пасты и правок добавляем обозначенный функционал. Давайте сделаем. Если понять, что и как можно сделать, так можно вообще конвертер написать, который обычный индикатор превращает в такой нестандартный (для текущего времени) тип.
У меня было, если найду выложу.
 
Meat:

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

Для конвертера это не проблема: запустил - готов правильный индикатор.

TheXpert:
У меня было, если найду выложу.
Ждем тогда конвертер. 
 
kbw74614:
Ждем тогда конвертер. 

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

Писано оно все оооочень давно, еще во время становления MQL5, но вроде пашет ) правда минорные косяки с отображением и т.п. возможны. Если надо скину.

Вот весь исходник советника чтобы было видно само подключение

#include <TheXpert/SettingsBar/SettingsBar.mqh>

SettingsBar Bar;

string GetSettingNameByID(int id)
{
   switch (id)
   {
      case 0: return "Bool Setting";
      case 1: return "Double Setting";
      case 2: return "Int Setting";
      case 3: return "Selection Setting";
      case 4: return "String Setting";
   }
   return "N\A";
}

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
   Bar.OnChartEvent(id, lparam, dparam, sparam);
   
   if (id == CHARTEVENT_CUSTOM + EVENT_SETTING_CHANGED)
   {
      Print("Setting < ", GetSettingNameByID(lparam), " > has been changed to ", sparam);
   }

   ChartRedraw();
}

int OnInit()
{
   Bar.AddBoolSetting("Bool Setting", 0, true);
   Bar.AddDoubleSetting("Double Setting", 1, 2.35, 0.1, -20, 20);
   Bar.AddIntSetting("Int Setting", 2, 10, 2, 0, 100);
   
   SelectionTable TF;

   TF.AddSelection(PERIOD_M1, "1 Minute");
   TF.AddSelection(PERIOD_M5, "5 Minutes");
   TF.AddSelection(PERIOD_M15, "15 Minutes");
   TF.AddSelection(PERIOD_M30, "30 Minutes");
   TF.AddSelection(PERIOD_H1, "1 Hour");
   TF.AddSelection(PERIOD_H4, "4 Hours");
   TF.AddSelection(PERIOD_D1, "1 Day");

   Bar.AddSelectionSetting("Selection Setting", 3, PERIOD_M1, TF);
   
   Bar.AddStringSetting("String Setting", 4, "string value");

   Bar.SetTitle("Settings Example");

   return(0);
}

void OnDeinit(const int reason)
{}

void OnTick()
{}
 
TheXpert:

Вот весь исходник советника чтобы было видно само подключение

Спасибо, теперь стало ясно. Конвертер, действительно, элементарно написать под это дело. И все индикаторы станут с динамическими входными параметрами!

Остались две проблемы:

  • Колесико мыши как задействовать?
  • В индикаторах при изменении входного параметра нужно OnCalculate запустить с нуля (все пересчитать). У меня не выходит сформировать входные параметры для OnCalculate. Делаю так:
    void FullOnCalculate( void )
    {
      long volume[];
      int spread[];
    
      ArraySetAsSeries(volume, TRUE);
      ArraySetAsSeries(spread, TRUE);
    
      const int Size = MathMin(CopyTickVolume(Symbol(), Period(), 0, Bars, volume),
                               CopySpread(Symbol(), Period(), 0, Bars, spread));
    
      OnCalculate(Size, 0, Time, Open, High, Low, Close, Volume, volume, spread);
    
      return;  
    }
 
kbw74614:

Спасибо, теперь стало ясно. Конвертер, действительно, элементарно написать под это дело. И все индикаторы станут с динамическими входными параметрами!

Остались две проблемы:

  • Колесико мыши как задействовать?
  • В индикаторах при изменении входного параметра нужно OnCalculate запустить с нуля (все пересчитать). У меня не выходит сформировать входные параметры для OnCalculate. Делаю так:
Переименовать OnCalculate в OnCalculate2, сделать новую пустую OnCalculate и вызывать из нее OnCalculate2
 
Integer:
Переименовать OnCalculate в OnCalculate2, сделать новую пустую OnCalculate и вызывать из нее OnCalculate2

Фактически так и делаю здесь:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
  return(Relation.Calculate(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread));
}

Но такой вызов происходит, когда OnCalculate запускается сам - например, по приходу нового тика. А как вызвать OnCalculate напрямую? Например, OnStart вызвать получается без проблем. А с OnCalculate вызов  делается без проблем (как написал в FullOnCalculate), но вот что-то странное затем творится с входными массивами - выход за пределы. Пробовал все входные массивы переопределить через CopyRates в MqlRates. Но все равно происходит выход за пределы массива при выполнении вызванного OnCalculate.

 

А при самостоятельном выполнении OnCalculate никаких проблем не возникает. Либо это баг, либо что-то делаю неправильно. Прошу помочь. 

Причина обращения: