Forex Trading StrategiesRule-Based Forex Strategy in MT5
Build a rule-based forex strategy in MT5 step by step — entries, exits, risk management, backtesting and forward testing, checklist included.
A trailing drawdown lock ratchets up with every new equity high and never gives ground back. Most EAs have no idea it exists.

Static drawdown is the version most people picture. A hard floor, set on day one from your starting balance. Touch it and the account is done.
A trailing drawdown lock moves. Every time the account prints a new high, the floor steps up behind it. Then it stays there. Lose the next day and it does not step back down with you.
That one difference breaks most EAs.
We keep meeting traders who proved out their risk logic on a static-drawdown demo and assumed it would carry over. It doesn't. Sizing that ignores the ratchet is why accounts get flagged in week two of an evaluation, usually on a day that felt completely ordinary.
Before the math, two details firms do not agree on.
The first is when the floor updates. Earn2Trade's evaluation accounts use an end-of-day drawdown: your minimum balance is recalculated from closed positions after the session ends, then holds for the whole next day. Apex is harsher. Its intraday trailing threshold follows your peak balance in real time, unrealized profit included, so a trade that spikes in your favour and gives it all back still drags the floor up permanently. Same word, "trailing", two very different risk pictures.
The second is units. Both of those are futures firms, so they count contracts, not lots. The logic below transfers. The numbers don't. Your firm's rule sheet gives you the constants; this post gives you the shape of the calculation.
Fixed lot sizing rests on one assumption: that your risk budget stays the same size. Under a trailing lock it doesn't. It shrinks every time the floor ratchets up behind you.
The failure looks the same every time we see it. A trader backtests an EA at a flat 0.1 lot on EUR/USD. It behaves on a static-drawdown demo. They deploy it on a funded account with a trailing lock, and the EA carries on risking an identical dollar amount per trade, with no idea where today's equity sits relative to the high-water mark.
Two accounts, same EA, same lot size, opposite outcomes:
A fixed lot size treats those two accounts as identical. Account B is one bad session from a breach and its sizing logic never said a word.
Stop sizing off the starting balance. Size off the live distance between current equity and the current lock level. That distance is the only money you actually have to lose.

buffer = current_equity - drawdown_lock_level
risk_amount = buffer x risk_per_trade_pct
lot_size = risk_amount / (stop_loss_pips x pip_value)
Three details decide whether this works in practice.
The base is buffer, never equity. Equity tells you how much money is in the account. Buffer tells you how much room is left before the firm switches you off, and that is the number a live sizing decision depends on.
risk_per_trade_pct should shrink as the buffer shrinks rather than sit at one figure forever. Percentages are below, but the principle is simple enough: the closer you sit to the lock, the smaller a bite each trade takes out of what remains.
pip_value has to come from the symbol. Gold and EUR/USD do not share a pip value per 0.01 lot, and a 4-digit broker feed does not agree with a 5-digit one. Hardcode a pip value and the formula keeps returning confident, wrong numbers on every symbol but the one you tested.
Risk per trade should shrink as the buffer to the lock narrows: roughly 0.75% early in an evaluation, 0.5% mid-evaluation, and 0.25% or flat once the buffer drops under 40%. A static floor never moves, so 1-1.5% stays standard risk there.
| Drawdown regime | Risk / trade | Why |
|---|---|---|
| Trailing lockEarly evaluation - buffer above 80% of max | 0.75% | Lock hasn't ratcheted much yet - buffer is close to full |
| Trailing lockMid-evaluation - buffer 40-80% | 0.5% | Lock has moved up; each trade risks a proportionally bigger share of what's left |
| Trailing lockNear lock - buffer under 40% | 0.25%or flat | Preserve the account; this isn't the trade to press |
| Static drawdownFunded or live - floor never moves | 1-1.5% | Floor doesn't move - sizing can stay closer to standard risk management |
| Remaining buffer | 0.75%> 80% left | 0.5%40-80% left | 0.25%< 40% left |
|---|---|---|---|
| $600 | $4.500.01 lots | $3.000.01 lots | $1.50under 0.01 min |
| $1,200 | $9.000.03 lots | $6.000.02 lots | $3.000.01 lots |
| $2,500 | $18.750.06 lots | $12.500.04 lots | $6.250.02 lots |
| $5,000 | $37.500.12 lots | $25.000.08 lots | $12.500.04 lots |
Look at the top-right cell. A $600 buffer at 0.25% funds $1.50 of risk, and the smallest lot your broker will accept costs $3.00 on a 30-pip stop. The honest answer there is no trade at all. Remember that cell, because it is the one most sizing code gets wrong.
These percentages are a starting frame, not constants. Apex and Earn2Trade calculate their floors from different things at different moments, and that changes what a sensible tier looks like on each.
A $50,000 evaluation account. The EA risks 30 pips per trade on EUR/USD.
Under a trailing lock, mid-evaluation, equity is $51,200 and the lock has ratcheted up to $50,600. Buffer: $600. Risking 0.5% of that is $3, which at $10 per pip and a 30-pip stop buys you 0.01 lots. Small. But the gains are already banked, and the job now is not handing them back.
Under static drawdown, same balance, the floor is still fixed at $47,500. Buffer: $3,700. Risking 1.5% is $55.50, which works out to $1.85 per pip, or 0.185 lots. On a 0.01 volume step you round down and trade 0.18.
Same EA, same account size, same day, eighteen times the position size. A flat 0.1-lot EA will never notice either situation.
Pull live equity, subtract the lock level you're tracking, and normalize the result to the symbol's volume step so the broker doesn't bounce the order.
//--- Inputs: set these from your firm's specific drawdown rule
input double RiskPctBuffer = 0.5; // % of buffer risked per trade
input double DrawdownLockLevel = 50600.0; // refreshed from your high-water calc
input int StopLossPips = 30;
double CalculateLotSize()
{
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double buffer = equity - DrawdownLockLevel;
if(buffer <= 0)
return 0.0; // no room left - do not open a new position
double riskAmount = buffer * (RiskPctBuffer / 100.0);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(tickValue <= 0 || tickSize <= 0)
return 0.0; // symbol data not ready - sizing would be guesswork
// A pip is 10 points only on 3- and 5-digit quotes.
double pipSize = (_Digits == 3 || _Digits == 5) ? _Point * 10 : _Point;
double pipValue = tickValue * (pipSize / tickSize);
double rawLot = riskAmount / (StopLossPips * pipValue);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lot = MathFloor(rawLot / lotStep) * lotStep;
if(lot < minLot)
return 0.0; // budget can't afford the minimum lot - skip, don't round up
return MathMin(maxLot, lot);
}
AccountInfoDouble(ACCOUNT_EQUITY) gives you equity rather than balance, and the difference is floating P/L, which is exactly what an intraday lock reacts to. The AccountInfoDouble reference lists the rest of the account properties. On MT4 the call is AccountEquity() and the arithmetic is unchanged.
The two return 0.0 guards are the whole point of the function. The first stops the EA trading once it is already through the lock. The second is that top-right table cell in code: when the risk budget cannot pay for the broker's minimum lot, the trade does not happen. Clamping up to minLot instead is a tempting one-liner and it quietly does the opposite of what you asked, taking more risk precisely when there is least room for it.
Rounding down to SYMBOL_VOLUME_STEP keeps the order acceptable. Send an unrounded volume and OrderSend fails with 4756, whose result structure carries retcode 10014, invalid volume. The outer code tells you nothing; the retcode is where the reason lives, so log both.
One caveat on pipSize. The 3-and-5-digit test covers forex. Metals, indices and crypto define a pip however the broker feels like it, so check SYMBOL_TRADE_TICK_VALUE against a known lot size on each symbol before you trust the output.
And DrawdownLockLevel is an input for a reason. It needs a routine that recalculates it on your firm's schedule, whether that is a session-close snapshot or a running peak. The sizing function is only ever as good as the lock value you hand it.
We have found this one in EAs that were otherwise well built. The lot-sizing function reads AccountBalance() once inside OnInit(), stores it, and never looks again.
On a static-drawdown account that is harmless, because the floor doesn't move either. On a trailing lock it is the entire problem. The EA is sizing every trade against a number that was true on day one and has not been true since.
Read equity fresh on every call, and pair it with a lock value that updates on schedule.
Here is what the difference costs. Both charts below show the same $100,000 account on gold, the same lock trailing 6,000 behind the high-water mark, and the same market: a run to 108,000 that ratchets the lock to 102,000, then two losing days. The only variable is how the EA sizes.
An account that is up on the month, breached. Not by a bad strategy, by a stale number.
None of this should touch a funded account untested. The MetaTrader 5 Strategy Tester lets you step through equity and watch the calculated lot size bar by bar in the Journal tab.
0.0 when the simulated buffer goes negative, and again when it is positive but too thin to fund the minimum lot. Eyeballing the equity curve will not show you either case.For the general mechanics of how different firms define their locks, PropScorer's explainer is a reasonable place to start. This post is the part that comes after: turning that rule into a lot size.
Size off the live buffer. Recalculate the lock on your firm's schedule. Return zero when there is nothing left to risk.
If tracking a moving lock by hand sounds like a spreadsheet you'll forget to update mid-session, that is the gap our Equity Tracker MT5 fills. It puts your live distance to the lock on the chart, so the number your EA sizes against is the number you are looking at.
A trailing drawdown lock is a floor that moves up every time the account posts a new equity high, then holds there. Unlike a static drawdown, it never steps back down, so the account's risk budget shrinks any time equity pulls back from its own high-water mark.
Fixed lot sizing assumes a constant risk budget. Under a trailing lock, the real budget is the buffer between equity and the lock, and that buffer shrinks every time the lock ratchets up. An EA that risks the same dollar amount regardless can breach an account that is still profitable overall.
The buffer, never raw equity. Equity shows how much money is in the account; buffer shows how much room is left before the firm switches trading off, and that is the number a live sizing decision has to depend on.
It sizes every trade against a number that was only ever true on day one. That is harmless on a static-drawdown account, but on a trailing lock it can breach an account that is still up on the month, because the lock has moved and the EA never noticed.
Because the buffer is the entire remaining risk budget, not a fixed pool. Risking a flat percentage of a shrinking buffer takes a proportionally bigger bite out of what's left with every trade near the lock, which is why risk per trade should scale down as the buffer narrows.