Библиотеки: Input_Struct

 

Input_Struct:

Структура входных параметров

Input_Struct

Автор: fxsaber

 
Пример применения библиотеки для кастомных алгоритмов оптимизации.
// Вариант через макросы,
#define iInput01 Amount
#define iInput02 Count
#define iInput03 Period

#define dInput01 Koef
#define dInput02 Log

#define bInput01 Flag
// но лучше через копирование mqh-файла и соответствующую замену в одно действие для каждого входного.

#include <fxsaber\Input_Struct\Input_Struct.mqh> // https://www.mql5.com/ru/code/47932
#include <fxsaber\MultiTester\MTTester.mqh> // https://www.mql5.com/ru/code/26132

INPUT_STRUCT inInputs;

MACROS_INPUT(int, Amount, 1); // Parameter Amount
MACROS_INPUT(int, Count, 2);  // Parameter Count
MACROS_INPUT(int, Period, 3); // Parameter Period

MACROS_INPUT(double, Koef, 4.56); // Parameter Koef
MACROS_INPUT(double, Log, 7.89);  // Parameter Log

MACROS_INPUT(bool, Flag, true); // Parameter Flag

// ФФ для штатного Оптимизатора - пример.
double OnTester()
{
  return(MathSin(inInputs.Amount) *
         MathSin(inInputs.Count) *
         MathSin(inInputs.Period) *
         MathSin(inInputs.Koef) *
         MathSin(inInputs.Log) *
         (inInputs.Flag ? 1 : -1));
}

int OnInit()
{
  const bool IsTester = MQLInfoInteger(MQL_TESTER);

  if (!IsTester)
  {
    string Settings;
    double ArgBest[];
    double BestResult;
    
    if (!MTTESTER::GetSettings2(Settings) ||
        ((Settings = StringSubstr(Settings, StringFind(Settings, "[TesterInputs]"))) == NULL) ||
        (inInputs.FromString(Settings) != inInputs.GetAmount()))        
      MessageBox("Поместите этот советник в Тестер и\nнастройте там входные параметры!" +
                 "\n\nЗатем запустите его снова в Терминале.");    
    else if (!OptimizationMode(Settings, BestResult, ArgBest))
      Print("\nError optimization!");
    else
    {
      inInputs = ArgBest;
      
      Print("\nBestResult = " + (string)BestResult + ": " + inInputs.ToString());
    }    
  }
  
  return(!IsTester);
}

// ФФ для кастомного Оптимизатора.
double FitnessFunction( const double &Arg[] )
{
  inInputs = Arg;
  
  return(OnTester());
}

// Режим запуска кастомного Оптимизатора.
bool OptimizationMode( const string Settings, double &Res, double &ArgBest[] )
{
  INPUT_STRUCT InputsDefault;
  
  INPUT_STRUCT InputsStart;
  INPUT_STRUCT InputsStep;
  INPUT_STRUCT InputsStop;
  INPUT_STRUCT InputsEnable;
  
  InputsDefault.FromString(Settings);

  InputsStart.FromString(Settings,  1);
  InputsStep.FromString(Settings,   2);
  InputsStop.FromString(Settings,   3);
  InputsEnable.FromString(Settings, 4);
  
  Print("\nНастройки оптимизации на языке именованных входных параметров:");
  Print("InputDefault: " + InputsDefault.ToString());
  Print("InputsStart: " +  InputsStart.ToString());
  Print("InputsStep: " +   InputsStep.ToString());
  Print("InputsStop: " +   InputsStop.ToString());
  Print("InputsEnable: " + InputsEnable.ToString());
  
  double ArgDefault[];
  double ArgStart[];
  double ArgStep[];
  double ArgStop[];
  double ArgEnable[];
  
  InputsDefault.ToArray(ArgDefault);
  InputsStart.ToArray(ArgStart);
  InputsStep.ToArray(ArgStep);
  InputsStop.ToArray(ArgStop);
  InputsEnable.ToArray(ArgEnable);
      
  Print("\nНастройки оптимизации на языке кастомного алгоритма оптимизации ФФ:");
  Print("ArgDefault:"); ArrayPrint(ArgDefault);
  Print("ArgStart:");   ArrayPrint(ArgStart);
  Print("ArgStep:");    ArrayPrint(ArgStep);
  Print("ArgStop:");    ArrayPrint(ArgStop);
  Print("ArgEnable:");  ArrayPrint(ArgEnable);

  return(Optimization(FitnessFunction, Res, ArgBest, ArgDefault, ArgStart, ArgStep, ArgStop, ArgEnable));  
}

typedef double (*TFitnessFunction)( const double &Arg[] ); 

// Кастомный Оптимизатор.
bool Optimization( const TFitnessFunction FF,
                   double &Res, double &ArgBest[], // Res = FF(ArgBest)
                   const double &ArgDefault[],
                   const double &ArgStart[],
                   const double &ArgStep[],
                   const double &ArgStop[],
                   const double &ArgEnable[])
{
// На основе Arg-данных алгоритм оптимизации должен создавать Arg[] для расчета FF(Arg).

  return(false); // false - в случае неудачи.
}


  1. Открываем этот советник в Тестере и настраиваем значения оптимизируемых параметров.
  2. Либо запускаем советник в Тестере - получаем результат штатного Оптимизатора.
  3. Либо запускаем советник в Терминале - получаем результат кастомного Оптимизатора. Входные подхватятся из п.1.

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

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: Input_Struct

fxsaber, 2024.01.19 18:16

// Кастомный Оптимизатор.
bool Optimization( const TFitnessFunction FF,
                   double &Res, double &ArgBest[], // Res = FF(ArgBest)
                   const double &ArgDefault[],
                   const double &ArgStart[],
                   const double &ArgStep[],
                   const double &ArgStop[],
                   const double &ArgEnable[] );
Подключил один кастомный алгоритм оптимизации.
#define vector vect
  #include <ParticleSwarm.mqh> // https://www.mql5.com/en/blogs/post/683577
#undef vector

class FF_Functor : public Functor
{
public:
  static TFitnessFunction FF;
  
  virtual double calculate( const double &Arg[] )
  {
    return(FF_Functor::FF(Arg));
  }
};

static TFitnessFunction FF_Functor::FF = NULL;

#define PSO_CYCLES 10

// Кастомный Оптимизатор.
bool Optimization( const TFitnessFunction FF,
                   double &Res, double &ArgBest[], // Res = FF(ArgBest)
                   const double &ArgDefault[],
                   const double &ArgStart[],
                   const double &ArgStep[],
                   const double &ArgStop[],
                   const double &ArgEnable[] )
{
  double Max[];
  double Min[];
  double Step[];

  const int Size = ArraySize(ArgDefault);
  
  ArrayResize(Max, Size);
  ArrayResize(Min, Size);
  ArrayResize(Step, Size);
  
  for (uint i = Size; (bool)i--;)
  {
    Min[i] = ArgEnable[i] ? ArgStart[i] : ArgDefault[i];
    Max[i] = ArgEnable[i] ? ArgStop[i] : ArgDefault[i];
    Step[i] = ArgEnable[i] ? ArgStep[i] : 0;
  }
  
  Swarm swarm(Size, Max, Min, Step);        

  FF_Functor FFObject;
  FF_Functor::FF = FF;
  
  Res = swarm.optimize(FFObject, PSO_CYCLES);  
  swarm.getSolution(ArgBest);

  return(true); // false - в случае неудачи.
}


На этих настройках


такой результат.


Штатный ГА был повержен на этом запуске. Скорее всего, это ни о чем не говорит, т.к. ФФ сомнительная.


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

MQL's OOP notes: Particle Swarm Speeds Up Expert Adviser Optimization On The Fly
MQL's OOP notes: Particle Swarm Speeds Up Expert Adviser Optimization On The Fly
  • 2016.11.21
  • www.mql5.com
In 2 previous chapters we have studied a library for on the fly optimization of expert advisers (part1, part2). One of drawbacks of the library is its slow method of optimization, because it's nothing
 
Спасибо!
 

Памятка.

#define iInput01 Amount
#define dInput01 Koef
#include <fxsaber\Input_Struct\Input_Struct.mqh> // https://www.mql5.com/ru/code/47932

#define TOSTRING(A) #A + " = " + (string)(A) + " "

void OnStart()
{
  INPUT_STRUCT Input;
  
  // Задание через массив.
  const double Array[] = {1, 2};  
  Input = Array; // Input.FromArray(Array);  
  
  // Вывод в строку.
  Print(Input[]); // Amount = 1, Koef = 2.0  
  Print(TOSTRING(Input.Amount) + TOSTRING(Input.Koef)); // Input.Amount = 1 Input.Koef = 2.0 

  // Задание через строку.
  Input = "Amount = 3"; // Input.FromString("Amount = 3");  
  Print(Input[]); // Amount = 3, Koef = 2.0
  
  // Вывод в строку - расширенный вариант.
  Print(Input + Input); // Amount = 3, Koef = 2.0, Amount = 3, Koef = 2.0
  Print(Input + "Hello!"); // Amount = 3, Koef = 2.0, Hello!
  Print(Input["SL = 1.5, Koef = 3.42, Hello!, Amount = 1"]); // Amount = 1, Koef = 3.42, SL = 1.5, Hello!

  // Вывод в массив.
  double Array2[];
  Input.ToArray(Array2);
  ArrayPrint(Array2); // 3.00000 2.00000
  
  // Задание через строку - расширенный вариант.
  Input.FromString("Amount=4||5||2||10||N", 0); Print(Input[]); // Amount = 4, Koef = 2.0
  Input.FromString("Amount=4||5||2||10||N", 1); Print(Input[]); // Amount = 5, Koef = 2.0
  Input.FromString("Amount=4||5||2||10||N", 2); Print(Input[]); // Amount = 2, Koef = 2.0
  Input.FromString("Amount=4||5||2||10||N", 3); Print(Input[]); // Amount = 10, Koef = 2.0
  Input.FromString("Amount=4||5||2||10||N", 4); Print(Input[]); // Amount = 0, Koef = 2.0
  Input.FromString("Amount=4||5||2||10||Y", 4); Print(Input[]); // Amount = 1, Koef = 2.0
  
  // Вывод в строку по маске.
  bool Mask1[] = {true, true};  Print(Input[Mask1]); // Amount = 1, Koef = 2.0
  bool Mask2[] = {true, false}; Print(Input[Mask2]); // Amount = 1
  bool Mask3[] = {false, true}; Print(Input[Mask3]); // Koef = 2.0
}
 
Подробная статья, как было сделано с инпутами (классика). И рефакторинг, как стало. По этим примерам можно хорошо понять, как действует библиотека и для чего она нужна.
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Обсуждение статьи "Разрабатываем мультивалютный советник (Часть 2): Переход к виртуальным позициям торговых стратегий"

fxsaber, 2024.02.12 02:09

Текущие результаты своей работы с инпутами снова (в приложении) применил к коду из данной статьи.

Удалось добиться единоразового прописывания в коде входных.

Пример того, как достаточно только один раз в коде прописать входные, а дальше готовы и соответствующие input-переменные и прием/передача их через строки в файлы/ООП.
 
fxsaber #:

Пример того, как достаточно только один раз в коде прописать входные, а дальше готовы и соответствующие input-переменные и прием/передача их через строки в файлы/ООП.

Значительно расширил возможности библиотеки.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Обсуждение статьи "Разрабатываем мультивалютный советник (Часть 2): Переход к виртуальным позициям торговых стратегий"

fxsaber, 2024.02.12 17:33

Добавил group, string-инпуты и кое-что по мелочи для удобства на будущее.

#define TYPENAME_INPUT StrategyInput

#define MACROS_MULTI                           \
  INPUT(symbol, string, "EURGBP")              \ // Торговый инструмент (символ)
  INPUT(timeframe, ENUM_TIMEFRAMES, PERIOD_H1) \ // Период графика (таймфрейм)
  GROUP("===  Параметры управление капиталом") \
  INPUT(fixedLot, double, 0.01)                  // Размер открываемых позиций (фиксированный)
#define TYPENAME_INPUT SimpleVolumesStrategyInput

#define MACROS_MULTI                           \
  GROUP("===  Параметры сигнала к открытию")   \
  INPUT(signalPeriod, int, 13)                 \ // Количество свечей для усреднения объемов
  INPUT(signalDeviation, double, 0.3)          \ // Относ. откл. от среднего для открытия первого ордера
  INPUT(signaAddlDeviation, double, 1)         \ // Относ. откл. от среднего для открытия второго и последующих ордеров
  GROUP("===  Параметры отложенных ордеров")   \
  INPUT(openDistance, int, 0)                  \ // Расстояние от цены до отлож. ордера
  INPUT(stopLevel, double, 10500)              \ // Stop Loss (в пунктах)
  INPUT(takeLevel, double, 465)                \ // Take Profit (в пунктах)
  INPUT(ordersExpiration, int, 1000)           \ // Время истечения отложенных ордеров (в минутах)
  GROUP("===  Параметры управление капиталом") \
  INPUT(maxCountOfOrders, int, 3)                // Макс. количество одновременно отрытых ордеров

Нетривиальный код библиотеки и простое ее использование.

 
#property script_show_inputs

#define iInput01 Amount
#define dInput01 Koef
#include <fxsaber\Input_Struct\Input_Struct.mqh> // https://www.mql5.com/ru/code/47932

// Задали инпут-переменные.
MACROS_INPUTS(int, Amount, 1);
MACROS_INPUTS(double, Koef, 2);

void OnStart()
{
  Print(inInputsAll); // Все input-переменные в одной строке.
}

Amount = 123, Koef = 4.567

Полноценный пример использования этой возможности здесь.

 

Бывают ситуации, когда при считывании сета не задано какое-то поле. Например, сеты давно были записаны. А позже был добавлен новый инпут. И, соответственно, он оказался не прописан в старых сохраненных сетах.

В подобных ситуациях пригодится Default-метод для задания новому полю значения по умолчанию.

#property script_show_inputs

#define iInput01 Amount
#define dInput01 Koef

#define INPUT_STRUCT_ADDON // Полная автоматизация input-переменных.
#include <fxsaber\Input_Struct\Input_Struct.mqh> // https://www.mql5.com/ru/code/47932

void OnStart()
{
  Print(inINPUT_STRUCT[]); // Автоматически созданный объект структуры с соответствующими инпутами.
  
  inINPUT_STRUCT.Default(); // Прописали значения input-переменных, что прописаны в коде.
  Print(inINPUT_STRUCT[]);
}


Результат.

Amount = 123, Koef = 4.567
Amount = 1, Koef = 2.0


 Потому что при задании input-переменных в коде были указаны такие значения.

#define TYPENAME_INPUT INPUT_STRUCT

#define MACROS_MULTI     \
  INPUT(Amount, int, 1)  \
  INPUT(Koef, double, 2)