//+------------------------------------------------------------------+ //| TimeFrame_Quality_Analyzer.mq4 | //| Copyright 2026, Rajesh Kumar Nait | //| https://www.mql5.com/en/users/rajeshnait | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Rajesh Kumar Nait" #property link "https://www.mql5.com/en/users/rajeshnait" #property version "1.00" #property strict #property indicator_chart_window #property indicator_buffers 0 #property indicator_plots 0 //--- inputs extern int InpWindow = 100; // Rolling Window Length extern int InpEntropyBins = 20; // Entropy Bin Count extern double InpWeightSNR = 0.25; // Weight: SNR extern double InpWeightAC = 0.15; // Weight: Autocorrelation extern double InpWeightHurst = 0.25; // Weight: Hurst extern double InpWeightDER = 0.20; // Weight: DER extern double InpWeightEntropy = 0.15; // Weight: Inverse Entropy extern int InpPanelX = 10; // Panel X Position extern int InpPanelY = 30; // Panel Y Position string P = "TQA_"; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { CreatePanel(); return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { int total = ObjectsTotal(); for(int i = total - 1; i >= 0; i--) { string name = ObjectName(i); if(StringFind(name, P) == 0) ObjectDelete(name); } ChartRedraw(); return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { int rates_total = Bars; if(rates_total < InpWindow + 2) return(0); int last = rates_total - 1; //--- build closes and returns for latest window only double closes[]; ArrayResize(closes, InpWindow + 1); for(int j = 0; j <= InpWindow; j++) closes[j] = Close[last - InpWindow + j]; double returns[]; ArrayResize(returns, InpWindow); for(int j = 0; j < InpWindow; j++) returns[j] = closes[j + 1] - closes[j]; double snr = CalcSNR(closes, InpWindow + 1); double ac = CalcAutocorrelation(returns, InpWindow); double hurst = CalcHurst(returns, InpWindow); double der = CalcDER(closes, InpWindow + 1); double entropy = CalcEntropy(returns, InpWindow, InpEntropyBins); double tqs = CalcTQS(snr, ac, hurst, der, entropy); UpdatePanel(snr, ac, hurst, der, entropy, tqs); return(0); } //+------------------------------------------------------------------+ //| Calculate Signal-to-Noise Ratio | //+------------------------------------------------------------------+ double CalcSNR(double &data[], int len) { double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0; for(int i = 0; i < len; i++) { sumX += i; sumY += data[i]; sumXY += i * data[i]; sumX2 += (double)i * i; } double n = (double)len; double denom = n * sumX2 - sumX * sumX; if(MathAbs(denom) < 1e-20) return 0; double slope = (n * sumXY - sumX * sumY) / denom; double intercept = (sumY - slope * sumX) / n; double meanY = sumY / n; double ssExp = 0, ssRes = 0; for(int i = 0; i < len; i++) { double fitted = intercept + slope * i; ssExp += (fitted - meanY) * (fitted - meanY); ssRes += (data[i] - fitted) * (data[i] - fitted); } if(ssRes < 1e-20) return 10.0; return MathMin(ssExp / ssRes, 10.0); } //+------------------------------------------------------------------+ //| Calculate Autocorrelation (lag-1) | //+------------------------------------------------------------------+ double CalcAutocorrelation(double &ret[], int len) { if(len < 3) return 0; double mean = 0; for(int i = 0; i < len; i++) mean += ret[i]; mean /= len; double num = 0, den = 0; for(int i = 0; i < len; i++) { double d = ret[i] - mean; den += d * d; if(i < len - 1) num += d * (ret[i + 1] - mean); } if(MathAbs(den) < 1e-20) return 0; return num / den; } //+------------------------------------------------------------------+ //| Calculate Hurst Exponent via R/S Analysis | //+------------------------------------------------------------------+ double CalcHurst(double &ret[], int len) { if(len < 20) return 0.5; int sizes[]; int cnt = 0; for(int s = 8; s <= len / 2; s *= 2) { cnt++; ArrayResize(sizes, cnt); sizes[cnt - 1] = s; } if(cnt < 2) return 0.5; double lnN[]; double lnRS[]; ArrayResize(lnN, cnt); ArrayResize(lnRS, cnt); for(int si = 0; si < cnt; si++) { int w = sizes[si]; int nw = len / w; double rsSum = 0; int valid = 0; for(int b = 0; b < nw; b++) { int st = b * w; double m = 0; for(int k = 0; k < w; k++) m += ret[st + k]; m /= w; double cum = 0, mx = -1e30, mn = 1e30, ss = 0; for(int k = 0; k < w; k++) { double d = ret[st + k] - m; cum += d; ss += d * d; if(cum > mx) mx = cum; if(cum < mn) mn = cum; } double S = MathSqrt(ss / w); if(S > 1e-20) { rsSum += (mx - mn) / S; valid++; } } lnN[si] = MathLog((double)w); lnRS[si] = (valid > 0) ? MathLog(rsSum / valid) : 0; } double sx = 0, sy = 0, sxy = 0, sx2 = 0; for(int i = 0; i < cnt; i++) { sx += lnN[i]; sy += lnRS[i]; sxy += lnN[i] * lnRS[i]; sx2 += lnN[i] * lnN[i]; } double n = (double)cnt; double dd = n * sx2 - sx * sx; if(MathAbs(dd) < 1e-20) return 0.5; return MathMax(0.0, MathMin(1.0, (n * sxy - sx * sy) / dd)); } //+------------------------------------------------------------------+ //| Calculate Directional Efficiency Ratio | //+------------------------------------------------------------------+ double CalcDER(double &data[], int len) { if(len < 2) return 0; double net = MathAbs(data[len - 1] - data[0]); double path = 0; for(int i = 1; i < len; i++) path += MathAbs(data[i] - data[i - 1]); if(path < 1e-20) return 0; return net / path; } //+------------------------------------------------------------------+ //| Calculate Normalised Shannon Entropy | //+------------------------------------------------------------------+ double CalcEntropy(double &ret[], int len, int bins) { if(len < 2 || bins < 2) return 1.0; double mn = ret[0], mx = ret[0]; for(int i = 1; i < len; i++) { if(ret[i] < mn) mn = ret[i]; if(ret[i] > mx) mx = ret[i]; } double rng = mx - mn; if(rng < 1e-20) return 0; int c[]; ArrayResize(c, bins); ArrayInitialize(c, 0); for(int i = 0; i < len; i++) { int b = (int)((ret[i] - mn) / rng * (bins - 1)); if(b < 0) b = 0; if(b >= bins) b = bins - 1; c[b]++; } double ent = 0, logB = MathLog((double)bins); if(logB < 1e-20) return 1.0; for(int i = 0; i < bins; i++) { if(c[i] > 0) { double p = (double)c[i] / (double)len; ent -= p * MathLog(p); } } return ent / logB; } //+------------------------------------------------------------------+ //| Calculate Timeframe Quality Score | //+------------------------------------------------------------------+ double CalcTQS(double snr, double ac, double hurst, double der, double entropy) { double nSNR = MathMin(snr / 5.0, 1.0); double nAC = MathMin(MathAbs(ac) * 3.0, 1.0); double nHurst = MathMin(MathAbs(hurst - 0.5) * 4.0, 1.0); double nDER = der; double nInvEnt = 1.0 - entropy; double tw = InpWeightSNR + InpWeightAC + InpWeightHurst + InpWeightDER + InpWeightEntropy; if(tw < 1e-10) tw = 1.0; return (InpWeightSNR * nSNR + InpWeightAC * nAC + InpWeightHurst * nHurst + InpWeightDER * nDER + InpWeightEntropy * nInvEnt) / tw; } //+------------------------------------------------------------------+ //| Create a rectangle label object | //+------------------------------------------------------------------+ void MakeRect(string name, int x, int y, int w, int h, color bg, color bd) { if(ObjectFind(name) >= 0) ObjectDelete(name); ObjectCreate(name, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSet(name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSet(name, OBJPROP_XDISTANCE, x); ObjectSet(name, OBJPROP_YDISTANCE, y); ObjectSet(name, OBJPROP_XSIZE, w); ObjectSet(name, OBJPROP_YSIZE, h); ObjectSet(name, OBJPROP_BGCOLOR, bg); ObjectSet(name, OBJPROP_COLOR, bd); ObjectSet(name, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSet(name, OBJPROP_BACK, false); ObjectSet(name, OBJPROP_SELECTABLE, false); ObjectSet(name, OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| Create a text label object | //+------------------------------------------------------------------+ void MakeLabel(string name, int x, int y, string text, color clr, string font, int sz) { if(ObjectFind(name) >= 0) ObjectDelete(name); ObjectCreate(name, OBJ_LABEL, 0, 0, 0); ObjectSet(name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSet(name, OBJPROP_XDISTANCE, x); ObjectSet(name, OBJPROP_YDISTANCE, y); ObjectSetText(name, text, sz, font, clr); ObjectSet(name, OBJPROP_BACK, false); ObjectSet(name, OBJPROP_SELECTABLE,false); ObjectSet(name, OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| Build the full panel at init time | //+------------------------------------------------------------------+ void CreatePanel() { int x = InpPanelX, y = InpPanelY; MakeRect(P+"BG", x, y, 340, 360, (color)C'15,15,28', (color)C'50,50,80'); MakeRect(P+"BG2", x+2, y+2, 336, 356, (color)C'20,20,35', (color)C'50,50,80'); int r = y + 8; MakeLabel(P+"T1", x+14, r, "TIMEFRAME QUALITY ANALYZER", clrWhite, "Arial Bold", 12); r += 22; MakeRect(P+"S1", x+8, r, 324, 1, clrDodgerBlue, clrDodgerBlue); r += 8; MakeLabel(P+"LW", x+14, r, "Window: "+IntegerToString(InpWindow)+" | TF: "+PeriodStr(), (color)C'120,120,150', "Consolas", 9); r += 22; MakeRect(P+"S1b", x+8, r, 324, 1, (color)C'40,40,60', (color)C'40,40,60'); r += 10; // SNR row MakeLabel(P+"LSNR", x+14, r, "SNR", (color)C'150,150,180', "Consolas", 10); MakeLabel(P+"VSNR", x+160, r, "---", clrDodgerBlue, "Consolas", 10); MakeLabel(P+"ISNR", x+230, r, "", (color)C'120,120,150', "Consolas", 9); r += 26; // AC row MakeLabel(P+"LAC", x+14, r, "Autocorrelation", (color)C'150,150,180', "Consolas", 10); MakeLabel(P+"VAC", x+160, r, "---", clrLime, "Consolas", 10); MakeLabel(P+"IAC", x+230, r, "", (color)C'120,120,150', "Consolas", 9); r += 26; // Hurst row MakeLabel(P+"LHU", x+14, r, "Hurst Exponent", (color)C'150,150,180', "Consolas", 10); MakeLabel(P+"VHU", x+160, r, "---", clrGold, "Consolas", 10); MakeLabel(P+"IHU", x+230, r, "", clrGold, "Consolas", 9); r += 26; // DER row MakeLabel(P+"LDER", x+14, r, "Dir. Efficiency", (color)C'150,150,180', "Consolas", 10); MakeLabel(P+"VDER", x+160, r, "---", clrMagenta, "Consolas", 10); MakeLabel(P+"IDER", x+230, r, "", (color)C'120,120,150', "Consolas", 9); r += 26; // Entropy row MakeLabel(P+"LENT", x+14, r, "Entropy (norm)", (color)C'150,150,180', "Consolas", 10); MakeLabel(P+"VENT", x+160, r, "---", clrOrangeRed, "Consolas", 10); MakeLabel(P+"IENT", x+230, r, "", (color)C'120,120,150', "Consolas", 9); r += 30; // Separator MakeRect(P+"S2", x+8, r, 324, 2, clrDodgerBlue, clrDodgerBlue); r += 10; // TQS MakeLabel(P+"LTQS", x+14, r, "QUALITY SCORE", clrWhite, "Arial Bold", 12); MakeLabel(P+"VTQS", x+200, r, "---", clrWhite, "Arial Bold", 16); r += 28; // Progress bar background + fill MakeRect(P+"BBG", x+14, r, 312, 18, (color)C'35,35,50', (color)C'55,55,75'); MakeRect(P+"BFG", x+14, r, 1, 18, clrDodgerBlue, clrDodgerBlue); r += 28; // Verdict MakeLabel(P+"VRD", x+14, r, "ANALYZING...", clrYellow, "Arial Bold", 15); r += 28; // Detail lines MakeLabel(P+"D1", x+14, r, "", (color)C'130,130,155', "Consolas", 9); r += 16; MakeLabel(P+"D2", x+14, r, "", (color)C'130,130,155', "Consolas", 9); r += 16; MakeLabel(P+"D3", x+14, r, "", (color)C'130,130,155', "Consolas", 9); } //+------------------------------------------------------------------+ //| Update all panel labels/objects with fresh metric values | //+------------------------------------------------------------------+ void UpdatePanel(double snr, double ac, double hurst, double der, double entropy, double tqs) { // SNR string sSNR; color cSNR; if(snr > 2.0) { sSNR = "Strong"; cSNR = clrLime; } else if(snr > 0.5) { sSNR = "Moderate"; cSNR = clrGold; } else { sSNR = "Weak"; cSNR = clrRed; } ObjectSetText(P+"VSNR", DoubleToString(snr, 3), 10, "Consolas", cSNR); ObjectSetText(P+"ISNR", sSNR, 9, "Consolas", cSNR); // AC bool acSig = MathAbs(ac) > 0.1; string sAC = acSig ? "Persistent" : "Noise"; color cAC = acSig ? clrLime : clrRed; ObjectSetText(P+"VAC", DoubleToString(ac, 4), 10, "Consolas", cAC); ObjectSetText(P+"IAC", sAC, 9, "Consolas", cAC); // Hurst string sHU; color cHU; if(hurst > 0.55) { sHU = "Trending"; cHU = clrLime; } else if(hurst < 0.45) { sHU = "Mean-Revert"; cHU = clrOrangeRed; } else { sHU = "Random Walk"; cHU = clrGray; } ObjectSetText(P+"VHU", DoubleToString(hurst, 4), 10, "Consolas", cHU); ObjectSetText(P+"IHU", sHU, 9, "Consolas", cHU); // DER string sDER; color cDER; if(der > 0.6) { sDER = "Structured"; cDER = clrLime; } else if(der > 0.3) { sDER = "Mixed"; cDER = clrGold; } else { sDER = "Noisy"; cDER = clrRed; } ObjectSetText(P+"VDER", DoubleToString(der, 4), 10, "Consolas", cDER); ObjectSetText(P+"IDER", sDER, 9, "Consolas", cDER); // Entropy string sENT; color cENT; if(entropy < 0.5) { sENT = "Ordered"; cENT = clrLime; } else if(entropy < 0.75) { sENT = "Mixed"; cENT = clrGold; } else { sENT = "Random"; cENT = clrRed; } ObjectSetText(P+"VENT", DoubleToString(entropy, 4), 10, "Consolas", cENT); ObjectSetText(P+"IENT", sENT, 9, "Consolas", cENT); // TQS score + progress bar color cTQS = (tqs > 0.65) ? clrLime : (tqs > 0.40) ? clrGold : clrRed; ObjectSetText(P+"VTQS", DoubleToString(tqs * 100, 1) + "%", 16, "Arial Bold", cTQS); int barW = (int)(tqs * 312); if(barW < 1) barW = 1; if(barW > 312) barW = 312; ObjectSet(P+"BFG", OBJPROP_XSIZE, barW); ObjectSet(P+"BFG", OBJPROP_BGCOLOR, cTQS); // Verdict string vrd; color cV; if(tqs > 0.65) { vrd = "HIGH STRUCTURE"; cV = clrLime; } else if(tqs > 0.40) { vrd = "MODERATE"; cV = clrGold; } else { vrd = "NOISE DOMINATED"; cV = clrRed; } ObjectSetText(P+"VRD", vrd, 15, "Arial Bold", cV); // Detail text rows ObjectSetText(P+"D1", "SNR=" + DoubleToString(snr,2) + " | AC=" + DoubleToString(ac,3), 9, "Consolas", (color)C'130,130,155'); ObjectSetText(P+"D2", "Hurst=" + DoubleToString(hurst,3) + " -> " + sHU, 9, "Consolas", (color)C'130,130,155'); ObjectSetText(P+"D3", "DER=" + DoubleToString(der,3) + " | Ent=" + DoubleToString(entropy,3), 9, "Consolas", (color)C'130,130,155'); ChartRedraw(); } //+------------------------------------------------------------------+ //| Return a human-readable period string | //+------------------------------------------------------------------+ string PeriodStr() { switch(Period()) { case PERIOD_M1: return "M1"; case PERIOD_M5: return "M5"; case PERIOD_M15: return "M15"; case PERIOD_M30: return "M30"; case PERIOD_H1: return "H1"; case PERIOD_H4: return "H4"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN1"; default: return "??"; } } //+------------------------------------------------------------------+
hope it is well coded?
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
Timeframe Quality Analyzer:
Find Perfect Timeframe to trade
Author: Rajesh Kumar Nait