PaPP v2 indicatore: descrizione a parole (percentile storico) per Cluster/Velocita'/Accelerazione/Volatilita'

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Pietro Giacobazzi
2026-06-17 06:56:47 +00:00
parent a1023b573e
commit b0012bf2fd
+97 -47
View File
@@ -175,62 +175,107 @@ double MedArr(double &src[],int c)
}
//+------------------------------------------------------------------+
// Velocita'/accelerazione/volatilita' = mediana delle 7 scale (dalle nostre MA, no ATR)
void ScaleMetrics(double &velo,double &acc,double &vol)
// Metriche a una specifica barra D1 (j), calcolate sui buffer gia' copiati mb[7]
double ClusterAtJ(PBuf &mb[],int j)
{
velo=0; acc=0; vol=0;
int need = MathMax(1+2*KSLOPE,1+NVOL)+1;
double va[7],aa[7],wa[7]; int cv=0,ca=0,cw=0;
double v[7]; int c=0;
for(int m=0;m<7;m++){ double x=mb[m].v[j]; if(IsVal(x)) v[c++]=x; }
if(c<2) return 0;
double md=MedArr(v,c); if(md<=0) return 0;
double ds=0; for(int m=0;m<c;m++) ds+=MathAbs(v[m]-md)/md*100.0;
return ds/c;
}
double VelAtJ(PBuf &mb[],int j,int K)
{
double v[7]; int c=0;
for(int m=0;m<7;m++){ double a=mb[m].v[j], b=mb[m].v[j+K]; if(IsVal(a)&&IsVal(b)) v[c++]=(a-b)/b*100.0; }
return MedArr(v,c);
}
double AccAtJ(PBuf &mb[],int j,int K)
{
double v[7]; int c=0;
for(int m=0;m<7;m++){ double a=mb[m].v[j], b=mb[m].v[j+K], d=mb[m].v[j+2*K];
if(IsVal(a)&&IsVal(b)&&IsVal(d)) v[c++]=(a-2.0*b+d)/d*100.0; }
return MedArr(v,c);
}
double VolAtJ(PBuf &mb[],int j,int N)
{
double v[7]; int c=0;
for(int m=0;m<7;m++)
{
double b[]; ArraySetAsSeries(b,true);
if(CopyBuffer(hMA[m],0,0,need,b)!=need) continue;
double x1=b[1], xK=b[1+KSLOPE], x2K=b[1+2*KSLOPE];
if(IsVal(x1)&&IsVal(xK)) va[cv++]=(x1-xK)/xK*100.0;
if(IsVal(x1)&&IsVal(xK)&&IsVal(x2K)) aa[ca++]=(x1-2.0*xK+x2K)/x2K*100.0;
double r[]; int rc=0; ArrayResize(r,NVOL);
for(int t=1;t<=NVOL;t++)
{ double a=b[t], bb=b[t+1]; if(IsVal(a)&&IsVal(bb)) r[rc++]=(a-bb)/bb*100.0; }
double r[]; int rc=0; ArrayResize(r,N);
for(int t=j;t<j+N;t++){ double a=mb[m].v[t], b=mb[m].v[t+1]; if(IsVal(a)&&IsVal(b)) r[rc++]=(a-b)/b*100.0; }
if(rc>=2)
{
double mean=0; for(int j=0;j<rc;j++) mean+=r[j]; mean/=rc;
double s=0; for(int j=0;j<rc;j++){ double dd=r[j]-mean; s+=dd*dd; }
wa[cw++]=MathSqrt(s/(rc-1));
double mn=0; for(int q=0;q<rc;q++) mn+=r[q]; mn/=rc;
double s=0; for(int q=0;q<rc;q++){ double dd=r[q]-mn; s+=dd*dd; }
v[c++]=MathSqrt(s/(rc-1));
}
}
velo=MedArr(va,cv); acc=MedArr(aa,ca); vol=MedArr(wa,cw);
return MedArr(v,c);
}
//+------------------------------------------------------------------+
// Contestualizza il cluster: percentile dell'ampiezza attuale sugli ultimi 'win' giorni D1
// cur = cluster oggi, pctl = posizione 0..1 nella storia, typ = ampiezza tipica (mediana storica)
void ClusterStats(int win,double &cur,double &pctl,double &typ)
// percentile (0..1) di cur fra i primi cc valori di arr
double PctlOf(double &arr[],int cc,double cur)
{
cur=0; pctl=0.5; typ=0;
int need=win+1;
if(cc<=0) return 0.5;
int b=0; for(int k=0;k<cc;k++) if(arr[k]<=cur) b++;
return (double)b/cc;
}
//+------------------------------------------------------------------+
// Valori correnti + percentile storico (win giorni D1) di cluster/velocita'/accel/volatilita'
// per i segnali con segno (vel/acc) il percentile e' calcolato sul VALORE ASSOLUTO (forza)
void AllMetrics(int win,
double &cluCur,double &cluPct,
double &velCur,double &velPct,
double &accCur,double &accPct,
double &volCur,double &volPct)
{
cluCur=velCur=accCur=volCur=0; cluPct=volPct=0.5; velPct=accPct=0;
int ext = MathMax(2*KSLOPE,NVOL+1);
int need = win+ext+2;
PBuf mb[7];
for(int m=0;m<7;m++)
{
ArraySetAsSeries(mb[m].v,true);
if(CopyBuffer(hMA[m],0,0,need,mb[m].v)!=need) return;
}
double cl[]; int cc=0; ArrayResize(cl,win);
double cA[],vA[],aA[],oA[]; int cc=0,vc=0,ac=0,oc=0;
ArrayResize(cA,win); ArrayResize(vA,win); ArrayResize(aA,win); ArrayResize(oA,win);
for(int j=1;j<=win;j++)
{
double vals[7]; int vc=0;
for(int m=0;m<7;m++){ double v=mb[m].v[j]; if(IsVal(v)) vals[vc++]=v; }
if(vc<2) continue;
double md=MedArr(vals,vc);
if(md<=0) continue;
double ds=0;
for(int m=0;m<vc;m++) ds+=MathAbs(vals[m]-md)/md*100.0;
cl[cc++]=ds/vc;
double cv=ClusterAtJ(mb,j); if(cv>0) cA[cc++]=cv;
vA[vc++]=MathAbs(VelAtJ(mb,j,KSLOPE));
aA[ac++]=MathAbs(AccAtJ(mb,j,KSLOPE));
double ov=VolAtJ(mb,j,NVOL); if(ov>0) oA[oc++]=ov;
}
if(cc<=0) return;
cur=cl[0]; // j=1 = ultima barra D1 chiusa
typ=MedArr(cl,cc);
int below=0; for(int k=0;k<cc;k++) if(cl[k]<=cur) below++;
pctl=(double)below/cc;
cluCur=ClusterAtJ(mb,1); velCur=VelAtJ(mb,1,KSLOPE);
accCur=AccAtJ(mb,1,KSLOPE); volCur=VolAtJ(mb,1,NVOL);
cluPct=PctlOf(cA,cc,cluCur);
volPct=PctlOf(oA,oc,volCur);
velPct=PctlOf(vA,vc,MathAbs(velCur)); // forza (su |valore|)
accPct=PctlOf(aA,ac,MathAbs(accCur));
}
//+------------------------------------------------------------------+
// descrizione a parole per una grandezza di sola ampiezza (cluster, volatilita')
string MagWord(double pct,string w0,string w1,string w2,string w3,string w4)
{
if(pct<0.20) return w0;
if(pct<0.40) return w1;
if(pct<0.60) return w2;
if(pct<0.80) return w3;
return w4;
}
//+------------------------------------------------------------------+
// descrizione a parole per un segnale con segno (velocita', accelerazione)
string DirWord(double val,double absPct,string up,string down,string flat)
{
if(absPct<0.15) return flat;
string forza = (absPct<0.40)?"lieve":((absPct<0.70)?"moderata":"forte");
return (val>0?up:down)+" "+forza;
}
//+------------------------------------------------------------------+
@@ -377,18 +422,23 @@ void DrawInfo()
Lbl("M","Median: "+DoubleToString(median,_Digits),x,y,FontSize,clrGold,false); y+=lh;
Lbl("D","Dist: "+distS,x,y,FontSize,distC,true); y+=lh+2;
//--- Cluster contestualizzato: valore + percentile storico (stretto/normale/largo)
double clu_cur,clu_pctl,clu_typ; ClusterStats(CLWIN,clu_cur,clu_pctl,clu_typ);
string clab = (clu_pctl<0.33)?"stretto":((clu_pctl>0.66)?"largo":"normale");
color cclr = (clu_pctl<0.33)?clrLimeGreen:((clu_pctl>0.66)?clrTomato:clrSilver);
Lbl("V",StringFormat("Cluster %.3f%% P%.0f %s (tip %.3f%%)",clu_cur,clu_pctl*100,clab,clu_typ),
x,y,FontSize,cclr,false); y+=lh;
//--- Cluster/Velocita'/Accelerazione/Volatilita' con percentile storico + descrizione a parole
double cluCur,cluPct,velCur,velPct,accCur,accPct,volCur,volPct;
AllMetrics(CLWIN,cluCur,cluPct,velCur,velPct,accCur,accPct,volCur,volPct);
//--- Velocita'/Accelerazione/Volatilita' = mediana delle 7 scale (dalle nostre MA)
double velo,acc,volat; ScaleMetrics(velo,acc,volat);
Lbl("VEL",StringFormat("Velocita' %dg: %+.3f%%",KSLOPE,velo),x,y,FontSize,(velo>0)?clrLimeGreen:clrTomato,false); y+=lh;
Lbl("ACC",StringFormat("Accel %dg: %+.4f%%",KSLOPE,acc),x,y,FontSize,(acc>0)?clrLimeGreen:clrTomato,false); y+=lh;
Lbl("VOL",StringFormat("Volatilita' %dg: %.4f%%",NVOL,volat),x,y,FontSize,clrAqua,false); y+=lh+2;
string cluTxt = MagWord(cluPct,"molto stretto","stretto","normale","largo","molto largo");
color cluC = (cluPct<0.40)?clrLimeGreen:((cluPct>0.60)?clrTomato:clrSilver);
Lbl("V",StringFormat("Cluster %.3f%% - %s (P%.0f)",cluCur,cluTxt,cluPct*100),x,y,FontSize,cluC,false); y+=lh;
string velTxt = DirWord(velCur,velPct,"in salita","in discesa","quasi piatta");
Lbl("VEL",StringFormat("Velocita' %+.3f%% - %s",velCur,velTxt),x,y,FontSize,(velCur>0)?clrLimeGreen:clrTomato,false); y+=lh;
string accTxt = DirWord(accCur,accPct,"in accelerazione","in decelerazione","stabile");
Lbl("ACC",StringFormat("Accel %+.4f%% - %s",accCur,accTxt),x,y,FontSize,(accCur>0)?clrLimeGreen:clrTomato,false); y+=lh;
string volTxt = MagWord(volPct,"molto bassa","bassa","normale","alta","molto alta");
color volC = (volPct<0.40)?clrLimeGreen:((volPct>0.60)?clrTomato:clrAqua);
Lbl("VOL",StringFormat("Volatilita' %.4f%% - %s (P%.0f)",volCur,volTxt,volPct*100),x,y,FontSize,volC,false); y+=lh+2;
//--- Valori delle 7 MA (giorni : valore) con colore = linea
for(int m=0;m<7;m++)