Validating automated trendline signals in MT5: pivot confirmation and entry timing

Hi everyone,

I’m working on an automated interpretation of a trendline trading approach in MQL5 and would appreciate technical feedback on how to validate its behavior in the MT5 Strategy Tester.

The strategy inspiration comes from Tori Trades’ video, “Once you master this strategy, trading becomes EASY.” The implementation reflects my interpretation of the approach.

My main question is how to verify that every historical trading decision uses only information available at that moment. Trendline anchors can appear obvious on a completed chart, while identifying those anchors during execution may require additional candles.

I would like to review three areas:

1. Pivot confirmation

When a swing high or low requires subsequent candles for confirmation, how should I distinguish the pivot’s original candle time from the time it becomes usable by the EA?

2. Trendline updates

When new price information changes a trendline, what is a reliable way to preserve the line coordinates used for earlier trading decisions? I want to check historical signals against the line that was active when each signal occurred.

3. Signal and execution timing

How should I compare an intrabar crossing with a completed-candle breakout, particularly when checking the signal time against the order request and execution time?

My proposed validation process is to log:

  • Each pivot’s candle time and confirmation time.

  • The anchor coordinates whenever a trendline becomes active or changes.

  • The price and trendline value used to evaluate each signal.

  • The signal, order request, and execution times.

I would then compare these records with the Strategy Tester’s visual output.

Would this process be sufficient to detect look-ahead errors or changes to historical signals? Are there additional checks you would recommend before evaluating performance?

Feedback on the relevant source code and on making these checks reproducible would be appreciated.

Thank you.

Your log covers the pivot and the line; it misses each signal's bar index and the modelling mode. I scan only closed bars: OnCalculate gives rates_total - 1 as forming, rates_total - 2 as the last closed. A pivot at p is usable once p + k closes; gate every use on the confirmation. Write the line's anchors to an append-only row keyed by activation bar; a redraw moves the object. A forming-bar signal is intrabar: at 1-minute OHLC each minute's ticks come from its OHLC at a per-bar fixed spread, so a real-tick run need not reproduce it. Stamp it at the tick, a closed-bar signal at its close, then compare each with your request and execution times.
read through your code, the swing part looks clean to me. you only check shift InpSwingRight+1 on a new bar, so the whole right side
  is closed bars, bar 0 never gets touched. for your log: pivot time = g_rates[shift].time, usable time = g_rates[0].time at the moment
  DetectConfirmedSwings adds it. gap should always be exactly InpSwingRight+1 bars, if you ever see less something is wrong

  the thing thats gonna confuse you in visual mode is DrawLine. it moves the same object every bar, so after the test you only see the
  latest line, not the one that actually fired the trade. thats probably why the lines "look obvious" afterwards. easy fix: when a
  signal fires, create a new OBJ_TREND with the signal time in the name and never move it again. then you can scroll back and see the
  exact line each trade used

  2 more checks, both cheap:
  1. run the same period A->B, then A->C with C later. every trade before B has to be identical in both reports. if old trades change
  when you add more data, you have lookahead/repaint somewhere. this one catches stuff logs miss
  2. run it on open prices only and on every tick. since everything is on bar close and you enter on the first tick, the first trades
  should match exactly. later ones can drift once a SL gets hit at a different price inside a bar, so just look at where the first
  difference shows up

  on intrabar vs close: if you ever switch to checking high/low against the line, backtest on bar data will look way better than live,
  so i'd keep it close based like you have now

  small one, OnInit restores g_activeSafety from the current best safety line, not the one used at entry. doesnt matter in the tester
  but on live after a restart the trail can jump
Yang Yu Qun #:
read through your code, the swing part looks clean to me. you only check shift InpSwingRight+1 on a new bar, so the whole right side
  is closed bars, bar 0 never gets touched. for your log: pivot time = g_rates[shift].time, usable time = g_rates[0].time at the moment
  DetectConfirmedSwings adds it. gap should always be exactly InpSwingRight+1 bars, if you ever see less something is wrong

  the thing thats gonna confuse you in visual mode is DrawLine. it moves the same object every bar, so after the test you only see the
  latest line, not the one that actually fired the trade. thats probably why the lines "look obvious" afterwards. easy fix: when a
  signal fires, create a new OBJ_TREND with the signal time in the name and never move it again. then you can scroll back and see the
  exact line each trade used

  2 more checks, both cheap:
  1. run the same period A->B, then A->C with C later. every trade before B has to be identical in both reports. if old trades change
  when you add more data, you have lookahead/repaint somewhere. this one catches stuff logs miss
  2. run it on open prices only and on every tick. since everything is on bar close and you enter on the first tick, the first trades
  should match exactly. later ones can drift once a SL gets hit at a different price inside a bar, so just look at where the first
  difference shows up

  on intrabar vs close: if you ever switch to checking high/low against the line, backtest on bar data will look way better than live,
  so i'd keep it close based like you have now

  small one, OnInit restores g_activeSafety from the current best safety line, not the one used at entry. doesnt matter in the tester
  but on live after a restart the trail can jump
Cheers
Jevon Naldo Yoshield #:
Your log covers the pivot and the line; it misses each signal's bar index and the modelling mode. I scan only closed bars: OnCalculate gives rates_total - 1 as forming, rates_total - 2 as the last closed. A pivot at p is usable once p + k closes; gate every use on the confirmation. Write the line's anchors to an append-only row keyed by activation bar; a redraw moves the object. A forming-bar signal is intrabar: at 1-minute OHLC each minute's ticks come from its OHLC at a per-bar fixed spread, so a real-tick run need not reproduce it. Stamp it at the tick, a closed-bar signal at its close, then compare each with your request and execution times.

Cheers