refactor(scripts): Updated with Sync Fix

This commit is contained in:
Toh4iem9
2026-02-12 12:23:16 +01:00
parent f380b399b9
commit 0ee80b3495
+89 -40
View File
@@ -1,10 +1,10 @@
//+------------------------------------------------------------------+
//| Market_Scanner_Pro.mq5 |
//| QuantScan 8.2 - Squeeze Momentum |
//| QuantScan 8.3 - Squeeze Momentum |
//| Copyright 2026, xxxxxxxx |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, xxxxxxxx"
#property version "8.20" // Added Squeeze Momentum output & input
#property version "8.30" // Updated with Sync Fix
#property description "Exports 'QuantScan 8.0' dataset for LLM Analysis."
#property description "Now includes Squeeze Momentum direction/value."
#property script_show_inputs
@@ -334,7 +334,7 @@ void OnStart()
}
//+------------------------------------------------------------------+
//| Core Logic |
//| Core Logic (v8.30 Updated with Sync Fix) |
//+------------------------------------------------------------------+
bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
{
@@ -373,7 +373,7 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
// TSI -> LIVE
Calc_TSI_Values(slow_o, slow_h, slow_l, slow_c, idx_live_slow, data.h1_tsi_val, data.h1_tsi_hist);
// Beta/Alpha -> LIVE
// --- BETA / ALPHA Calculation (TIME-SYNC FIXED) ---
bool is_benchmark = (sym == InpBenchmark || sym == InpForexBench);
if(is_benchmark)
{
@@ -387,49 +387,99 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
if(IsForexPair(sym) && SymbolSelect(InpForexBench, true))
bench_sym = InpForexBench;
// Ensure sync for benchmark on H1
if(CDataSync::EnsureDataReady(bench_sym, InpTFSlow, InpBetaLookback+2))
// Fetch Benchmark Full History (Same depth as asset) to ensure we find matching times
double b_c[], b_o[], b_h[], b_l[];
long b_v[];
datetime b_t[];
// Force Sync Bench Data first
if(CDataSync::EnsureDataReady(bench_sym, InpTFSlow, InpScanHistory))
{
double bench_c[];
if(CopyClose(bench_sym, InpTFSlow, 0, InpBetaLookback+2, bench_c) > InpBetaLookback)
// Fetch using helper
if(FetchData(bench_sym, InpTFSlow, InpScanHistory, b_t, b_o, b_h, b_l, b_c, b_v))
{
CMathStatisticsCalculator stats;
double asset_ret[], bench_ret[];
// Build subset from LIVE backwards
int h1_size = ArraySize(slow_c);
int bench_size = ArraySize(bench_c);
int bench_size = ArraySize(b_c);
// Allocate subsets
double asset_subset[];
ArrayResize(asset_subset, InpBetaLookback);
double bench_subset[];
ArrayResize(bench_subset, InpBetaLookback);
// i=0 is oldest in subset. We want subset[last] to be current live.
int valid_points = 0;
// Loop backwards from current LIVE bar [size-1]
// We fill the subset from End (Newest) to Start (Oldest) to keep chronological order for Returns Calc
for(int k=0; k<InpBetaLookback; k++)
{
asset_subset[k] = slow_c[h1_size - InpBetaLookback + k];
bench_subset[k] = bench_c[bench_size - InpBetaLookback + k];
// Asset Index
int a_idx = h1_size - 1 - k;
if(a_idx < 0)
break;
datetime a_time = slow_t[a_idx];
// Find Matching Benchmark Index by Time
// Since arrays are non-series (0=Oldest), we can't use simple math if gaps exist.
// We use Binary Search (ArrayBsearch) on bench time array
int b_idx_arr = ArrayBsearch(b_t, a_time);
// ArrayBsearch returns index. Check if time matches exactly (or close enough)
if(b_idx_arr >= 0 && b_idx_arr < bench_size && b_t[b_idx_arr] == a_time)
{
// Match found!
int sub_idx = InpBetaLookback - 1 - k; // Fill from end
asset_subset[sub_idx] = slow_c[a_idx];
bench_subset[sub_idx] = b_c[b_idx_arr];
valid_points++;
}
else
{
// Gap found (e.g. Asset open, Bench closed).
// For strict stats, we skip this point or fill with previous?
// Skipping creates holes in return calc.
// Simple approach: Use previous bench value (Fill forward)?
// Better: Simply don't increment valid_points, leave 0? No, stats need continuous series.
// Let's copy previous value if match fails (Flat return).
int sub_idx = InpBetaLookback - 1 - k;
asset_subset[sub_idx] = slow_c[a_idx];
// Use prev from subset if k>0? Tricky loop direction.
// Simple fallback: Use bench at index approx? No.
// If missing, we assume price didnt change from last valid.
if(k>0 && sub_idx+1 < InpBetaLookback)
bench_subset[sub_idx] = bench_subset[sub_idx+1]; // Prev Loop value (Newer)
}
}
stats.ComputeReturns(asset_subset, asset_ret);
stats.ComputeReturns(bench_subset, bench_ret);
double beta_val = stats.CalculateBeta(asset_ret, bench_ret);
double a_tot = (asset_subset[InpBetaLookback-1] - asset_subset[0]) / asset_subset[0];
double b_tot = (bench_subset[InpBetaLookback-1] - bench_subset[0]) / bench_subset[0];
double alpha_val = stats.CalculateAlpha(a_tot, b_tot, beta_val);
double rel_val = (a_tot - b_tot) * 100.0;
// Only calc if we have enough synced data
if(valid_points > InpBetaLookback / 2)
{
double asset_ret[], bench_ret[];
stats.ComputeReturns(asset_subset, asset_ret);
stats.ComputeReturns(bench_subset, bench_ret);
data.rel_strength_str = DoubleToString(rel_val, 2) + "%";
data.beta_str = DoubleToString(beta_val, 2);
data.alpha_str = DoubleToString(alpha_val, 4);
double beta_val = stats.CalculateBeta(asset_ret, bench_ret);
// Period Alpha
double a_tot = (asset_subset[InpBetaLookback-1] - asset_subset[0]) / asset_subset[0];
double b_tot = (bench_subset[InpBetaLookback-1] - bench_subset[0]) / bench_subset[0];
double alpha_val = stats.CalculateAlpha(a_tot, b_tot, beta_val);
double rel_val = (a_tot - b_tot) * 100.0;
data.rel_strength_str = DoubleToString(rel_val, 2) + "%";
data.beta_str = DoubleToString(beta_val, 2);
data.alpha_str = DoubleToString(alpha_val, 4);
}
else
{
data.rel_strength_str = "-";
data.beta_str = "0";
data.alpha_str = "0";
}
}
}
else
{
data.rel_strength_str = "0%";
data.beta_str = "0";
data.alpha_str = "0";
}
}
// =================================================================
@@ -453,8 +503,6 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
Calc_VWAP_Series(mid_t, mid_o, mid_h, mid_l, mid_c, mid_v, PERIOD_SESSION, vwap_series);
data.m15_vwap_slope = CMetricsTools::CalculateSlope(vwap_series[idx_live_mid], vwap_series[idx_live_mid - InpSlopeLookback], mid_atr, InpSlopeLookback);
//data.spread_cost = CMetricsTools::CalculateSpreadCost(sym, mid_atr);
double atr_f = Calc_ATR(mid_o, mid_h, mid_l, mid_c, 5, idx_live_mid);
double atr_s = Calc_ATR(mid_o, mid_h, mid_l, mid_c, 50, idx_live_mid);
data.m15_vola_regime = (atr_s!=0) ? atr_f/atr_s : 1.0;
@@ -482,13 +530,14 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
return false;
int idx_live_fast = ArraySize(fast_c) - 1;
double fast_atr = Calc_ATR(fast_o, fast_h, fast_l, fast_c, InpATRPeriod, idx_live_fast);
double fast_atr = Calc_ATR(fast_o, fast_h, fast_l, fast_c, InpATRPeriod, idx_live_fast);
data.spread_cost = CMetricsTools::CalculateSpreadCost(sym, fast_atr); // Calc cost on M5 ATR
data.m5_momentum = Calc_LaguerreRSI(fast_o, fast_h, fast_l, fast_c, idx_live_fast);
data.m5_vol_qual = Calc_RVOL(fast_v, InpRVOLPeriod, idx_live_fast);
Calc_TSI_Values(fast_o, fast_h, fast_l, fast_c, idx_live_fast, data.m5_tsi_val, data.m5_tsi_hist);
data.m5_velocity = Calc_Velocity(fast_c, fast_atr, 3, idx_live_fast);
data.spread_cost = CMetricsTools::CalculateSpreadCost(sym, fast_atr);
// =================================================================
// COMPOSITES
@@ -511,13 +560,13 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
data.rev_prob = score;
// Absorption: Use Last Closed M15 (idx_live_mid - 1) for safety
int idx_abs = idx_live_mid - 1;
if(idx_abs >= 0 && mid_atr > 0)
int idx_cl_mid = idx_live_mid - 1;
if(idx_cl_mid >= 0 && mid_atr > 0)
{
double body = MathAbs(mid_c[idx_abs] - mid_o[idx_abs]);
double body = MathAbs(mid_c[idx_cl_mid] - mid_o[idx_cl_mid]);
CRelativeVolumeCalculator rv;
rv.Init(InpRVOLPeriod);
double bar_rvol = rv.CalculateSingle(ArraySize(mid_v), mid_v, idx_abs);
double bar_rvol = rv.CalculateSingle(ArraySize(mid_v), mid_v, idx_cl_mid);
if(bar_rvol > 2.0 && body < (0.4 * mid_atr))
data.absorption = "YES";
else
@@ -526,7 +575,7 @@ bool RunQuantAnalysis(string sym, double bench_change, QuantData &data)
else
data.absorption = "-";
// MTF Align (Based on TSI Histogram sign)
// MTF Align (Based on Hist direction)
bool h1_bull = (data.h1_tsi_hist > 0);
bool m15_bull = (data.m15_tsi_hist > 0);
bool m5_bull = (data.m5_tsi_hist > 0);