//+------------------------------------------------------------------+ //| Market_Scanner_Pro.mq5 | //| QuantScan 7.2 - Signed Velocity | //| Copyright 2026, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" #property version "7.20" // Velocity is now Directional (Signed) #property description "Exports 'QuantScan 7.0' dataset for LLM Analysis." #property description "Includes Breadth, Cost, and Velocity Vector." #property script_show_inputs //--- Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //--- Parameters input group "Scanner Config" input bool InpUseMarketWatch = false; // Scan all Market Watch symbols input string InpSymbolList = "EURUSD,USDJPY,GBPUSD,USDCHF,AUDUSD,XAUUSD,US500,DE40,XTIUSD,ETHUSD"; input string InpBenchmark = "US500"; // Global Benchmark input string InpForexBench = "DX"; // Forex Benchmark input string InpBrokerTimeZone = "EET (UTC+2)"; input int InpScanHistory = 500; // Max History Bars to fetch input group "Benchmark Settings" input int InpBetaLookback = 60; // Beta Calculation Period input group "Timeframes" input ENUM_TIMEFRAMES InpTFFast = PERIOD_M5; // Layer 3 (Trigger) input ENUM_TIMEFRAMES InpTFMiddle= PERIOD_M15; // Layer 2 (Flow) input ENUM_TIMEFRAMES InpTFSlow = PERIOD_H1; // Layer 1 (Context) input group "Metric Settings" input int InpDSMAPeriod = 40; input double InpLaguerreGamma = 0.50; input int InpMurreyPeriod = 64; input int InpATRPeriod = 14; input int InpRSBars = 24; input int InpRVOLPeriod = 20; input int InpERPeriod = 10; input int InpZScorePeriod = 20; input int InpSlopeLookback = 5; input group "TSI Settings" input int InpTSI_Slow = 25; input int InpTSI_Fast = 13; input int InpTSI_Signal = 13; input group "Squeeze Settings" input int InpSqueezeLength = 20; input double InpBBMult = 2.0; input double InpKCMult = 1.5; //--- QuantData Struct struct QuantData { string timestamp; string symbol; double price; // --- Layer 1: H1 Context --- double trend_score; double trend_qual; double trend_slope; string zone; string rel_strength_str; string beta_str; string alpha_str; string h1_tsi_dir; // --- Layer 2: M15 Flow - MOVED DIST_PDH/PDL HERE double dist_pdh; double dist_pdl; double m15_momentum; double m15_vol_qual; string m15_squeeze; double m15_vwap_slope; double m15_z_score; double m15_vola_regime; string m15_tsi_dir; double spread_cost; // --- Layer 3: M5 Trigger --- double m5_momentum; double m5_vol_qual; string m5_tsi_dir; double m5_velocity; // --- Composites --- double rev_prob; string absorption; string mtf_align; }; //+------------------------------------------------------------------+ //| Helper: Detect Asset Class | //+------------------------------------------------------------------+ bool IsForexPair(string sym) { // Safety: If symbol IS one of the benchmarks, we don't classify it as generic forex pair here if(sym == InpBenchmark || sym == InpForexBench) return false; if(StringFind(sym, "USD") != -1 || StringFind(sym, "EUR") != -1 || StringFind(sym, "GBP") != -1 || StringFind(sym, "JPY") != -1 || StringFind(sym, "CHF") != -1 || StringFind(sym, "AUD") != -1 || StringFind(sym, "CAD") != -1 || StringFind(sym, "NZD") != -1 || StringFind(sym, "XAU") != -1 || StringFind(sym, "XAG") != -1) { if(StringFind(sym, "XTI") != -1) return false; if(StringFind(sym, "UKO") != -1) return false; if(StringFind(sym, "USO") != -1) return false; if(StringFind(sym, "BTC") != -1) return false; if(StringFind(sym, "ETH") != -1) return false; return true; } return false; } //+------------------------------------------------------------------+ //| Helper: Get Sentiment String for TF | //+------------------------------------------------------------------+ string GetSentimentForTF(ENUM_TIMEFRAMES tf) { double u_close[2], d_close[2]; if(CopyClose(InpBenchmark, tf, 1, 2, u_close) != 2) return "N/A"; if(CopyClose(InpForexBench, tf, 1, 2, d_close) != 2) return "N/A"; double us500_chg = (u_close[1] - u_close[0]); double dxy_chg = (d_close[1] - d_close[0]); double us500_pct = (u_close[0]!=0) ? (us500_chg / u_close[0])*100 : 0; double dxy_pct = (d_close[0]!=0) ? (dxy_chg / d_close[0])*100 : 0; string state = "MIXED"; if(dxy_chg < 0 && us500_chg > 0) state = "RISK-ON"; else if(dxy_chg > 0 && us500_chg < 0) state = "RISK-OFF"; else if(dxy_chg > 0 && us500_chg > 0) state = "STRESS"; else if(dxy_chg < 0 && us500_chg < 0) state = "DEFLATION"; string tf_name = EnumToString(tf); StringReplace(tf_name, "PERIOD_", ""); return StringFormat("%s: %s (US:%.2f%% DX:%.2f%%)", tf_name, state, us500_pct, dxy_pct); } //+------------------------------------------------------------------+ //| WRAPPER DECLARATIONS (Forward Declaration not strictly needed) | //+------------------------------------------------------------------+ bool FetchData(string sym, ENUM_TIMEFRAMES tf, int count, datetime &t[], double &o[], double &h[], double &l[], double &c[], long &v[]); double Calc_ATR(const double &o[], const double &h[], const double &l[], const double &c[], int p); double Calc_ER(const double &o[], const double &h[], const double &l[], const double &c[], int p); double Calc_ZScore(const double &o[], const double &h[], const double &l[], const double &c[], int p); double Calc_RVOL(const long &vol[], int p); double Calc_DSMA_Score(const double &o[], const double &h[], const double &l[], const double &c[], double atr); string Calc_Squeeze(string sym, ENUM_TIMEFRAMES tf, const double &o[], const double &h[], const double &l[], const double &c[]); double Calc_LaguerreRSI(const double &o[], const double &h[], const double &l[], const double &c[]); void Calc_TSI_Dir(const double &o[], const double &h[], const double &l[], const double &c[], string &dir); string Calc_MurreyZone(string symbol, ENUM_TIMEFRAMES tf); void Calc_DSMA_Series(const double &o[], const double &h[], const double &l[], const double &c[], double &out_buf[]); void Calc_VWAP_Series(const datetime &t[], const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], ENUM_VWAP_PERIOD p, double &out_buf[]); double Calc_Velocity(const double &close[], double atr, int period); double Calc_RVOL_Single_Help(const long &vol[], int period, int index); // Helper proxy //+------------------------------------------------------------------+ //| Script Start | //+------------------------------------------------------------------+ void OnStart() { string symbols[]; int total_symbols = 0; if(InpUseMarketWatch) { total_symbols = SymbolsTotal(true); ArrayResize(symbols, total_symbols); for(int i=0; i 0 && CopyOpen(InpBenchmark, InpTFSlow, InpRSBars, 1, b_open) > 0) if(b_open[0] != 0) bench_change_pct = ((b_close[0] - b_open[0]) / b_open[0]) * 100.0; } string filename = "QuantScan_" + TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES) + ".csv"; StringReplace(filename, ":", ""); StringReplace(filename, " ", "_"); int file_handle = FileOpen(filename, FILE_CSV|FILE_WRITE|FILE_ANSI, ";"); if(file_handle == INVALID_HANDLE) return; // 3. SCAN & STORE PrintFormat("Scanning %d symbols...", total_symbols); QuantData results[]; int success_count = 0; for(int i=0; i 0) vel_pos_count++; if(StringFind(results[i].mtf_align, "FULL_") != -1) mtf_full_count++; } double breadth_tsi = (success_count>0) ? ((double)tsi_bull_count/success_count)*100.0 : 0; double breadth_vel = (success_count>0) ? ((double)vel_pos_count/success_count)*100.0 : 0; string sentiment_line = "### GLOBAL_SENTIMENT | "; if(has_us500 && has_dxy) { sentiment_line += GetSentimentForTF(InpTFSlow) + " | " + GetSentimentForTF(InpTFMiddle) + " | " + GetSentimentForTF(InpTFFast); } else sentiment_line += "Benchmarks Missing"; sentiment_line += StringFormat(" ### BREADTH_SCORE | TSI_BULL: %d/%d (%.0f%%) | VEL_POS: %d/%d (%.0f%%) | MTF_ALIGN: %d ###", tsi_bull_count, success_count, breadth_tsi, vel_pos_count, success_count, breadth_vel, mtf_full_count); // 5. WRITE HEADER FileWrite(file_handle, sentiment_line); string str_slow = EnumToString(InpTFSlow); StringReplace(str_slow, "PERIOD_", ""); string str_mid = EnumToString(InpTFMiddle); StringReplace(str_mid, "PERIOD_", ""); string str_fast = EnumToString(InpTFFast); StringReplace(str_fast, "PERIOD_", ""); string csv_header = "TIME (" + InpBrokerTimeZone + ");SYMBOL;PRICE;"; // Context Header csv_header += StringFormat("TREND_SC_%s;TREND_QUAL_%s;TREND_SLOPE_%s;ZONE_%s;REL_STR_%s;BETA_%s;ALPHA_%s;",str_slow, str_slow, str_slow, str_slow, str_slow, str_slow, str_slow); // Flow Header (Added DIST_PDH/PDL with current TF suffix) csv_header += StringFormat("DIST_PDH_%s;DIST_PDL_%s;MOM_%s;RVOL_%s;SQZ_%s;VWAP_SLOPE_%s;Z_SCORE_%s;VOL_REGIME_%s;COST_ATR_%s;TSI_DIR_%s;", str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid); // Trigger Header csv_header += StringFormat("MOM_%s;RVOL_%s;TSI_DIR_%s;VEL_%s;", str_fast, str_fast, str_fast, str_fast); csv_header += "REV_PROB;ABSORPTION;MTF_ALIGN"; FileWrite(file_handle, csv_header); for(int i=0; i InpBetaLookback) { CMathStatisticsCalculator stats; double asset_ret[], bench_ret[]; int h1_size = ArraySize(slow_c); double asset_subset[]; ArrayResize(asset_subset, InpBetaLookback); double bench_subset[]; ArrayResize(bench_subset, InpBetaLookback); for(int k=0; k 3.0) score += 40; else if(MathAbs(data.m15_z_score) > 2.0) score += 20; if(StringFind(data.zone, "Extreme") >= 0) score += 30; if(data.m15_momentum > 0.90 || data.m15_momentum < 0.10) score += 30; data.rev_prob = score; int idx_cl = ArraySize(mid_c) - 2; if(idx_cl >= 0 && mid_atr > 0) { double body = MathAbs(mid_c[idx_cl] - mid_o[idx_cl]); double bar_rvol = Calc_RVOL_Single_Help(mid_v, InpRVOLPeriod, idx_cl); if(bar_rvol > 2.0 && body < (0.4 * mid_atr)) data.absorption = "YES"; else data.absorption = "NO"; } else data.absorption = "-"; // MTF Align if(data.h1_tsi_dir == data.m15_tsi_dir && data.m15_tsi_dir == data.m5_tsi_dir) data.mtf_align = "FULL_" + data.h1_tsi_dir; else if(data.h1_tsi_dir == data.m15_tsi_dir) data.mtf_align = "MAJOR_" + data.h1_tsi_dir; else data.mtf_align = "MIXED"; return true; } //+------------------------------------------------------------------+ //| WRAPPER FUNCTIONS (IMPLEMENTATION) | //+------------------------------------------------------------------+ bool FetchData(string sym, ENUM_TIMEFRAMES tf, int count, datetime &t[], double &o[], double &h[], double &l[], double &c[], long &v[]) { if(!CDataSync::EnsureDataReady(sym, tf, count)) return false; // Ensure Sync ArraySetAsSeries(t, false); ArraySetAsSeries(o, false); ArraySetAsSeries(h, false); ArraySetAsSeries(l, false); ArraySetAsSeries(c, false); ArraySetAsSeries(v, false); if(CopyTime(sym, tf, 0, count, t)!=count || CopyOpen(sym, tf, 0, count, o)!=count || CopyHigh(sym, tf, 0, count, h)!=count || CopyLow(sym, tf, 0, count, l)!=count || CopyClose(sym, tf, 0, count, c)!=count || CopyTickVolume(sym, tf, 0, count, v)!=count) return false; return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Calc_DSMA_Series(const double &o[], const double &h[], const double &l[], const double &c[], double &out_buf[]) { CDSMACalculator calc; if(!calc.Init(InpDSMAPeriod)) return; int total=ArraySize(c); ArrayResize(out_buf, total); calc.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, out_buf); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Calc_VWAP_Series(const datetime &t[], const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], ENUM_VWAP_PERIOD p, double &out_buf[]) { CVWAPCalculator calc; if(!calc.Init(p, VOLUME_TICK, 0, true)) return; double odd[], even[]; int total=ArraySize(c); ArrayResize(odd, total); ArrayResize(even, total); calc.Calculate(total, 0, t, o, h, l, c, v, v, odd, even); ArrayResize(out_buf, total); for(int i=0; i k_lo[idx])) ? "ON" : "OFF"; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double Calc_LaguerreRSI(const double &o[], const double &h[], const double &l[], const double &c[]) { CLaguerreRSICalculator calc; calc.Init(InpLaguerreGamma, 3, SMA); double lrsi[], sig[]; int total=ArraySize(c); ArrayResize(lrsi, total); ArrayResize(sig, total); calc.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, lrsi, sig); return lrsi[total-2] / 100.0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Calc_TSI_Dir(const double &o[], const double &h[], const double &l[], const double &c[], string &dir) { CTSICalculator calc; calc.Init(InpTSI_Slow, EMA, InpTSI_Fast, EMA, InpTSI_Signal, EMA); double tsi[], sig[], osc[]; int total=ArraySize(c); ArrayResize(tsi, total); ArrayResize(sig, total); ArrayResize(osc, total); calc.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, tsi, sig, osc); if(tsi[total-2] > sig[total-2]) dir = "BULL"; else dir = "BEAR"; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string Calc_MurreyZone(string symbol, ENUM_TIMEFRAMES tf) { CMurreyMathCalculator calc; calc.Init(symbol, tf, InpMurreyPeriod, 0); double levels[]; if(!calc.Calculate(levels)) return "N/A"; double price = iClose(symbol, tf, 1); if(price < levels[2]) return "Extreme Low"; if(price > levels[10]) return "Extreme High"; if(price >= levels[2] && price < levels[3]) return "0/8-1/8 (Bottom)"; if(price >= levels[3] && price < levels[4]) return "1/8-2/8 (Weak)"; if(price >= levels[4] && price < levels[6]) return "2/8-4/8 (Lower)"; if(price >= levels[6] && price < levels[8]) return "4/8-6/8 (Upper)"; if(price >= levels[8] && price < levels[9]) return "6/8-7/8 (Weak)"; return "7/8-8/8 (Top)"; } //+------------------------------------------------------------------+