DEV Community

Cover image for The Maths Behind Prop Firm Challenge Failures (And How to Fix It With Code)
Precious Lyna Anusiem
Precious Lyna Anusiem

Posted on

The Maths Behind Prop Firm Challenge Failures (And How to Fix It With Code)

Most prop firm challenge post-mortems I've read online are vague. "I overtraded." "I didn't respect my drawdown." "I was emotional."

Helpful. Thanks.

This post is going to be specific. I want to walk through the actual numbers behind why challenges fail, show you the formulas that fix the most common problems, and share how an MT5 expert advisor can enforce the rules you already know but consistently break under pressure.

If you trade or are thinking about attempting a prop firm challenge, this is the quantitative breakdown nobody writes.


First: What the Challenge Structure Actually Optimises For

A standard two-phase prop firm challenge looks like this:

Phase Profit Target Max Daily Loss Max Total Drawdown Min Trading Days
Phase 1 8–10% 4–5% 8–10% 4–10
Phase 2 4–5% 4–5% 8–10% 4–10
Funded None 4–5% 8–10% Ongoing

The asymmetry here is worth noticing. The profit target is fixed and achievable. The drawdown limits are permanent (total DD doesn't reset) and zero-tolerance (one breach and it's over).

This structure rewards consistency over aggression. The optimal play is not to maximise profit per unit time — it's to maximise the probability of staying within the loss boundaries while accumulating gains.

Which means it's fundamentally an optimisation problem, not a prediction problem.


The Position Sizing Formula (And Why Most Traders Get It Wrong)

The most common quantitative mistake I see in challenge attempts is fixed lot sizing. "I trade 0.1 lots on EUR/USD" — regardless of what the market is doing.

The correct formula:

Position Size (lots) = (Account Balance × Risk %) ÷ (Stop Loss in pips × Pip Value per lot)
Enter fullscreen mode Exit fullscreen mode

Let's run this properly for a few scenarios on a $10,000 account at 1% risk:

EUR/USD — Low Volatility Day (ATR: 35 pips)

Stop Loss = 1.5 × 35 = 52.5 pips
Position Size = $100 ÷ (52.5 × $10) = 0.19 lots
Enter fullscreen mode Exit fullscreen mode

EUR/USD — High Volatility Day (ATR: 80 pips)

Stop Loss = 1.5 × 80 = 120 pips
Position Size = $100 ÷ (120 × $10) = 0.08 lots
Enter fullscreen mode Exit fullscreen mode

Same instrument, same 1% risk, same entry logic — and the position size varies by more than 2×. If you're using a fixed 0.1 lot size, on high-volatility days you're actually risking ~1.9%, and on low-volatility days you're leaving risk on the table or being stopped out by normal noise.

This is why ATR-based stop losses matter so much in a challenge context. Your risk per trade needs to be real, not nominal.


Simulating the Drawdown Risk at Different Position Sizes

Let's model what consecutive losing trades look like at different risk percentages on a $10,000 challenge account with a 10% total drawdown limit ($1,000 max loss):

def simulate_drawdown(balance, risk_pct, n_losses, max_dd_pct):
    max_dd = balance * (max_dd_pct / 100)
    current_balance = balance
    total_loss = 0

    for i in range(1, n_losses + 1):
        loss = current_balance * (risk_pct / 100)
        current_balance -= loss
        total_loss += loss
        remaining_buffer = max_dd - total_loss
        print(f"Loss {i}: Balance ${current_balance:.2f} | "
              f"Total DD: ${total_loss:.2f} | Buffer left: ${remaining_buffer:.2f}")
        if total_loss >= max_dd:
            print(f"CHALLENGE FAILED at loss {i}")
            break

# At 1% risk
print("=== 1% Risk per Trade ===")
simulate_drawdown(10000, 1.0, 10, 10)

print("\n=== 2% Risk per Trade ===")
simulate_drawdown(10000, 2.0, 10, 10)
Enter fullscreen mode Exit fullscreen mode

Output:

=== 1% Risk per Trade ===
Loss 1: Balance $9900.00 | Total DD: $100.00 | Buffer left: $900.00
Loss 2: Balance $9801.00 | Total DD: $199.00 | Buffer left: $801.00
...
Loss 10: Balance $9043.82 | Total DD: $956.18 | Buffer left: $43.82
(Still alive after 10 consecutive losses)

=== 2% Risk per Trade ===
Loss 1: Balance $9800.00 | Total DD: $200.00 | Buffer left: $800.00
...
Loss 5: Balance $9039.21 | Total DD: $960.79 | Buffer left: $39.21
Loss 6: ...
CHALLENGE FAILED at loss 6
Enter fullscreen mode Exit fullscreen mode

The difference between 1% and 2% risk isn't 2× the danger — it's the difference between surviving 10 consecutive losses and failing on the 6th. In a challenge context, those six losses can happen in two bad trading days.


The Daily Drawdown Problem Is More Subtle Than People Think

Most traders focus on total drawdown but the daily limit is what ends the majority of challenges. Here's why:

Suppose you're at a $10,000 account and you've had three moderately bad days — down 2.5% total, sitting at $9,750. You now have $750 of total DD buffer remaining.

Your firm's daily loss limit is 5% of the day's opening balance. But your personal available daily budget is now constrained by two things simultaneously:

  1. The firm's daily limit: $10,000 × 5% = $500
  2. Your remaining total DD buffer: $750

If you lose more than $500 today, you breach the daily limit regardless of total DD. If you've had one particularly bad day earlier in the challenge and you're at $9,300, your total buffer ($700) is actually tighter than the daily limit on some days.

The correct daily maximum loss to trade to is: min(firm_daily_limit, remaining_total_dd_buffer × 0.5)

Never put more than half your remaining total buffer at risk in a single day. This gives you at least two more bad days before failure, rather than one.


How GlimTrader Pro Handles This Automatically

After working through all of this manually for a while, I started using GlimTrader Pro — an MT5 expert advisor specifically built for prop firm challenges. I want to be specific about how it solves the problems above rather than just saying "it does risk management."

ATR-based position sizing:

// Pseudocode of the sizing logic
atr = iATR(symbol, timeframe, 14)
stop_distance = atr * ATR_SL_Multiplier  // default 1.5
pip_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
risk_amount = AccountBalance() * (RiskPercentage / 100)
lot_size = risk_amount / (stop_distance * pip_value)
lot_size = MathMin(lot_size, MaxLotSize)
lot_size = MathMax(lot_size, MinLotSize)
Enter fullscreen mode Exit fullscreen mode

This runs on every entry signal. You never manually set the lot size.

Daily loss enforcement:
The EA tracks g_dailyLoss against MaxDailyLossPercent. When the threshold is crossed, CheckDailyLimits() returns true and the entry logic is blocked for the rest of the day. There's no override because there's no UI element to override it with — the decision is made before the session starts via the parameter, not in the moment.

The 6-factor signal confluence system:
The EA only opens trades when all of the following align:

  • EMA stack: Fast(8) > Slow(21) > Trend(50) for longs
  • H4 timeframe EMA(50) in agreement (when UseMultiTimeframeConfirm = true)
  • MACD histogram showing momentum in signal direction
  • RSI not in overbought/oversold zone
  • Price within Bollinger Bands (20, 2.0)
  • Previous candle confirms direction (when RequireCandleConfirmation = true)

The multi-factor requirement naturally reduces trade frequency, which in a challenge context is usually a feature not a bug. Fewer trades means fewer opportunities to breach the daily limit.


Optimal Parameters for Each Challenge Phase

This is what I run — and what I include in the configuration guide bundled with the EA:

// Phase 1 & 2  Conservative
RiskPercentage = 0.75
MaxDailyLossPercent = 3.0       // buffer below firm's 4-5%
MaxDailyProfitPercent = 5.0     // stop trading after good days
MaxConcurrentTrades = 1
UseMultiTimeframeConfirm = true
RequireCandleConfirmation = true
ATR_SL_Multiplier = 1.5
ATR_TP_Multiplier = 3.0         // enforces minimum 2:1 R:R
UseBreakeven = true
BreakevenTriggerATR = 1.0
UseTrailingStop = true
TradeLondonSession = true
TradeNewYorkSession = true
TradeAsiaSession = false
MaxSpreadPoints = 30
Enter fullscreen mode Exit fullscreen mode

The key ones most people configure wrong:

MaxDailyProfitPercent — stopping after a profitable day sounds counterintuitive but it prevents the single most common way traders give back gains: continuing to trade an already-volatile session after a strong run, often in worse conditions.

TradeAsiaSession = false — the Asia session has lower volume and more erratic price action for EUR/USD and major pairs. The signal quality drops and spread quality worsens. Turning this off removes a category of trades that have worse expected value.

MaxConcurrentTrades = 1 — stacking two 1% positions is a 2% position. This one line prevents silent leverage creep.


The Firm-Specific Settings That Matter

Not all firms have identical rules. Here's what changes by platform:

Firm Daily DD Max DD Trailing DD MaxDailyLossPercent Setting
FTMO 5% 10% No 3.5%
The Funded Trader 5% 10% Yes (from equity high) 3.0%
E8 Funding 5% 8% No 3.0%
Apex Trader 3% 6% No 1.5%
Topstep FX 2% 6% No 1.5%

The trailing drawdown at The Funded Trader is the one that catches people most often. If your equity reaches $10,800 and then pulls back to $10,000, you've used $800 of your $1,000 trailing DD limit — even though you're still above your starting balance. The practical adjustment is to treat +3% days as a signal to stop trading, not to continue pushing.


If You Want the Full System

I put together a detailed guide covering all of this — the drawdown maths, position sizing formulas, firm-specific settings, a printable daily tracker, and full GlimTrader Pro configuration for each phase and each major firm. It's available on Gumroad at a flat rate, bundled with the EA.

Not trying to upsell — I'm sharing it because working through this stuff analytically (the way this post tries to) is what finally made the difference after three failed challenges. The guide documents all of it in one place.

GlimTrader Pro — Pass Prop Firm Challenges Faster →


If you're working through the maths on your own challenge setup and have questions, drop them in the comments. Happy to go deeper on any of the formulas or the EA configuration logic.

Top comments (0)