Discussing the article: "Developing a multi-currency Expert Advisor (Part 2): Transition to virtual positions of trading strategies" - page 5

 
mytarmailS #:
It is not a fact that in the market the complication of the model will work better than a basket of simple TSs
Well, it is necessary not to drink each TS to the trough, but just add new TS after several passes of the optimiser.
 
Maxim Dmitrievsky bagging (basket) of strategies, but boosting. This is when one strategy is optimised first, then its signals are substituted as a parameter for the second strategy, the second strategy is optimised, and so on.

It seems to me that the implementation of the highlighted is a very non-trivial task. Usually, strategy parameters are set at the start, and the opening/closing signals are determined by some algorithm while the strategy is running. If we save the history of openings in some unified form, then it will have to be fed to the input of the second strategy.... Is it so? If we give this information in the form of an algorithm (function) and its fixed parameters, won't it turn out that we have come to the same bagging, but with a backdoor?

 

Thank you very much, I read it with interest. I want to do just something similar, only with more automation, for which I plan to mercilessly put into operation your libraries for working with *.opt and *.tst files of the tester.

 
Yuriy Bykov #:

It seems to me that implementation of the highlighted is a very non-trivial task. Usually strategy parameters are set at startup, and opening/closing signals are determined by some algorithm while the strategy is running. If we save the history of openings in some unified form, then all of it will have to be fed to the input of the second strategy.... Is it so? If we give this information in the form of an algorithm (function) and its fixed parameters, won't it turn out that we have come to the same bagging, but with a backdoor?

I haven't thought about how to do it through the optimiser. No, it should turn out that each next strategy will improve the previous one, i.e. build on top of it. How exactly to visualise it is a matter of time. You can just look up how boosted trees work in the Internet and use them as a basis for your design. There may be a lot of nuances, yes. But I won't do it myself, because all this is already in the MO algorithms. And it is not a panacea, but it can be better than a TC portfolio in terms of its properties.

 
Maxim Dmitrievsky #:

Hadn't thought about how to do it through the optimiser.

This is a routine that can be fully automated through connecting the appropriate mqh to mq5.


The algorithm is as follows.

  1. The folder contains previous passes (if there were no passes - empty) in the form of files.
  2. A new optimisation is started: the TS itself is traded + trade from point 1 is added. In this case MM is distributed evenly between p.1 and TS.
  3. The best pass (OnTester of any kind) of the optimisation is recorded in item 1.
  4. In p.2. as many times as the TS wants in the portfolio.

So you can mix anything you want. It is obvious that even with a complete search, the final result will depend on the sequence in which the TSs are launched.

It is also clear that even on the SB there will be an improvement of indicators with each pass, but it will be a fitting.

 
Yuriy Bykov #:

Thank you very much, I have looked at the code. I will look into passing input parameters later. If it doesn't work out to take this approach completely, some points are likely to be very useful.

I applied the current results of my work with inputs again (in the appendix) to the code from this article.

Here is an example of what SimpleVolumesExpertSingle.mq5 has become.

#define  INPUT_STRUCT_ADDON
#include "Advisor.mqh"
#include "SimpleVolumesStrategy.mqh"
#include "VolumeReceiver.mqh"

input string      symbol_              = "EURGBP";    // Торговый инструмент (символ)
input group "===  Параметры советника"
input ulong       magic_              = 27181; // Magic

CAdvisor     *expert;         // Указатель на объект эксперта

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   expert = new CAdvisor(new CVolumeReceiver(magic_));

   // Добавляем один экземпляр стратегии
   expert.Add(new CSimpleVolumesStrategy( symbol_, inStrategyInput + inSimpleVolumesStrategyInput));

   return(INIT_SUCCEEDED);
}


I managed to achieve a one-time prescription of inputs(SimpleVolumesStrategyInput.mqh) in the code.

// https://www.mql5.com/ru/code/47932
// Use this string to find all Inputs mqh.
// #include <fxsaber\Input_Struct\Input_Struct.mqh> // Original

#define  TYPENAME_INPUT SimpleVolumesStrategyInput

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

Files:
 
fxsaber #:

I applied the current results of my work with inputs again (in the appendix) to the code from this article.

An example of what SimpleVolumesExpertSingle.mq5 has become.


I managed to achieve a single entry of inputs(SimpleVolumesStrategyInput.mqh) in the code.

It seemed to me somehow noticeably easier than the previous variant. Although, maybe it's just that when you look at someone else's code once again, it becomes clearer and simpler each time. Thank you very much! While studying, a question arose, is it possible to place the code that comes after "// Copy-Paste update from here:" in an include file and plug it in instead of pasting it? It's not convenient to just experiment right now, so I thought I'd ask.

In the third article I haven't got to the input parameters yet :(. But it will come for sure.

 
Yuriy Bykov #:

While studying, a question arose, is it possible to place the code that comes after "// Copy-Paste update from here:" in an include file and plug it in instead of pasting it? It's not convenient to just experiment right now, so I decided to ask.

Unfortunately, you can't, because #include of the same file happens only once - the first encounter. After that it is ignored.

This is one of the reasons why you had to make a completely identical file with a different name here.


But in general, the Copy-Paste option is a couple of clicks. Understanding that code is not required.

PriceChannel
PriceChannel
  • www.mql5.com
Ценовой канал произвольной длительности (таймфрейм) бара.
 
Yuriy Bykov #:

In the third article, the input parameters have not yet reached the input parameters :(. But it will come for sure.

Your architecture is somewhat different from mine, so I didn't provide INPUT_STRUCT with a lot of things that would be useful in this project.

It's good that you didn't publish it, because I've redone it again - to the most concise and convenient version (it seems to be the final one).

I added group, string-inputs and some other small things for future convenience.

#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)                // Макс. количество одновременно отрытых ордеров


Pieces of application code to demonstrate how it is used.

#define  INPUT_STRUCT_ADDON
#include "Advisor.mqh"
#include "SimpleVolumesStrategy.mqh"
#include "VolumeReceiver.mqh"

input group "===  Параметры советника"
input ulong       magic_              = 27181; // Magic

CAdvisor     *expert;         // Указатель на объект эксперта

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   expert = new CAdvisor(new CVolumeReceiver(magic_));

   // Добавляем один экземпляр стратегии
   expert.Add(new CSimpleVolumesStrategy(inStrategyInput + inSimpleVolumesStrategyInput));

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CSimpleVolumesStrategy::CSimpleVolumesStrategy( const string sInputs ) : CStrategy(sInputs)
{
   this.Input = sInputs;

   ArrayResize(m_orders, this.Input.maxCountOfOrders);

   // Загружаем индикатор для получения тиковых объемов
   iVolumesHandle = iVolumes(this.InputStrategy.symbol, this.InputStrategy.timeframe, VOLUME_TICK);

// Устанавливаем размер массива-приемника тиковых объемов и нужную адресацию
   ArrayResize(volumes, this.Input.signalPeriod);
   ArraySetAsSeries(volumes, true);
}
//+------------------------------------------------------------------+
//| Конструктор                                                                |
//+------------------------------------------------------------------+
CStrategy::CStrategy( const string sInputs ) : m_isChanged(false)
{
  this.InputStrategy = sInputs;
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
// Проверяем корректность параметров
   if(startIndex_ < 0 || startIndex_ + totalStrategies_ > 9) {
      return INIT_PARAMETERS_INCORRECT;
   }

// Создаем и наполняем массив из экземпляров стратегий
   CStrategy *strategies[9];

   StrategyInput InputBase;
   SimpleVolumesStrategyInput Input;

   InputBase.timeframe = PERIOD_H1;

   // Первый способ задания - через инициализацию.
   const StrategyInput InputBase0 = {"EURGBP", PERIOD_H1, NormalizeDouble(0.01 / 0.16 * depoPart_, 2)};
   const SimpleVolumesStrategyInput Input0 = {13, 0.3, 1.0, 0, 10500, 465, 1000, 3};
   strategies[0] = new CSimpleVolumesStrategy(InputBase0 + Input0);

   // Второй способ задания - через строку и массив.
   InputBase.fixedLot = NormalizeDouble(0.01 / 0.09 * depoPart_, 2);
   const double Array1[] = {17, 1.7, 0.5, 0, 16500, 220, 1000, 3};
   strategies[1] = new CSimpleVolumesStrategy(InputBase["symbol = EURGBP"] + "," + Input[Array1]);

   // Третий способ задания - через задание полей.
   InputBase.fixedLot = NormalizeDouble(0.01 / 0.16 * depoPart_, 2);
   InputBase.symbol = "EURGBP";
   const double Array2[] = {51, 0.5, 1.1, 0, 19500, 370, 22000, 3};
   strategies[2] = new CSimpleVolumesStrategy(InputBase + Input[Array2]);
Files:
 
fxsaber #:

It's a good thing they didn't post, as I've redone it again - to the most concise and user-friendly version (seems to be the final one).

Yes, very familiar situation. Everything seems to be there, and then you redo it and it's even better. I think that this is not the final version either, because you oriented on those scenarios of using parameters in code that have already been published. When it comes to building parameters into sets, and even more so to automatic building into sets, you'll probably find that you can improve/simplify as well.

Thanks!!!