From 1cd30c1060987aff42229c956663c6197269bd3b Mon Sep 17 00:00:00 2001 From: Pietro Giacobazzi Date: Tue, 16 Jun 2026 19:00:26 +0000 Subject: [PATCH 1/3] PaPP v2: vera mediana su 7 MA (rimossa SMA(1) ovunque) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- PaPP v2/PaPP_Median.mq5 | 34 ++++++++++++++++++++------------ PaPP v2/PaPP_Median_EA.mq5 | 40 ++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/PaPP v2/PaPP_Median.mq5 b/PaPP v2/PaPP_Median.mq5 index 49c4cdc..50eb14f 100644 --- a/PaPP v2/PaPP_Median.mq5 +++ b/PaPP v2/PaPP_Median.mq5 @@ -4,7 +4,7 @@ //+------------------------------------------------------------------+ #property copyright "PaPP v2" #property version "2.00" -#property description "PaPP Median - Media 8 MA (1g-1y)" +#property description "PaPP Median - Mediana 7 MA (3g-1y)" #property description "Linea singola = fair value multi-TF" #property indicator_chart_window #property indicator_buffers 1 @@ -14,8 +14,8 @@ input int FontSize = 9; double Buff_Median[]; -int hMA[8]; -int bars[8]; +int hMA[7]; +int bars[7]; string _pfx = "PM_"; //+------------------------------------------------------------------+ @@ -33,10 +33,10 @@ int TimeToBars(int d) //+------------------------------------------------------------------+ int OnInit() { - int days[8] = {365,182,121,30,14,7,3,1}; - for(int i=0;i<8;i++) + int days[7] = {365,182,121,30,14,7,3}; + for(int i=0;i<7;i++) { - bars[i] = (i<7) ? TimeToBars(days[i]) : 1; + bars[i] = TimeToBars(days[i]); hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); if(hMA[i]==INVALID_HANDLE) return INIT_FAILED; } @@ -55,7 +55,7 @@ int OnInit() //+------------------------------------------------------------------+ void OnDeinit(const int reason) { - for(int i=0;i<8;i++) if(hMA[i]!=INVALID_HANDLE) IndicatorRelease(hMA[i]); + for(int i=0;i<7;i++) if(hMA[i]!=INVALID_HANDLE) IndicatorRelease(hMA[i]); ObjectsDeleteAll(0,_pfx); } @@ -67,6 +67,15 @@ double GetMA(int idx,int m) return 0; } +//+------------------------------------------------------------------+ +double Median(double &a[],int n) + { + if(n<=0) return 0; + ArraySort(a); + if((n&1)==1) return a[n/2]; + return 0.5*(a[n/2-1]+a[n/2]); + } + //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, @@ -87,13 +96,14 @@ int OnCalculate(const int rates_total, for(int idx=limit;idx>=0;idx--) { - double sum=0; int cnt=0; - for(int m=0;m<8;m++) + double vals[]; int cnt=0; ArrayResize(vals,7); + for(int m=0;m<7;m++) { double v = GetMA(idx,m); - if(v>0) { sum+=v; cnt++; } + if(v>0) { vals[cnt]=v; cnt++; } } - Buff_Median[idx]=(cnt>0) ? sum/cnt : 0; + ArrayResize(vals,cnt); + Buff_Median[idx]=Median(vals,cnt); } DrawInfo(); @@ -121,7 +131,7 @@ void DrawInfo() //--- Dispersione MA e bande (info) double ds=0; int dc=0; - for(int m=0;m<8;m++) { double v=GetMA(0,m); if(v>0) { ds+=MathAbs(v-median)/median*100; dc++; } } + for(int m=0;m<7;m++) { double v=GetMA(0,m); if(v>0) { ds+=MathAbs(v-median)/median*100; dc++; } } double vol = (dc>0)?ds/dc:0; Lbl("V","Cluster +/-"+DoubleToString(vol,3)+"%",x,y,FontSize,clrGray,false); y+=lh; Lbl("H","Sopra=SELL | Sotto=BUY",x,y,FontSize-1,clrGray,false); diff --git a/PaPP v2/PaPP_Median_EA.mq5 b/PaPP v2/PaPP_Median_EA.mq5 index 36d0d6f..37ccd6e 100644 --- a/PaPP v2/PaPP_Median_EA.mq5 +++ b/PaPP v2/PaPP_Median_EA.mq5 @@ -7,7 +7,7 @@ #property copyright "PaPP v2" #property version "2.00" #property description "PaPP Median EA - Mean Reversion puro" -#property description "Linea mediana (media 8 MA 1g-1y) = unico segnale" +#property description "Linea mediana (mediana 7 MA 3g-1y) = unico segnale" #property description "Sopra = SELL | Sotto = BUY" input double LotSize = 0.01; @@ -18,8 +18,8 @@ input bool DebugPrint = true; input int Magic = 2024002; input int Slippage = 30; -int hMA[8]; -int bars[8]; +int hMA[7]; +int bars[7]; datetime lastBar = 0; bool buyFired = false; bool sellFired = false; @@ -40,16 +40,16 @@ int TimeToBars(int d) //+------------------------------------------------------------------+ int OnInit() { - int days[8] = {365,182,121,30,14,7,3,1}; - for(int i=0;i<8;i++) + int days[7] = {365,182,121,30,14,7,3}; + for(int i=0;i<7;i++) { - bars[i] = (i<7) ? TimeToBars(days[i]) : 1; + bars[i] = TimeToBars(days[i]); hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); if(hMA[i]==INVALID_HANDLE) return INIT_FAILED; } if(DebugPrint) Print("=== PaPP Median EA v2.00 INIT ==="); Print(" Lot=",LotSize," Trail=",TrailStart,"/",TrailStep," MaxPos=",MaxPosPerSide); - for(int i=0;i<8;i++) Print(" MA[",i,"] bars=",bars[i]); + for(int i=0;i<7;i++) Print(" MA[",i,"] bars=",bars[i]); buyFired = (CountPos(POSITION_TYPE_BUY) > 0); sellFired = (CountPos(POSITION_TYPE_SELL) > 0); if(DebugPrint) Print(" Flags restored: buyFired=",buyFired," sellFired=",sellFired); @@ -59,7 +59,7 @@ int OnInit() //+------------------------------------------------------------------+ void OnDeinit(const int reason) { - for(int i=0;i<8;i++) if(hMA[i]!=INVALID_HANDLE) IndicatorRelease(hMA[i]); + for(int i=0;i<7;i++) if(hMA[i]!=INVALID_HANDLE) IndicatorRelease(hMA[i]); } //+------------------------------------------------------------------+ @@ -70,6 +70,15 @@ double GetMA(int idx,int m) return 0; } +//+------------------------------------------------------------------+ +double Median(double &a[],int n) + { + if(n<=0) return 0; + ArraySort(a); + if((n&1)==1) return a[n/2]; + return 0.5*(a[n/2-1]+a[n/2]); + } + //+------------------------------------------------------------------+ int CountPos(int type) { @@ -163,17 +172,18 @@ void OnTick() double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); double point = SymbolInfoDouble(_Symbol,SYMBOL_POINT); - //--- Leggi le 8 MA e calcola mediana - double mv[8]; int valid=0; double sum=0; - for(int m=0;m<8;m++) { mv[m]=GetMA(0,m); if(mv[m]>0) { sum+=mv[m]; valid++; } } - if(valid==0 || sum<=0) { if(DebugPrint) Print("SKIP: valid=",valid); return; } + //--- Leggi le 7 MA e calcola mediana + double mv[7]; double vals[]; int valid=0; ArrayResize(vals,7); + for(int m=0;m<7;m++) { mv[m]=GetMA(0,m); if(mv[m]>0) { vals[valid]=mv[m]; valid++; } } + if(valid==0) { if(DebugPrint) Print("SKIP: valid=",valid); return; } + ArrayResize(vals,valid); - double median = sum/valid; + double median = Median(vals,valid); //--- Update TP/SL per tutte le posizioni con la mediana corrente UpdateTPSL(median); - //--- Banda = min/max di MA0-MA6 (1Y a 3G), esclude MA7 (SMA(1)=noise) + //--- Banda = min/max delle 7 MA (1Y a 3G) double minMA=mv[0], maxMA=mv[0]; for(int m=1;m<7;m++) if(mv[m]>0) { @@ -208,7 +218,7 @@ void OnTick() Print("Dist=",DoubleToString(distPct,3),"% Range=",DoubleToString((maxMA-minMA)/median*100,3),"%"); Print("Trend: ",trendUp?"UP":trendDown?"DOWN":"MIX", " Allow: ",allowBuy?"B":"-",allowSell?"S":"-"); Print("Band: [",DoubleToString(buyBand,_Digits)," <- ",DoubleToString(sellBand,_Digits)," ] Pos: ",nBuy,"B ",nSell,"S"); - for(int m=0;m<8;m++) + for(int m=0;m<7;m++) if(mv[m]>0) Print(" MA",m,"=",DoubleToString(mv[m],_Digits), " diff=",DoubleToString(bid-mv[m],_Digits)); From 598917d4ae76052cfcdd2098db53a5783ef7e1a7 Mon Sep 17 00:00:00 2001 From: Pietro Giacobazzi Date: Tue, 16 Jun 2026 19:05:22 +0000 Subject: [PATCH 2/3] PaPP v2: ancora le MA a D1 (linea identica su ogni timeframe, non-repaint) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- PaPP v2/PaPP_Median.mq5 | 27 +++++++++++++++++++-------- PaPP v2/PaPP_Median_EA.mq5 | 15 +++++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/PaPP v2/PaPP_Median.mq5 b/PaPP v2/PaPP_Median.mq5 index 50eb14f..bf3c1f0 100644 --- a/PaPP v2/PaPP_Median.mq5 +++ b/PaPP v2/PaPP_Median.mq5 @@ -5,13 +5,15 @@ #property copyright "PaPP v2" #property version "2.00" #property description "PaPP Median - Mediana 7 MA (3g-1y)" -#property description "Linea singola = fair value multi-TF" +#property description "Calcolo ancorato a D1 = linea uguale su ogni timeframe" #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 input int FontSize = 9; +#define ANCHOR_TF PERIOD_D1 // calcolo ancorato a D1: linea identica su ogni TF + double Buff_Median[]; int hMA[7]; @@ -24,10 +26,10 @@ int TimeToBars(int d) datetime n = TimeCurrent(); if(n==0) { - long s = (long)d*86400L, p = PeriodSeconds((ENUM_TIMEFRAMES)_Period); + long s = (long)d*86400L, p = PeriodSeconds(ANCHOR_TF); return (int)MathMax(1,s/p); } - return MathMax(1,Bars(_Symbol,_Period,n-d*86400,n)); + return MathMax(1,Bars(_Symbol,ANCHOR_TF,n-d*86400,n)); } //+------------------------------------------------------------------+ @@ -37,7 +39,7 @@ int OnInit() for(int i=0;i<7;i++) { bars[i] = TimeToBars(days[i]); - hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); + hMA[i] = iMA(_Symbol,ANCHOR_TF,bars[i],0,MODE_SMA,PRICE_CLOSE); if(hMA[i]==INVALID_HANDLE) return INIT_FAILED; } @@ -48,6 +50,7 @@ int OnInit() PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrGold); PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2); PlotIndexSetString(0,PLOT_LABEL,"PaPP Median"); + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); IndicatorSetString(INDICATOR_SHORTNAME,"PaPP Median"); return INIT_SUCCEEDED; } @@ -60,10 +63,12 @@ void OnDeinit(const int reason) } //+------------------------------------------------------------------+ -double GetMA(int idx,int m) +// d1shift = indice (serie) della barra D1 da cui leggere la SMA +double GetMA(int m,int d1shift) { + if(d1shift<0) return 0; double buf[1]; - if(CopyBuffer(hMA[m],0,idx+1,1,buf)==1) return buf[0]; + if(CopyBuffer(hMA[m],0,d1shift,1,buf)==1) return buf[0]; return 0; } @@ -90,16 +95,22 @@ int OnCalculate(const int rates_total, { if(rates_total<2) return 0; ArraySetAsSeries(close,true); + ArraySetAsSeries(time,true); int limit = rates_total - prev_calculated; if(limit>1) limit=rates_total-1; for(int idx=limit;idx>=0;idx--) { + //--- ultima barra D1 chiusa rispetto al tempo di questa barra grafico + int d1 = iBarShift(_Symbol,ANCHOR_TF,time[idx],false); + if(d1<0) { Buff_Median[idx]=0; continue; } + d1 += 1; + double vals[]; int cnt=0; ArrayResize(vals,7); for(int m=0;m<7;m++) { - double v = GetMA(idx,m); + double v = GetMA(m,d1); if(v>0) { vals[cnt]=v; cnt++; } } ArrayResize(vals,cnt); @@ -131,7 +142,7 @@ void DrawInfo() //--- Dispersione MA e bande (info) double ds=0; int dc=0; - for(int m=0;m<7;m++) { double v=GetMA(0,m); if(v>0) { ds+=MathAbs(v-median)/median*100; dc++; } } + for(int m=0;m<7;m++) { double v=GetMA(m,1); if(v>0) { ds+=MathAbs(v-median)/median*100; dc++; } } double vol = (dc>0)?ds/dc:0; Lbl("V","Cluster +/-"+DoubleToString(vol,3)+"%",x,y,FontSize,clrGray,false); y+=lh; Lbl("H","Sopra=SELL | Sotto=BUY",x,y,FontSize-1,clrGray,false); diff --git a/PaPP v2/PaPP_Median_EA.mq5 b/PaPP v2/PaPP_Median_EA.mq5 index 37ccd6e..f870726 100644 --- a/PaPP v2/PaPP_Median_EA.mq5 +++ b/PaPP v2/PaPP_Median_EA.mq5 @@ -18,6 +18,8 @@ input bool DebugPrint = true; input int Magic = 2024002; input int Slippage = 30; +#define ANCHOR_TF PERIOD_D1 // calcolo ancorato a D1: stessa fair value su ogni TF + int hMA[7]; int bars[7]; datetime lastBar = 0; @@ -31,10 +33,10 @@ int TimeToBars(int d) datetime n = TimeCurrent(); if(n==0) { - long s = (long)d*86400L, p = PeriodSeconds((ENUM_TIMEFRAMES)_Period); + long s = (long)d*86400L, p = PeriodSeconds(ANCHOR_TF); return (int)MathMax(1,s/p); } - return MathMax(1,Bars(_Symbol,_Period,n-d*86400,n)); + return MathMax(1,Bars(_Symbol,ANCHOR_TF,n-d*86400,n)); } //+------------------------------------------------------------------+ @@ -44,7 +46,7 @@ int OnInit() for(int i=0;i<7;i++) { bars[i] = TimeToBars(days[i]); - hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); + hMA[i] = iMA(_Symbol,ANCHOR_TF,bars[i],0,MODE_SMA,PRICE_CLOSE); if(hMA[i]==INVALID_HANDLE) return INIT_FAILED; } if(DebugPrint) Print("=== PaPP Median EA v2.00 INIT ==="); @@ -63,10 +65,11 @@ void OnDeinit(const int reason) } //+------------------------------------------------------------------+ -double GetMA(int idx,int m) +// legge la SMA dall'ultima barra D1 chiusa (non-repaint) +double GetMA(int m) { double buf[1]; - if(CopyBuffer(hMA[m],0,idx+1,1,buf)==1) return buf[0]; + if(CopyBuffer(hMA[m],0,1,1,buf)==1) return buf[0]; return 0; } @@ -174,7 +177,7 @@ void OnTick() //--- Leggi le 7 MA e calcola mediana double mv[7]; double vals[]; int valid=0; ArrayResize(vals,7); - for(int m=0;m<7;m++) { mv[m]=GetMA(0,m); if(mv[m]>0) { vals[valid]=mv[m]; valid++; } } + for(int m=0;m<7;m++) { mv[m]=GetMA(m); if(mv[m]>0) { vals[valid]=mv[m]; valid++; } } if(valid==0) { if(DebugPrint) Print("SKIP: valid=",valid); return; } ArrayResize(vals,valid); From 3c4909af0f2431ab38a31764d72bc4faa0c769a4 Mon Sep 17 00:00:00 2001 From: Pietro Giacobazzi Date: Tue, 16 Jun 2026 19:07:17 +0000 Subject: [PATCH 3/3] PaPP v2 indicatore: linea morbida (interpolazione D1, input Smooth) + pannello con i 7 valori MA a schermo Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- PaPP v2/PaPP_Median.mq5 | 62 +++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/PaPP v2/PaPP_Median.mq5 b/PaPP v2/PaPP_Median.mq5 index bf3c1f0..8d37f00 100644 --- a/PaPP v2/PaPP_Median.mq5 +++ b/PaPP v2/PaPP_Median.mq5 @@ -11,11 +11,13 @@ #property indicator_plots 1 input int FontSize = 9; +input bool Smooth = true; // interpola tra i valori D1 -> linea morbida #define ANCHOR_TF PERIOD_D1 // calcolo ancorato a D1: linea identica su ogni TF double Buff_Median[]; +int gDays[7] = {365,182,121,30,14,7,3}; int hMA[7]; int bars[7]; string _pfx = "PM_"; @@ -35,10 +37,9 @@ int TimeToBars(int d) //+------------------------------------------------------------------+ int OnInit() { - int days[7] = {365,182,121,30,14,7,3}; for(int i=0;i<7;i++) { - bars[i] = TimeToBars(days[i]); + bars[i] = TimeToBars(gDays[i]); hMA[i] = iMA(_Symbol,ANCHOR_TF,bars[i],0,MODE_SMA,PRICE_CLOSE); if(hMA[i]==INVALID_HANDLE) return INIT_FAILED; } @@ -81,6 +82,17 @@ double Median(double &a[],int n) return 0.5*(a[n/2-1]+a[n/2]); } +//+------------------------------------------------------------------+ +// Mediana delle 7 MA su una specifica barra D1 +double MedianAtD1(int d1shift) + { + if(d1shift<0) return 0; + double vals[]; int cnt=0; ArrayResize(vals,7); + for(int m=0;m<7;m++) { double v=GetMA(m,d1shift); if(v>0) { vals[cnt]=v; cnt++; } } + ArrayResize(vals,cnt); + return Median(vals,cnt); + } + //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, @@ -102,19 +114,29 @@ int OnCalculate(const int rates_total, for(int idx=limit;idx>=0;idx--) { - //--- ultima barra D1 chiusa rispetto al tempo di questa barra grafico - int d1 = iBarShift(_Symbol,ANCHOR_TF,time[idx],false); - if(d1<0) { Buff_Median[idx]=0; continue; } - d1 += 1; + //--- barra D1 che contiene il tempo di questa barra grafico + int d1cur = iBarShift(_Symbol,ANCHOR_TF,time[idx],false); + if(d1cur<0) { Buff_Median[idx]=0; continue; } - double vals[]; int cnt=0; ArrayResize(vals,7); - for(int m=0;m<7;m++) + if(!Smooth) { - double v = GetMA(m,d1); - if(v>0) { vals[cnt]=v; cnt++; } + //--- gradino: ultima barra D1 chiusa (non-repaint) + Buff_Median[idx]=MedianAtD1(d1cur+1); + continue; } - ArrayResize(vals,cnt); - Buff_Median[idx]=Median(vals,cnt); + + //--- linea morbida: interpola tra mediana di inizio e fine giornata + double vEnd = MedianAtD1(d1cur); // giornata corrente + double vStart = MedianAtD1(d1cur+1); // giornata precedente + datetime t0 = iTime(_Symbol,ANCHOR_TF,d1cur); + datetime t1 = (d1cur>0) ? iTime(_Symbol,ANCHOR_TF,d1cur-1) + : t0 + PeriodSeconds(ANCHOR_TF); + double frac = (t1>t0) ? (double)(time[idx]-t0)/(double)(t1-t0) : 0.0; + frac = MathMax(0.0,MathMin(1.0,frac)); + + if(vStart>0 && vEnd>0) Buff_Median[idx]=vStart+frac*(vEnd-vStart); + else if(vEnd>0) Buff_Median[idx]=vEnd; + else Buff_Median[idx]=vStart; } DrawInfo(); @@ -125,7 +147,7 @@ int OnCalculate(const int rates_total, void DrawInfo() { double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); - double median = Buff_Median[0]; + double median = MedianAtD1(1); // valore D1 chiuso (stabile, non-repaint) if(median<=0) return; int x=10,y=30,lh=FontSize+4; @@ -144,7 +166,19 @@ void DrawInfo() double ds=0; int dc=0; for(int m=0;m<7;m++) { double v=GetMA(m,1); if(v>0) { ds+=MathAbs(v-median)/median*100; dc++; } } double vol = (dc>0)?ds/dc:0; - Lbl("V","Cluster +/-"+DoubleToString(vol,3)+"%",x,y,FontSize,clrGray,false); y+=lh; + Lbl("V","Cluster +/-"+DoubleToString(vol,3)+"%",x,y,FontSize,clrGray,false); y+=lh+2; + + //--- Valori delle 7 MA (giorni : valore) + for(int m=0;m<7;m++) + { + double v=GetMA(m,1); + color cma = (v>median)?clrSalmon:clrLightGreen; + Lbl("a"+IntegerToString(m), + StringFormat("MA %3dg: %s",gDays[m],DoubleToString(v,_Digits)), + x,y,FontSize-1,(v>0)?cma:clrGray,false); + y+=lh-2; + } + y+=2; Lbl("H","Sopra=SELL | Sotto=BUY",x,y,FontSize-1,clrGray,false); }