Vizion-Trading-EA/Scripts/cashcow.mq5

362 lines
13 KiB
MQL5
Raw Permalink Normal View History

//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+