topkek

🧩 Syntax:
//+------------------------------------------------------------------+
//| Expert advisor: CandlePatternRiskTrailingEA_M5.mq5              |
//| Versie voor M5 timeframe                                        |
//| Stop-loss en trailing in euro's, max 1 Buy & 1 Sell positie     |
//+------------------------------------------------------------------+
#property strict

//--- inputs
input int    GreenCandlesForBuy  = 3;     // aantal groene candles voor buy
input int    RedCandlesForSell   = 3;     // aantal rode candles voor sell
input double RiskInEuro          = 22.0;  // stop-loss in euro
input double TrailingInEuro      = 5.0;   // trailing-afstand in euro
input double TrailingStartEuro   = 5.0;   // start trailing pas na € winst
input double LotSize             = 0.01;  // vaste lotgrootte
input bool   EnableTrailingStop  = true;  // trailing aan/uit

//--- globals
datetime lastBarTime = 0;
int      minStopsLevel;
double   tickValue, tickSize;

//+------------------------------------------------------------------+
//| Expert initialization                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   minStopsLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   tickValue     = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   tickSize      = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

   Print("INIT: minStopsLevel=", minStopsLevel,
         " tickValue=", tickValue,
         " tickSize=", tickSize);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                            |
//+------------------------------------------------------------------+
void OnTick()
{
   int needed = MathMax(GreenCandlesForBuy, RedCandlesForSell) + 2;
   MqlRates rates[];
   if(CopyRates(_Symbol, PERIOD_M5, 0, needed, rates) < needed) return;
   ArraySetAsSeries(rates, true);

   if(rates[0].time == lastBarTime) return;
   lastBarTime = rates[0].time;

   bool hasBuy = false, hasSell = false;
   for(int i=0; i<PositionsTotal(); i++)
   {
      ulong tk = PositionGetTicket(i);
      if(tk==0 || !PositionSelectByTicket(tk)) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      ENUM_POSITION_TYPE t = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      if(t == POSITION_TYPE_BUY)  hasBuy  = true;
      if(t == POSITION_TYPE_SELL) hasSell = true;
   }

   if(!hasBuy && CountConsecutive(rates, GreenCandlesForBuy, true))
      PlaceOrder(ORDER_TYPE_BUY);

   if(!hasSell && CountConsecutive(rates, RedCandlesForSell, false))
      PlaceOrder(ORDER_TYPE_SELL);

   if(EnableTrailingStop)
      ApplyTrailing();
}

//+------------------------------------------------------------------+
bool CountConsecutive(const MqlRates &r[], int cnt, bool bullish)
{
   for(int i=1; i<=cnt; i++)
   {
      if(bullish  && r[i].close <= r[i].open)  return false;
      if(!bullish && r[i].close >= r[i].open)  return false;
   }
   return true;
}

//+------------------------------------------------------------------+
void PlaceOrder(ENUM_ORDER_TYPE type)
{
   double entry = (type == ORDER_TYPE_BUY)
                  ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                  : SymbolInfoDouble(_Symbol, SYMBOL_BID);

   double ptsSL = RiskInEuro / (tickValue * LotSize) * (tickSize / _Point);
   ptsSL = NormalizeDouble(ptsSL, 0);

   int guard = minStopsLevel + 1;
   if(ptsSL < guard)
   {
      Print("  ptsSL <",guard," -> forceren naar ",guard);
      ptsSL = guard;
   }

   double sl_price = (type==ORDER_TYPE_BUY)
                     ? entry - ptsSL * _Point
                     : entry + ptsSL * _Point;
   sl_price = NormalizeDouble(sl_price, _Digits);

   MqlTradeRequest rq; MqlTradeResult rs;
   ZeroMemory(rq); ZeroMemory(rs);
   rq.action       = TRADE_ACTION_DEAL;
   rq.symbol       = _Symbol;
   rq.volume       = LotSize;
   rq.type         = type;
   rq.price        = NormalizeDouble(entry, _Digits);
   rq.sl           = sl_price;
   rq.tp           = 0;
   rq.deviation    = 10;
   rq.magic        = 20250607;
   rq.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(rq, rs))
      Print("OrderSend failed: ", rs.retcode);
   else if(rs.retcode != TRADE_RETCODE_DONE)
      Print("Order rejected: ", rs.retcode, " / ", rs.comment);
   else
      Print("Order placed: ", EnumToString(type),
            " entry=", DoubleToString(rq.price,_Digits),
            " SL=", DoubleToString(sl_price,_Digits));
}

//+------------------------------------------------------------------+
void ApplyTrailing()
{
   for(int i=0; i<PositionsTotal(); i++)
   {
      ulong tk = PositionGetTicket(i);
      if(tk==0 || !PositionSelectByTicket(tk)) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;

      ENUM_POSITION_TYPE t = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double openP    = PositionGetDouble(POSITION_PRICE_OPEN);
      double curP     = (t==POSITION_TYPE_BUY)
                        ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
                        : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      double curSL    = PositionGetDouble(POSITION_SL);
      double vol      = PositionGetDouble(POSITION_VOLUME);

      double diffPts = MathAbs(curP - openP) / _Point;
      double eurGain = diffPts * (tickValue * vol);

      if(eurGain < TrailingStartEuro) 
         continue;

      double ptsTR = TrailingInEuro / (tickValue * vol) * (tickSize / _Point);
      ptsTR = NormalizeDouble(ptsTR, 0);

      int guard = minStopsLevel + 1;
      if(ptsTR < guard) ptsTR = guard;

      double newSL = (t==POSITION_TYPE_BUY)
                     ? curP - ptsTR * _Point
                     : curP + ptsTR * _Point;
      newSL = NormalizeDouble(newSL, _Digits);

      if((t==POSITION_TYPE_BUY  && newSL > curSL) ||
         (t==POSITION_TYPE_SELL && newSL < curSL))
      {
         MqlTradeRequest rq; MqlTradeResult rs;
         ZeroMemory(rq); ZeroMemory(rs);
         rq.action   = TRADE_ACTION_SLTP;
         rq.position = tk;
         rq.sl       = newSL;
         rq.tp       = 0;
         if(!OrderSend(rq, rs))
            Print("Trailing SL failed: ", rs.retcode);
         else
            Print("Trailing SL updated pos#",tk,
                  " to ", DoubleToString(newSL,_Digits));
      }
   }
}
//+------------------------------------------------------------------+