362 lines
13 KiB
MQL5
362 lines
13 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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;
|
|
}
|
|
//+------------------------------------------------------------------+
|