Five Percent of the Trades, All of the Profit: Why My Gold EA Has No Take-Profit

27 August 2026, 15:00
Yuki Nakayama
0
28

This is the third entry in a public incubation diary for a gold Expert Advisor I am building toward a release around December 2026 or January 2027. The rule I set for myself is that everything goes in the diary — the measurements that came out the way I expected, and the ones that did not. The previous entry audited my EA against its own Python reference and found two checks that had passed for the wrong reason. This one is about an exit rule that is not in the EA at all, and why the matrix that removed it also tells me something uncomfortable about the strategy that remains.

Where the forward test stands

The EA trades one session on XAUUSD — UTC 10:00 to 13:45, the European–US overlap — placing stop orders at both edges of a 128-bar M15 Donchian channel, with an initial stop at 0.50 ATR and a trailing stop that arms at 0.50 ATR of open profit and gives back 0.25 ATR.

As of 2026-08-27 the demo forward test has 15 closed positions, all from that one session, logged by the EA itself to a CSV ledger at fill time. Six were profitable, averaging +1.4715 R; nine were losses, averaging −1.0695 R. The overall result is −0.0531 R per trade, or −0.7964 R in total.

That number is negative, and at this sample size it is uninformative. The per-trade dispersion in my backtest is 2.0769 R, which puts the standard error at n=15 around 0.54 R. The gap between the backtested +0.3181 and the live −0.0531 is 0.37 R — about two thirds of one standard error. Fifteen trades cannot tell those two numbers apart, and I am not going to pretend otherwise in either direction. I set myself a minimum of 20 stop-loss exits in advance before I would judge the live cost figures, and I am at 15.

What the 15 trades can settle is a question about mechanics rather than profit. Here are the holding times in minutes, sorted:

0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 6, 9

The longest position I have held in live forward testing is nine minutes. The EA's MaxHoldMinutes input is 480. That gap is the subject of the rest of this entry.

The input the EA does not have

My EA has 45 inputs. None of them is a take-profit. There is InitialStopATR , TrailArmATR , TrailGiveBackATR , MaxHoldMinutes — and no target. That was a deliberate deletion, and the deletion came out of a pre-registered exit matrix I ran on 2026-08-10 before the forward test started.

The matrix ran on 16.5 years of Dukascopy XAUUSD M1 data, from 2010-01-04 to 2026-07-23 — 5.9 million minute bars. Restricted to the one session, that produces 36,409 simulated trades. They overlap heavily: the EA re-evaluates the channel every M15 bar, so a single genuine breakout can generate several entries. Every t-statistic I quote below is computed on a 480-minute non-overlapping subsample for exactly that reason. Costs are charged as $0.247 + 0.0653 × ATR per round turn, and R is defined as net result divided by the initial stop distance.

The baseline — the configuration now running live — comes out at +0.3181 R per trade, 58.9% win rate, profit factor 1.563, non-overlapping t of +7.12, positive in 15 of 17 calendar years.

Then I added a fixed take-profit and swept it. No trailing stop in these rows; stop at 0.50 ATR, target at the stated multiple of ATR:

Take-profit= in RR / tradeWin rateProfit factorPositive years
1.0 ATR2.0 R−0.073545.1%0.9066 / 17
2.0 ATR4.0 R+0.098930.5%1.10012 / 17
3.0 ATR6.0 R+0.199223.4%1.18314 / 17
4.0 ATR8.0 R+0.274019.7%1.24014 / 17
6.0 ATR12.0 R+0.362916.2%1.30416 / 17
none (stop and time only)+0.543314.7%1.44716 / 17

The ordering is monotone across the whole sweep, and it points in one direction: the further away the target, the better the result, with the best case being no target at all. Note also what happens to the win rate. The take-profit at 2 R produces a 45% win rate and loses money. The no-target configuration wins 14.7% of the time and produces the highest expectancy in the table. Any exit rule tuned to make the equity curve feel better is tuned in exactly the wrong direction here.

Why: a census of where the money is

The reason is not subtle once you count it. Under the live configuration, across all 36,409 backtested trades, the exits break down like this:

ExitCountShareR / tradeTotal R
Initial stop14,45939.71%−1.4187−20,512
Trailing stop21,95060.29%+1.4621+32,092
Time stop (480 min)00.00%
Take-profit00.00%

Total is +11,580 R over 16.5 years. Now the tail:

SliceCountTotal RShare of all profitMean R of everything else
Best 1%365+4,21336.4%+0.2044
Best 5%1,821+12,025103.8%−0.0129
Best 10%3,641+17,401150.3%−0.1776

Read the middle row carefully, because it is the least comfortable line in this diary so far. The best 5% of trades account for 103.8% of the total profit. The other 95%, taken together, lose money. Strip out the top twentieth and the profit factor falls to 0.978 and expectancy to −0.0129 R — a coin flip on which you pay costs.

Once that is on the table, the take-profit result stops being a finding and becomes arithmetic. Trades finishing above +2 R are 12.74% of the population (4,640 of them) and carry +19,595 R, which is 169% of everything the strategy makes. A take-profit at 2 R is, by construction, a rule that goes into that specific 12.74% and truncates it, while doing nothing whatsoever to the losing side. Truncating the realised outcomes at 2 R — a floor rather than an estimate, since a real target would also bank 2 R on trades that touched the level and gave it back — already drops the mean from +0.3181 to +0.0348. The simulated take-profit is worse still, at −0.0735, and the reason is worth naming: those rows have no trailing stop, so the exit census changes shape. Stop-outs rise from 14,459 to 19,993, because trades that never reach 2 R — the ones the trail would have closed in profit — now ride all the way back to the initial stop. A target does not simply cap the winners. It also removes the mechanism that was harvesting the middle of the distribution.

The largest single trade in the 16.5-year sample is +21.28 R. There is no version of a 2 R target that survives contact with a distribution shaped like that.

The insurance target that never fires

My next idea was the one most people land on: keep the trailing stop, and add a target so far out that it cannot cut the tail — insurance against a spike that reverses before the trail can follow. I tested it at 4.0, 6.0 and 8.0 ATR on top of the live trailing configuration.

All three came back identical to the no-target run. Not close — identical in every column, to four decimals, because the take-profit fired zero times in 36,409 trades. The trailing stop always got there first. The same is true of the 480-minute time stop under this configuration: zero fires in 16.5 years. And the live ledger agrees, as strongly as 15 trades can agree with anything: longest hold nine minutes, no time-stop exits, and the only exit type ever recorded is a stop order.

So across the range I tested, a take-profit on this system is either harmful or inert. It is harmful when it is close enough to fire, and inert when it is far enough not to. I did not find a setting where it helps. I should be exact about the scope of that claim: I swept targets from 1.0 to 6.0 ATR without a trail, and 4.0 to 8.0 ATR with one. I did not test every combination that exists, and this is one instrument, one session, one entry rule.

The parameter that never fires, and what it actually costs

Here is the part I did not expect when I started writing this up, and it includes a mistake I made while writing it. I had described MaxHoldMinutes = 480 as dead, since it has never triggered an exit in either the backtest or the live account. It is not dead. It is wired into a second rule.

The EA blocks new entries late on Friday so that a fill cannot survive past the weekend close. The cutoff is FridayCloseMinServer (23:59) minus MaxHoldMinutes (480), which lands at 15:59 server time. It fires on schedule — the log printed [FRI-CUTOFF] at UTC 13:00 and 13:30 last Friday.

I had never measured what that costs, so I measured it. My first answer was wrong, and the error is more interesting than the correction. The cutoff is fixed in server time, and my broker's server runs UTC+3 under daylight time and UTC+2 outside it. In summer, 15:59 server is 12:59 UTC, which deletes the whole UTC-13 hour of Friday — four of the session's sixteen bars. In winter it is 13:59 UTC, which falls after the last entry bar at 13:45, so it blocks nothing at all. My first pass counted every Friday UTC-13 trade in the sample: 1,691 of 36,409, worth +549 R, or 4.74% of the strategy's total. That is the cost of a rule that bites all year, and mine does not.

Restricted to the daylight-time months, where the cutoff actually applies, the blocked set is 905 trades — 2.49% of the sample, mean +0.1720 R, total +156 R. The weekend guard costs 1.34% of the backtested profit, not 4.7%. The blocked hour also earns well below the sample average per trade, which I would not have guessed.

I am keeping the rule. A leveraged gold position carried across a weekend is exposed to a gap that this backtest, built on continuous intraday bars, is not equipped to price, and I would rather pay a measured 1.34% than carry an unmeasured risk. But there is a difference between accepting a cost, not knowing you are paying it, and holding the wrong figure for it. Until this week I was in the second category, and for part of this week I was in the third.

What the live trades say about the same question

Since I have an MFE column in the ledger, I can ask what a 1.0 ATR fixed target — 2 R, since the stop is 0.5 ATR — would have done to the 15 live positions. The answer is exact rather than estimated: if a trade's maximum favourable excursion reached the target, the target would have filled.

Two of the 15 change. One improves — a trade that reached 2.294 R and exited at +1.7939 would have banked 2.0 R, gaining 0.21 R. One gets much worse: my best live trade so far, on 2026-08-19, ran to 3.754 R and closed at +3.1847 R after two minutes; a 2 R target turns it into +2.0 R, costing 1.19 R. The other thirteen are untouched. Net, the target takes the sample from −0.0531 to −0.1183 R per trade.

Fifteen trades and two altered outcomes prove nothing statistically, and I am not presenting this as evidence. I ran it because a mechanism claimed from 36,409 simulated trades ought to be visible in the actual fills, and if it had not been, I would have had a problem worth chasing.

What this does not establish

The honest limits, in the order they bother me.

The edge has decayed. Split at 2018-02, the in-sample half runs +0.4519 R per trade and the out-of-sample half +0.1935 — under half. Year by year: 2013 was +0.9561, but 2018 was −0.0074, 2019 +0.0332, 2020 +0.0054 and 2025 −0.0494. Four of the last nine years are flat or negative. The 15-of-17 positive-years figure is real, and it is also carried by 2012–2016.

All of this comes from one dataset. The exit matrix was part of a larger sweep in which I ended up running 278 cells against a pre-declared 173. I recalculated the expected maximum t under the null for the larger count — 2.91 by the formula I had declared — and kept the pre-registered 3.29 rather than relaxing to it. But the IS/OOS split is a split inside the same 2010–2026 file, not a genuine out-of-sample test, and the take-profit conclusion is a conclusion about the history I happen to have.

The P0 battery has not been run on this configuration. Deflated Sharpe ratio, probability of backtest overfitting, walk-forward and Monte Carlo permutation testing are all still outstanding. That work is queued, and it will appear in this diary whichever way it comes out.

The cost model and the live broker disagree, in both directions. At current ATR levels the simulator charges roughly 18.6% of the stop distance per round turn, while the spread measured at fill on my live account has a median of 5.71% over the 15 trades — the model is about three times harsher than the broker has been. That is the safe direction. The unsafe direction is entry slippage: the simulator assumes stop orders fill at the level, and my reconciliation work found live fills landing on the adverse side in every case measured, at a median of 2.69% of the stop distance. Both effects are small next to a tail that runs to 21 R, but I would rather name them than average them away. The backtest is also Dukascopy data while the live account is an XM feed, which is a mismatch I have not yet quantified.

Next

There is an irony in this entry that I will point at rather than hide. The Python-versus-MQL5 reconciliation I have been publishing passed its first stage — the decision inputs, where Donchian levels matched to five decimals across 92 bars — and passed three of its five criteria in the second stage, on fills. The criterion still outstanding is the total-R comparison, and it is outstanding for one reason: I have not yet implemented the exit side of the reproduction. I have spent this article arguing about exits on the strength of a simulator whose exit logic I have not yet proven matches the robot's, on the same data, trade for trade.

That is the next piece of work, and the sample has grown from 7 fills to 15 since I last checked, which helps. Until it is done, the correct description of everything above is: this is what my simulator says, and my simulator has not yet been fully cross-examined.

The EA is not for sale and will not be until it has a live track record measured in months rather than days. If you want to see the tooling this came out of, my free indicators are on my seller profile. The diary continues weekly.