topkek
🧩 Syntax:
//+------------------------------------------------------------------+
//| Expert advisor: CandlePatternRiskTrailingEA_v3.mq5 |
//| Buy/Sell X H1 candles, SL/TS in EUR, max 1 Buy & 1 Sell |
//+------------------------------------------------------------------+
#property strict
//--- inputs
input int GreenCandlesForBuy = 3; // aantal groene candles voor buy
input int RedCandlesForSell = 3; // aantal rode candles voor sell
input double RiskInEuro = 10.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
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert tick |
//+------------------------------------------------------------------+
void OnTick()
{
// 1) Nieuwe H1-candle?
int needed = MathMax(GreenCandlesForBuy, RedCandlesForSell) + 2;
MqlRates rates[];
if(CopyRates(_Symbol, PERIOD_H1, 0, needed, rates) < needed) return;
ArraySetAsSeries(rates, true);
if(rates[0].time == lastBarTime) return;
lastBarTime = rates[0].time;
// 2) Check open posities
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;
}
// 3) Signalen
if(!hasBuy && CountConsecutive(rates,GreenCandlesForBuy,true))
PlaceOrder(ORDER_TYPE_BUY);
if(!hasSell && CountConsecutive(rates,RedCandlesForSell,false))
PlaceOrder(ORDER_TYPE_SELL);
// 4) Trailing
if(EnableTrailingStop) ApplyTrailing();
}
//+------------------------------------------------------------------+
//| Tel consecutive bullish/bearish |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| Open marketorder met SL check |
//+------------------------------------------------------------------+
void PlaceOrder(ENUM_ORDER_TYPE type)
{
double entry = (type==ORDER_TYPE_BUY)
? SymbolInfoDouble(_Symbol,SYMBOL_ASK)
: SymbolInfoDouble(_Symbol,SYMBOL_BID);
// SL in punten
double ptsSL = CalcPoints(RiskInEuro);
// min stops
int minStops = (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)+1;
if(ptsSL < minStops)
{
Print("SL-te-klein bij order, aanpassen van ", ptsSL, " naar ", minStops, " pts");
ptsSL = minStops;
}
double sl = (type==ORDER_TYPE_BUY) ? entry-ptsSL*_Point : entry+ptsSL*_Point;
sl = NormalizeDouble(sl,_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;
rq.tp = 0;
rq.deviation = 10;
rq.magic = 20250529;
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 opened: ", EnumToString(type),
" @", rq.price, " SL@", sl);
}
//+------------------------------------------------------------------+
//| Bereken punten uit eurorisico |
//+------------------------------------------------------------------+
double CalcPoints(double euro)
{
double tv = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
double ts = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
if(tv<=0||ts<=0) return(1);
double ppp = tv/ts;
double pts = euro/(ppp*LotSize);
return(MathMax(NormalizeDouble(pts,0),1.0));
}
//+------------------------------------------------------------------+
//| Trailing stop update met min-stop-check |
//+------------------------------------------------------------------+
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);
// winst in EUR
double diff = MathAbs(curP-openP)/_Point;
double eur = diff * (SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE)
/SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE)) * vol;
// debug print
Print("Pos ",tk," profit€=",DoubleToString(eur,2)," curSL=",DoubleToString(curSL,_Digits));
if(eur < TrailingStartEuro)
continue;
// bereken gewenste newSL
double ptsTR = CalcPoints(TrailingInEuro);
double newSL = (t==POSITION_TYPE_BUY) ? curP-ptsTR*_Point : curP+ptsTR*_Point;
newSL = NormalizeDouble(newSL,_Digits);
// min-stop check
int minStops = (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)+1;
double actual = MathAbs(curP - newSL)/_Point;
if(actual < minStops)
{
Print("Trailing SL te klein (",actual," pts), aanpassen naar ", minStops);
newSL = (t==POSITION_TYPE_BUY) ? curP-minStops*_Point : curP+minStops*_Point;
newSL = NormalizeDouble(newSL,_Digits);
}
// update als opschuift
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 to ",DoubleToString(newSL,_Digits));
}
}
}
//+------------------------------------------------------------------+