diff --git a/PaPP v2/PaPP_Median.mq5 b/PaPP v2/PaPP_Median.mq5 index 49c4cdc..8d37f00 100644 --- a/PaPP v2/PaPP_Median.mq5 +++ b/PaPP v2/PaPP_Median.mq5 @@ -4,18 +4,22 @@ //+------------------------------------------------------------------+ #property copyright "PaPP v2" #property version "2.00" -#property description "PaPP Median - Media 8 MA (1g-1y)" -#property description "Linea singola = fair value multi-TF" +#property description "PaPP Median - Mediana 7 MA (3g-1y)" +#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; +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 hMA[8]; -int bars[8]; +int gDays[7] = {365,182,121,30,14,7,3}; +int hMA[7]; +int bars[7]; string _pfx = "PM_"; //+------------------------------------------------------------------+ @@ -24,20 +28,19 @@ 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)); } //+------------------------------------------------------------------+ int OnInit() { - int days[8] = {365,182,121,30,14,7,3,1}; - for(int i=0;i<8;i++) + for(int i=0;i<7;i++) { - bars[i] = (i<7) ? TimeToBars(days[i]) : 1; - hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); + 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; } @@ -48,6 +51,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; } @@ -55,18 +59,40 @@ 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); } //+------------------------------------------------------------------+ -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; } +//+------------------------------------------------------------------+ +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]); + } + +//+------------------------------------------------------------------+ +// 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, @@ -81,19 +107,36 @@ 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--) { - double sum=0; int cnt=0; - for(int m=0;m<8;m++) + //--- 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; } + + if(!Smooth) { - double v = GetMA(idx,m); - if(v>0) { sum+=v; cnt++; } + //--- gradino: ultima barra D1 chiusa (non-repaint) + Buff_Median[idx]=MedianAtD1(d1cur+1); + continue; } - Buff_Median[idx]=(cnt>0) ? sum/cnt : 0; + + //--- 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(); @@ -104,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; @@ -121,9 +164,21 @@ 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(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); } diff --git a/PaPP v2/PaPP_Median_EA.mq5 b/PaPP v2/PaPP_Median_EA.mq5 index 36d0d6f..f870726 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,10 @@ input bool DebugPrint = true; input int Magic = 2024002; input int Slippage = 30; -int hMA[8]; -int bars[8]; +#define ANCHOR_TF PERIOD_D1 // calcolo ancorato a D1: stessa fair value su ogni TF + +int hMA[7]; +int bars[7]; datetime lastBar = 0; bool buyFired = false; bool sellFired = false; @@ -31,25 +33,25 @@ 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)); } //+------------------------------------------------------------------+ 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; - hMA[i] = iMA(_Symbol,_Period,bars[i],0,MODE_SMA,PRICE_CLOSE); + bars[i] = TimeToBars(days[i]); + 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 ==="); 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,17 +61,27 @@ 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]); } //+------------------------------------------------------------------+ -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; } +//+------------------------------------------------------------------+ +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 +175,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(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 +221,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));