【Development Log】Why can’t indicators be ported? The struggle with the “misfit indicators” ADX and ATR
In the previous development log, I recorded the structural differences of the environment that arise when porting Python-built logic to MT4/MT5. This time, I want to delve into what is arguably the most troublesome part in practice—the problem that the internal calculations of technical indicators themselves do not match across environments. I feel this is a realm that can hardly be shared as a concrete impression unless you have actually done the porting work yourself.
1. Indicators are not "official" but "implemented"
Indicators like ADX and ATR appear to have a single textbook definition. In reality, however, there are multiple variations in the calculation methods, such as the type of moving average used for smoothing (simple moving average, exponential moving average, or Wilder's smoothing), handling of initial values, and timing of rounding.
The source code of MT4’s internal implementation is not public, and there is no external way to precisely know which smoothing method or initialization logic is adopted. In other words, even for indicators with the same name like ADX or ATR, the "implementation" could differ by environment, which is the starting point. If development begins without this premise, you will endlessly struggle with the phenomenon of “the same indicator is being used, yet the results don’t match.” It’s easy for developers to waste time before realizing that the cause lies in the internal calculation of the indicator itself, not in some transplantation error.
2. The limits of trying to closely match calculations on the Python side
Naturally, during development we try to bring Python’s calculations as close as possible to MT4’s outputs. It is the process of implementing multiple smoothing methods, adjusting initial values and warm-up periods, and cross-checking numerical results.
However, this has practical limits. In particular, Wilder-type smoothing uses coefficients that differ subtly from simple exponential moving averages, making reproducibility prone to traps. No matter how much precision is pushed, there will ultimately be tiny differences below the decimal point, preventing perfect matches. More troublesome is that this error is not fixed; it shifts depending on market variability and data retrieval periods. In one period the results almost coincide, while in another period the divergence is pronounced, which is not uncommon.
3. The danger of using "non-matching indicators" as filters
These sub-decimal differences may seem minor, but in practice they can cause fatal problems. Many filter conditions are designed as “enter when a threshold is exceeded,” so even a slight difference in the indicator value can shift the timing of crossing the threshold itself.
As a result, even if you port parameters that were best for Python-based backtests directly to MT4, the signal timing may not align, causing a non-negligible gap between validation results and actual results. This isn’t a porting mistake; it’s a structural issue stemming from the indicator’s calculation method not matching in the first place. Even though the surface-level logic and parameters may appear the same, one side may show an edge while the other side’s edge disappears—that is the trap most prone to misjudgment during porting.
4. A shift in thinking: build logic only from elements whose calculations do not change
A practical solution to this problem is not to chase the reproducibility of the indicator to the extreme. Rather, it is a shift in thinking to rebuild the filter logic using elements that are unaffected by implementation differences in the first place.
Specifically, limit to elements based on raw price differences or high/low/close simple comparisons, or indicators whose calculation methods are uniquely defined, such as simple moving average (SMA) that do not rely on complex smoothing. With such elements, Python-side and MT4-side computations will align, allowing structural elimination of the divergence between validation results and real-world results. It is a shift toward a design philosophy of building up reliable, reproducible elements instead of chasing flashy, complex indicators.
5. The steady work of seeking conditions that still yield good results
However, this approach comes with a clear trade-off. The set of usable indicators becomes significantly narrower, so the work of finding effective filter conditions and advantageous logic within that set is more challenging than when options are plentiful.
With limited tools, how can you discover reproducible, advantageous signals? I believe this is a realm that can only be truly understood by someone who has experience doing development in Python and porting it all the way to MT4. Many developers, upon hitting this wall, either give up on indicator precision or abandon the porting altogether. By narrowing the options, you must still find combinations that maintain advantage, which typically requires more rigorous brute-force testing and validation than ordinary parameter searches.
The earthy but unavoidable processes Semura Lab. faces
We at Semura Lab. have no intention of fleeing this battle with “incompatible indicators.” We believe that continuing to search for conditions that retain an edge using only elements whose calculations reliably match is an unavoidable process when shaping Python development into a MT4 product. Rather than compromising indicator precision itself, we aim to avoid the root of the problem by carefully selecting dependencies—whether this shift in thinking can determine the success or failure of porting.
Behind flashy backtest results lie these quiet, but indispensable, stacks of verification. In this development log, we will continue to honestly record such less-visible steps as well.