//+------------------------------------------------------------------+ //| VIZION_MFIB_MA_Setups_Signal_v1.mq5 | //| Indicator: Labels + arrows for your MASTER system | //| - MA roles: 7/14/21/50/140/230/500/1400 | //| - Trend confirm: EMA7 crosses EMA50 (lookback window) | //| - MFIB Bias: ATH/ATL anchored, uses 0.32 + stacking through levels | //| - Entry style: "Enter on 14 after trend is confirmed" | //+------------------------------------------------------------------+ #property strict #property indicator_chart_window #property indicator_plots 2 #property indicator_label1 "LongEntry14" #property indicator_type1 DRAW_ARROW #property indicator_color1 clrLime #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #property indicator_label2 "ShortEntry14" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrTomato #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //-------------------- Inputs -------------------- input ENUM_TIMEFRAMES InpTF = PERIOD_CURRENT; // MA periods input int InpEMA7 = 7; input int InpEMA14 = 14; input int InpEMA21 = 21; input int InpEMA50 = 50; input int InpEMA140 = 140; input int InpEMA230 = 230; input int InpEMA500 = 500; input int InpEMA1400 = 1400; // Trend confirmation input int InpCrossLookbackBars = 18; // how far back a 7/50 cross can be and still count as "confirmed" // Entry on 14 logic input int InpTouchTolPoints = 35; // touch tolerance (points) input bool InpRequireCloseBackOver14 = true; // if true: must close back above/below EMA14 after touch input bool InpRequireMAStackForTrend = true; // if true: require 7>21>50 for longs, 7<21<50 for shorts // Optional Stoch timing (kept simple) input bool InpUseStochFilter = false; input int InpStochK = 9; input int InpStochD = 5; input int InpStochSlowing = 3; input double InpStochOS = 20.0; input double InpStochOB = 80.0; // MFIB Bias input bool InpUseMFIBBiasFilter = true; input int InpMFIBLookbackBars = 2500; // scan window for ATH/ATL anchor input bool InpUseCloseForMFIBBreaks = true; // if true: breaks are based on Close; else High/Low // Visual labels input bool InpShowCornerLabel = true; //-------------------- Buffers -------------------- double LongArrow[]; double ShortArrow[]; //-------------------- Handles -------------------- int h7=-1,h14=-1,h21=-1,h50=-1,h140=-1,h230=-1,h500=-1,h1400=-1; int hStoch=-1; //-------------------- Helpers -------------------- string CornerLabelName = "VIZION_SYS_LABEL"; // Get the price used for MFIB breaks (close vs extreme) double BreakPrice(const double close, const double high, const double low, const bool bull, const bool useClose) { if(useClose) return close; return (bull ? high : low); } void SetCornerLabel(const string txt) { if(!InpShowCornerLabel) return; if(ObjectFind(0, CornerLabelName) < 0) { ObjectCreate(0, CornerLabelName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, CornerLabelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, CornerLabelName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, CornerLabelName, OBJPROP_YDISTANCE, 12); ObjectSetInteger(0, CornerLabelName, OBJPROP_FONTSIZE, 10); ObjectSetString(0, CornerLabelName, OBJPROP_FONT, "Consolas"); ObjectSetInteger(0, CornerLabelName, OBJPROP_COLOR, clrWhite); } ObjectSetString(0, CornerLabelName, OBJPROP_TEXT, txt); } // returns true if EMA7 crossed EMA50 in direction within lookback bars bool CrossedWithin(const double &ema7[], const double &ema50[], const int i, const int lookback, const bool bull) { int start = MathMin(i+lookback, ArraySize(ema7)-2); for(int k=i; k<=start; k++) { // cross happens between k+1 -> k (because arrays are series) double prevDiff = ema7[k+1] - ema50[k+1]; double currDiff = ema7[k] - ema50[k]; if(bull) { if(prevDiff <= 0.0 && currDiff > 0.0) return true; } else { if(prevDiff >= 0.0 && currDiff < 0.0) return true; } } return false; } // MFIB: compute anchor range (ATL->ATH) over lookback starting at bar i bool ComputeMFIB(const double &high[], const double &low[], const int i, const int lookback, double &atl, double &ath) { int last = MathMin(i + lookback, ArraySize(high)-1); atl = low[i]; ath = high[i]; for(int k=i; k<=last; k++) { if(low[k] < atl) atl = low[k]; if(high[k] > ath) ath = high[k]; } if(ath <= atl) return false; return true; } double FibLevel(const double atl, const double ath, const double r) { // from ATL to ATH return atl + (ath-atl)*r; } // Determine MFIB bias and stacking strength // Bull bias: price above 0.32 and at least holding/breaking 0.5 // Bear bias: price below 0.32 and at least holding/breaking 0.5 (in reverse sense) int MFIBBiasState(const double bp, const double atl, const double ath, int &stackCount, bool &bullBias) { double f032 = FibLevel(atl,ath,0.32); double f050 = FibLevel(atl,ath,0.50); double f0618= FibLevel(atl,ath,0.618); double f0786= FibLevel(atl,ath,0.786); // stackCount meaning: // 0 = none, 1 = 0.5, 2 = 0.618, 3 = 0.786 (directional) stackCount = 0; // Bull bias candidate if(bp > f032) { bullBias = true; if(bp > f050) stackCount = 1; if(bp > f0618) stackCount = 2; if(bp > f0786) stackCount = 3; // require at least 0.5 to call it real bias if(stackCount >= 1) return +1; return 0; // neutral/trap } // Bear bias candidate (reverse) if(bp < f032) { bullBias = false; // For bear stacking, interpret "breaking levels downward" // Equivalent thresholds mirrored: below 0.5, below 0.618, below 0.786 if(bp < f050) stackCount = 1; if(bp < f0618) stackCount = 2; if(bp < f0786) stackCount = 3; if(stackCount >= 1) return -1; return 0; } bullBias = false; return 0; } //-------------------- Init/Deinit -------------------- int OnInit() { SetIndexBuffer(0, LongArrow, INDICATOR_DATA); SetIndexBuffer(1, ShortArrow, INDICATOR_DATA); ArraySetAsSeries(LongArrow, true); ArraySetAsSeries(ShortArrow, true); PlotIndexSetInteger(0, PLOT_ARROW, 233); // up arrow PlotIndexSetInteger(1, PLOT_ARROW, 234); // down arrow h7 = iMA(_Symbol, InpTF, InpEMA7, 0, MODE_EMA, PRICE_CLOSE); h14 = iMA(_Symbol, InpTF, InpEMA14, 0, MODE_EMA, PRICE_CLOSE); h21 = iMA(_Symbol, InpTF, InpEMA21, 0, MODE_EMA, PRICE_CLOSE); h50 = iMA(_Symbol, InpTF, InpEMA50, 0, MODE_EMA, PRICE_CLOSE); h140 = iMA(_Symbol, InpTF, InpEMA140, 0, MODE_EMA, PRICE_CLOSE); h230 = iMA(_Symbol, InpTF, InpEMA230, 0, MODE_EMA, PRICE_CLOSE); h500 = iMA(_Symbol, InpTF, InpEMA500, 0, MODE_EMA, PRICE_CLOSE); h1400 = iMA(_Symbol, InpTF, InpEMA1400, 0, MODE_EMA, PRICE_CLOSE); if(InpUseStochFilter) hStoch = iStochastic(_Symbol, InpTF, InpStochK, InpStochD, InpStochSlowing, MODE_SMA, STO_LOWHIGH); if(h7<0 || h14<0 || h21<0 || h50<0 || h140<0 || h230<0 || h500<0 || h1400<0) return(INIT_FAILED); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { if(ObjectFind(0, CornerLabelName) >= 0) ObjectDelete(0, CornerLabelName); } //-------------------- Main -------------------- 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(InpEMA1400, InpMFIBLookbackBars) + 10) return 0; // Local MA arrays static double ema7[], ema14[], ema21[], ema50[], ema140[], ema230[], ema500[], ema1400[]; ArrayResize(ema7, rates_total); ArrayResize(ema14, rates_total); ArrayResize(ema21, rates_total); ArrayResize(ema50, rates_total); ArrayResize(ema140, rates_total); ArrayResize(ema230, rates_total); ArrayResize(ema500, rates_total); ArrayResize(ema1400, rates_total); ArraySetAsSeries(ema7,true); ArraySetAsSeries(ema14,true); ArraySetAsSeries(ema21,true); ArraySetAsSeries(ema50,true); ArraySetAsSeries(ema140,true); ArraySetAsSeries(ema230,true); ArraySetAsSeries(ema500,true); ArraySetAsSeries(ema1400,true); if(CopyBuffer(h7,0,0,rates_total,ema7) <= 0) return 0; if(CopyBuffer(h14,0,0,rates_total,ema14) <= 0) return 0; if(CopyBuffer(h21,0,0,rates_total,ema21) <= 0) return 0; if(CopyBuffer(h50,0,0,rates_total,ema50) <= 0) return 0; if(CopyBuffer(h140,0,0,rates_total,ema140) <= 0) return 0; if(CopyBuffer(h230,0,0,rates_total,ema230) <= 0) return 0; if(CopyBuffer(h500,0,0,rates_total,ema500) <= 0) return 0; if(CopyBuffer(h1400,0,0,rates_total,ema1400) <= 0) return 0; // Stoch (optional) static double stochK[]; if(InpUseStochFilter) { ArrayResize(stochK, rates_total); ArraySetAsSeries(stochK, true); // buffer 0 = %K in MT5 iStochastic if(CopyBuffer(hStoch, 0, 0, rates_total, stochK) <= 0) return 0; } int start = (prev_calculated > 0 ? prev_calculated-1 : rates_total-2); start = MathMin(start, rates_total-2); // reset arrows for(int i=start; i>=0; i--) { LongArrow[i] = EMPTY_VALUE; ShortArrow[i] = EMPTY_VALUE; } // For top-left info label (use current bar 0) { double atl, ath; int stack=0; bool bullBias=false; int bias=0; if(ComputeMFIB(high, low, 0, InpMFIBLookbackBars, atl, ath)) { double bp = BreakPrice(close[0], high[0], low[0], true, InpUseCloseForMFIBBreaks); bias = MFIBBiasState(bp, atl, ath, stack, bullBias); } string biasTxt = (bias>0 ? "MFIB_BULL" : (bias<0 ? "MFIB_BEAR" : "MFIB_NEUTRAL")); string stackTxt= "Stack:" + IntegerToString(stack) + " (>=1 means 0.5+)"; string maTxt = StringFormat("MA: 7=%.1f 14=%.1f 21=%.1f 50=%.1f 140=%.1f 230=%.1f 500=%.1f 1400=%.1f", ema7[0], ema14[0], ema21[0], ema50[0], ema140[0], ema230[0], ema500[0], ema1400[0]); SetCornerLabel(biasTxt + " | " + stackTxt + "\n" + maTxt); } // Main logic: "Enter on 14 AFTER trend confirmed" for(int i=start; i>=0; i--) { // 1) Trend confirmation (EMA7 crossed EMA50 within window) bool trendBull = CrossedWithin(ema7, ema50, i, InpCrossLookbackBars, true); bool trendBear = CrossedWithin(ema7, ema50, i, InpCrossLookbackBars, false); // Optional stack requirement (prevents weak flips) if(InpRequireMAStackForTrend) { trendBull = trendBull && (ema7[i] > ema21[i] && ema21[i] > ema50[i]); trendBear = trendBear && (ema7[i] < ema21[i] && ema21[i] < ema50[i]); } // 2) MFIB Bias filter (ATH/ATL anchored) if(InpUseMFIBBiasFilter) { double atl, ath; if(!ComputeMFIB(high, low, i, InpMFIBLookbackBars, atl, ath)) continue; int stack=0; bool bullBias=false; double bpBull = BreakPrice(close[i], high[i], low[i], true, InpUseCloseForMFIBBreaks); double bpBear = BreakPrice(close[i], high[i], low[i], false, InpUseCloseForMFIBBreaks); // Use same bp for both; we just need bias direction at bar i. // We'll use close by default. int bias = MFIBBiasState(close[i], atl, ath, stack, bullBias); // require bias aligns and has at least 0.5 stacking (stack>=1) if(trendBull && !(bias > 0 && stack >= 1)) trendBull = false; if(trendBear && !(bias < 0 && stack >= 1)) trendBear = false; } // 3) Optional stoch filter if(InpUseStochFilter) { if(trendBull && !(stochK[i] <= 60.0)) trendBull = false; // simple "reset-ish" gate if(trendBear && !(stochK[i] >= 40.0)) trendBear = false; } // 4) Entry ON 14 after trend confirmed: // Long: price touches EMA14 (low <= ema14 + tol) then closes above EMA14 (optional) // Short: price touches EMA14 (high >= ema14 - tol) then closes below EMA14 (optional) double tol = InpTouchTolPoints * _Point; bool touch14Long = (low[i] <= ema14[i] + tol); bool touch14Short = (high[i] >= ema14[i] - tol); bool closeOkLong = (!InpRequireCloseBackOver14) || (close[i] > ema14[i]); bool closeOkShort = (!InpRequireCloseBackOver14) || (close[i] < ema14[i]); if(trendBull && touch14Long && closeOkLong) { LongArrow[i] = low[i] - (10*_Point); // arrow below candle } if(trendBear && touch14Short && closeOkShort) { ShortArrow[i] = high[i] + (10*_Point); // arrow above candle } } return rates_total; } //+------------------------------------------------------------------+