- MQL5 82.6%
- Python 16.1%
- MQL4 1.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| docs/images | ||
| LICENSES | ||
| mql4/Experts/PriorDayBreakout | ||
| mql5/Experts/PriorDayBreakout | ||
| presets | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| requirements.txt | ||

Prior Day Breakout (MetaTrader 5 and MetaTrader 4)
A free Expert Advisor that trades the previous-day high/low breakout on XAUEUR: on a closed bar, the first close above yesterday's high is a buy, the first close below yesterday's low is a sell, once per side per day, with the stop at the other side of yesterday's range and a fixed target. Fixed 0.01 lot. Source for both editions, a Python statement of the rule, the tests, and the honest backtest evidence, which is thin.
Website: allanninal.dev/mql5 (Expert Advisors) · MT4 editions · allanninal.dev · Contact: message me on LinkedIn.
This EA promises no profit. Every number here is a backtest on broker history, not live trading, and the evidence is weak (see What the backtest does and does not show).
Get it on the MQL5 Market
| Edition | Platform | Price | Link |
|---|---|---|---|
| Prior Day Breakout | MT5 | free | https://www.mql5.com/en/market/product/201959 |
| Prior Day Breakout MT4 | MT4 | free | MT4 edition: coming soon on the MQL5 Market |
| Prior Day Breakout Pro | MT5 | paid | https://www.mql5.com/en/market/product/201963 |
| Prior Day Breakout Pro MT4 | MT4 | paid | MT4 edition: coming soon on the MQL5 Market |
The Market builds are the same code as the source in this repository. The Pro edition is a separate, paid product that is not part of this repository (see Free vs Pro).
Contents
- What it is and who it is for
- Why it was built
- How it works
- What the backtest does and does not show
- How it was tested
- Architecture
- Inputs, presets, install and compile
- Run the Python reference and the tests
- Honest limits
- Free vs Pro
- Licence
What it is and who it is for
What: a mechanical, once-a-day breakout rule. Levels are the high and low of the previous trading day. A buy needs a bar to close above the high, a sell a close below the low. The EA sends a market order at the next bar's open, puts the stop at the other side of yesterday's range, the target at a fixed multiple of that distance (R), and closes whatever is open at 23:00 server time. One position at a time. The panel shows the rule, the preset status, the levels, the last signal and the open position.
Live safety gate: live, the EA opens orders only on the two validated presets (XAUEUR H1 with target 2 R, XAUEUR M15 with target 1 R). On any other symbol, timeframe or target the panel reads "not validated" and no orders are sent. The Strategy Tester accepts any symbol, so the MQL5 Market validator can run it.
For: traders who want this exact rule automated and are willing to read the evidence below first. Also for developers who want a small, tested EA example with a Python statement of its rule.
Not for: anyone looking for a proven edge. There is none shown here.
![]() |
![]() |
![]() |
![]() |
Image notes: the charts and equity curves are drawn from broker history and the Strategy Tester trade lists by a script, and
the input screens are generated from the .set values; they are illustrations, not terminal captures. MT4 versions are in
docs/images/mt4/.
Why it was built
The motivations, stated with the evidence we actually have:
- It came out of a screen, not out of a belief. The rule was one of the combinations in a pre-registered strategy screen (37 symbols, several timeframes, in-sample 2020-01 to 2023-06, out-of-sample 2023-07 to 2026-10). It was the only combination that passed both the Python backtest and the MetaTrader 5 Strategy Tester, so the EA ships for that symbol and those timeframes only.
- Weak demand, stated plainly. No demand research backs this specific rule. Breakout EAs are plentiful on the MQL5 Market, and this one exists because it passed the gates, not because buyers asked for it. It is a free, transparent reference implementation.
- Provable behaviour. The rule is written down in
tests/reference.pyand compared with the EA's own trades, entry for entry.
mindmap
root((Prior Day Breakout))
Origin
Pre-registered screen, 37 symbols
One combination passed both gates
XAUEUR only
Design rules
Closed bars only, no repaint
Once per side per day
Flat at 23:00
Live only on validated presets
Proof
Python statement of the rule
Same entries as the EA, 612 of 612 and 690 of 690
Evidence is thin, stated plainly
How it works
The rule, step by step
Times are the broker's server clock (the tests used UTC+2, UTC+3 in US summer time). H and L are the previous trading day's
high and low, taken from 1-minute bars of the latest earlier day that has bars (up to 7 days back).
- Levels. At the start of the day,
H = max(high)andL = min(low)of the previous trading day. - Signal. On each closed chart bar that opened at or after 01:00: a buy if
close > Hand no buy has fired today; a sell ifclose < Land no sell has fired today. The side is used up even if the entry turns out to be disallowed. - Entry window. The order is sent at the open of the next bar, only if that bar opens before 20:00 of the same day and no position is open.
- Fill and stop. A buy fills at the ask, a sell at the bid. The stop is the other side of the range:
Lfor a buy,Hfor a sell. The stop distance issd = (fill - stop) x side. - Skip. The trade is skipped if
sdis not positive or is under 8 times the entry spread, or if the stop would lose more than 50% of equity at 0.01 lot, or if free margin is short. - Target.
fill + side x R x sd, withRthe preset's target (2 on H1, 1 on M15). - Exit. Target, stop, or flat at 23:00 server time (at the first tick after 23:00 if the market is closed then).
The lot is fixed: 0.01, or the broker's minimum lot when that is larger. After a restart the EA replays today's closed bars, so a side that already fired today is not taken again.
Per-bar algorithm
flowchart TD
A[New bar: look at the bar that just closed] --> B{Bar opened at or after 01:00?}
B -- no --> Z[Nothing]
B -- yes --> C[Levels: previous trading day high H and low L]
C --> D{Close above H and no buy yet today?}
D -- yes --> S1[Signal BUY, buy side used up]
D -- no --> E{Close below L and no sell yet today?}
E -- yes --> S2[Signal SELL, sell side used up]
E -- no --> Z
S1 --> F{Now before 20:00, same day, no position open?}
S2 --> F
F -- no --> Z
F -- yes --> G{Algo trading on, market open, preset validated?}
G -- no --> Z2[Skipped, reason on the panel]
G -- yes --> H2{Stop at least 8 x spread, loss under 50% of equity, margin ok?}
H2 -- no --> Z2
H2 -- yes --> I[Market order: stop at the other side, target R x stop]
Day cycle
stateDiagram-v2
[*] --> WaitingForSignal: new server day, levels read, sides reset
WaitingForSignal --> InTrade: signal and order sent at the next open
WaitingForSignal --> WaitingForSignal: bar closes inside the range
InTrade --> Flat: target or stop hit
InTrade --> Flat: 23:00 server time
Flat --> WaitingForSignal: the other side may still fire once
Flat --> [*]: day ends
WaitingForSignal --> [*]: day ends
One trading day
sequenceDiagram
participant D as New server day
participant E as EA
participant T as Terminal
participant B as Broker
D->>E: first bar of the day
E->>T: M1 history of the previous trading day
T-->>E: high H and low L
loop every closed bar from 01:00
E->>E: close vs H and L, once per side
end
E->>B: market order at the next open, stop at the far side, target R x stop
B-->>E: filled
alt target or stop first
B-->>E: position closed by the broker
else 23:00 server time
E->>B: close the position (waits for an open market)
end
What the backtest does and does not show
All numbers are the Strategy Tester run of the EA itself (1-minute OHLC, XAUEUR, 0.01 lot, results in R where R is the
stop distance of each trade, spread and swap included, no commission), out of sample 2023-07-01 to 2026-10-09, settings
frozen on 2020 to mid-2023 data first. Source: tests/results/oos-summary.md.
| Preset | Target | OOS trades | Profit factor | net R | t | max drawdown (R) |
|---|---|---|---|---|---|---|
| XAUEUR H1 | 2 R | 612 | 1.37 | 39.3 | 2.91 | 6.9 |
| XAUEUR M15 | 1 R | 690 | 1.27 | 36.6 | 2.47 | 6.7 |
Reading them with care, as the screen's own write-up does:
- One idea in two forms. The two presets share most of their trades.
- Chance-level evidence. Of 392 judged units over 37 symbols, 8 passed nominally against 8.3 expected from chance alone, and none survives the Holm multiple-testing correction (smallest adjusted p 0.33). XAUUSD with the same rule is just under the bar; the FX pairs and crypto fail.
- Mostly buys, in a gold rally. Gold rose about 110% over the out-of-sample period. The buy side earned 35 to 37 R, the sell side 1 to 2 R.
- Small per-trade edge. In-sample profit factors were only 1.05 to 1.09; win rate about 52%, average win 0.46 R, average loss 0.36 R, about +0.06 R per trade, so costs matter and commission was not modelled.
xychart-beta
title "Out-of-sample net R by side (backtest, gross of swap)"
x-axis ["H1 buys", "H1 sells", "M15 buys", "M15 sells"]
y-axis "R" 0 --> 40
bar [36.98, 3.93, 34.57, 2.82]
Source: tests/results/quarterly-gross-r.json, the reference run (gross R, before swap, so
slightly above the net R in the table).
xychart-beta
title "XAUEUR H1, target 2 R: gross R per quarter, out of sample"
x-axis ["23Q3", "23Q4", "24Q1", "24Q2", "24Q3", "24Q4", "25Q1", "25Q2", "25Q3", "25Q4", "26Q1", "26Q2", "26Q3"]
y-axis "R" -2 --> 10
bar [1.92, 2.05, 0.51, 3.04, 7.07, 4.82, 9.02, -1.48, 3.83, 2.31, 7.12, 0.53, 0.85]
(26Q4 holds 3 trades, -0.68 R, and is left out of the chart.)
How it was tested
| Check | Result |
|---|---|
Rule invariants on synthetic data, 60 runs, 1,931 trades (tests/check_reference.py) |
PASS, 0 violations |
| Reference vs the EA in the MT5 Strategy Tester, XAUEUR H1, 2023-07 to 2026-10 | 612 of 612 entries identical (time and side) |
| Reference vs the EA in the MT5 Strategy Tester, XAUEUR M15 | 690 of 690 entries identical |
| Reference vs the EA, same exit minute | 521 of 612 (H1), 502 of 690 (M15): the tester builds its own tick path from M1 bars |
| Reference vs the research simulation the presets were selected with | 612 of 612 and 690 of 690 trades identical, exits and exit prices too (largest difference 0.0) |
| MT4 edition vs the simulation (MT4 Strategy Tester, every tick, fixed 25-point spread) | same trade counts (612 and 690); entries match on 99.84% and 99.86% |
| MT5 release check (memory, speed, non-repainting, validator-style runs) | PASS: 364 MB, 1 min 21 s for 52 M ticks, 142 signals identical on every tick and on 1-minute OHLC, 0 error lines |
| MT5 and MT4 editions compiled with MetaEditor (clean scratch folder, only this repository's files) | 0 errors, 0 warnings each |
| MT5 Market build | passed the MQL5 Market's automated product validation before publication (the Market's own check) |
Sources: tests/results/. Full tables, including the MT4 gate and the release check, are in
tests/results/oos-summary.md.
xychart-beta
title "Entries compared: reference vs the EA (all identical)"
x-axis ["XAUEUR H1", "XAUEUR M15"]
y-axis "entries" 0 --> 800
bar [612, 690]
flowchart LR
M[M1 bars of the symbol<br/>server time, bid, spread] --> R[reference.py<br/>the rule in Python]
M --> TST[Strategy Tester<br/>EA with the debug log on]
TST --> L[TRD lines in the log<br/>entry time, exit time, side, prices]
L --> C{compare_trades.py<br/>same entry time and side?}
R --> C
C -- yes --> P[PASS]
C -- no --> F[list the differences, fix, rerun]
SY[synthetic random walks] --> K[check_reference.py<br/>rule invariants]
R --> K
K --> P2[PASS]
S5[PriorDayBreakout.mq5] --> MC5[MetaEditor 0 errors, 0 warnings]
S4[PriorDayBreakout.mq4] --> MC4[MetaEditor 4 0 errors, 0 warnings]
Not covered: forward (live) trading, commission and slippage, and tick-level fills (the tests use 1-minute OHLC for MT5 and a fixed 25-point spread for MT4). The tester and live behaviour of the preset refusal on other symbols is by design and was read, not run live. The reference is not a bit-for-bit copy of the tester's fills: only entries are compared exactly.
Architecture
flowchart TB
subgraph MT5["mql5/Experts/PriorDayBreakout"]
E5[PriorDayBreakout.mq5<br/>the program]
C5[PriorDayBreakout.mqh<br/>rule, orders, panel, events]
P5[DbPanel.mqh<br/>cached labels, boxes, rows]
R5[DbPresets.mqh<br/>the two validated presets]
E5 --> C5
C5 --> P5
C5 --> R5
end
subgraph MT4["mql4/Experts/PriorDayBreakout"]
E4[PriorDayBreakout.mq4]
C4[PriorDayBreakout.mqh<br/>MT4 orders and clock]
PR4[DbPanel.mqh, DbPresets.mqh<br/>same text as MT5]
E4 --> C4
C4 --> PR4
end
subgraph TESTS[tests]
RF[reference.py]
CK[check_reference.py]
CT[compare_trades.py]
CK --> RF
CT --> RF
end
RF -. same rule .-> C5
classDiagram
class PriorDayBreakout {
+InpTargetR double
+InpMagic long
+InpSlippage int
+InpPanel bool
+InpLevels bool
+InpDebug bool
+OnInit()
+OnTick()
+OnTimer()
+OnTradeTransaction()
}
class Rule {
+PrevDay()
+Decide()
+ReplayToday()
+OnNewBar()
+ManageTimed()
}
class Orders {
+EntryLots()
+EntryBlocked()
+OpenTrade()
+MarketOpen()
}
class DbPresets {
+g_db_presets
+DbPresetValidated()
}
class DbPanel {
+Text()
+Box()
+Row()
+Section()
}
class reference {
+run()
}
PriorDayBreakout --> Rule
PriorDayBreakout --> Orders
PriorDayBreakout --> DbPresets
PriorDayBreakout --> DbPanel
reference ..> Rule : same rule, compared entry by entry
Inputs, presets, install and compile
| Input | Default | Meaning |
|---|---|---|
| Target, x the stop distance (R) | 2.0 (1.0 on M15) | the preset's own value; live, other values are refused |
| Magic number | 26101801 | identifies this EA's position |
| Maximum slippage, points | 30 | order deviation |
| Show the panel | true | rule, preset status, levels, signal, position |
| Draw the previous-day high and low | true | dotted lines across the current day |
| Log every signal and trade (Experts tab) | false | prints signals and one TRD line per closed trade |
Preset files (inputs only): presets/ (MT5) and presets/mt4/. Load the file that matches the
chart's timeframe.
Install from source. Copy the mql5/Experts/PriorDayBreakout folder into <terminal data folder>/MQL5/Experts/ (MT5) or
the mql4/Experts/PriorDayBreakout folder into <data folder>/MQL4/Experts/ (MT4). Open PriorDayBreakout.mq5 or .mq4
in MetaEditor and press Compile (F7). Both compile with 0 errors and 0 warnings. Keep the files of each edition together:
the program includes PriorDayBreakout.mqh, which includes DbPanel.mqh and DbPresets.mqh from its own folder.
Run it. Open an XAUEUR chart (a prefixed or suffixed name is fine) on H1 or M15, attach the EA, keep Algo Trading (MT5) or AutoTrading (MT4) on. The tests used a server clock of UTC+2 (UTC+3 in US summer time); the 01:00 to 20:00 window follows your server clock, so check that it matches. Minimum balance suggested by the Market listing: 1,500 USD at 0.01 lot (recommended 3,000 USD); the out-of-sample backtest's largest drawdown at 0.01 lot was 673 USD and the largest single loss 373 USD. These are backtest figures, not a limit on future losses.
Run the Python reference and the tests
python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
python3 tests/check_reference.py # synthetic data, no broker history needed; prints PASS or FAIL
import sys; sys.path.insert(0, "tests")
from reference import run
# m1: pandas DataFrame indexed by server time with open, high, low, close (bid) and spread (price units)
trades = run(m1, tf_minutes=60, target_r=2.0) # one row per trade, gross of swap
To repeat the entry comparison on your own data:
- Run the EA in the Strategy Tester with "Log every signal and trade" on, on your XAUEUR history.
- Export the symbol's M1 bars to a CSV with the header
time,open,high,low,close,spread(server time, bid, spread in price units). python3 tests/compare_trades.py <log file> <m1.csv> --tf 60 --target 2.0 --from 2023-07-01lists the entries both share and those only one of them has.
The broker price history and the EA's trade lists used for the published numbers are not in this repository.
Honest limits
- No edge is shown. The evidence is a single 3.3-year window in one gold regime, with 8 nominal passes where 8.3 were expected by chance. Treat the EA as unproven automation.
- Mostly buys. The result depends on the buy side in a period of rising gold.
- Costs. Commission and slippage are not modelled; the swap is from the broker's sheet at the time; the test ticks are 1-minute OHLC.
- XAUEUR is offered by few brokers. The EA refuses live orders on other symbols and timeframes (the tester accepts any).
- Server clock. The entry window and the 23:00 exit follow the broker's server time, not UTC.
- Settings were chosen by in-sample profit factor only, and no walk-forward test was run.
- MetaTrader 4 has no economic calendar and a different tick model; the MT4 edition's numbers come from its own tester run on a fixed spread.
- No profit or accuracy claim is made.
Free vs Pro
| Free: Prior Day Breakout | Paid: Prior Day Breakout Pro | |
|---|---|---|
| Platforms | MT5 201959, MT4 coming soon | MT5 201963, MT4 coming soon |
| Price | free | paid (see the Market page) |
| What you get | the rule above, fixed 0.01 lot, XAUEUR H1 and M15 presets | the same rule with risk-based sizing, news modes, spread and Friday filters, as described on its Market listing |
| Source | this repository | not published |
No need to buy the paid product to use the free one: the free EA is complete on its own. Website: allanninal.dev/mql5 (MT4).
Licence
Everything in this repository is © 2026 Allan Niñal under the
PolyForm Noncommercial License 1.0.0: source-available, free for personal and
other noncommercial use, not for commercial use. Each source file has an SPDX-License-Identifier line. Text:
LICENSE. The previous-day high/low breakout is a public idea; this is an independent implementation. The licence
applies to this source, not to anything you build or trade with the EA. Trading involves risk; the software is provided as is.
Website: allanninal.dev/mql5 · MT4 · allanninal.dev · Questions: message me on LinkedIn.




