#include "sierrachart.h"
int myDCPeriod(SCStudyGraphRef sc, SCFloatArrayRef Price, int i);
float percentile(SCStudyGraphRef sc, SCFloatArrayRef In, SCFloatArrayRef Out, int numBars, int pos, float Pct);
int compare (const void *a, const void *b);

#define FALSE 0
#define TRUE 1
#define LONG 1
#define SHORT -1
#define GREEN RGB(0,255,0)
#define DKGREEN RGB(0,128,0)
#define YELLOW RGB(255,255,0)
#define LTYELLOW RGB(255,255,128)
#define RED RGB(255,0,0)
#define DKRED RGB(198,0,0)
#define BLACK RGB(0,0,1)
#define WHITE RGB(255,255,255)
#define CYAN RGB(0,255,255)
#define PURPLE RGB(255,0,255)
#define GREY RGB(192,192,192)
#define BLUE RGB(0,0,255)
#define ORANGE RGB(255, 127, 0)
#define DRKBLUE RGB(0, 0, 127)

SCDLLName("Adaptive Moving Percentile 2"); 
SCSFExport scsf_AdaptiveMovingPercentile(SCStudyGraphRef sc)
{

	SCSubgraphRef SGPercentile0	= 		sc.Subgraph[0];
	SCSubgraphRef SGPercentile1	= 		sc.Subgraph[1];
	SCSubgraphRef SGPercentile2	= 		sc.Subgraph[2];
	SCSubgraphRef SGPercentile3	= 		sc.Subgraph[3];
	SCSubgraphRef SGPercentile4	= 		sc.Subgraph[4];
	SCSubgraphRef   p01         =         sc.Subgraph[5];
	
	SCInputRef INlength 		= 		sc.Input[0];
	SCInputRef INperiod			= 		sc.Input[1];
	SCInputRef INadaptive		= 		sc.Input[2];
	SCInputRef INPCT			=		sc.Input[3];
	SCInputRef Study1Ref        =       sc.Input[4];
	SCInputRef MINMOV        =       sc.Input[5];
    SCInputRef DIST       =       sc.Input[6];
	

	if (sc.SetDefaults)
	{
		// Set the configuration and defaults
		
		sc.GraphName = "Adaptive Moving Percentile";
		
		sc.StudyDescription = "This study calculates the Moving Percentile. Lengths are Adaptive or Manual";
		sc.MaintainAdditionalChartDataArrays=1;            

        sc.DrawZeros = 0;
        sc.AutoLoop = 1;
        sc.GraphRegion = 0;
		sc.FreeDLL=1; // 1 = dll is freed up, this allows debugging. Change back to 0 when code is complete	
		
		SGPercentile0.Name = "Percentile1";
	    SGPercentile0.DrawStyle = DRAWSTYLE_LINE;
        SGPercentile0.LineWidth = 1;
        SGPercentile0.PrimaryColor = GREEN;
        SGPercentile0.SecondaryColor = RED;

		INlength.Name = "Input Data";
		INlength.SetInputDataIndex(SC_LAST);
		
		INperiod.Name = "Length";
		INperiod.SetInt(11);
		INperiod.SetIntLimits(1, 1000);

		INadaptive.Name = "Adaptive Period? (1-Yes,0-No)?";
		INadaptive.SetInt(1);
        INadaptive.SetIntLimits(0,1);
		
		INPCT.Name = "Percentile - 50 is median";
        INPCT.SetFloat(50.0f);
        INPCT.SetFloatLimits(0.05f,99.95f);

		Study1Ref.Name = "Study 1 Value";
		Study1Ref.SetStudySubgraphValues(1000000,1);
		
		MINMOV.Name= " minimum moving of zz";
		MINMOV.SetFloat(0.21f);
		
		DIST.Name= " distance between price and adaptive percentile";
		DIST.SetFloat(0.2f);		
		return;
	}
    int Length= INperiod.GetInt();
	int Length1,Length2;
	float Length3,Length4,zzvalue,zzmov,lowp,highp,vdiff;					
	
	int adaptive 				= INadaptive.GetInt();	
	float PCT	 				= INPCT.GetFloat();	
     zzmov=MINMOV.GetFloat();
	
	        	SCFloatArray line1;			
	         sc.GetStudyArrayUsingID(Study1Ref.GetStudyID(), Study1Ref.GetSubgraphIndex(), line1);
			 zzvalue=fabs(line1[sc.Index]);
	
	SCFloatArrayRef Price 		= sc.Subgraph[0].Arrays[0];
	SCFloatArrayRef PriceHL		= sc.Subgraph[0].Arrays[1];
	SCFloatArrayRef Temp 		= sc.Subgraph[0].Arrays[2];
	SCFloatArrayRef Out 		= sc.Subgraph[0].Arrays[3];	
	
	Price[sc.Index]= sc.BaseData[INlength.GetInputDataIndex()][sc.Index];
	PriceHL[sc.Index]= sc.BaseData[INlength.GetInputDataIndex()][sc.Index];
	
	if (adaptive == 1)	
	{
	Length = myDCPeriod(sc, PriceHL, sc.Index);
	}
	
	else 
	{
	Length = INperiod.GetInt();
	}

	sc.DataStartIndex = Length+10;
	SGPercentile0[sc.Index] = percentile(sc, Price, Out, Length, sc.Index, PCT);
	
	          // check if close is up or down
		 if (sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_CLOSED)
	        {
			if(sc.BaseData[SC_RENKO_CLOSE][sc.Index]>sc.BaseData[SC_RENKO_OPEN][sc.Index])   // high bar
			{
		    if (sc.BaseData[SC_RENKO_OPEN][sc.Index]>sc.BaseData[SC_LOW][sc.Index])
			{
                lowp=sc.BaseData[SC_LOW][sc.Index] ;
                highp=sc.BaseData[SC_HIGH][sc.Index];
			}
			else 
			if (sc.BaseData[SC_RENKO_OPEN][sc.Index]<sc.BaseData[SC_LOW][sc.Index])
			{
                lowp=sc.BaseData[SC_RENKO_OPEN][sc.Index];
                highp=sc.BaseData[SC_HIGH][sc.Index];
			}
            }
			
			else                                                                 
			
			if(sc.BaseData[SC_RENKO_CLOSE][sc.Index]<sc.BaseData[SC_RENKO_OPEN][sc.Index])  // low bar
			{
		    if (sc.BaseData[SC_RENKO_OPEN][sc.Index]>sc.BaseData[SC_HIGH][sc.Index])
			{
                lowp=sc.BaseData[SC_LOW][sc.Index] ;
                highp=sc.BaseData[SC_RENKO_OPEN][sc.Index];
			}
			else 
			if (sc.BaseData[SC_RENKO_OPEN][sc.Index]<sc.BaseData[SC_HIGH][sc.Index])
			{
                lowp=sc.BaseData[SC_LOW][sc.Index];
                highp=sc.BaseData[SC_HIGH][sc.Index];
			}
            }			
			}
			
			
			
	 
	 if (sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_CLOSED)
 {
	    
	 if (zzvalue>=zzmov ) // price moving  #ticks required 
	{
	 if ( SGPercentile0[sc.Index]< sc.BaseData[SC_RENKO_CLOSE][sc.Index])
	 {
	     if ( sc.BaseData[SC_RENKO_CLOSE][sc.Index]-SGPercentile0[sc.Index]>DIST.GetFloat()) // price above adaptive percentile #ticks
		 {
		 vdiff=(sc.BaseData[SC_RENKO_CLOSE][sc.Index]-SGPercentile0[sc.Index])-DIST.GetFloat();
		 SGPercentile0[sc.Index]=SGPercentile0[sc.Index]+vdiff; 
		 }
     }
	 
	 if ( SGPercentile0[sc.Index]> sc.BaseData[SC_RENKO_CLOSE][sc.Index])
	 {
	     if (SGPercentile0[sc.Index]- sc.BaseData[SC_RENKO_CLOSE][sc.Index]>DIST.GetFloat())      // price below adaptive percentile #ticks
		 {
		 vdiff=(SGPercentile0[sc.Index]- sc.BaseData[SC_RENKO_CLOSE][sc.Index])-DIST.GetFloat();
		 SGPercentile0[sc.Index]=SGPercentile0[sc.Index]-vdiff; 
		 }
     }	 
	 
    }
	else
	{
	SGPercentile0[sc.Index]=SGPercentile0[sc.Index-1];             // price doesn't move #ticks required
	}
  } 	
}
int myDCPeriod(SCStudyGraphRef sc, SCFloatArrayRef Price, int i)
{
	// John Ehlers Dominant Cycle code for SC
	 SCFloatArrayRef Phase = 			sc.Subgraph[22].Arrays[1];
	 SCFloatArrayRef MAMA =				sc.Subgraph[22].Arrays[2];
	 SCFloatArrayRef FAMA =				sc.Subgraph[22].Arrays[3];
	 SCFloatArrayRef Smooth =			sc.Subgraph[22].Arrays[4];
	 SCFloatArrayRef Detrender =		sc.Subgraph[22].Arrays[5];
	 SCFloatArrayRef Q1	=				sc.Subgraph[22].Arrays[6];
	 SCFloatArrayRef I1 =				sc.Subgraph[22].Arrays[7];
	 SCFloatArrayRef jI =				sc.Subgraph[23].Arrays[0];
	 SCFloatArrayRef jQ =				sc.Subgraph[23].Arrays[1];
	 SCFloatArrayRef I2 =				sc.Subgraph[23].Arrays[2];
	 SCFloatArrayRef Q2 = 				sc.Subgraph[23].Arrays[3];
	 SCFloatArrayRef Re =				sc.Subgraph[23].Arrays[4];
	 SCFloatArrayRef Im =				sc.Subgraph[23].Arrays[5];
	 SCFloatArrayRef Period =			sc.Subgraph[23].Arrays[6];
	 SCFloatArrayRef SmoothPeriod =		sc.Subgraph[23].Arrays[7];	
	// smooth
	Smooth[i] = (4*Price[i] + 3*Price[i-1] + 2*Price[i-2] + Price[i-3])/10; 		
	
	// detrender
	Detrender[i] = (0.0962f*Smooth[i] + 0.5769f*Smooth[i-2] - 0.5769f*Smooth[i-4] - 0.0962f*Smooth[i-6])*(0.075f*Period[i-1] + 0.54f); 		
		
	// compute InPhase and Quadrature components
	Q1[i] = (0.0962f*Detrender[i] + 0.5769f*Detrender[i-2] - 0.5769f*Detrender[i-4] - 0.0962f*Detrender[i-6])*(0.075f*Period[i-1] + 0.54f); 
	I1[i] = Detrender[i-3];
		
	// Advance the phase of I1 and Q1 by 90 degrees
	jI[i] = (0.0962f*I1[i] + 0.5769f*I1[i-2] - 0.5769f*I1[i-4] - 0.0962f*I1[i-6])*(0.075f*Period[i-1] + 0.54f); 
	jQ[i] = (0.0962f*Q1[i] + 0.5769f*Q1[i-2] - 0.5769f*Q1[i-4] - 0.0962f*Q1[i-6])*(0.075f*Period[i-1] + 0.54f);

	// Phasor addition for 3 bar averaging
	I2[i] = I1[i] - jQ[i]; 
	Q2[i] = Q1[i] + jI[i];
		
	// Smooth the I and Q components before applying the discriminator
	I2[i] = 0.2f*I2[i] + 0.8f*I2[i-1]; 
	Q2[i] = 0.2f*Q2[i] + 0.8f*Q2[i-1];
		
	// Homodyne Discriminator
	Re[i] = I2[i]*I2[i-1] + Q2[i]*Q2[i-1]; 
	Im[i] = I2[i]*Q2[i-1] - Q2[i]*I2[i-1]; 
	Re[i] = 0.2f*Re[i] + 0.8f*Re[i-1]; 
	Im[i] = 0.2f*Im[i] + 0.8f*Im[i-1]; 
		
	if (Im[i] != 0.0f && Re[i] != 0.0f)
		Period[i] = 360/(57.3f*atan(Im[i]/Re[i]));
	if (Period[i] > 1.5f*Period[i-1])
		Period[i] = 1.5f*Period[i-1];
	if (Period[i] < 0.67f*Period[i-1])
		Period[i] = 0.67f*Period[i-1] ;
	if (Period[i] < 6)
		Period[i] = 6 ;
	if (Period[i] > 50)
		Period[i] = 50 ;
	Period[i] = 0.2f*Period[i] + 0.8f*Period[i-1];
	SmoothPeriod[i] = 0.33f*Period[i] + 0.67f*SmoothPeriod[i-1];
	return int(SmoothPeriod[i]);
}
float percentile(SCStudyGraphRef sc, SCFloatArrayRef In, SCFloatArrayRef Out, int numBars, int pos, float Pct)
{
  float* pTmp;
  pTmp = new float[numBars];
  int x, ir;
  double rank, fractpart, intpart;
    
 // transfer elements to temp array
  for (x=0;x < numBars;x++)
  {
    pTmp[x] = In[pos-x];
  }

  //sort array in ascending order
  //http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/
  qsort(pTmp, numBars, sizeof(float), compare);

  // get the rank and fraction of the array
  //http://cnx.org/content/m10805/latest/
  rank = ((Pct/100.0f)*(numBars-1.0f)) + 1.0f;
  
  // separate the fractional part and the value to the left of decimal
  //http://www.cplusplus.com/reference/clibrary/cmath/modf/
  fractpart = modf (rank , &intpart);
  
  // get the rank.  1 is subtracted to match the array which starts at zero
  ir = int(intpart)-1;

  // calculate the percentile
  Pct = fractpart*(pTmp[ir+1] - pTmp[ir]) + pTmp[ir];
  delete[] pTmp;
  
  // return the value
  Out[pos] = Pct;
  return(Out[pos]);
}

int compare (const void *a, const void *b)
{
return ( *(int*)a - *(int*)b );
}