Skip to content

Instantly share code, notes, and snippets.

@Elvmeen
Last active November 23, 2025 09:28
Show Gist options
  • Select an option

  • Save Elvmeen/303b4cc58209739c544c753d55460b5d to your computer and use it in GitHub Desktop.

Select an option

Save Elvmeen/303b4cc58209739c544c753d55460b5d to your computer and use it in GitHub Desktop.
Version 6.7
//+------------------------------------------------------------------+
//| Proportional Trailing EA (Corrected) |
//| SL reaches breakeven at 50% progress, continues trailing after |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
input double TrailStepPercent = 2.0; // Update every X% of progress
input int CheckIntervalMS = 1000; // Milliseconds between checks
input bool ShowDebugInfo = true; // Show trailing logs
CTrade trade;
datetime lastCheck = 0;
struct TradeMemory {
ulong ticket;
double initialSL;
};
TradeMemory mem[200];
double GetInitialSL(ulong ticket, double currentSL)
{
for(int i = 0; i < 200; i++)
{
if(mem[i].ticket == ticket)
return mem[i].initialSL;
if(mem[i].ticket == 0)
{
mem[i].ticket = ticket;
mem[i].initialSL = currentSL;
return currentSL;
}
}
return currentSL;
}
void OnTick()
{
if((TimeCurrent() - lastCheck) < CheckIntervalMS / 1000.0) return;
lastCheck = TimeCurrent();
int total = PositionsTotal();
for(int i = 0; i < total; i++)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
string sym = PositionGetString(POSITION_SYMBOL);
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
long type = PositionGetInteger(POSITION_TYPE);
if(currentSL == 0 || tp == 0) continue;
double initialSL = GetInitialSL(ticket, currentSL);
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
if(type == POSITION_TYPE_BUY)
{
double price = SymbolInfoDouble(sym, SYMBOL_BID);
double progress = (price - entry) / (tp - entry);
if(progress <= 0) continue;
double step = TrailStepPercent / 100.0;
double stepsCompleted = MathFloor(progress / step);
double effectiveProgress = stepsCompleted * step;
double newSL;
if(effectiveProgress <= 0.5)
{
// Phase 1: Move from initialSL to breakeven (entry)
// At 50% progress, SL should be at entry
newSL = initialSL + (entry - initialSL) * (effectiveProgress * 2.0);
}
else
{
// Phase 2: Continue from breakeven toward midpoint
// At 100% progress, SL should be at entry + 50% of (TP - entry)
double beyondBreakeven = effectiveProgress - 0.5;
double profitDistance = (tp - entry) * 0.5;
newSL = entry + (profitDistance * beyondBreakeven * 2.0);
}
// Safety buffer
int stopsLevel = (int)SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = MathMax(stopsLevel * point, point * 5);
double maxAllowedSL = price - minDistance;
if(newSL > maxAllowedSL) newSL = maxAllowedSL;
if(newSL > currentSL)
{
if(trade.PositionModify(ticket, newSL, tp))
{
if(ShowDebugInfo)
{
string status = (newSL >= entry) ? "βœ… BREAKEVEN+" : "🟑 Trailing to BE";
Print("BUY ", sym, " | Progress: ", DoubleToString(progress * 100, 1), "%",
" | New SL: ", DoubleToString(newSL, _Digits),
" | Entry: ", DoubleToString(entry, _Digits),
" | ", status);
}
}
}
}
else if(type == POSITION_TYPE_SELL)
{
double price = SymbolInfoDouble(sym, SYMBOL_ASK);
double progress = (entry - price) / (entry - tp);
if(progress <= 0) continue;
double step = TrailStepPercent / 100.0;
double stepsCompleted = MathFloor(progress / step);
double effectiveProgress = stepsCompleted * step;
double newSL;
if(effectiveProgress <= 0.5)
{
newSL = initialSL - (initialSL - entry) * (effectiveProgress * 2.0);
}
else
{
double beyondBreakeven = effectiveProgress - 0.5;
double profitDistance = (entry - tp) * 0.5;
newSL = entry - (profitDistance * beyondBreakeven * 2.0);
}
int stopsLevel = (int)SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = MathMax(stopsLevel * point, point * 5);
double minAllowedSL = price + minDistance;
if(newSL < minAllowedSL) newSL = minAllowedSL;
if(newSL < currentSL)
{
if(trade.PositionModify(ticket, newSL, tp))
{
if(ShowDebugInfo)
{
string status = (newSL <= entry) ? "βœ… BREAKEVEN+" : "🟑 Trailing to BE";
Print("SELL ", sym, " | Progress: ", DoubleToString(progress * 100, 1), "%",
" | New SL: ", DoubleToString(newSL, _Digits),
" | Entry: ", DoubleToString(entry, _Digits),
" | ", status);
}
}
}
}
}
}
int OnInit()
{
for(int i = 0; i < 200; i++)
{
mem[i].ticket = 0;
mem[i].initialSL = 0;
}
Print("========================================");
Print("πŸš€ Proportional Trailing EA (CORRECTED)");
Print("========================================");
Print("βš™οΈ Phase 1 (0-50%): SL moves to breakeven");
Print("βš™οΈ Phase 2 (50-100%): SL locks profit");
Print("βš™οΈ At 50% progress β†’ SL = Breakeven (GUARANTEED)");
Print("βš™οΈ At 100% progress β†’ SL locks 50% of profit");
Print("βš™οΈ Trail Step: ", TrailStepPercent, "%");
Print("========================================");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
Print("❌ EA Stopped");
}
//+------------------------------------------------------------------+
@Elvmeen
Copy link
Author

Elvmeen commented Oct 30, 2025

Logical Bug;

  1. SL stucking at at breakeven,
  2. Movement of the SL is still aggressive not propotional to breakeven and 1:2 RRR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment