// Downloaded From https://www.WiseStockTrader.com
// AFL code by Edward Pottasch, Dec 2012
// Bullish + Bearish Head and Shoulder pattern

function swap_func(arrayin)
{
	arrayout=Null;
	for(i=0;i<BarCount;i++)
	{
		arrayout[i]=arrayin[BarCount-i-1];
	}
	return arrayout;
}

xx=BarIndex();x=xx;Lx=LastValue(x);
nbar=Param("N Pivot Bars",5,2,50,1); 
tf=Param("Time Frame (min)",5,1,100000,1);tfrm=in1Minute*tf;
atrfac=Param("ATR tolerance factor (Shoulders)",1.5,0,50,0.01); 
atrfac2=Param("ATR tolerance factor (Head)",0.1,0,50,0.01); 
CleanPivots=ParamToggle("Use Clean Pivots","Off|On",1);
PivotSymmetry=ParamToggle("Use Symmetric Pivots","Off|On",0);
dispbeHS=ParamToggle("Display bearish HS","Off|On",1);
dispbuHS=ParamToggle("Display bullish HS","Off|On",1);
extendN=Param("Extension neckline (bars)",100,0,500,1); 
validSignalRangeCheck=ParamToggle("Signal Validity Range Check","Off|On",1);

TimeFrameSet(tfrm); 
atra=ATR(20)*atrfac;
if(PivotSymmetry)
{
	fc=1;
	pk=H>Ref(HHV(H,nbar*fc),-1) AND Ref(HHV(H,nbar),nbar)<=H;
	tr=L<Ref(LLV(L,nbar*fc),-1) AND Ref(LLV(L,nbar),nbar)>=L;
}
else
{
	fc=2;
	pk=H>Ref(HHV(H,nbar*fc),-1) AND Ref(HHV(H,nbar),nbar)<=H;
	tr=L<Ref(LLV(L,nbar*fc),-1) AND Ref(LLV(L,nbar),nbar)>=L;
}

px0=ValueWhen(pk,x,0); tx0=ValueWhen(tr,x,0);
px1=ValueWhen(pk,x,1); tx1=ValueWhen(tr,x,1);
px2=ValueWhen(pk,x,2); tx2=ValueWhen(tr,x,2);
px3=ValueWhen(pk,x,3); tx3=ValueWhen(tr,x,3);
ph0=ValueWhen(pk,H,0); tl0=ValueWhen(tr,L,0);
ph1=ValueWhen(pk,H,1); tl1=ValueWhen(tr,L,1);
ph2=ValueWhen(pk,H,2); tl2=ValueWhen(tr,L,2);
ph3=ValueWhen(pk,H,3); tl3=ValueWhen(tr,L,3);

if(CleanPivots)
{
	tr=IIf((tr==1 AND pk==1) AND px2<tx2,False,tr);
	pk=IIf((tr==1 AND pk==1) AND px2>tx2,False,pk);

	px0=ValueWhen(pk,x,0); tx0=ValueWhen(tr,x,0);
	px1=ValueWhen(pk,x,1); tx1=ValueWhen(tr,x,1);
	px2=ValueWhen(pk,x,2); tx2=ValueWhen(tr,x,2);
	px3=ValueWhen(pk,x,3); tx3=ValueWhen(tr,x,3);	
	ph0=ValueWhen(pk,H,0); tl0=ValueWhen(tr,L,0);
	ph1=ValueWhen(pk,H,1); tl1=ValueWhen(tr,L,1);
	ph2=ValueWhen(pk,H,2); tl2=ValueWhen(tr,L,2);
	ph3=ValueWhen(pk,H,3); tl3=ValueWhen(tr,L,3);	
	
	tr=IIf(tr AND ((tx0<px0 AND tl1>tl0) OR (tx2>px1 AND tl1>=tl2) OR (px0==px1 AND tl1>tl0)),False,tr);
	pk=IIf(pk AND ((px0<tx0 AND ph1<ph0) OR (px2>tx1 AND ph1<=ph2) OR (tx0==tx1 AND ph1<ph0)),False,pk);

	px0=ValueWhen(pk,x,0); tx0=ValueWhen(tr,x,0);
	px1=ValueWhen(pk,x,1); tx1=ValueWhen(tr,x,1);
	px2=ValueWhen(pk,x,2); tx2=ValueWhen(tr,x,2);
	px3=ValueWhen(pk,x,3); tx3=ValueWhen(tr,x,3);
	ph0=ValueWhen(pk,H,0); tl0=ValueWhen(tr,L,0);
	ph1=ValueWhen(pk,H,1); tl1=ValueWhen(tr,L,1);
	ph2=ValueWhen(pk,H,2); tl2=ValueWhen(tr,L,2);
	ph3=ValueWhen(pk,H,3); tl3=ValueWhen(tr,L,3);	

	tr=IIf(tr AND ((tx0<px0 AND tl1>tl0) OR (tx2>px1 AND tl1>=tl2) OR (px0==px1 AND tl1>tl0)),False,tr);
	pk=IIf(pk AND ((px0<tx0 AND ph1<ph0) OR (px2>tx1 AND ph1<=ph2) OR (tx0==tx1 AND ph1<ph0)),False,pk);

	px0=ValueWhen(pk,x,0); tx0=ValueWhen(tr,x,0);
	px1=ValueWhen(pk,x,1); tx1=ValueWhen(tr,x,1);
	px2=ValueWhen(pk,x,2); tx2=ValueWhen(tr,x,2);
	px3=ValueWhen(pk,x,3); tx3=ValueWhen(tr,x,3);
	ph0=ValueWhen(pk,H,0); tl0=ValueWhen(tr,L,0);
	ph1=ValueWhen(pk,H,1); tl1=ValueWhen(tr,L,1);
	ph2=ValueWhen(pk,H,2); tl2=ValueWhen(tr,L,2);
	ph3=ValueWhen(pk,H,3); tl3=ValueWhen(tr,L,3);	
}
pkh=IIf(pk,H,Null);
trl=IIf(tr,L,Null);
TimeFrameRestore();
fact=Max(tfrm/60,Interval()/60)/(Interval()/60);
Lkbk=tfrm/Interval();
if(Lkbk>1)
{
	pk=TimeFrameExpand(pk,tfrm,expandFirst);
	pkh=TimeFrameExpand(pkh,tfrm,expandFirst);
	pkhs=IIf(!IsEmpty(pkh),1,0);pkhs=pkhs-Ref(pkhs,-1);
	pk=pk AND H==pkh;
	cond1=Sum(pk,BarsSince(pkhs==1)+1)==1 AND pk;
	pk=pk AND cond1;
	
	tr=TimeFrameExpand(tr,tfrm,expandFirst);	
	trl=TimeFrameExpand(trl,tfrm,expandFirst);
	trls=IIf(!IsEmpty(trl),1,0);trls=trls-Ref(trls,-1);
	tr=tr AND L==trl;
	cond1=Sum(tr,BarsSince(trls==1)+1)==1 AND tr;
	tr=tr AND cond1;
	
	px0=ValueWhen(pk,x,0); tx0=ValueWhen(tr,x,0);
	px1=ValueWhen(pk,x,1); tx1=ValueWhen(tr,x,1);
	px2=ValueWhen(pk,x,2); tx2=ValueWhen(tr,x,2);
	px3=ValueWhen(pk,x,3); tx3=ValueWhen(tr,x,3);
	ph0=ValueWhen(pk,H,0); tl0=ValueWhen(tr,L,0);
	ph1=ValueWhen(pk,H,1); tl1=ValueWhen(tr,L,1);
	ph2=ValueWhen(pk,H,2); tl2=ValueWhen(tr,L,2);
	ph3=ValueWhen(pk,H,3); tl3=ValueWhen(tr,L,3);
	
	atra=TimeFrameExpand(atra,tfrm,expandFirst);
}
ll=tr AND tl1<tl2;
hl=tr AND tl1>tl2;
hh=pk AND ph1>ph2;
lh=pk AND ph1<ph2;
dt=pk AND ph1==ph2;
db=tr AND tl1==tl2;

ll_h=IIf(ll,1,0);
hl_h=IIf(hl,2,0);
hh_h=IIf(hh,3,0);
lh_h=IIf(lh,4,0);
dt_h=IIf(dt,5,0);
db_h=IIf(db,6,0);

combi=ll_h+hl_h+lh_h+hh_h+dt_h+db_h;

t0=ValueWhen(combi,combi,0);
t1=ValueWhen(combi,combi,1);
t2=ValueWhen(combi,combi,2);
t3=ValueWhen(combi,combi,3);
t4=ValueWhen(combi,combi,4);
t5=ValueWhen(combi,combi,5);

// bearisch pattern
beHS=pk AND t1==4 AND (t2==1 OR t2==2) AND t3==3 AND t4==2 AND (t5==3 OR t5==4)
AND abs(tl1-tl2)<atra*atrfac AND abs(ph1-ph3)<atra*atrfac AND ph2>(ph1+ph3)/2 AND ph2>(Max(ph1,ph3)+atra*atrfac2);
beAx=ValueWhen(beHS,px3);beAy=ValueWhen(beHS,ph3);
beBx=ValueWhen(beHS,tx2);beBy=ValueWhen(beHS,tl2);
beCx=ValueWhen(beHS,px2);beCy=ValueWhen(beHS,ph2);
beDx=ValueWhen(beHS,tx1);beDy=ValueWhen(beHS,tl1);
beEx=ValueWhen(beHS,px1);beEy=ValueWhen(beHS,ph1);
beFx=ValueWhen(beHS,px1);aa=(beDy-beBy)/(beDx-beBx);bb=beDy;ii=px1-beDx;beFy=aa*ii+bb;
rr=BarsSince(beHS)>=0 AND BarsSince(beHS)<extendN;
idx=IIf(rr,xx-ValueWhen(beHS,beDx),Null);
beNeckline=IIf(idx,aa*idx+bb,Null);
beValidSignalArea=Flip(Ref(beHS,-1),pk);
if(validSignalRangeCheck) beNeckline=IIf(beValidSignalArea,beNeckline,Null);

// bullish pattern
buHS=tr AND t1==2 AND (t2==3 OR t2==4) AND t3==1 AND t4==4 AND (t5==1 OR t5==2)
AND abs(ph1-ph2)<atra*atrfac AND abs(tl1-tl3)<atra*atrfac AND tl2<(tl1+tl3)/2 AND tl2<(Max(tl1,tl3)-atra*atrfac2); 
buAx=ValueWhen(buHS,tx3);buAy=ValueWhen(buHS,tl3);
buBx=ValueWhen(buHS,px2);buBy=ValueWhen(buHS,ph2);
buCx=ValueWhen(buHS,tx2);buCy=ValueWhen(buHS,tl2);
buDx=ValueWhen(buHS,px1);buDy=ValueWhen(buHS,ph1);
buEx=ValueWhen(buHS,tx1);buEy=ValueWhen(buHS,tl1);
buFx=ValueWhen(buHS,tx1);aa=(buDy-buBy)/(buDx-buBx);bb=buDy;ii=tx1-buDx;buFy=aa*ii+bb;
rr=BarsSince(buHS)>=0 AND BarsSince(buHS)<extendN;
idx=IIf(rr,xx-ValueWhen(buHS,buDx),Null);
buNeckline=IIf(idx,aa*idx+bb,Null);
buValidSignalArea=Flip(Ref(buHS,-1),tr);
if(validSignalRangeCheck) buNeckline=IIf(buValidSignalArea,buNeckline,Null);

SetChartBkColor(ColorRGB(0,0,0));
SetChartOptions(0,chartShowDates);
SetBarFillColor(IIf(C>O,colorGreen,IIf(C<=O,colorRed,colorLightGrey)));
Plot(C,"Price",IIf(C>O,colorDarkGreen,IIf(C<=O,colorDarkRed,colorLightGrey)),64,0,0,0,0);
Plot(pkh,"",colorRed,styleThick,0,0,0,-1);
Plot(trl,"",colorBrightGreen,styleThick,0,0,0,-1);	
PlotShapes(shapeSmallCircle*tr,IIf(Lx-ValueWhen(tr,x)>nbar*fact,ColorRGB(0,100,0),colorWhite),0,L,-10);
PlotShapes(shapeSmallCircle*pk,IIf(Lx-ValueWhen(pk,x)>nbar*fact,ColorRGB(255,0,0),colorWhite),0,H,10);
Plot(beNeckline,"",colorYellow,styleLine,0,0,0,0,2);
Plot(buNeckline,"",colorYellow,styleLine,0,0,0,0,2);

Buy=Cross(C,buNeckline) AND !IsEmpty(buNeckline);Buy=Ref(Buy,-1);BuyPrice=O;
Buy=ExRem(Buy,buHS);
PlotShapes(IIf(Buy,shapeUpArrow,shapeNone),colorDarkGreen,0,L,-15);
PlotShapes(IIf(Buy,shapeSmallCircle,shapeNone),colorWhite,0,BuyPrice,0);
Short=Cross(beNeckline,C) AND !IsEmpty(beNeckline);Short=Ref(Short,-1);ShortPrice=O;
Short=ExRem(Short,beHS);
PlotShapes(IIf(Short,shapeSmallDownTriangle,shapeNone),colorRed,0,H,-15);
PlotShapes(IIf(Short,shapeSmallCircle,shapeNone),colorWhite,0,ShortPrice,0);

qq=Interval()/60;
if(qq < 60){tf=" min";tt=qq;}
else if(qq >= 60 AND qq < 1440){tf=" hrs";tt=qq/60;}
else if(qq >= 1440){tf=" days";tt=(qq/60)/24;}
qq=Max(tfrm/60,Interval()/60);
if(qq < 60){tfa=" min";tta=qq;}
else if(qq >= 60 AND qq < 1440){tfa=" hrs";tta=qq/60;}
else if(qq >= 1440){tfa=" days";tta=(qq/60)/24;}

Title = Name() + 
"\nNbar: " + nbar + 
"\nChart TF: " + tt + tf + 
"\nTrend TF: " + tta + tfa;

abcdy_up=20;
abcdy_dn=28;
function GetVisibleBarCount() 
{
	lvb=Status("lastvisiblebar");
	fvb=Status("firstvisiblebar");
	return Min(lvb-fvb,BarCount-fvb);
} 
function GfxConvertPixelsToBarX(Pixels)
{
	lvb=Status("lastvisiblebar");
	fvb=Status("firstvisiblebar");
	pxchartleft=Status("pxchartleft");
	pxchartwidth=Status("pxchartwidth");
	fac=pxchartwidth/Pixels;
	bar=(lvb-fvb)/fac;
	return bar;
} 
function GfxConvertPixelToValueY(Pixels) 
{
	local Miny,Maxy,pxchartbottom,pxchartheight;
	Miny=Status("axisminy");
	Maxy=Status("axismaxy");
	pxchartbottom=Status("pxchartbottom");
	pxchartheight=Status("pxchartheight");
	fac=pxchartheight/Pixels;
	Value=(Maxy-Miny)/fac;
	return Value;
} 

AllVisibleBars=GetVisibleBarCount();
fvb=Status("firstvisiblebar");
abcdy_up=GfxConvertPixelToValueY(abcdy_up);
abcdy_dn=GfxConvertPixelToValueY(abcdy_dn);
for(i=0;i<AllVisibleBars;i++) 
{
	if(beHS[i+fvb] AND dispbeHS)
	{
		clr=colorRed;
		lvix=i+fvb;
		Plot(LineArray(beAx[lvix],beAy[lvix],beBx[lvix],beBy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(beBx[lvix],beBy[lvix],beCx[lvix],beCy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(beCx[lvix],beCy[lvix],beDx[lvix],beDy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(beDx[lvix],beDy[lvix],beEx[lvix],beEy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(beDx[lvix],beDy[lvix],beFx[lvix],beFy[lvix],0,True ),"",clr,styleDashed);
		Plot(LineArray(beBx[lvix],beBy[lvix],beDx[lvix],beDy[lvix],0,True ),"",clr,styleDashed);
		PlotText("S1",beAx[lvix]-1,beAy[lvix]+abcdy_up,colorRed,colorDefault); 
		PlotText("H",beCx[lvix]-1,beCy[lvix]+abcdy_up,colorRed,colorDefault); 
		PlotText("S2",beEx[lvix]-1,beEy[lvix]+abcdy_up,colorRed,colorDefault);
	}
	if(buHS[i+fvb] AND dispbuHS)
	{
		clr=colorGreen;
		lvix=i+fvb;
		Plot(LineArray(buAx[lvix],buAy[lvix],buBx[lvix],buBy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(buBx[lvix],buBy[lvix],buCx[lvix],buCy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(buCx[lvix],buCy[lvix],buDx[lvix],buDy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(buDx[lvix],buDy[lvix],buEx[lvix],buEy[lvix],0,True ),"",clr,styleThick);
		Plot(LineArray(buDx[lvix],buDy[lvix],buFx[lvix],buFy[lvix],0,True ),"",clr,styleDashed);
		Plot(LineArray(buBx[lvix],buBy[lvix],buDx[lvix],buDy[lvix],0,True ),"",clr,styleDashed);
		PlotText("S1",buAx[lvix]-1,buAy[lvix]-abcdy_dn,colorGreen,colorDefault); 
		PlotText("H",buCx[lvix]-1,buCy[lvix]-abcdy_dn,colorGreen,colorDefault); 
		PlotText("S2",buEx[lvix]-1,buEy[lvix]-abcdy_dn,colorGreen,colorDefault);
	}	
}