201 lines
13 KiB
Plaintext
201 lines
13 KiB
Plaintext
//------------------------------------------------------------------
|
|
#property copyright "© mladen, 2019"
|
|
#property link "mladenfx@gmail.com"
|
|
//------------------------------------------------------------------
|
|
#property indicator_chart_window
|
|
#property indicator_buffers 2
|
|
#property indicator_plots 1
|
|
#property indicator_label1 "Hull"
|
|
#property indicator_type1 DRAW_COLOR_LINE
|
|
#property indicator_color1 clrGray,clrMediumSeaGreen,clrOrangeRed
|
|
#property indicator_width1 2
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
input int inpPeriod = 20; // Period
|
|
input double inpDivisor = 2.0; // Divisor ("speed")
|
|
input ENUM_APPLIED_PRICE inpPrice = PRICE_CLOSE; // Price
|
|
|
|
double val[],valc[];
|
|
|
|
//------------------------------------------------------------------
|
|
//
|
|
//------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
|
|
int OnInit()
|
|
{
|
|
SetIndexBuffer(0,val,INDICATOR_DATA);
|
|
SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
|
|
iHull.init(inpPeriod,inpDivisor);
|
|
IndicatorSetString(INDICATOR_SHORTNAME,"Hull ("+(string)inpPeriod+")");
|
|
return (INIT_SUCCEEDED);
|
|
}
|
|
void OnDeinit(const int reason)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
//
|
|
//------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
int i= prev_calculated-1; if (i<0) i=0; for (; i<rates_total && !_StopFlag; i++)
|
|
{
|
|
val[i] = iHull.calculate(getPrice(inpPrice,open,high,low,close,i),i,rates_total);
|
|
valc[i] = (i>0) ? (val[i]>val[i-1]) ? 1 : (val[i]<val[i-1]) ? 2 : valc[i-1] : 0;
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Custom function(s)
|
|
//------------------------------------------------------------------
|
|
//
|
|
//---
|
|
//
|
|
|
|
class CHull
|
|
{
|
|
private :
|
|
int m_fullPeriod;
|
|
int m_halfPeriod;
|
|
int m_sqrtPeriod;
|
|
int m_arraySize;
|
|
double m_weight1;
|
|
double m_weight2;
|
|
double m_weight3;
|
|
struct sHullArrayStruct
|
|
{
|
|
double value;
|
|
double value3;
|
|
double wsum1;
|
|
double wsum2;
|
|
double wsum3;
|
|
double lsum1;
|
|
double lsum2;
|
|
double lsum3;
|
|
};
|
|
sHullArrayStruct m_array[];
|
|
|
|
public :
|
|
CHull() : m_fullPeriod(1), m_halfPeriod(1), m_sqrtPeriod(1), m_arraySize(-1) { }
|
|
~CHull() { ArrayFree(m_array); }
|
|
|
|
///
|
|
///
|
|
///
|
|
|
|
bool init(int period, double divisor)
|
|
{
|
|
m_fullPeriod = (int)(period>1 ? period : 1);
|
|
m_halfPeriod = (int)(m_fullPeriod>1 ? m_fullPeriod/(divisor>1 ? divisor : 1) : 1);
|
|
m_sqrtPeriod = (int) MathSqrt(m_fullPeriod);
|
|
m_arraySize = -1; m_weight1 = m_weight2 = m_weight3 = 1;
|
|
return(true);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
double calculate( double value, int i, int bars)
|
|
{
|
|
if (m_arraySize<bars) { m_arraySize = ArrayResize(m_array,bars+500); if (m_arraySize<bars) return(0); }
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
m_array[i].value=value;
|
|
if (i>m_fullPeriod)
|
|
{
|
|
m_array[i].wsum1 = m_array[i-1].wsum1+value*m_halfPeriod-m_array[i-1].lsum1;
|
|
m_array[i].lsum1 = m_array[i-1].lsum1+value-m_array[i-m_halfPeriod].value;
|
|
m_array[i].wsum2 = m_array[i-1].wsum2+value*m_fullPeriod-m_array[i-1].lsum2;
|
|
m_array[i].lsum2 = m_array[i-1].lsum2+value-m_array[i-m_fullPeriod].value;
|
|
}
|
|
else
|
|
{
|
|
m_array[i].wsum1 = m_array[i].wsum2 =
|
|
m_array[i].lsum1 = m_array[i].lsum2 = m_weight1 = m_weight2 = 0;
|
|
for(int k=0, w1=m_halfPeriod, w2=m_fullPeriod; w2>0 && i>=k; k++, w1--, w2--)
|
|
{
|
|
if (w1>0)
|
|
{
|
|
m_array[i].wsum1 += m_array[i-k].value*w1;
|
|
m_array[i].lsum1 += m_array[i-k].value;
|
|
m_weight1 += w1;
|
|
}
|
|
m_array[i].wsum2 += m_array[i-k].value*w2;
|
|
m_array[i].lsum2 += m_array[i-k].value;
|
|
m_weight2 += w2;
|
|
}
|
|
}
|
|
m_array[i].value3=2.0*m_array[i].wsum1/m_weight1-m_array[i].wsum2/m_weight2;
|
|
|
|
//
|
|
//---
|
|
//
|
|
|
|
if (i>m_sqrtPeriod)
|
|
{
|
|
m_array[i].wsum3 = m_array[i-1].wsum3+m_array[i].value3*m_sqrtPeriod-m_array[i-1].lsum3;
|
|
m_array[i].lsum3 = m_array[i-1].lsum3+m_array[i].value3-m_array[i-m_sqrtPeriod].value3;
|
|
}
|
|
else
|
|
{
|
|
m_array[i].wsum3 =
|
|
m_array[i].lsum3 = m_weight3 = 0;
|
|
for(int k=0, w3=m_sqrtPeriod; w3>0 && i>=k; k++, w3--)
|
|
{
|
|
m_array[i].wsum3 += m_array[i-k].value3*w3;
|
|
m_array[i].lsum3 += m_array[i-k].value3;
|
|
m_weight3 += w3;
|
|
}
|
|
}
|
|
return(m_array[i].wsum3/m_weight3);
|
|
}
|
|
};
|
|
CHull iHull;
|
|
|
|
//
|
|
//---
|
|
//
|
|
|
|
template <typename T>
|
|
double getPrice(ENUM_APPLIED_PRICE tprice, T& open[], T& high[], T& low[], T& close[], int i)
|
|
{
|
|
switch(tprice)
|
|
{
|
|
case PRICE_CLOSE: return(close[i]);
|
|
case PRICE_OPEN: return(open[i]);
|
|
case PRICE_HIGH: return(high[i]);
|
|
case PRICE_LOW: return(low[i]);
|
|
case PRICE_MEDIAN: return((high[i]+low[i])/2.0);
|
|
case PRICE_TYPICAL: return((high[i]+low[i]+close[i])/3.0);
|
|
case PRICE_WEIGHTED: return((high[i]+low[i]+close[i]+close[i])/4.0);
|
|
}
|
|
return(0);
|
|
}
|
|
//------------------------------------------------------------------
|