//+------------------------------------------------------------------+ //| TradingEvolution.mq5 | //| Trading Evolution — https://tradingevolution.site | //| Indicateur v2 : nuage de tendance EMA, structure de marché | //| (HH/HL/LH/LL, BOS), order blocks, fair value gaps, signaux | //| ACHAT / VENTE avec alertes et notifications push. | //+------------------------------------------------------------------+ #property copyright "Trading Evolution" #property link "https://tradingevolution.site" #property version "2.00" #property description "Trading Evolution v2 — tendance, structure, zones et signaux" #property indicator_chart_window #property indicator_buffers 6 #property indicator_plots 4 // Nuage de tendance #property indicator_label1 "EMA rapide" #property indicator_type1 DRAW_LINE #property indicator_color1 C'22,87,214' #property indicator_width1 2 #property indicator_label2 "EMA lente" #property indicator_type2 DRAW_LINE #property indicator_color2 C'33,150,243' #property indicator_width2 1 // Signaux #property indicator_label3 "ACHAT" #property indicator_type3 DRAW_ARROW #property indicator_color3 C'22,87,214' #property indicator_width3 2 #property indicator_label4 "VENTE" #property indicator_type4 DRAW_ARROW #property indicator_color4 C'10,22,40' #property indicator_width4 2 //--- Paramètres input group "Tendance (trend cloud)" input int InpFast = 12; // EMA rapide input int InpSlow = 34; // EMA lente input int InpBias = 200; // EMA filtre de biais (0 = désactivé) input group "Structure de marché" input int InpSwing = 5; // Force des swings input bool InpLabels = true; // Étiquettes HH / HL / LH / LL input bool InpBOS = true; // Cassures de structure input group "Zones" input bool InpOB = true; // Order blocks input bool InpFVG = true; // Fair value gaps input int InpMaxZones = 6; // Zones affichées (max) input group "Signaux" input bool InpSignals = true; // Signaux ACHAT / VENTE input bool InpUseBias = true; // Filtrer par l'EMA de biais input int InpATR = 14; // ATR (stop suggéré) input double InpATRMult = 1.5; // Multiplicateur ATR input double InpRR = 2.0; // Ratio risque / rendement input group "Alertes" input bool InpAlertPopup= true; // Alerte à l'écran input bool InpAlertPush = false; // Notification push (MetaQuotes ID) input bool InpAlertMail = false; // E-mail //--- Buffers double BufFast[], BufSlow[], BufBuy[], BufSell[], BufBias[], BufATR[]; int hFast, hSlow, hBias, hATR; datetime lastAlert = 0; string PFX = "TE_"; //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, BufFast, INDICATOR_DATA); SetIndexBuffer(1, BufSlow, INDICATOR_DATA); SetIndexBuffer(2, BufBuy, INDICATOR_DATA); SetIndexBuffer(3, BufSell, INDICATOR_DATA); SetIndexBuffer(4, BufBias, INDICATOR_CALCULATIONS); SetIndexBuffer(5, BufATR, INDICATOR_CALCULATIONS); PlotIndexSetInteger(2, PLOT_ARROW, 233); PlotIndexSetInteger(3, PLOT_ARROW, 234); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE); ArraySetAsSeries(BufFast, false); ArraySetAsSeries(BufSlow, false); ArraySetAsSeries(BufBuy, false); ArraySetAsSeries(BufSell, false); ArraySetAsSeries(BufBias, false); ArraySetAsSeries(BufATR, false); hFast = iMA(_Symbol, _Period, InpFast, 0, MODE_EMA, PRICE_CLOSE); hSlow = iMA(_Symbol, _Period, InpSlow, 0, MODE_EMA, PRICE_CLOSE); hBias = InpBias > 0 ? iMA(_Symbol, _Period, InpBias, 0, MODE_EMA, PRICE_CLOSE) : INVALID_HANDLE; hATR = iATR(_Symbol, _Period, InpATR); if(hFast == INVALID_HANDLE || hSlow == INVALID_HANDLE || hATR == INVALID_HANDLE) return(INIT_FAILED); IndicatorSetString(INDICATOR_SHORTNAME, "Trading Evolution v2"); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0, PFX); } //+------------------------------------------------------------------+ //| Outils de dessin | //+------------------------------------------------------------------+ void Label(string name, datetime t, double p, string txt, color c, bool above) { if(!InpLabels) return; if(ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_TEXT, 0, t, p); ObjectSetString(0, name, OBJPROP_TEXT, txt); ObjectSetInteger(0, name, OBJPROP_COLOR, c); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, name, OBJPROP_ANCHOR, above ? ANCHOR_LOWER : ANCHOR_UPPER); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } void Zone(string name, datetime t1, double p1, datetime t2, double p2, color c, string txt) { if(ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, p1, t2, p2); ObjectSetInteger(0, name, OBJPROP_COLOR, c); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetString(0, name, OBJPROP_TOOLTIP, txt); } void HLine(string name, datetime t1, double p, datetime t2, color c, ENUM_LINE_STYLE st) { if(ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_TREND, 0, t1, p, t2, p); ObjectSetInteger(0, name, OBJPROP_COLOR, c); ObjectSetInteger(0, name, OBJPROP_STYLE, st); ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } // Conserve seulement les N zones les plus récentes d'un type void Prune(string type) { int total = ObjectsTotal(0, 0, OBJ_RECTANGLE), count = 0; for(int i = total - 1; i >= 0; i--) { string n = ObjectName(0, i, 0, OBJ_RECTANGLE); if(StringFind(n, PFX + type) == 0) { count++; if(count > InpMaxZones) ObjectDelete(0, n); } } } bool IsSwingHigh(const double &high[], int i, int n, int total) { if(i < n || i + n >= total) return false; for(int k = 1; k <= n; k++) if(high[i] <= high[i - k] || high[i] <= high[i + k]) return false; return true; } bool IsSwingLow(const double &low[], int i, int n, int total) { if(i < n || i + n >= total) return false; for(int k = 1; k <= n; k++) if(low[i] >= low[i - k] || low[i] >= low[i + k]) return false; return true; } //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < MathMax(InpSlow, InpBias) + 10) return 0; if(CopyBuffer(hFast, 0, 0, rates_total, BufFast) <= 0) return 0; if(CopyBuffer(hSlow, 0, 0, rates_total, BufSlow) <= 0) return 0; if(CopyBuffer(hATR, 0, 0, rates_total, BufATR) <= 0) return 0; if(hBias != INVALID_HANDLE) { if(CopyBuffer(hBias, 0, 0, rates_total, BufBias) <= 0) return 0; } int start = prev_calculated > 1 ? prev_calculated - 1 : InpSlow + 1; static double lastH = 0, prevH = 0, lastL = 0, prevL = 0; static int lastHBar = -1, lastLBar = -1; if(prev_calculated == 0) { lastH = prevH = lastL = prevL = 0; lastHBar = lastLBar = -1; ObjectsDeleteAll(0, PFX); } for(int i = start; i < rates_total; i++) { BufBuy[i] = EMPTY_VALUE; BufSell[i] = EMPTY_VALUE; int s = i - InpSwing; // bougie de swing confirmée //--- Structure if(s > InpSwing && IsSwingHigh(high, s, InpSwing, rates_total)) { prevH = lastH; lastH = high[s]; lastHBar = s; Label(PFX + "H" + IntegerToString(s), time[s], high[s], prevH == 0 ? "H" : (high[s] > prevH ? "HH" : "LH"), C'22,87,214', true); } if(s > InpSwing && IsSwingLow(low, s, InpSwing, rates_total)) { prevL = lastL; lastL = low[s]; lastLBar = s; Label(PFX + "L" + IntegerToString(s), time[s], low[s], prevL == 0 ? "L" : (low[s] > prevL ? "HL" : "LL"), C'33,150,243', false); } //--- BOS + order block bool bosUp = InpBOS && lastH > 0 && close[i] > lastH && close[i - 1] <= lastH; bool bosDn = InpBOS && lastL > 0 && close[i] < lastL && close[i - 1] >= lastL; if(bosUp) { HLine(PFX + "BOSU" + IntegerToString(i), time[lastHBar], lastH, time[i], C'22,87,214', STYLE_DASH); if(InpOB) for(int k = 1; k < 20 && i - k > 0; k++) if(close[i - k] < open[i - k]) { Zone(PFX + "OBU" + IntegerToString(i), time[i - k], high[i - k], time[i] + PeriodSeconds() * 20, low[i - k], C'214,226,250', "Order block haussier"); break; } Prune("OBU"); } if(bosDn) { HLine(PFX + "BOSD" + IntegerToString(i), time[lastLBar], lastL, time[i], C'10,22,40', STYLE_DASH); if(InpOB) for(int k = 1; k < 20 && i - k > 0; k++) if(close[i - k] > open[i - k]) { Zone(PFX + "OBD" + IntegerToString(i), time[i - k], high[i - k], time[i] + PeriodSeconds() * 20, low[i - k], C'226,229,236', "Order block baissier"); break; } Prune("OBD"); } //--- FVG if(InpFVG && i >= 2) { double rng = high[i - 2] - low[i - 2]; if(low[i] > high[i - 2] && (low[i] - high[i - 2]) > rng * 0.5) { Zone(PFX + "FVG" + IntegerToString(i), time[i - 1], low[i], time[i] + PeriodSeconds() * 15, high[i - 2], C'205,231,252', "FVG haussier"); Prune("FVG"); } if(high[i] < low[i - 2] && (low[i - 2] - high[i]) > rng * 0.5) { Zone(PFX + "FVG" + IntegerToString(i), time[i - 1], low[i - 2], time[i] + PeriodSeconds() * 15, high[i], C'205,231,252', "FVG baissier"); Prune("FVG"); } } //--- Signaux if(InpSignals && i > 0) { bool biasUp = !InpUseBias || hBias == INVALID_HANDLE || close[i] > BufBias[i]; bool biasDn = !InpUseBias || hBias == INVALID_HANDLE || close[i] < BufBias[i]; bool cUp = BufFast[i - 1] <= BufSlow[i - 1] && BufFast[i] > BufSlow[i]; bool cDn = BufFast[i - 1] >= BufSlow[i - 1] && BufFast[i] < BufSlow[i]; if(cUp && biasUp) { BufBuy[i] = low[i] - BufATR[i] * 0.3; double sl = close[i] - BufATR[i] * InpATRMult, tp = close[i] + (close[i] - sl) * InpRR; HLine(PFX + "SL" + IntegerToString(i), time[i], sl, time[i] + PeriodSeconds() * 12, C'224,65,63', STYLE_DOT); HLine(PFX + "TP" + IntegerToString(i), time[i], tp, time[i] + PeriodSeconds() * 12, C'22,87,214', STYLE_DOT); if(i == rates_total - 1 && time[i] != lastAlert) { Notify("ACHAT " + _Symbol + " " + EnumToString(_Period) + " @ " + DoubleToString(close[i], _Digits)); lastAlert = time[i]; } } if(cDn && biasDn) { BufSell[i] = high[i] + BufATR[i] * 0.3; double sl2 = close[i] + BufATR[i] * InpATRMult, tp2 = close[i] - (sl2 - close[i]) * InpRR; HLine(PFX + "SL" + IntegerToString(i), time[i], sl2, time[i] + PeriodSeconds() * 12, C'224,65,63', STYLE_DOT); HLine(PFX + "TP" + IntegerToString(i), time[i], tp2, time[i] + PeriodSeconds() * 12, C'22,87,214', STYLE_DOT); if(i == rates_total - 1 && time[i] != lastAlert) { Notify("VENTE " + _Symbol + " " + EnumToString(_Period) + " @ " + DoubleToString(close[i], _Digits)); lastAlert = time[i]; } } } } Comment("Trading Evolution v2 | Tendance : ", BufFast[rates_total - 1] > BufSlow[rates_total - 1] ? "HAUSSIÈRE" : "BAISSIÈRE", " | ATR : ", DoubleToString(BufATR[rates_total - 1], _Digits)); return rates_total; } //+------------------------------------------------------------------+ void Notify(string msg) { string full = "Trading Evolution — " + msg; if(InpAlertPopup) Alert(full); if(InpAlertPush) SendNotification(full); if(InpAlertMail) SendMail("Trading Evolution", full); } //+------------------------------------------------------------------+