Discussing the article: "Neural Networks in Trading: Recurrent Modeling of Market Micromovements (Conclusion)"

Check out the new article: Neural Networks in Trading: Recurrent Modeling of Market Micromovements (Conclusion).

The implementation of the EV-MGRFlowNet framework demonstrates its key advantages: modularity, resilience to market fluctuations, and the ability to develop strategies independently. These features make the framework a powerful tool for analysis, forecasting, and the development of autonomous trading strategies.

Now that the EV-MGRFlowNet framework has been integrated into the environment state encoder, our model is ready to enter its first training arena. This stage can be compared to a novice trader practicing with historical data. The model receives a map of past market conditions, studies price movements, and tries to understand how to act in different situations.

Imagine that EURUSD from January 2024 through June 2025 is its training ground. Like a novice trader, the model examines every candlestick, analyzes trading volume, and looks for hidden patterns among key features. And EV-MGRFlowNet is its mentor: it points out what to focus on, builds an informative state representation for the Actor and the Critic, and helps it develop a trader's intuition. With each step, it learns to predict market movements and assess risks, gradually progressing from a student to a confident trainee.

The next step is real-time online training using the MetaTrader 5 Strategy Tester. The luxury of calmly working with historical data is now gone. Each candlestick is like a real-time market reaction. The model reacts instantly, analyzes noise fluctuations, adapts to sudden spikes, and adjusts its behavior during periods of low liquidity. EV-MGRFlowNet acts as an invisible mentor, keeping the network from making mistakes and advising it when to act boldly and when to exercise caution. The underlying structure, built on historical data, remains its foundation, but the model is now learning to respond flexibly to the current situation, much like a trader with real-world trading experience.

The final exam is testing the model on new data from July through September 2025. All the skills acquired in the previous stages are put to the test: no hints—just the market and its own decisions. The test results are presented below.


Author: Dmitriy Gizlyk

I downloaded the attached archive to have a go at the programmes described in the article. But there are 127 folders, and they contain files with identical names.

Could you please advise me – where should I look, and what should I run?

Screenshot

Vadim Zotov #:

I downloaded the attached archive to have a go at the programmes described in the article. But there are 127 folders, and they contain files with identical names.

Could you please advise where to look and what to run?


Good evening, Vadim.
The folder names correspond to the models. For this article: "MQL5\Experts\EVMGRFlowNet\"
Dmitriy Gizlyk #:
Good evening, Vadim.
The folder names correspond to the models. For this article: "MQL5\Experts\EVMGRFlowNet\"
Got it. Thanks!
Hello, I’m getting an error when compiling. What might I be doing wrong?
Files:
hgn_mg7bp.jpg  98 kb
djgagarin #:
Hello, I’m getting an error when compiling. What might I be doing wrong?

You have an error in a file that isn’t mentioned in the article. So the screenshot won’t help at all

Programmes used in the article

# Name Type Description
1 Study.mq5 Expert Advisor Expert Advisor for offline model training
2 StudyOnline.mq5 Expert Expert Advisor for online model training
3 Test.mq5 Expert Expert Advisor for model testing
4 Trajectory.mqh Class library Structure for describing the system state and model architecture
5 NeuroNet.mqh Class library Class library for creating a neural network
6 NeuroNet.cl Library OpenCL programme code library


Rashid Umarov #:

You have an error in a file that isn’t mentioned in the article. So the image won’t help at all

I took the files from the relevant folder and placed them in the correct locations, but the Study file won’t compile.

djgagarin #:

I took the files from the relevant folder and placed them in the correct locations, but the ‘Study’ file won’t compile.

Yes, it’s clearly not specified in the article’s table. Based on the compiler errors, I realised I needed to copy two more folders – I’ve highlighted them in red


djgagarin #:
Hello, I’m getting an error during compilation. What might I be doing wrong?

Good afternoon,

Where did you get ‘...\Trajectory.mqh’ from?
It should be the file from the attachment containing the function

bool CreateDescriptions(CArrayObj *&encoder,
                        CArrayObj *&stfs,
                        CArrayObj *&actor,
                        CArrayObj *&critic
                       )
  {
//---
   CLayerDescription *descr;
//---
   if(!encoder)
     {
      encoder = new CArrayObj();
      if(!encoder)
         return false;
     }
   if(!stfs)
     {
      stfs = new CArrayObj();
      if(!stfs)
         return false;
     }
   if(!actor)
     {
      actor = new CArrayObj();
      if(!actor)
         return false;
     }
   if(!critic)
     {
      critic = new CArrayObj();
      if(!critic)
         return false;
     }
//--- Encoder
   encoder.Clear();
//--- Input layer
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   uint prev_count = descr.count = (HistoryBars * BarDescr);
   descr.activation = None;
   descr.optimization = ADAM;
   if(!encoder.Add(descr))
     {
      delete descr;
      return false;
     }
   iLatentLayer = 0;
//--- layer 1
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBatchNormWithNoise;
   descr.count = prev_count;
   descr.batch = BatchSize;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!encoder.Add(descr))
     {
      delete descr;
      return false;
     }
   iLatentLayer++;
//--- Layer 2
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronConcatDiff;
   prev_count = descr.count = HistoryBars;
   descr.layers = BarDescr;
   descr.step = 1;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   descr.activation = None;
   if(!encoder.Add(descr))
     {
      delete descr;
      return false;
     }
   iLatentLayer++;
   uint prev_out = descr.layers * 2 ;
//--- layer 3
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defMamba4CastEmbeding;
   prev_count = descr.count = HistoryBars;
   descr.window = prev_out;
   prev_out = descr.window_out = NSkills;
     {
      uint temp[] = {PeriodSeconds(PERIOD_D1), PeriodSeconds(PERIOD_MN1)};
      if(ArrayCopy(descr.windows, temp) < (int)temp.Size())
         return false;
     }
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   descr.activation = None;
   if(!encoder.Add(descr))
     {
      delete descr;
      return false;
     }
   iLatentLayer++;
//--- layer 4
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronEVMGRFlowNet;
     {
      uint temp[] = {prev_out,                  // Channels In
                     32,
                     64,
                     128                        // Channels Out
                    };
      if(ArrayCopy(descr.windows, temp) < (int)temp.Size())
         return false;
     }
   descr.count = prev_count;              // Units In
   descr.optimization = ADAM;
   descr.batch = BatchSize;
   if(!encoder.Add(descr))
     {
      delete descr;
      return false;
     }
   iLatentLayer++;
//---
   uint window = descr.windows[0];
   uint count = descr.count;
//--- STFS
   stfs.Clear();
//--- Input layer
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   descr.count = (window * count);
   descr.activation = None;
   descr.optimization = ADAM;
   if(!stfs.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 1
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSTFS;
     {
      uint temp[] = {window,              // Channels In
                     BarDescr             // Channels Out
                    };
      if(ArrayCopy(descr.windows, temp) < (int)temp.Size())
         return false;
     }
     {
      uint temp[] = {count,               // Units In
                     NForecast            // Units Out
                    };
      if(ArrayCopy(descr.units, temp) < (int)temp.Size())
         return false;
     }
   descr.activation = TANH;
   descr.optimization = ADAM;
   if(!stfs.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Layer 2
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBatchNormOCL;
   descr.count = NForecast * BarDescr;
   descr.batch = BatchSize;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!stfs.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Actor
   actor.Clear();
//--- Input layer
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   descr.count = AccountDescr;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 1
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBatchNormOCL;
   descr.count = AccountDescr;
   descr.batch = BatchSize;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Layer 2
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronCrossDMHAttention;
     {
      uint temp[] = {AccountDescr,           // Inputs window
                     window                  // Cross-window
                    };
      if(ArrayCopy(descr.windows, temp) < (int)temp.Size())
         return false;
     }
     {
      uint temp[] = {1,                      // Input units
                     count                   // Cross units
                    };
      if(ArrayCopy(descr.units, temp) < (int)temp.Size())
         return false;
     }
   descr.step = NHeads;                      // Heads
   descr.window_out = 32;
   descr.batch = 1 e4;
   descr.layers = AttentionLayers;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 3
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSpikeConv;
   descr.count = 1;
   descr.window = AccountDescr;
   descr.step = AccountDescr;
   descr.window_out = EmbeddingSize;
   descr.variables = 1;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 4
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSpikeConv;
   descr.count = 1;
   descr.window = EmbeddingSize;
   descr.step = EmbeddingSize;
   descr.window_out = LatentCount;
   descr.variables = 1;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 5
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   descr.count = 2 * NActions;
   descr.activation = SIGMOID;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 6
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronVAEOCL;
   descr.count = NActions;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Layer 7
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronConvOCL;
   descr.count = NActions / 3;
   descr.window = 3;
   descr.step = 3;
   descr.window_out = 3;
   descr.activation = SIGMOID;
   descr.optimization = ADAM;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Critic
   critic.Clear();
//--- Input layer
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   descr.count = NActions;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 1
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBatchNormOCL;
   descr.count = NActions;
   descr.batch = BatchSize;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//--- Layer 2
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronCrossDMHAttention;
     {
      uint temp[] = {3,                // Inputs window
                     window            // Cross-window
                    };
      if(ArrayCopy(descr.windows, temp) < (int)temp.Size())
         return false;
     }
     {
      uint temp[] = {NActions / 3,     // Input units
                     count             // Cross units
                    };
      if(ArrayCopy(descr.units, temp) < (int)temp.Size())
         return false;
     }
   descr.step = NHeads;                     // Heads
   descr.window_out = 32;
   descr.batch = 1 e4;
   descr.layers = AttentionLayers;
   descr.activation = None;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 3
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSpikeConv;
   descr.count = NActions / 3;
   descr.window = 3;
   descr.step = 3;
   descr.window_out = EmbeddingSize;
   descr.variables = 1;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 4
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSpikeConv;
   descr.count = NActions / 3;
   descr.window = EmbeddingSize;
   descr.step = EmbeddingSize;
   descr.window_out = LatentCount / descr.count;
   descr.variables = 1;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//--- layer 5
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronBaseOCL;
   prev_count = descr.count = NRewards;
   descr.activation = None;
   descr.batch = BatchSize;
   descr.optimization = ADAM;
   if(!critic.Add(descr))
     {
      delete descr;
      return false;
     }
//---
   return true;
  }
Files:
Trajectory.mqh  70 kb

...I’ll carry on. You’ve got some VERY interesting articles. I’m interested in everything to do with neural networks, particularly in trading. I try to learn something new. But to be honest, the articles are VERY lacking in instructions on what to do, where to put things, which folder to use, and which time frame to run it on to get the same result as you. In the end, it only worked when I put the ‘trajectory’ file in the ‘experts’ folder, even though I’d thought *.mqh files needed to be copied into the ‘include’ folder.

As the folders contain experts and libraries with identical names, I think it would be better to add the name of the folder in which each expert (or library) is stored at the start of its name – for example, EVMGRFlow_Net_Study – to avoid confusion when viewing (or running) your other works.

I’m certainly not picking on you; I’m genuinely very interested in what you’re writing and adapting for MQL, but many people who read and try to run your work encounter compilation errors because they don’t know where to copy the files. As a result, they give up and move on. These are just my suggestions, as an ordinary user.

Now, regarding this particular piece of work. I’ll describe the steps I took to run it, and please do correct me if I’m wrong:

1. EURUSD H1

2. The ‘Study’ expert advisor. I selected the same time period as specified in the expert advisor. (Is it possible or necessary to change this, and should the period in the expert advisor match the one I’ve chosen, which differs from yours?)

3. Four files with the *.nnw extension were created in the ‘files’ folder

4. I ran StudyOnline on the same time frame (if I’ve understood correctly). Trades appeared. Finished.

5. I ran Test on the test period. And here there’s just a solid line representing the balance, not a single trade.


What am I doing wrong?

I used the same time intervals as specified in the article to achieve your result.

djgagarin #:

....
The folders all have the same names for experts and libraries; I think it would be better to add the name of the folder in which each expert (library) is stored at the beginning of its name, for example EVMGRFlow_Net_Study, to avoid confusion when viewing (running) your other projects.
....

Good afternoon,
First of all, thank you for your interest in my work.
The ‘Experts’ folder allows for subfolders, which minimises confusion even when experts have identical names. For example, in my terminal it looks like this