From a6f6c0510b023603200306b7a936b6e0b040030c Mon Sep 17 00:00:00 2001 From: Pietro Giacobazzi Date: Tue, 16 Jun 2026 20:12:09 +0000 Subject: [PATCH 1/2] PaPP v2: script export CSV degli incroci (ancorato a D1, intervallo date o tutto lo storico, feature + esiti 1/3/5/10/20g) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- PaPP v2/PaPP_CrossExport.mq5 | 221 +++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 PaPP v2/PaPP_CrossExport.mq5 diff --git a/PaPP v2/PaPP_CrossExport.mq5 b/PaPP v2/PaPP_CrossExport.mq5 new file mode 100644 index 0000000..5dcc504 --- /dev/null +++ b/PaPP v2/PaPP_CrossExport.mq5 @@ -0,0 +1,221 @@ +//+------------------------------------------------------------------+ +//| PaPP_CrossExport.mq5 | +//| PaPP v2 | +//| Esporta in CSV TUTTI gli incroci tra le 9 linee (prezzo+Mediana | +//| +7 MA), calcolati ANCORATI a D1 (come l'indicatore), con il | +//| contesto di ogni incrocio e gli esiti futuri a 1/3/5/10/20 g. | +//| Si puo' esportare un intervallo di date oppure tutto lo storico. | +//+------------------------------------------------------------------+ +#property copyright "PaPP v2" +#property version "1.00" +#property script_show_inputs + +//--- input +input string InpSymbol = ""; // simbolo ("" = simbolo del grafico) +input bool InpAllHistory = true; // true = tutto lo storico D1 +input datetime InpStart = D'2010.01.01'; // inizio intervallo (se AllHistory=false) +input datetime InpEnd = D'2100.01.01'; // fine intervallo (se AllHistory=false) +input string InpFileName = ""; // nome file ("" = automatico) + +//--- costanti (stesse 7 MA dell'indicatore) +#define ANCHOR_TF PERIOD_D1 +#define NSER 9 // PRICE, MED, MA365..MA3 +#define KSLOPE 5 // barre per pendenza / variazione cluster +#define MAXH 20 // orizzonte massimo per gli esiti + +int gDays[7] = {365,182,121,30,14,7,3}; +string SER[NSER]= {"PRICE","MED","MA365","MA182","MA121","MA30","MA14","MA7","MA3"}; +int gHor[5] = {1,3,5,10,20}; + +//+------------------------------------------------------------------+ +int TimeToBarsD1(string sym,int d) + { + datetime n = TimeCurrent(); + if(n==0) return MathMax(1,(int)((long)d*86400L/PeriodSeconds(ANCHOR_TF))); + return MathMax(1,Bars(sym,ANCHOR_TF,n-(long)d*86400,n)); + } + +//+------------------------------------------------------------------+ +double Median7(double &v[]) // mediana dei valori >0 in v[0..6] + { + double a[]; int c=0; ArrayResize(a,7); + for(int m=0;m<7;m++) if(v[m]>0) { a[c]=v[m]; c++; } + if(c==0) return 0; + ArrayResize(a,c); ArraySort(a); + if((c&1)==1) return a[c/2]; + return 0.5*(a[c/2-1]+a[c/2]); + } + +//+------------------------------------------------------------------+ +void OnStart() + { + string sym = (InpSymbol=="") ? _Symbol : InpSymbol; + if(!SymbolSelect(sym,true)) { Print("Simbolo non valido: ",sym); return; } + int digits = (int)SymbolInfoInteger(sym,SYMBOL_DIGITS); + + //--- handle delle 7 MA su D1 + ATR + int hMA[7]; + for(int m=0;m<7;m++) + { + int per = TimeToBarsD1(sym,gDays[m]); + hMA[m] = iMA(sym,ANCHOR_TF,per,0,MODE_SMA,PRICE_CLOSE); + if(hMA[m]==INVALID_HANDLE) { Print("iMA fallita m=",m); return; } + } + int hATR = iATR(sym,ANCHOR_TF,14); + if(hATR==INVALID_HANDLE) { Print("iATR fallita"); return; } + + //--- attendo che lo storico D1 sia pronto + int total=0; + for(int t=0; t<100; t++) + { + total = Bars(sym,ANCHOR_TF); + bool ok = (total>MAXH+KSLOPE+50); + for(int m=0;m<7 && ok;m++) if(BarsCalculated(hMA[m])=total) break; + Sleep(100); + } + total = Bars(sym,ANCHOR_TF); + if(total<=MAXH+KSLOPE+50) { Print("Storico D1 insufficiente: ",total," barre"); return; } + + //--- carico tutta la storia D1 (indice 0 = piu' vecchio) + datetime tm[]; double cl[],hi[],lo[],atr[]; + double ma[7][]; + ArraySetAsSeries(tm,false); ArraySetAsSeries(cl,false); + ArraySetAsSeries(hi,false); ArraySetAsSeries(lo,false); + ArraySetAsSeries(atr,false); + if(CopyTime(sym,ANCHOR_TF,0,total,tm)<=0) { Print("CopyTime KO"); return; } + if(CopyClose(sym,ANCHOR_TF,0,total,cl)<=0) { Print("CopyClose KO"); return; } + if(CopyHigh(sym,ANCHOR_TF,0,total,hi)<=0) { Print("CopyHigh KO"); return; } + if(CopyLow(sym,ANCHOR_TF,0,total,lo)<=0) { Print("CopyLow KO"); return; } + if(CopyBuffer(hATR,0,0,total,atr)<=0) { Print("CopyATR KO"); return; } + for(int m=0;m<7;m++) + { + ArraySetAsSeries(ma[m],false); + if(CopyBuffer(hMA[m],0,0,total,ma[m])<=0) { Print("CopyBuffer MA KO m=",m); return; } + } + int n = ArraySize(cl); + + //--- costruisco le 9 serie allineate per barra: S[i][k] + double S[][NSER]; + ArrayResize(S,n); + for(int i=0;i=from) { iStart=i; break; } + for(int i=n-1;i>=0;i--) if(tm[i]<=to) { iEnd=i; break; } + + //--- apro il file CSV + string fname = (InpFileName=="") ? ("PaPP_crosses_"+sym+"_D1.csv") : InpFileName; + int fh = FileOpen(fname,FILE_WRITE|FILE_TXT|FILE_ANSI); + if(fh==INVALID_HANDLE) { Print("FileOpen KO: ",fname," err=",GetLastError()); return; } + + //--- header + string head = "time,symbol,pair,a,b,dir,price,med,ma365,ma182,ma121,ma30,ma14,ma7,ma3," + "dist_med_pct,cluster_pct,cluster_exp,slope_a,slope_b,trend,atr_pct,dow,month"; + for(int hh=0;hh<5;hh++) + { + string s=IntegerToString(gHor[hh]); + head += ",ret_"+s+",mfe_"+s+",mae_"+s+",dir_"+s+",rev_"+s; + } + head += ",bars_to_revert,disc_max_pct"; + FileWriteString(fh,head+"\r\n"); + + //--- scansione incroci + long rows=0; + for(int i=iStart;i<=iEnd;i++) + { + if(i0)?(price-med)/med*100.0:0; + double cmax=-1, cmin=1e18; + for(int k=2;k0){ if(v>cmax)cmax=v; if(v0 && price>0)?(cmax-cmin)/price*100.0:0; + double cmaxP=-1,cminP=1e18; + for(int k=2;k0){ if(v>cmaxP)cmaxP=v; if(v0)?(cmaxP-cminP)/S[i-KSLOPE][0]*100.0:0; + double cluster_exp = cluster-clusterP; + int trend = (price>ma365 && ma365>0)?1:-1; + double atr_pct = (price>0)?atr[i]/price*100.0:0; + MqlDateTime dt; TimeToStruct(tm[i],dt); + + //--- esito globale: ritorno alla Mediana entro MAXH + int side = (price>med)?1:-1; + int b2rev=-1; double discMax=0; + int jmax = MathMin(i+MAXH,n-1); + for(int j=i+1;j<=jmax;j++) + { + if(S[j][0]<=0 || S[j][1]<=0) continue; + int sj=(S[j][0]>S[j][1])?1:-1; + if(b2rev<0 && sj!=side) b2rev=j-i; + double d=(S[j][0]-S[j][1])/S[j][1]*100.0; + if(MathAbs(d)>MathAbs(discMax)) discMax=d; + } + + //--- controllo ogni coppia (a,b) + for(int a=0;a0) dir=1; else if(d0>=0 && d1<0) dir=-1; + if(dir==0) continue; + + double slope_a = (S[i-KSLOPE][a]>0)?(S[i][a]-S[i-KSLOPE][a])/S[i-KSLOPE][a]*100.0:0; + double slope_b = (S[i-KSLOPE][b]>0)?(S[i][b]-S[i-KSLOPE][b])/S[i-KSLOPE][b]*100.0:0; + double thr = 0.25*atr_pct; + + string row = StringFormat("%s,%s,%sx%s,%s,%s,%d,", + TimeToString(tm[i],TIME_DATE),sym,SER[a],SER[b],SER[a],SER[b],dir); + row += DoubleToString(price,digits)+","+DoubleToString(med,digits)+","; + for(int k=2;kn-1 || S[i][0]<=0) { row += ",,,,,"; continue; } + double ret=(cl[iH]-cl[i])/cl[i]*100.0; + double mxh=-1e18,mnl=1e18; + for(int j=i+1;j<=iH;j++){ if(hi[j]>mxh)mxh=hi[j]; if(lo[j]thr)?1:((ret<-thr)?-1:0); + int rev=(b2rev>0 && b2rev<=h)?1:0; + row += ","+DoubleToString(ret,5)+","+DoubleToString(mfe,5)+"," + +DoubleToString(mae,5)+","+IntegerToString(dlab)+","+IntegerToString(rev); + } + row += ","+(b2rev>0?IntegerToString(b2rev):"")+","+DoubleToString(discMax,5); + FileWriteString(fh,row+"\r\n"); + rows++; + } + if((i%200)==0) Comment(StringFormat("PaPP export: %d/%d barre, %d eventi",i-iStart,iEnd-iStart,(int)rows)); + } + + FileClose(fh); + for(int m=0;m<7;m++) IndicatorRelease(hMA[m]); + IndicatorRelease(hATR); + Comment(""); + PrintFormat("PaPP export COMPLETATO: %d incroci -> %s (cartella MQL5\\Files)",(int)rows,fname); + Print("Periodo: ",TimeToString(tm[iStart])," -> ",TimeToString(tm[iEnd])); + } +//+------------------------------------------------------------------+ From 8e6fe91b70cee7c0ba0bbb97eaadda2b58e669d5 Mon Sep 17 00:00:00 2001 From: Pietro Giacobazzi Date: Tue, 16 Jun 2026 20:15:53 +0000 Subject: [PATCH 2/2] PaPP v2 export: fix compile (array MA 2D non valido in MQL5 -> struct MABuf) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- PaPP v2/PaPP_CrossExport.mq5 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PaPP v2/PaPP_CrossExport.mq5 b/PaPP v2/PaPP_CrossExport.mq5 index 5dcc504..1171fe2 100644 --- a/PaPP v2/PaPP_CrossExport.mq5 +++ b/PaPP v2/PaPP_CrossExport.mq5 @@ -27,6 +27,9 @@ int gDays[7] = {365,182,121,30,14,7,3}; string SER[NSER]= {"PRICE","MED","MA365","MA182","MA121","MA30","MA14","MA7","MA3"}; int gHor[5] = {1,3,5,10,20}; +//--- contenitore per un buffer MA dinamico (MQL5 non permette double ma[7][]) +struct MABuf { double v[]; }; + //+------------------------------------------------------------------+ int TimeToBarsD1(string sym,int d) { @@ -79,7 +82,7 @@ void OnStart() //--- carico tutta la storia D1 (indice 0 = piu' vecchio) datetime tm[]; double cl[],hi[],lo[],atr[]; - double ma[7][]; + MABuf ma[7]; ArraySetAsSeries(tm,false); ArraySetAsSeries(cl,false); ArraySetAsSeries(hi,false); ArraySetAsSeries(lo,false); ArraySetAsSeries(atr,false); @@ -90,8 +93,8 @@ void OnStart() if(CopyBuffer(hATR,0,0,total,atr)<=0) { Print("CopyATR KO"); return; } for(int m=0;m<7;m++) { - ArraySetAsSeries(ma[m],false); - if(CopyBuffer(hMA[m],0,0,total,ma[m])<=0) { Print("CopyBuffer MA KO m=",m); return; } + ArraySetAsSeries(ma[m].v,false); + if(CopyBuffer(hMA[m],0,0,total,ma[m].v)<=0) { Print("CopyBuffer MA KO m=",m); return; } } int n = ArraySize(cl); @@ -101,7 +104,7 @@ void OnStart() for(int i=0;i