MQL5 Wizard Techniques you should know (Part 97): Using Convex Hull and a miniature GRU Network in a Custom Trailing Stop Class
Introduction
We resume this series on the MQL5 Wizard where we rotate our focus between entry signals, money management and trailing stops. These three domains are the main ways Expert Advisors assembled with the MQL5 Wizard, can be customized beyond the built-in classes. For the last published articles we have looked at entry signals and then money management which means that trailing stops are our focus for this article. In the last piece on trailing stops we married the Reservoir Sampling algorithm with a linear regression network to build a model whose goal was hugging a 'fair median' price. This was meant to guard open-positions from sideways chop.
This approach can work well in choppy markets but in trending markets it would be strained, marginally at least. Today therefore we venture into 'trading the median for the perimeter". We introduce a trailing stop class that is run by the Convex Hull algorithm - logic that is purposeful in defining an "outer-shell" of price action and we pair this as always with a neural network, with the choice for this article being a simplified Gated Recurrent Unit (GRU). The network serves as a momentum filter.
This addition to the MQL5 library arsenal, as always, is not a silver bullet but rather an alternative approach for momentum traders to ride explosive breakouts. When in tight ranges of price action it is bound to struggle which is why the adopting trader needs to be one with the discipline/ specialty in handling breakout momentum setups.
Intended Market Environment
To appreciate why this new trailing stop setup is important, lets consider what defines its environment. In the last article on custom trailing stops where we used Reservoir Sampling and Linear Regression we were particularly targeting mean-reverting markets. In these ranging situations, price is ever snapping back to a center of gravity and our aim then was to filter out the noise of "false breakouts" by locking onto the 'fair-median'.
However when one is dealing with assets that are prone to "fat-tails" - or sudden directional bursts in volatility like tech reacting to earnings, or volatile crypto trends or even forex reacting to the Fed's report card the NFP, then alternative approach could be necessary. In these settings establishing new price levels is the norm and reverting to the stable median rarely happens.
The trading approach therefore geared towards dealing with this would be momentum trend-following. Here the trader is not trying to scalp 10 pips within a tight channel; rather they are hunting the 200 pip wave. The biggest frustration is not being wrong per se but rather getting prematurely whipsawed or violently tagged out by volatile retracements, prior to the main trend resumes.
If a momentum trader tries to adapt the Linear Regression model we used in the last trailing stop article, for example, they will likely get "left-behind". Why? Because Linear Regression is in principle a smoothing mechanism. In addition Reservoir Sampling was deliberately retaining older price data in order to preserve a balanced historical sample. When there is an explosive breakout, old data becomes toxic! It anchors regression line to the past, leading to the trailing stop to drag heavily or to work out price medians that do not reflect the new price reality.
With high-momentum trading, we are not after smoothing out the price extremes, but rather we embrace them. In doing so, the Convex Hull algorithm is able to shine. Rather than calculating the median, this algorithm connects absolute structural extremes in order to construct an outer boundary. By pairing this with a GRU network - that is used to evaluate sequential memory of momentum instead of simple averages - our model learns too separate a temporary structural pullback from a real trend reversal.
The Whipsaw Dilemma
Before we jump in lets have another take at the problem our model could help solve. Consider this scenario. You have accurately spotted a major price breakout. The market is surging and you make the decision to trail this position to lock in your profits. You apply a standard trailing stop basing on a fixed pip distance or the price gap from an indicator such as a moving average. With that you are now in the green, riding the wave.
If, unexpectedly, we get a solo bearish candle print, which many deem as a sign of classical institutional liquidity grab or it may be a news-driven anomaly, your trailing stop will get clipped. You get out of the trade, not with a loss but a modest gain. In the very next price bar, the market shakes off this anomaly and then aggressively resumes its uptrend for another 150 pips. You on the other hand are on the sidelines, watching your accurately called trade drift away from you. This is the "Whipsaw Dilemma".
For a momentum trader a regular trailing stop does expose a fundamental flaw. If you set it too tight it gets hunted by market noise, and yet on the flipside if it is too generous you would be surrendering a considerable portion of a positions floating profits when a genuine reversal plays out.
Surviving this, in these circumstances, traders could adapt two part solutions. Firstly they could adapt a system that dynamically wraps around the absolute "outer-price-boundary" of a trend's structure and not an average. A physical mapping of price extreme limits. Secondly, we could use a mechanism that acts like an intelligent filter. It should have the capacity to freeze the trailing stop in its place when volatile price action goes against broader established momentum. This on paper could allow the position to weather the storm instead of getting in the way of liquidity grabs.
Model's Description
In addressing the whipsaw dilemma, a trailing stop would not depend on just one metric. As per our problem definition above, we need to distinguish the spatial placement of stops from the temporal context of market's momentum. We get close to realizing this by separating the model mechanism into two distinct cooperative engines, inline with our approach in past articles of dual engines.
Engine 1: The Convex Hull Algorithm
Our first engine's task is mostly geometric. Rather than calculate moving averages, we map the absolute boundaries of recent price action. This gives us a dynamic shell around the traded asset. As the trend evolves the shell gets to adapt accordingly. This in theory helps mark out where a stop loss is protected from standard market noise.
Engine 2: The GRU Network
The next engine gives us context. Being powered by a Gated Recurrent Unit (GRU) it serves as a forward predictive momentum filter. GRUs are often good at processing sequential data, and this can make them very efficient at reading the immediate history of deltas in price, thus spotting momentum shifts.
The Synergy
The power of our model therefore could lie in the engines' interaction. Engine 1 could propose where key stop loss placement should be basing on the dynamically updated shell, while Engine 2 would be on the lookout for anomalies like volatility spikes that are contradicted by prevailing market settings. The network would be able to override the algorithm by temporarily "freezing" the adjustment of current stop-loss levels and opting to weather price spikes. This should ensure that the stoploss only gets adjusted when price geometry and the underlying momentum are concurring.
Model's Math
So we now get to the portion of our article where we strip away the metaphors and look at what's inside. To reiterate, we are no longer focused on mean reversion as was the case with Reservoir Sampling algorithm therefore we are not computing averages.
Spatial Math: Convex Hull Extremes
A regular moving average adds up closing prices and divides this total by the period of summation, in essence pulling the final value towards the center of all the averaged data points. The convex Hull algorithm ignores the core. Rather it separates the absolute structural extremes over a rolling window of time (n). For a trailing stop on a long position for instance, the outer shell 'S_long' is simply the lowest recorded in the buffered historical window:
![]()
By anchoring only to minimums (or maximums if this was a short position), the math gives us a sturdy boundary. Our main thesis here is that Trend-following price-action is not able to cross this geometric line without breaking its market structure.
Temporal Math: GRU Gate Mechanics
While an exponential Moving Average (EMA) can forget old data at a fixed linear mathematical decay rate, a GRU would forget contextually. This network not only processes the current price changes (x_t); it processes these changes alongside their own internal memory state (h_t-1). In realizing this the GRU uses separate gates that are ruled by the sigmoid (sigma) and hyperbolic-tangent (tanh) functions. This is guided by trained weights (W, U) and biases (b):
- 1 Update Gate (z_t): This chooses what amount of the prior trend memory gets kept. If a sudden price spike happens, this gate picks whether this is transient noise or a systemic shift. Its formula is as follows:
![]()
- 2 The Reset Gate (r_t): This gate gets to set which portion of the past memory is mostly irrelevant and therefore needs to be dropped. Its formula is as follows:
![]()
- 3 The Candidate State(tilde_h_t) and Hidden State(h_t) Calculations: At the last step, the network works out a new potential trend inference(tilde_h_t) and blends this with the old memory by using the Update Gate. This gives us the final directional momentum output (h_t):
![]()
![]()
Thus, instead of dragging a sluggish average for the price, our equations are meant to allow the neural network dynamically filter localized structural noise from genuine loss in trend momentum.
MQL5 Implementation
We now attempt to translate the spatial geometry of the Convex Hull and temporal memory of the GRU into a custom class, compatible with MQL5 Wizard that will help us trail open positions in high-volatility trending markets. As per usual, in order to keep a seamless integration with the MetaTrader 5 ecosystem we inherit from the built-in 'CExpertTrailing' base class.
The model architecture we adopt is split in two thanks to our two engines. As we go over this below, we start by delineating the setup and execution of the Spatial Engine (Convex Hull), and then follow this up by covering the Temporal engine of the GRU network. We then simply conclude with how these two are merged to work together.
1. Class Setup and Indicator Choices
In the last article where we had a custom trailing stop class we mostly depended on moving averages to get our "center" of price action as this was our basis then of making stops adjustments. Here though, moving averages go against the core of our algorithm so we cannot use them. We thus need raw unfiltered price extremes. Therefore, the first "indicator" for the Convex Hull algorithm chosen is not from the built-in assortment of indicators but a raw algorithmic arrays that we are labelling 'm_high_history[]' and 'm_low_history[]'. The second indicator is the Average True Range (ATR). Why the ATR? Well because geometry alone can fail to account for changing market conditions. A 20-pip outer shell could be perfectly safe in the Asian session but very vulnerable at the New York open. The ATR is able to translate raw structural price geometry into a format that is volatility adjusted.
class CTrailingConvexHullGRU : public CExpertTrailing { protected: //--- Indicators CiATR m_atr; // Indicator 1: ATR (Volatility) // Indicator 2: Price Action Local Extrema (Computed algorithmically) //--- Convex Hull Parameters int m_hull_period; int m_hull_mode; int m_atr_period; //--- Price History Buffers for Hull double m_high_history[]; double m_low_history[]; int m_history_count;
Within the inherited class virtual function 'InitIndicators', we initialize these "indicator" components:
//+------------------------------------------------------------------+ //| Initialize Indicators and Arrays | //+------------------------------------------------------------------+ bool CTrailingConvexHullGRU::InitIndicators(CIndicators *indicators) { if(!CExpertTrailing::InitIndicators(indicators)) return false; //--- Parameter bounds check if(m_hull_period <= 0) m_hull_period = 20; if(m_atr_period <= 0) m_atr_period = 14; //--- Initialize ATR Indicator if(!indicators.Add(GetPointer(m_atr))) { printf(__FUNCTION__ + ": error adding ATR object"); return false; } if(!m_atr.Create(m_symbol.Name(), m_period, m_atr_period)) { printf(__FUNCTION__ + ": error initializing ATR"); return false; } //--- Resize rolling window buffers for Convex Hull ArrayResize(m_high_history, m_hull_period); ArrayResize(m_low_history, m_hull_period); ArrayInitialize(m_high_history, 0.0); ArrayInitialize(m_low_history, 0.0); return true; }
Here is are the key parts of what we are doing-
- The first if clause 'if(!CExpertTrailing::InitIndicators(indicators))' checks to ensure that the parent class initialization had succeeded, before we proceed.
- The second if clause 'if(m_hull_period <= 0)' implements standard parameter bounds checking to prevent dividing by zero or array out of bounds errors.
- The ATR handle is initialized with 'm_atr.Create(...)' where it gets bound to the current symbol and timeframe.
- We dynamically size the raw price arrays in order to match the mathematical n period of our convex hull shell.
2. Spatial Engine, Managing the Algorithmic Shell
Prior to working out the shell, we need to continuously provide real-time data to the algorithm. Unlike regular MQL5 indicators that read closed price-bars (e.g. 'iClose') trailing stops do have to be very reactive in certain situations and therefore should be able to access real-time highs and lows of the yet to be closed price bar especially if the traded timeframe is significantly large such as the 4-hour or even Daily etc.
//+------------------------------------------------------------------+ //| Hull Buffer Manager (Rolling Window) | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::UpdateHullState(double high, double low) { if(m_history_count < m_hull_period) { m_high_history[m_history_count] = high; m_low_history[m_history_count] = low; m_history_count++; } else { for(int i = 0; i < m_hull_period - 1; i++) { m_high_history[i] = m_high_history[i + 1]; m_low_history[i] = m_low_history[i + 1]; } m_high_history[m_hull_period - 1] = high; m_low_history[m_hull_period - 1] = low; } }
In our above listing, we start off by checking to ensure that the array is not yet full and has room to be appended. When this passes we increment the high/low to counter. When the array is finally full we run a for-loop where we apply a rolling window (first-in, first-out), and shift every element in the array by one index to the left. In this shift, the oldest price point gets overwritten by the second oldest effectively dropping old data. After the loop is done, we simply append the newest price action to the very end of the array. With the spatial memory array defined we now have to consider our four possible operation modes. These are the 4 convex Hull modes where each represents a different flavor of momentum trading.
Mode 1. Standard Pure Extrema:
The first mode is the raw geometric math that finds absolute support/resistance borders within the rolling window:
//+------------------------------------------------------------------+ //| Mode 1: Standard Pure Extrema (Price Action Support/Resistance) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeStandard(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double extreme_val = is_long ? m_low_history[0] : m_high_history[0]; for(int i = 1; i < count; i++) { if(is_long && m_low_history[i] < extreme_val) extreme_val = m_low_history[i]; if(!is_long && m_high_history[i] > extreme_val) extreme_val = m_high_history[i]; } return extreme_val; }
Above, we are initializing our baseline extreme to the value that is oldest within the current window. After this in the subsequent for-loop we iterate through the rest of the window. If we are short, we would be looking for the highest point to place our stop above. Once the current loop value is higher than our baseline, we overwrite it.
Mode 2. ATR Expanded Shell:
Some times markets can suffer unexpected liquidity grabs, which plays into our whipsaw dilemma above, and in these situations mode-1 would be too light or more likely to be stopped out. Mode 2 therefore pushes the price geometric boundary outward.
//+------------------------------------------------------------------+ //| Mode 2: ATR Expanded Shell (Hull shifted by Volatility) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeATRExpanded(bool is_long) { double base_shell = HullModeStandard(is_long); m_atr.Refresh(); double current_atr = m_atr.Main(1); // Get previous bar's ATR //--- Expand the shell outward based on current market volatility return is_long ? (base_shell - current_atr) : (base_shell + current_atr); }
What we are doing in mode 2's listing above is fetching the absolute geometric extreme first, and then we ensure that the ATR buffer is updated before fetching the value of the last fully completed price bar (price bar with defined OHLC values). If the position we have is short, we add the ATR from the highest high, thus extending the shell upward, creating more "breathing room" against potential volatility spikes.
Mode 3. Smoothed Average Shell:
While it is accepted that moving averages lag in prices, finding the mean of the boundaries can sometimes be a useful tactic in a very volatile asset price moves, if they appear too erratic.
//+------------------------------------------------------------------+ //| Mode 3: Smoothed Average Shell (Median of boundaries) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeSmoothed(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double sum = 0.0; for(int i = 0; i < count; i++) { sum += is_long ? m_low_history[i] : m_high_history[i]; } return sum / count; }
In the listing above, rather than finding the absolute minimum, we sum every low point in the window and divide it by the count. This gives us a median of extremes, to serve as our proxy for suitable stop loss placement.
Mode 4. Momentum-Biased Shell:
In our final iteration mode, we weight recent price action's geometry above that of the older. The intended good benefit of this is allowing the stop-loss to aggressively track price acceleration. Their could be market settings or asset types or news events where this could be warranted.
//+------------------------------------------------------------------+ //| Mode 4: Momentum-Biased Shell (Recent Extremes Weighted Higher) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeRecentBiased(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double global_extreme = HullModeStandard(is_long); double recent_extreme = is_long ? m_low_history[count - 1] : m_high_history[count - 1]; //--- Bias: 60% standard absolute shell, 40% most recent price shell return (global_extreme * 0.6) + (recent_extreme * 0.4); }
First thing we do in our listing above is identify the true extreme of the entire data window. We then declare another extreme, 'recent_extreme', that focuses on data points in a more recent and smaller time window. We finally combine these two extreme values in an asymmetric shell. By default we are anchoring 60% to the global price structure while allotting the balance 40% to the recent or immediate price action. A smaller percentage for the more recent than the whole pool is still a net larger weight for recent prices vs simply taking the average of the entire pool as is typically the case.
3. The Temporal Engine: Implementing the GRU Network
The programming language of MQL5 was built in C++. This gives us the benefit of processing sequential logic very quickly, however hosting deep-learning models often requires external ONNX integration. If we are developing a custom trailing class for Wizard built Expert Advisors, arguably, ONNX could be deemed overkill especially since it introduces execution latency. Rather, we implement the GRU mathematics natively within MQL5, by using deterministic pseudo-weights that are tuned to spot momentum.
//+------------------------------------------------------------------+ //| Initialize Deterministic Weights for GRU Filter | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::InitGRUWeights() { //--- Emulating a trained trend-following/momentum configuration Wz = 0.5; Uz = 0.5; bz = 0.0; Wr = 0.5; Ur = 0.5; br = 0.0; Wh = 0.8; Uh = 0.2; bh = 0.0; }
These initialized parameters get to determine how aggressively the network is able to "remember" or "forget" momentum. The high 'Wh' (assigned 0.8) ends up heavily weighing current price action into the candidate state, while the 'Uh' (given 0.2) means we only allow a small portion of the past context to have any effect on the immediate evaluation. This could be perfect for trend following. The activation functions are important when running the GRU.
//+------------------------------------------------------------------+ //| Sigmoid Activation Function | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::Sigmoid(double x) { return 1.0 / (1.0 + MathExp(-x)); }
We are relying on MQL5's native exponential function. The Sigmoid helps map infinite price changes into a narrow restricted band of 0.0 to 1.0 range. This is a probability range and therefore serves as a true gate. With this defined we would need to run the forward pass of the GRU on every incoming price bar.
//+------------------------------------------------------------------+ //| Update GRU Network States (Forward Pass) | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::UpdateGRU(double price) { if(m_gru_prev_price == 0.0) { m_gru_prev_price = price; return; } //--- Input x is the normalized price delta double x = (price - m_gru_prev_price) / m_symbol.Point(); m_gru_prev_price = price; //--- GRU Equations double z_gate = Sigmoid((Wz * x) + (Uz * m_gru_h) + bz); double r_gate = Sigmoid((Wr * x) + (Ur * m_gru_h) + br); double h_candidate = MathTanh((Wh * x) + (Uh * (r_gate * m_gru_h)) + bh); //--- Update hidden state (memory) m_gru_h = (1.0 - z_gate) * m_gru_h + (z_gate * h_candidate); }
From the listing above, we are calculating the normalized input vector 'x'. The GRU is not fed with raw price data but rather it receives the delta or price-change momentums that are converted into points. 'z_gate', the Update Gate parameter is declared by multiplying the current delta 'x' by the weight 'Wz', to which we add the previous hidden state 'm_gru_h' that is multiplied by the weight 'Uz'. This sum gets propagated through the Sigmoid to give us a value that sets by how much we can trust the trend. 'r_gate', the Reset Gate variable follows similar logic in definition. It gets to decide which portion of 'm_gru_h' to drop entirely.
We then define the candidate state, 'h_candidate'. In this parameter's product definition we multiply 'r_gate' with 'm_gru_h'. When 'm_gru_h' is close to zero, the GRU will ignore the past and respond only to 'x'. The 'MathTanh' function constrains the output to be between -1 and +1. The last major action in the above code is updating the hidden state. This is the final memory momentum. When 'z_gate' is high, the system overwrites its old memory ('m_gru_h') with the new 'h_candidate'.
4. The Execution Logic: Fusing Spatial and Temporal
With the algorithm and network underpinnings laid out, we now examine how it all comes together. This is where the geometric shell meets the neural filter.
bool CTrailingConvexHullGRU::CheckTrailingStopLong(CPositionInfo *position, double &sl, double &tp) { if(position == NULL) return false; double current_bid = m_symbol.Bid(); //--- 1. Update State UpdateHullState(m_symbol.Ask(), m_symbol.Bid()); // Simplified H/L emulation using Ask/Bid //--- 2. Network: GRU Filter if(m_use_gru) { UpdateGRU(current_bid); // If GRU trend implies heavy downward momentum, hold the stop where it is if(m_history_count >= m_hull_period && GetGRUTrend() < -0.5) return false; }
In the main function where we adjust the stop loss for long positions, we commence by feeding real-time price data into our array to update the Convex Hull Geometry. We then feed the price into the GRU forward pass in order to update the momentum memory. In doing this we also need to see to it that our arrays and GRU memory are completely filled with data prior to using them. The code line 'if(m_history_count >= m_hull_period && GetGRUTrend() < -0.5)' in many ways serves as the crux of this dual engine.
The function 'GetGRUTrend()' gives us a bounded variable (-1 to 1) whereby a value below -0.5 would most certainly indicate aggressive downward momentum is in play. In this situation, even though for instance, the Convex Hull algorithm would be green lighting a move of the stop loss upwards, the GRU our secondary filer would be disagreeing and effectively overruling the algorithm. The function would then return 'false', terminating the run immediately. The trailing stop price would then be "frozen" or kept in place which in theory would protect the position from a potential whipsaw liquidity grab.
//--- 3. Algorithm: Select Convex Hull Mode double shell_price = current_bid; switch(m_hull_mode) { case 1: shell_price = HullModeStandard(true); break; case 2: shell_price = HullModeATRExpanded(true); break; case 3: shell_price = HullModeSmoothed(true); break; case 4: shell_price = HullModeRecentBiased(true); break; default: shell_price = HullModeStandard(true); break; } //--- 4. Execution Logic double new_sl = NormalizeDouble(shell_price - (((2 * m_symbol.Spread()) + m_symbol.FreezeLevel() + m_symbol.StopsLevel()) * m_symbol.Point()), m_symbol.Digits()); double current_sl = position.StopLoss(); sl = EMPTY_VALUE; tp = EMPTY_VALUE; //--- Only move stop up if(new_sl > current_sl || current_sl == 0.0) { sl = new_sl; return true; } return false; }
In the concluding portion we run the switch directive on the Expert Advisor's input parameter 'm_hull_mode'. This sets the algorithm's spatial math function. When this is done, we calculate the outer boundary ('shell_price') and see to it that it complies with the broker's minimum stops-level as well as freeze-level. We also ensure it is at least far away from the current stop-loss by the current spread. We finally normalize this new target stop loss price to the digits allowed by the traded symbol. Before returning true or acquiescing to a stop loss adjustment, the if clause that follows checks to ensure we are abiding by the cardinal rule of trailing stops. We only ever move the stop loss in the direction of the profit. With that our implementation in MQL5 would be bridging current price action with momentum forecasts.
Post-Optimization Analysis
To transition from theory to execution, we assemble the custom trailing class 'CTrailingConvexHullGRU' with built-in input signals of Envelopes and RSI in the MQL5 Wizard. We are testing with the symbol USD JPY on the 2-hour timeframe. As per usual for each test we optimize then do a forward walk, where tuning period is the whole year 2025 while the forward walk is from 2026.01.01 to 2026.05.01. We also have two engines so the first test is only with the algorithm and the second test combines both the algorithm and neural network.
Baseline Test: Pure Algorithm
To optimize the Expert Advisor only with the Convex Hull algorithm we disable the GRU. From this stint the chosen input settings favored highly reactive short term memory setups with the Envelopes' averaging period being just 3, a deviation of 0.425, and a very high opening/entry threshold of 96. The pure algorithm run seems to have performed as intended it took advantage of price extremes to lock in capital.

Nonetheless it can be argued that this report demonstrates the "whipsaw dilemma" mentioned at the introduction because a few position were closed too soon. There was a sizeable loss that in the end turned out to be only half the worst equity drawdown that was sustained. This usually points to a negative profit to MAE correlation which is never good especially when we are trying to building a custom trailing stop class.
Adding the Network
Activating the GRU neural network does introduce some sizeable changes. Keep in mind that we are testing over a limited time window and on just one forex pair. These results do not guarantee repeatability in the future with this symbol or even other assets in the same time window. If we start by looking at the optimized inputs, we can see that the envelopes' averaging period was increased to 21 and the deviation dropped to 0.03. Also the opening threshold was relaxed to 50.

With the introduction of our miniature GRU we place more trades, and the net results flips to green however the equity drawdown is almost triple what we net. There could have been some advantages in waiting to adjust the stop loss but they are not conclusive. More testing outside of this time window and with other symbols would clearly be required. Also this being only a trailing stop the entry signal, of the envelopes, and RSI, clearly has an understated role here and the fact that input parameters get almost wholly adjusted for each of the test runs does not enable us get a clear picture on the relative merits of the algorithm v the neural network. These are aspects that the reader can independently pursue to get a better sense of what works for his system and what can he do without.
Conclusion
We started by considering the "whipsaw dilemma" of positions getting clipped out of from volatility anomalies that are localized and how this could be addressed with the dual engine approach of the Convex Hull and a GRU. The algorithm and Spatial Engine we used to map the outer boundaries of price action while the Temporal Engine (GRU) was a filter on sequential momentum which allowed the halting of stop loss adjustments in scenarios or market setups that were found to resemble liquidity-grabs or short-term price jerks.
Markets ultimately get through different phases and some traders choose to specialize or capitalize on a particular phase or an asset that mostly trades with a specific price action format. We attempted to provide a tool that can help traders survive and thrive in trending-regimes by avoiding explosive, fat tail momentum.
| name | description |
|---|---|
| wz_97.mq5 | Wizard Assembled Expert Advisor |
| TrailingConvexHullGRU.mqh | Custom Trailing Class required in Wizard Assembly |
| r1.set | Input settings for first run |
| r2.set | Input settings for second run |
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
Trading Options Without Options (Part 2): Use in Real Trading
Beyond the Clock (Part 3): Building an Indicator Window for Alternative Bars in MQL5
Features of Experts Advisors
Building a Divergence System: Creating the MPO4 Custom Indicator
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use