diff --git a/Scripts/MyScripts/Market_Scanner_Pro.mq5 b/Scripts/MyScripts/Market_Scanner_Pro.mq5 index 8c882ed..17e898d 100644 --- a/Scripts/MyScripts/Market_Scanner_Pro.mq5 +++ b/Scripts/MyScripts/Market_Scanner_Pro.mq5 @@ -1,12 +1,12 @@ //+------------------------------------------------------------------+ //| Market_Scanner_Pro.mq5 | -//| QuantScan 10.2 - Next Gen Statistics | +//| QuantScan 10.38 - Historical Audit Master | //| Copyright 2026, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" -#property version "10.20" // Volume Pressure (Tick Delta Proxy) Integration -#property description "Exports 'QuantScan 9.0' dataset for LLM Analysis." -#property description "Features Advanced Statistical Filters (VHF, R2, V-Score)." +#property version "10.38" // Restored live Symbol BID pricing and dynamic live/historical Murrey price routing +#property description "Exports 'QuantScan' dataset for LLM Analysis." +#property description "Features High-Performance Object Caching and precise Historical Audits." #property script_show_inputs //--- Includes @@ -19,7 +19,6 @@ #include #include #include -// NEW Integrations: #include #include #include @@ -35,6 +34,13 @@ input string InpForexBench = "DX"; input string InpBrokerTimeZone = "EET (UTC+2)"; input int InpScanHistory = 500; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +input group "Historical Target Settings (For Backtesting/Audits)" +input bool InpUseTargetTime = false; // Use Historical Target Time? +input datetime InpTargetTime = D'2026.02.10 14:00'; // Target Evaluation Time (Broker Time) + input group "Benchmark Settings" input int InpBetaLookback = 60; @@ -48,7 +54,6 @@ input int InpVHFPeriod = 28; // VHF Lookback input int InpR2Period = 20; // R-Squared Lookback input int InpVScorePeriod = 20; // V-Score Period input int InpAutoCorrPeriod = 20; // Autocorrelation Window -// Standard settings input int InpMurreyPeriod = 64; input int InpATRPeriod = 14; input int InpRSBars = 24; @@ -71,53 +76,465 @@ input int InpSqueezeMom = 12; input group "Output Settings" input int InpPrecision = 3; // Decimal places for CSV Output -//--- QuantData Struct (Updated Layout) +//--- QuantData Struct struct QuantData { string timestamp; string symbol; double price; - - // H1 Context - string alpha_str; // Alpha - string beta_str; // Beta - double vhf; // VHF - double r2; // R-Squared - string zone; // Murrey Zone - - // M15 Flow - double v_score_week; // NEW: W1 VWAP Z-Score - double v_score_day; // VWAP Z-Score - double autocorr; // Lag-1 Correlation - double vol_regime; // ATR(5)/ATR(55) - string sqz; // Squeeze State - double sqz_mom; // New - double m15_vhf; // New - double m15_r2; // New + string alpha_str; + string beta_str; + double vhf; + double r2; + string zone; + double v_score_week; + double v_score_day; + double autocorr; + double vol_regime; + string sqz; + double sqz_mom; + double m15_vhf; + double m15_r2; double dist_pdh; double dist_pdl; - - // M5 Trigger double velocity; - double v_pressure; // NEW - double vol_thrust; // M5 RVOL / M15 RVOL + double v_pressure; + double vol_thrust; double cost_atr; - - // Composites string absorption; string mtf_align; - string vwap_align; // NEW: Alignment state - - // Internal TSI Hist for Breadth/Align + string vwap_align; double h1_tsi_hist; double m15_tsi_hist; double m5_tsi_hist; }; -//--- Helper: Detect Asset Class -bool IsForexPair(string sym) +//+==================================================================+ +//| CLASS: CMarketScanner (Flyweight Engine) | +//+==================================================================+ +class CMarketScanner + { +private: + // Persistent Engines to avoid heap/stack allocation storms + CATRCalculator m_atr; + CRelativeVolumeCalculator m_rvol; + CSqueezeCalculator m_squeeze; + CMurreyMathCalculator m_murrey; + CTSICalculator m_tsi; + CVHFCalculator m_vhf; + CLinearRegressionCalculator m_linreg; + CVScoreCalculator m_vscore_day; + CVScoreCalculator m_vscore_week; + CAutocorrelationCalculator m_autocorr; + CVolumePressureCalculator m_vpressure; + CSessionLevelsCalculator m_sess; + CMathStatisticsCalculator m_stats; + + // Reuseable calculation buffers + double m_temp_buf1[]; + double m_temp_buf2[]; + double m_temp_buf3[]; + double m_temp_buf4[]; + + bool FetchData(string sym, ENUM_TIMEFRAMES tf, int count, datetime &t[], double &o[], double &h[], double &l[], double &c[], long &v[]); + bool IsForexPair(string sym); + string CalculateAbsorption(const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], double atr, int idx); + +public: + CMarketScanner(void) {} + ~CMarketScanner(void) {} + + bool Init(void); + bool RunAnalysis(string sym, QuantData &data); + }; + +//+------------------------------------------------------------------+ +//| Init: Pre-allocate and initialize all engines once | +//+------------------------------------------------------------------+ +bool CMarketScanner::Init(void) + { + if(!m_atr.Init(InpATRPeriod, ATR_POINTS)) + return false; + if(!m_rvol.Init(InpRVOLPeriod)) + return false; + if(!m_squeeze.Init(InpSqueezeLength, InpBBMult, InpKCMult, InpSqueezeMom)) + return false; + if(!m_vhf.Init(InpVHFPeriod, VHF_MODE_HIGH_LOW)) + return false; + if(!m_linreg.Init(InpR2Period)) + return false; + if(!m_vscore_day.Init(InpVScorePeriod, PERIOD_SESSION)) + return false; + if(!m_vscore_week.Init(InpVScorePeriod, PERIOD_WEEK)) + return false; + if(!m_autocorr.Init(InpAutoCorrPeriod)) + return false; + if(!m_vpressure.Init(1)) + return false; + if(!m_tsi.Init(InpTSI_Slow, EMA, InpTSI_Fast, EMA, InpTSI_Signal, EMA)) + return false; + if(!m_sess.Init(PERIOD_D1)) + return false; + + return true; + } + +//+------------------------------------------------------------------+ +//| RunAnalysis: High-speed, allocation-free execution per symbol | +//+------------------------------------------------------------------+ +bool CMarketScanner::RunAnalysis(string sym, QuantData &data) + { + double slow_o[], slow_h[], slow_l[], slow_c[]; + long slow_v[]; + datetime slow_t[]; + if(!FetchData(sym, InpTFSlow, InpScanHistory, slow_t, slow_o, slow_h, slow_l, slow_c, slow_v)) + return false; + +// Get precise H1 rates_total equivalent + int h1_total = ArraySize(slow_c); + int idx_l1 = h1_total - 1; + +// 1. Beta / Alpha Caclulation (Optimized) + bool is_benchmark = (sym == InpBenchmark || sym == InpForexBench); + if(is_benchmark) + { + data.beta_str = "1.0"; + data.alpha_str = "0.0"; + } + else + { + string bench_sym = InpBenchmark; + if(IsForexPair(sym) && SymbolSelect(InpForexBench, true)) + bench_sym = InpForexBench; + + double b_c[], dum_o[], dum_h[], dum_l[]; + long dum_v[]; + datetime b_t[]; + if(CDataSync::EnsureDataReady(bench_sym, InpTFSlow, InpScanHistory) && + FetchData(bench_sym, InpTFSlow, InpScanHistory, b_t, dum_o, dum_h, dum_l, b_c, dum_v)) + { + int h1_size = ArraySize(slow_c); + int bench_size = ArraySize(b_c); + int lookback_beta = InpBetaLookback; + + double asset_subset[], bench_subset[]; + ArrayResize(asset_subset, lookback_beta); + ArrayResize(bench_subset, lookback_beta); + + int valid_points = 0; + for(int k = 0; k < lookback_beta; k++) + { + int a_idx = h1_size - 1 - k; + if(a_idx < 0) + break; + + datetime a_time = slow_t[a_idx]; + int b_idx_arr = ArrayBsearch(b_t, a_time); + + double a_val = slow_c[a_idx]; + double b_val = (b_idx_arr >= 0 && b_idx_arr < bench_size && b_t[b_idx_arr] == a_time) ? b_c[b_idx_arr] : 0.0; + + if(b_idx_arr < 0 || b_t[b_idx_arr] != a_time) + { + if(k > 0) + b_val = bench_subset[lookback_beta - k]; + else + b_val = b_c[MathMin(bench_size - 1, b_idx_arr > 0 ? b_idx_arr : 0)]; + } + + int sub_idx = lookback_beta - 1 - k; + asset_subset[sub_idx] = a_val; + bench_subset[sub_idx] = b_val; + valid_points++; + } + + if(valid_points > lookback_beta / 2) + { + double asset_ret[], bench_ret[]; + m_stats.ComputeReturns(asset_subset, asset_ret); + m_stats.ComputeReturns(bench_subset, bench_ret); + + double beta_val = m_stats.CalculateBeta(asset_ret, bench_ret); + double a_tot_beta = (asset_subset[lookback_beta - 1] - asset_subset[0]) / asset_subset[0]; + double b_tot_beta = (bench_subset[lookback_beta - 1] - bench_subset[0]) / bench_subset[0]; + double alpha_val = m_stats.CalculateAlpha(a_tot_beta, b_tot_beta, beta_val); + + data.beta_str = DoubleToString(beta_val, 2); + data.alpha_str = DoubleToString(alpha_val, 4); + } + else + { + data.beta_str = "0.0"; + data.alpha_str = "0.0"; + } + } + } + +// 2. VHF (H1) + ArrayResize(m_temp_buf1, h1_total); + m_vhf.Calculate(h1_total, 0, PRICE_CLOSE, slow_o, slow_h, slow_l, slow_c, m_temp_buf1); + data.vhf = m_temp_buf1[idx_l1]; + +// 3. R2 (Linear Regression H1) + ArrayResize(m_temp_buf1, h1_total); + ArrayResize(m_temp_buf2, h1_total); + ArrayResize(m_temp_buf3, h1_total); + m_linreg.CalculateState(h1_total, 0, slow_o, slow_h, slow_l, slow_c, PRICE_CLOSE, m_temp_buf1, m_temp_buf2, m_temp_buf3); + data.r2 = m_temp_buf2[idx_l1]; + +// 4. Murrey Math Zones (Uses dynamic price routing: live iClose in live mode vs historical H1 close in target mode) + m_murrey.Init(sym, InpTFSlow, InpMurreyPeriod, 0); + double m_levels[]; + if(m_murrey.Calculate(m_levels)) + { + double price = InpUseTargetTime ? slow_c[idx_l1] : iClose(sym, InpTFSlow, 0); + if(price < m_levels[2]) + data.zone = "Extreme Low"; + else + if(price > m_levels[10]) + data.zone = "Extreme High"; + else + if(price >= m_levels[2] && price < m_levels[3]) + data.zone = "0/8-1/8 (Bottom)"; + else + if(price >= m_levels[3] && price < m_levels[4]) + data.zone = "1/8-2/8 (Weak)"; + else + if(price >= m_levels[4] && price < m_levels[6]) + data.zone = "2/8-4/8 (Lower)"; + else + if(price >= m_levels[6] && price < m_levels[8]) + data.zone = "4/8-6/8 (Upper)"; + else + if(price >= m_levels[8] && price < m_levels[9]) + data.zone = "6/8-7/8 (Weak)"; + else + data.zone = "7/8-8/8 (Top)"; + } + else + data.zone = "N/A"; + +// 5. TSI H1 Metrics (H1) + ArrayResize(m_temp_buf1, h1_total); + ArrayResize(m_temp_buf2, h1_total); + ArrayResize(m_temp_buf3, h1_total); + m_tsi.Calculate(h1_total, 0, PRICE_CLOSE, slow_o, slow_h, slow_l, slow_c, m_temp_buf1, m_temp_buf2, m_temp_buf3); + data.h1_tsi_hist = m_temp_buf1[idx_l1] - m_temp_buf2[idx_l1]; + +//---------------------------------------------------------------- +// LAYER 2: FLOW (M15) +//---------------------------------------------------------------- + double mid_o[], mid_h[], mid_l[], mid_c[]; + long mid_v[]; + datetime mid_t[]; + if(!FetchData(sym, InpTFMiddle, InpScanHistory, mid_t, mid_o, mid_h, mid_l, mid_c, mid_v)) + return false; + +// Get precise M15 rates_total equivalent + int m15_total = ArraySize(mid_c); + int idx_l2 = m15_total - 1; + +// 1. ATR Flow + ArrayResize(m_temp_buf1, m15_total); + m_atr.Calculate(m15_total, 0, mid_o, mid_h, mid_l, mid_c, m_temp_buf1); + double mid_atr = m_temp_buf1[idx_l2]; + +// 2. V-Score Day (Reset: Session) (M15) + ArrayResize(m_temp_buf2, m15_total); + m_vscore_day.Calculate(m15_total, 0, mid_t, mid_o, mid_h, mid_l, mid_c, mid_v, mid_v, m_temp_buf2); + data.v_score_day = m_temp_buf2[idx_l2]; + +// 3. V-Score Week (Using H1 data with correct h1_total parameter and idx_l1 index) + ArrayResize(m_temp_buf3, h1_total); + m_vscore_week.Calculate(h1_total, 0, slow_t, slow_o, slow_h, slow_l, slow_c, slow_v, slow_v, m_temp_buf3); + data.v_score_week = m_temp_buf3[idx_l1]; + +// 4. Autocorrelation Lag-1 (M15) + ArrayResize(m_temp_buf2, m15_total); + m_autocorr.Calculate(m15_total, 0, PRICE_CLOSE, mid_o, mid_h, mid_l, mid_c, m_temp_buf2); + data.autocorr = m_temp_buf2[idx_l2]; + +// 5. Volatility Regime (M15) + CATRCalculator atr_reg_calc; + double atr_fast_buf[], atr_slow_buf[]; + atr_reg_calc.Init(5, ATR_POINTS); + atr_reg_calc.Calculate(m15_total, 0, mid_o, mid_h, mid_l, mid_c, atr_fast_buf); + atr_reg_calc.Init(55, ATR_POINTS); + atr_reg_calc.Calculate(m15_total, 0, mid_o, mid_h, mid_l, mid_c, atr_slow_buf); + data.vol_regime = (atr_slow_buf[idx_l2] != 0.0) ? (atr_fast_buf[idx_l2] / atr_slow_buf[idx_l2]) : 1.0; + +// 6. Squeeze (M15) + double sqz_mom[], sqz_val[], sqz_col[]; + ArrayResize(sqz_mom, m15_total); + ArrayResize(sqz_val, m15_total); + ArrayResize(sqz_col, m15_total); + m_squeeze.Calculate(m15_total, 0, PRICE_CLOSE, mid_o, mid_h, mid_l, mid_c, sqz_mom, sqz_val, sqz_col); + data.sqz = (sqz_col[idx_l2] == 1.0) ? "ON" : "OFF"; + data.sqz_mom = sqz_mom[idx_l2]; + +// 7. VHF & R2 (M15) + ArrayResize(m_temp_buf1, m15_total); + m_vhf.Calculate(m15_total, 0, PRICE_CLOSE, mid_o, mid_h, mid_l, mid_c, m_temp_buf1); + data.m15_vhf = m_temp_buf1[idx_l2]; + + ArrayResize(m_temp_buf1, m15_total); + ArrayResize(m_temp_buf2, m15_total); + ArrayResize(m_temp_buf3, m15_total); + m_linreg.CalculateState(m15_total, 0, mid_o, mid_h, mid_l, mid_c, PRICE_CLOSE, m_temp_buf1, m_temp_buf2, m_temp_buf3); + data.m15_r2 = m_temp_buf2[idx_l2]; + +// 8. Dist PDH / PDL (M15) + SessionLevels sl; + if(m_sess.GetLevels(sym, mid_t[idx_l2], sl)) + { + data.dist_pdh = CMetricsTools::CalculateDistance(mid_c[idx_l2], sl.prev_high, mid_atr); + data.dist_pdl = CMetricsTools::CalculateDistance(mid_c[idx_l2], sl.prev_low, mid_atr); + } + else + { + data.dist_pdh = 0.0; + data.dist_pdl = 0.0; + } + +// 9. TSI M15 (M15) + ArrayResize(m_temp_buf1, m15_total); + ArrayResize(m_temp_buf2, m15_total); + ArrayResize(m_temp_buf3, m15_total); + m_tsi.Calculate(m15_total, 0, PRICE_CLOSE, mid_o, mid_h, mid_l, mid_c, m_temp_buf1, m_temp_buf2, m_temp_buf3); + data.m15_tsi_hist = m_temp_buf1[idx_l2] - m_temp_buf2[idx_l2]; + +// 10. RVOL M15 for Thrust + double rvol_m15 = m_rvol.CalculateSingle(m15_total, mid_v, idx_l2); + +//---------------------------------------------------------------- +// LAYER 3: TRIGGER (M5) +//---------------------------------------------------------------- + double fast_o[], fast_h[], fast_l[], fast_c[]; + long fast_v[]; + datetime fast_t[]; + if(!FetchData(sym, InpTFFast, 300, fast_t, fast_o, fast_h, fast_l, fast_c, fast_v)) + return false; + +// Get precise M5 rates_total equivalent + int m5_total = ArraySize(fast_c); + int idx_l3 = m5_total - 1; + +// 1. Volatility Trigger (M5) + ArrayResize(m_temp_buf1, m5_total); + m_atr.Calculate(m5_total, 0, fast_o, fast_h, fast_l, fast_c, m_temp_buf1); + double fast_atr = m_temp_buf1[idx_l3]; + +// 2. Velocity + data.velocity = (fast_atr > 0.0) ? CMetricsTools::CalculateSlope(fast_c[idx_l3], fast_c[idx_l3 - 5], fast_atr, 5) : 0.0; + +// 3. Volume Pressure (Tick Delta Proxy) (M5) + ArrayResize(m_temp_buf2, m5_total); + m_vpressure.Calculate(m5_total, 0, fast_h, fast_l, fast_c, m_temp_buf2); + data.v_pressure = m_temp_buf2[idx_l3]; + +// 4. Volume Thrust + double rvol_m5 = m_rvol.CalculateSingle(m5_total, fast_v, idx_l3); + data.vol_thrust = (rvol_m15 > 0.0) ? (rvol_m5 / rvol_m15) : 0.0; + +// 5. Cost + data.cost_atr = CMetricsTools::CalculateSpreadCost(sym, fast_atr); + +// 6. TSI M5 (M5) + ArrayResize(m_temp_buf1, m5_total); + ArrayResize(m_temp_buf2, m5_total); + ArrayResize(m_temp_buf3, m5_total); + m_tsi.Calculate(m5_total, 0, PRICE_CLOSE, fast_o, fast_h, fast_l, fast_c, m_temp_buf1, m_temp_buf2, m_temp_buf3); + data.m5_tsi_hist = m_temp_buf1[idx_l3] - m_temp_buf2[idx_l3]; + +//---------------------------------------------------------------- +// LAYER 4: COMPOSITES & ALIGNMENT +//---------------------------------------------------------------- + +// 1. Institutional Absorption (Wyckoff VSA Logic) using normalized size (m15_total) + data.absorption = CalculateAbsorption(mid_o, mid_h, mid_l, mid_c, mid_v, mid_atr, idx_l2 - 1); + +// 2. MTF Align + bool h1_bull = (data.h1_tsi_hist > 0.0); + bool m15_bull = (data.m15_tsi_hist > 0.0); + bool m5_bull = (data.m5_tsi_hist > 0.0); + + if(h1_bull == m15_bull && m15_bull == m5_bull) + data.mtf_align = "FULL_" + (h1_bull ? "BULL" : "BEAR"); + else + if(h1_bull == m15_bull) + data.mtf_align = "MAJOR_" + (h1_bull ? "BULL" : "BEAR"); + else + data.mtf_align = "MIXED"; + +// 3. VWAP Align + bool day_bull = (data.v_score_day > 0.0); + bool week_bull = (data.v_score_week > 0.0); + + if(day_bull && week_bull) + data.vwap_align = "FULL_BULL"; + else + if(!day_bull && !week_bull) + data.vwap_align = "FULL_BEAR"; + else + data.vwap_align = "MIXED"; + +// --- EXACT TARGET TIME AND LIVE PRICE ALIGNMENTS --- +// Map precision timestamp to reflect the exact target minute (08:32 / 09:37) + data.timestamp = InpUseTargetTime ? TimeToString(InpTargetTime, TIME_DATE|TIME_MINUTES) + : TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES); + + data.symbol = sym; // FIXED: Re-added the missing symbol assignment! + +// RESTORED: Using live Bid price for the active symbol as requested for consistency + data.price = SymbolInfoDouble(sym, SYMBOL_BID); + + return true; + } + +//+------------------------------------------------------------------+ +//| Helper: Dynamic pricing data fetcher with Historical Offset | +//+------------------------------------------------------------------+ +bool CMarketScanner::FetchData(string sym, ENUM_TIMEFRAMES tf, int count, datetime &t[], double &o[], double &h[], double &l[], double &c[], long &v[]) + { + int start_bar = 0; + +// If historical target scan is enabled, calculate the bar shift offset dynamically + if(InpUseTargetTime) + { + start_bar = iBarShift(sym, tf, InpTargetTime, false); + if(start_bar < 0) + return false; + } + +// Synchronize history up to the target evaluation window + if(!CDataSync::EnsureDataReady(sym, tf, start_bar + count)) + return false; + + ArraySetAsSeries(t, false); + ArraySetAsSeries(o, false); + ArraySetAsSeries(h, false); + ArraySetAsSeries(l, false); + ArraySetAsSeries(c, false); + ArraySetAsSeries(v, false); + +// Copy history window starting from historical offset + if(CopyTime(sym, tf, start_bar, count, t) != count || + CopyOpen(sym, tf, start_bar, count, o) != count || + CopyHigh(sym, tf, start_bar, count, h) != count || + CopyLow(sym, tf, start_bar, count, l) != count || + CopyClose(sym, tf, start_bar, count, c) != count || + CopyTickVolume(sym, tf, start_bar, count, v) != count) + { + return false; + } + return true; + } + +//+------------------------------------------------------------------+ +//| Helper: Detect Forex Pair | +//+------------------------------------------------------------------+ +bool CMarketScanner::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; @@ -127,15 +544,9 @@ bool IsForexPair(string sym) 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) + if(StringFind(sym, "XTI") != -1 || StringFind(sym, "UKO") != -1 || + StringFind(sym, "USO") != -1 || StringFind(sym, "BTC") != -1 || + StringFind(sym, "ETH") != -1) return false; return true; } @@ -143,60 +554,45 @@ bool IsForexPair(string sym) } //+------------------------------------------------------------------+ -//| Helper: Get Sentiment String for TF (Extended Format) | +//| Helper: Calculate Institutional Absorption | //+------------------------------------------------------------------+ -string GetSentimentForTF(ENUM_TIMEFRAMES tf) +string CMarketScanner::CalculateAbsorption(const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], double atr, int idx) { - if(!CDataSync::EnsureDataReady(InpBenchmark, tf, 2)) - return "N/A"; - if(!CDataSync::EnsureDataReady(InpForexBench, tf, 2)) - return "N/A"; + if(idx < 0 || atr <= 0.0) + return "-"; - double u_clos[2], d_clos[2]; - if(CopyClose(InpBenchmark, tf, 1, 2, u_clos) != 2) - return "N/A"; - if(CopyClose(InpForexBench, tf, 1, 2, d_clos) != 2) - return "N/A"; + double body = MathAbs(c[idx] - o[idx]); + double total_range = h[idx] - l[idx]; + double bar_rvol = m_rvol.CalculateSingle(ArraySize(v), v, idx); - double u_chg = u_clos[1] - u_clos[0]; - double d_chg = d_clos[1] - d_clos[0]; - double u_pct = (u_clos[0]!=0) ? (u_chg / u_clos[0])*100.0 : 0; - double d_pct = (d_clos[0]!=0) ? (d_chg / d_clos[0])*100.0 : 0; + bool high_effort = (bar_rvol > 2.0); + bool low_result = (body < (0.35 * atr)); - string state = "MIXED"; - if(d_chg < 0 && u_chg > 0) - state = "RISK-ON"; - else - if(d_chg > 0 && u_chg < 0) - state = "RISK-OFF"; + if(high_effort && low_result) + { + double close_pos = 0.5; + if(total_range > 0.0) + close_pos = (c[idx] - l[idx]) / total_range; + + if(close_pos > 0.66) + return "BULL_ABS"; else - if(d_chg > 0 && u_chg > 0) - state = "STRESS"; + if(close_pos < 0.33) + return "BEAR_ABS"; else - if(d_chg < 0 && u_chg < 0) - state = "DEFLATION"; + return "NEUT_ABS"; + } + else + if(bar_rvol > 3.5 && body < (0.6 * atr)) + { + return "CLIMAX"; + } - string tf_name = EnumToString(tf); - StringReplace(tf_name, "PERIOD_", ""); - -// FIX: Return full format string - return StringFormat("%s: %s (US:%.2f%% DX:%.2f%%)", tf_name, state, u_pct, d_pct); + return "NO"; } -//--- Forward Declarations -// Updated list of wrappers -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, int idx); -string Calc_Squeeze(string sym, ENUM_TIMEFRAMES tf, const double &o[], const double &h[], const double &l[], const double &c[], int idx); -string Calc_MurreyZone(string symbol, ENUM_TIMEFRAMES tf); -double Calc_Velocity(const double &close[], double atr, int period, int idx); -double Calc_RVOL(const long &vol[], int p, int idx); -void Calc_TSI_Values(const double &o[], const double &h[], const double &l[], const double &c[], int idx, double &val, double &hist); -// New Wrappers -double Calc_VHF(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx); -double Calc_R2(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx); -double Calc_VScore(string sym, const datetime &t[], const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], int p, int idx); -double Calc_AutoCorr(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx); +//--- Global Scanner Engine Instance +CMarketScanner g_scanner; //+------------------------------------------------------------------+ //| Script Start | @@ -220,6 +616,13 @@ void OnStart() total_symbols = StringSplit(InpSymbolList, u_sep, symbols); } +// Initialize the high-performance global scanner + if(!g_scanner.Init()) + { + Print("Critical Error: Failed to initialize CMarketScanner Engine."); + return; + } + // --- Global Sentiment --- string sentiment_line = "### GLOBAL_SENTIMENT | "; bool has_us500 = SymbolSelect(InpBenchmark, true); @@ -231,19 +634,27 @@ void OnStart() else sentiment_line += "Benchmarks Missing ###"; -// Sync for RS +// Sync Benchmark historical arrays if needed if(has_us500) - CDataSync::EnsureDataReady(InpBenchmark, InpTFSlow); + { + int start_bar_bench = 0; + if(InpUseTargetTime) + start_bar_bench = iBarShift(InpBenchmark, InpTFSlow, InpTargetTime, false); + CDataSync::EnsureDataReady(InpBenchmark, InpTFSlow, start_bar_bench + InpScanHistory); + } - string filename = "QuantScan_" + TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES) + ".csv"; - StringReplace(filename, ":", ""); - StringReplace(filename, " ", "_"); +// Dynamic CSV filename including target date if historical mode is active + string time_str = InpUseTargetTime ? TimeToString(InpTargetTime, TIME_DATE|TIME_MINUTES) : TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES); + StringReplace(time_str, ":", ""); + StringReplace(time_str, " ", "_"); + StringReplace(time_str, ".", ""); + string filename = "QuantScan_" + time_str + ".csv"; int file_handle = FileOpen(filename, FILE_CSV|FILE_WRITE|FILE_ANSI, ";"); if(file_handle == INVALID_HANDLE) return; -// --- SCAN & STORE for Breadth --- +// --- SCAN & STORE --- PrintFormat("Scanning %d symbols...", total_symbols); QuantData results[]; int success_count = 0; @@ -255,7 +666,7 @@ void OnStart() StringTrimRight(sym); QuantData temp_data; ZeroMemory(temp_data); - if(RunQuantAnalysis(sym, temp_data)) + if(g_scanner.RunAnalysis(sym, temp_data)) { ArrayResize(results, success_count + 1); results[success_count] = temp_data; @@ -266,12 +677,11 @@ void OnStart() } // --- BREADTH SCORE --- -// Count TSI Bullishness across portfolio (H1 or M15?) usually Trend Context (H1) matters most for Breadth. int bulls = 0; for(int i=0; i 0) - bulls++; // Using H1 Histogram direction + bulls++; } double breadth_pct = (success_count>0) ? ((double)bulls/success_count)*100.0 : 0; sentiment_line += StringFormat(" BREADTH: %d/%d (%.0f%% Bullish)", bulls, success_count, breadth_pct); @@ -287,12 +697,9 @@ void OnStart() StringReplace(str_fast, "PERIOD_", ""); string header = "TIME (" + InpBrokerTimeZone + ");SYMBOL;PRICE;"; -// Layer 1 header += StringFormat("ALPHA_%s;BETA_%s;VHF_%s;R2_%s;ZONE_%s;", str_slow, str_slow, str_slow, str_slow, str_slow); -// Layer 2 - header += StringFormat("V_SCORE_W1_%s;V_SCORE_D1_%s;AUTOCORR_%s;VOL_REGIME_%s;SQZ_%s;SQZ_MOM_%s;VHF_%s;R2_%s;DIST_PDH;DIST_PDL;", str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid);// Layer 3 + header += StringFormat("V_SCORE_W1_%s;V_SCORE_D1_%s;AUTOCORR_%s;VOL_REGIME_%s;SQZ_%s;SQZ_MOM_%s;VHF_%s;R2_%s;DIST_PDH;DIST_PDL;", str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid, str_mid); header += StringFormat("VEL_%s;V_PRES_%s;VOL_THRUST;COST_ATR_%s;", str_fast, str_fast, str_fast); -// Composites header += "ABSORPTION;MTF_ALIGN;VWAP_ALIGN"; FileWrite(file_handle, header); @@ -304,15 +711,13 @@ void OnStart() results[i].timestamp, results[i].symbol, DoubleToString(results[i].price, (int)SymbolInfoInteger(results[i].symbol, SYMBOL_DIGITS)), - // L1 results[i].alpha_str, results[i].beta_str, DoubleToString(results[i].vhf, InpPrecision), DoubleToString(results[i].r2, InpPrecision), results[i].zone, - // L2 - DoubleToString(results[i].v_score_week, InpPrecision), // New - DoubleToString(results[i].v_score_day, InpPrecision), // Renamed from v_score + DoubleToString(results[i].v_score_week, InpPrecision), + DoubleToString(results[i].v_score_day, InpPrecision), DoubleToString(results[i].autocorr, InpPrecision), DoubleToString(results[i].vol_regime, InpPrecision), results[i].sqz, @@ -321,15 +726,13 @@ void OnStart() DoubleToString(results[i].m15_r2, InpPrecision), DoubleToString(results[i].dist_pdh, InpPrecision), DoubleToString(results[i].dist_pdl, InpPrecision), - // L3 DoubleToString(results[i].velocity, InpPrecision), - DoubleToString(results[i].v_pressure, InpPrecision), // NEW + DoubleToString(results[i].v_pressure, InpPrecision), DoubleToString(results[i].vol_thrust, InpPrecision), DoubleToString(results[i].cost_atr, InpPrecision), - // Composite results[i].absorption, results[i].mtf_align, - results[i].vwap_align // New + results[i].vwap_align ); } @@ -338,557 +741,51 @@ void OnStart() } //+------------------------------------------------------------------+ -//| Core Logic | +//| Helper: Get Sentiment String for TF | //+------------------------------------------------------------------+ -bool RunQuantAnalysis(string sym, QuantData &data) +string GetSentimentForTF(ENUM_TIMEFRAMES tf) { - data.timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES); - StringReplace(data.timestamp, ".", "."); - data.symbol = sym; - data.price = SymbolInfoDouble(sym, SYMBOL_BID); - -// ================================================================= -// LAYER 1: CONTEXT (H1) - LIVE -// ================================================================= - double slow_o[], slow_h[], slow_l[], slow_c[]; - long slow_v[]; - datetime slow_t[]; - if(!FetchData(sym, InpTFSlow, InpScanHistory, slow_t, slow_o, slow_h, slow_l, slow_c, slow_v)) - return false; - int idx_l1 = ArraySize(slow_c) - 1; - -// 1. Alpha / Beta (Live) -// --- BETA / ALPHA + REL STRENGTH (Time-Synced) --- - bool is_benchmark = (sym == InpBenchmark || sym == InpForexBench); - if(is_benchmark) + int start_bar_bench = 0; + if(InpUseTargetTime) { - //data.rel_strength_str="BENCH"; - data.beta_str="1.0"; - data.alpha_str="0.0"; - } - else - { - string bench_sym = InpBenchmark; - if(IsForexPair(sym) && SymbolSelect(InpForexBench, true)) - bench_sym = InpForexBench; - - // Fetch Benchmark Full History - double b_c[], dum_o[], dum_h[], dum_l[]; - long dum_v[]; - datetime b_t[]; - if(CDataSync::EnsureDataReady(bench_sym, InpTFSlow, InpScanHistory)) - { - if(FetchData(bench_sym, InpTFSlow, InpScanHistory, b_t, dum_o, dum_h, dum_l, b_c, dum_v)) - { - CMathStatisticsCalculator stats; - int h1_size = ArraySize(slow_c); - int bench_size = ArraySize(b_c); - - // Allocate for Beta (Longer period usually) - int lookback_beta = InpBetaLookback; - double asset_subset[]; - ArrayResize(asset_subset, lookback_beta); - double bench_subset[]; - ArrayResize(bench_subset, lookback_beta); - - int valid_points = 0; - - // Variables for RS Calculation (Shorter period) - double rs_asset_start = 0, rs_bench_start = 0; - double rs_asset_end = 0, rs_bench_end = 0; - bool rs_start_found = false; - - // Loop backwards from current LIVE bar - for(int k=0; k= 0 && b_idx_arr < bench_size && b_t[b_idx_arr] == a_time) ? - b_c[b_idx_arr] : (k>0 ? bench_subset[lookback_beta - k] : 0); - - if(b_idx_arr >= 0 && b_idx_arr < bench_size && b_t[b_idx_arr] == a_time) - { - b_val = b_c[b_idx_arr]; - } - else - { - // Gap filling - if(k>0 && (lookback_beta-k) < lookback_beta) - b_val = bench_subset[lookback_beta-k]; // Next element in array (which is 'newer' since we fill from end) - else - b_val = b_c[MathMin(bench_size-1, b_idx_arr>0?b_idx_arr:0)]; // Fallback - } - - int sub_idx = lookback_beta - 1 - k; - asset_subset[sub_idx] = a_val; - bench_subset[sub_idx] = b_val; - valid_points++; - - // --- RS Logic Capture --- - // End Price (k=0) - if(k==0) - { - rs_asset_end = a_val; - rs_bench_end = b_val; - } - - // Start Price (k = InpRSBars) - if(k == InpRSBars) - { - rs_asset_start = a_val; - rs_bench_start = b_val; - rs_start_found = true; - } - } - - // 1. Calc Beta/Alpha (Long Term) - if(valid_points > lookback_beta / 2) - { - double asset_ret[], bench_ret[]; - stats.ComputeReturns(asset_subset, asset_ret); - stats.ComputeReturns(bench_subset, bench_ret); - - double beta_val = stats.CalculateBeta(asset_ret, bench_ret); - - // Alpha on Beta Period - double a_tot_beta = (asset_subset[lookback_beta-1] - asset_subset[0]) / asset_subset[0]; - double b_tot_beta = (bench_subset[lookback_beta-1] - bench_subset[0]) / bench_subset[0]; - double alpha_val = stats.CalculateAlpha(a_tot_beta, b_tot_beta, beta_val); - - data.beta_str = DoubleToString(beta_val, 2); - data.alpha_str = DoubleToString(alpha_val, 4); - } - else - { - data.beta_str = "0"; - data.alpha_str = "0"; - } - - // 2. Calc Relative Strength (Short Term - InpRSBars) - //if(rs_start_found && rs_asset_start != 0 && rs_bench_start != 0) - // { - // double a_perf = (rs_asset_end - rs_asset_start) / rs_asset_start; - // double b_perf = (rs_bench_end - rs_bench_start) / rs_bench_start; - // double rel_val = (a_perf - b_perf) * 100.0; - //data.rel_strength_str = DoubleToString(rel_val, 2) + "%"; - //} - //else - // { - // data.rel_strength_str = "-"; - // } - } - } + start_bar_bench = iBarShift(InpBenchmark, tf, InpTargetTime, false); + if(start_bar_bench < 0) + return "N/A"; } -// 2. VHF (Live) - data.vhf = Calc_VHF(slow_o, slow_h, slow_l, slow_c, InpVHFPeriod, idx_l1); - -// 3. R-Squared (Live) - data.r2 = Calc_R2(slow_o, slow_h, slow_l, slow_c, InpR2Period, idx_l1); - -// 4. Zone (Murrey) - data.zone = Calc_MurreyZone(sym, InpTFSlow); - -// 5. Calc TSI H1 (Hidden from CSV but used for MTF Align Breadth) - double tsi_main_h1=0; - Calc_TSI_Values(slow_o, slow_h, slow_l, slow_c, idx_l1, tsi_main_h1, data.h1_tsi_hist); - -// ================================================================= -// LAYER 2: FLOW (M15) - LIVE -// ================================================================= - double mid_o[], mid_h[], mid_l[], mid_c[]; - long mid_v[]; - datetime mid_t[]; - if(!FetchData(sym, InpTFMiddle, InpScanHistory, mid_t, mid_o, mid_h, mid_l, mid_c, mid_v)) - return false; - int idx_l2 = ArraySize(mid_c) - 1; - - double mid_atr = Calc_ATR(mid_o, mid_h, mid_l, mid_c, InpATRPeriod, idx_l2); - -// 1. V-Score (Live) - data.v_score_day = Calc_VScore(sym, mid_t, mid_o, mid_h, mid_l, mid_c, mid_v, InpVScorePeriod, PERIOD_SESSION, idx_l2); - -// 2. Autocorrelation (Live) - data.autocorr = Calc_AutoCorr(mid_o, mid_h, mid_l, mid_c, InpAutoCorrPeriod, idx_l2); - -// 3. Vol Regime (Live) - double atr_f = Calc_ATR(mid_o, mid_h, mid_l, mid_c, 5, idx_l2); - double atr_s = Calc_ATR(mid_o, mid_h, mid_l, mid_c, 55, idx_l2); - data.vol_regime = (atr_s!=0) ? atr_f/atr_s : 1.0; - -// 4. Squeeze - Calc_Squeeze_Full(sym, InpTFMiddle, mid_o, mid_h, mid_l, mid_c, idx_l2, data.sqz, data.sqz_mom); - -// 5. VHF & R2 (Live) - data.m15_vhf = Calc_VHF(mid_o, mid_h, mid_l, mid_c, InpVHFPeriod, idx_l2); - data.m15_r2 = Calc_R2(mid_o, mid_h, mid_l, mid_c, InpR2Period, idx_l2); - -// 6. Dist PDH/PDL - CSessionLevelsCalculator sess_calc; - if(sess_calc.Init(PERIOD_D1)) - { - SessionLevels sl; - if(sess_calc.GetLevels(sym, mid_t[idx_l2], sl)) - { - data.dist_pdh = CMetricsTools::CalculateDistance(mid_c[idx_l2], sl.prev_high, mid_atr); - data.dist_pdl = CMetricsTools::CalculateDistance(mid_c[idx_l2], sl.prev_low, mid_atr); - } - } - -// 7. V-Score Weekly (W1) - data.v_score_week = Calc_VScore(sym, slow_t, slow_o, slow_h, slow_l, slow_c, slow_v, InpVScorePeriod, PERIOD_WEEK, idx_l2); - -// M15 TSI for Align - double tsi_main_m15=0; - Calc_TSI_Values(mid_o, mid_h, mid_l, mid_c, idx_l2, tsi_main_m15, data.m15_tsi_hist); - -// RVOL M15 for Thrust - double rvol_m15 = Calc_RVOL(mid_v, InpRVOLPeriod, idx_l2); - -// ================================================================= -// LAYER 3: TRIGGER (M5) - LIVE -// ================================================================= - double fast_o[], fast_h[], fast_l[], fast_c[]; - long fast_v[]; - datetime fast_t[]; - if(!FetchData(sym, InpTFFast, 300, fast_t, fast_o, fast_h, fast_l, fast_c, fast_v)) - return false; - int idx_l3 = ArraySize(fast_c) - 1; - - double fast_atr = Calc_ATR(fast_o, fast_h, fast_l, fast_c, InpATRPeriod, idx_l3); - -// 1. Velocity - data.velocity = Calc_Velocity(fast_c, fast_atr, 5, idx_l3); - -// 2. Volume Pressure (Tick Delta Proxy) - data.v_pressure = Calc_VPressure(fast_h, fast_l, fast_c, idx_l3); // NEW - -// 3. Volume Thrust - double rvol_m5 = Calc_RVOL(fast_v, InpRVOLPeriod, idx_l3); - if(rvol_m15 > 0) - data.vol_thrust = rvol_m5 / rvol_m15; - else - data.vol_thrust = 0; - -// 4. Cost - data.cost_atr = CMetricsTools::CalculateSpreadCost(sym, fast_atr); - - double tsi_main_m5 = 0; - Calc_TSI_Values(fast_o, fast_h, fast_l, fast_c, idx_l3, tsi_main_m5, data.m5_tsi_hist); - -// ================================================================= -// COMPOSITES -// ================================================================= - -// ================================================================= -// ADVANCED ABSORPTION LOGIC (Wyckoff Effort/Result) -// ================================================================= -// Using Last Closed M15 Bar for pattern validation - int idx_cl_mid = idx_l2 - 1; - - if(idx_cl_mid >= 0 && mid_atr > 0) - { - double body = MathAbs(mid_c[idx_cl_mid] - mid_o[idx_cl_mid]); - double total_range = mid_h[idx_cl_mid] - mid_l[idx_cl_mid]; - - // Calculate specific bar RVOL using helper - // Note: We use a local calculator instance to be safe or reuse helper logic - CRelativeVolumeCalculator rv_calc; - rv_calc.Init(InpRVOLPeriod); - double bar_rvol = rv_calc.CalculateSingle(ArraySize(mid_v), mid_v, idx_cl_mid); - - bool high_effort = (bar_rvol > 2.0); - bool low_result = (body < (0.35 * mid_atr)); // Stricter 35% ATR rule - - data.absorption = "NO"; // Default - - if(high_effort && low_result) - { - // Analyze Close Position relative to High-Low Range - // Position 0.0 (Low) to 1.0 (High) - double close_pos = 0.5; - if(total_range > 0) - close_pos = (mid_c[idx_cl_mid] - mid_l[idx_cl_mid]) / total_range; - - if(close_pos > 0.66) - data.absorption = "BULL_ABS"; // Closing High = Demand absorbed Supply - else - if(close_pos < 0.33) - data.absorption = "BEAR_ABS"; // Closing Low = Supply absorbed Demand - else - data.absorption = "NEUT_ABS"; // Doji-like struggle - } - else - if(bar_rvol > 3.5 && body < (0.6 * mid_atr)) - { - // Volume Climax: Excessive volume with moderate move implies churn/exhaustion - data.absorption = "CLIMAX"; - } - } - else - { - data.absorption = "-"; - } - -// MTF Align (Based on TSI Histogram Direction) -// + Hist = Bull pressure, - Hist = Bear pressure - bool h1_bull = (data.h1_tsi_hist > 0); - bool m15_bull = (data.m15_tsi_hist > 0); - bool m5_bull = (data.m5_tsi_hist > 0); - - if(h1_bull == m15_bull && m15_bull == m5_bull) - data.mtf_align = "FULL_" + (h1_bull ? "BULL" : "BEAR"); - else - if(h1_bull == m15_bull) - data.mtf_align = "MAJOR_" + (h1_bull ? "BULL" : "BEAR"); - else - data.mtf_align = "MIXED"; - -// VWAP Alignment Logic (New) -// Compares Price location relative to Daily and Weekly Institutional Average -// V_Score > 0 implies Price > VWAP (Bullish Hold) -// V_Score < 0 implies Price < VWAP (Bearish Hold) - - bool day_bull = (data.v_score_day > 0); - bool week_bull = (data.v_score_week > 0); - - if(day_bull && week_bull) - data.vwap_align = "FULL_BULL"; - else - if(!day_bull && !week_bull) - data.vwap_align = "FULL_BEAR"; - else - data.vwap_align = "MIXED"; - - return true; - } - -//+------------------------------------------------------------------+ -//| WRAPPERS (Helpers) - NEW ONES INCLUDED | -//+------------------------------------------------------------------+ -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; - 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; - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_ATR(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx) - { - CATRCalculator calc; - if(!calc.Init(p, ATR_POINTS)) - return 0; - double buf[]; - int total=ArraySize(c); - calc.Calculate(total, 0, o, h, l, c, buf); - return buf[idx]; - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_RVOL(const long &vol[], int p, int idx) - { - CRelativeVolumeCalculator calc; - calc.Init(p); - return calc.CalculateSingle(ArraySize(vol), vol, idx); - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_Velocity(const double &close[], double atr, int period, int idx) - { - if(atr == 0) - return 0; - int total = ArraySize(close); -// We measure displacement from [idx - period] to [idx] - if(idx < period) - return 0; - return CMetricsTools::CalculateSlope(close[idx], close[idx-period], atr, period); - } - -//+------------------------------------------------------------------+ -//| WRAPPER: Squeeze | -//+------------------------------------------------------------------+ -void Calc_Squeeze_Full(string sym, ENUM_TIMEFRAMES tf, const double &o[], const double &h[], const double &l[], const double &c[], int idx, string &state, double &mom_val) - { - int total = ArraySize(c); - CSqueezeCalculator sqz; - if(!sqz.Init(InpSqueezeLength, InpBBMult, InpKCMult, 12)) - { - state="ERR"; - mom_val=0; - return; - } - - double mom[], val[], col[]; - ArrayResize(mom, total); - ArrayResize(val, total); - ArrayResize(col, total); - - sqz.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, mom, val, col); - - if(idx < total) - { - state = (col[idx] == 1.0) ? "ON" : "OFF"; - mom_val = mom[idx]; - } - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -string Calc_MurreyZone(string symbol, ENUM_TIMEFRAMES tf) - { - CMurreyMathCalculator calc; - calc.Init(symbol, tf, InpMurreyPeriod, 0); - double levels[]; - if(!calc.Calculate(levels)) + if(!CDataSync::EnsureDataReady(InpBenchmark, tf, start_bar_bench + 2)) + return "N/A"; + if(!CDataSync::EnsureDataReady(InpForexBench, tf, start_bar_bench + 2)) return "N/A"; - double price = iClose(symbol, tf, 0); // Always Live Price - 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)"; - } -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -void Calc_TSI_Values(const double &o[], const double &h[], const double &l[], const double &c[], int idx, double &val, double &hist) - { - 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(idx < total) - { - val = tsi[idx]; - hist = tsi[idx] - sig[idx]; - } - } + double u_clos[2], d_clos[2]; + if(CopyClose(InpBenchmark, tf, start_bar_bench, 2, u_clos) != 2) + return "N/A"; + if(CopyClose(InpForexBench, tf, start_bar_bench, 2, d_clos) != 2) + return "N/A"; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_VHF(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx) - { - CVHFCalculator calc; - calc.Init(p, VHF_MODE_HIGH_LOW); // Using High-Low mode for Pro - double buf[]; - int total = ArraySize(c); - ArrayResize(buf, total); -// VHF Calc expects OHLC if using HighLow mode - calc.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, buf); - return buf[idx]; - } + double u_chg = u_clos[1] - u_clos[0]; + double d_chg = d_clos[1] - d_clos[0]; + double u_pct = (u_clos[0]!=0) ? (u_chg / u_clos[0])*100.0 : 0; + double d_pct = (d_clos[0]!=0) ? (d_chg / d_clos[0])*100.0 : 0; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_R2(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx) - { - CLinearRegressionCalculator calc; - calc.Init(p); - double s[], r2[], f[]; - int total = ArraySize(c); - ArrayResize(s, total); - ArrayResize(r2, total); - ArrayResize(f, total); + string state = "MIXED"; + if(d_chg < 0 && u_chg > 0) + state = "RISK-ON"; + else + if(d_chg > 0 && u_chg < 0) + state = "RISK-OFF"; + else + if(d_chg > 0 && u_chg > 0) + state = "STRESS"; + else + if(d_chg < 0 && u_chg < 0) + state = "DEFLATION"; -// FIX: Pass explicit arrays for all OHLC positions - calc.CalculateState(total, 0, o, h, l, c, PRICE_CLOSE, s, r2, f); + string tf_name = EnumToString(tf); + StringReplace(tf_name, "PERIOD_", ""); - return r2[idx]; - } - -//+------------------------------------------------------------------+ -//| WRAPPER: Calculator V-Score (Updated with Reset Period param) | -//+------------------------------------------------------------------+ -double Calc_VScore(string sym, const datetime &t[], const double &o[], const double &h[], const double &l[], const double &c[], const long &v[], int p, ENUM_VWAP_PERIOD reset, int idx) - { - CVScoreCalculator calc; -// Init with specific Reset Period (Session or Week) - calc.Init(p, reset); - - double buf[]; - int total = ArraySize(c); - ArrayResize(buf, total); - - calc.Calculate(total, 0, t, o, h, l, c, v, v, buf); - return buf[idx]; - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_AutoCorr(const double &o[], const double &h[], const double &l[], const double &c[], int p, int idx) - { - CAutocorrelationCalculator calc; - calc.Init(p); - double buf[]; - int total = ArraySize(c); - ArrayResize(buf, total); - calc.Calculate(total, 0, PRICE_CLOSE, o, h, l, c, buf); - return buf[idx]; - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -double Calc_VPressure(const double &h[], const double &l[], const double &c[], int idx) - { -// Use raw calc (smooth=1) for pure candle analysis - CVolumePressureCalculator calc; - if(!calc.Init(1)) - return 0; - - double buf[]; - int total = ArraySize(c); - ArrayResize(buf, total); - -// Need Arrays. H/L/C passed directly. -// But Calc takes full arrays and fills buffer. -// Assuming wrapper logic similar to others. -// Wait, calc.CalculateSignature: (total, prev, h, l, c, buf). - calc.Calculate(total, 0, h, l, c, buf); - return buf[idx]; + return StringFormat("%s: %s (US:%.2f%% DX:%.2f%%)", tf_name, state, u_pct, d_pct); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+