forked from rosh/MQL5Book
182 lines
5.8 KiB
MQL5
182 lines
5.8 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| UseWPRFractals.mq5 |
| |||
//| Copyright 2021, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#property indicator_chart_window
| |||
#property indicator_buffers 3
| |||
#property indicator_plots 3
| |||
| |||
// drawing settings
| |||
#property indicator_type1 DRAW_ARROW
| |||
#property indicator_color1 clrRed
| |||
#property indicator_width1 1
| |||
#property indicator_label1 "Sell"
| |||
| |||
#property indicator_type2 DRAW_ARROW
| |||
#property indicator_color2 clrBlue
| |||
#property indicator_width2 1
| |||
#property indicator_label2 "Buy"
| |||
| |||
#property indicator_type3 DRAW_NONE
| |||
#property indicator_color3 clrGreen
| |||
#property indicator_width3 1
| |||
#property indicator_label3 "Filter"
| |||
| |||
// inputs
| |||
input int PeriodWPR = 11;
| |||
input int PeriodEMA = 5;
| |||
input int FractalOrder = 1;
| |||
input int Offset = 0;
| |||
input double Threshold = 0.2;
| |||
| |||
// indicator buffers
| |||
double UpBuffer[]; // up side means overbought, hence sell
| |||
double DownBuffer[]; // down side means oversold, hence buy
| |||
double Filter[]; // direction filter according to fractals
| |||
| |||
// global variables for subordinate indicators
| |||
int handleWPR, handleEMA3, handleFractals;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom indicator initialization function |
| |||
//+------------------------------------------------------------------+
| |||
int OnInit()
| |||
{
| |||
if(Offset < 0 || Offset > 1)
| |||
{
| |||
Alert("Offset should take index for signal bar: 0 or 1");
| |||
return INIT_PARAMETERS_INCORRECT;
| |||
}
| |||
// indicator buffers mapping
| |||
SetIndexBuffer(0, UpBuffer);
| |||
SetIndexBuffer(1, DownBuffer);
| |||
SetIndexBuffer(2, Filter, INDICATOR_DATA); // could be INDICATOR_CALCULATIONS
| |||
ArraySetAsSeries(UpBuffer, true);
| |||
ArraySetAsSeries(DownBuffer, true);
| |||
ArraySetAsSeries(Filter, true);
| |||
| |||
// set bullets
| |||
PlotIndexSetInteger(0, PLOT_ARROW, 234);
| |||
PlotIndexSetInteger(1, PLOT_ARROW, 233);
| |||
| |||
// subordinate indicators
| |||
handleWPR = iCustom(_Symbol, _Period, "IndWPR", PeriodWPR);
| |||
handleEMA3 = iCustom(_Symbol, _Period, "IndTripleEMA", PeriodEMA, 0, handleWPR);
| |||
handleFractals = iCustom(_Symbol, _Period, "IndFractals", FractalOrder);
| |||
if(handleWPR == INVALID_HANDLE
| |||
|| handleEMA3 == INVALID_HANDLE
| |||
|| handleFractals == INVALID_HANDLE)
| |||
{
| |||
return INIT_FAILED;
| |||
}
| |||
| |||
return INIT_SUCCEEDED;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Read indicator buffers and make decision for trade signals |
| |||
//+------------------------------------------------------------------+
| |||
int MarkSignals(const int bar, const int offset, const double &data[])
| |||
{
| |||
double wpr[2];
| |||
double peaks[1], hollows[1];
| |||
if(CopyBuffer(handleEMA3, 0, bar + offset, 2, wpr) == 2
| |||
&& CopyBuffer(handleFractals, 0, bar + offset + FractalOrder, 1, peaks) == 1
| |||
&& CopyBuffer(handleFractals, 1, bar + offset + FractalOrder, 1, hollows) == 1)
| |||
{
| |||
int filterdirection = (int)Filter[bar + 1]; // pick up previous direction
| |||
| |||
// take latest fractal as indication of beginning of opposite movement
| |||
if(peaks[0] != EMPTY_VALUE)
| |||
{
| |||
filterdirection = -1; // sell
| |||
}
| |||
if(hollows[0] != EMPTY_VALUE)
| |||
{
| |||
filterdirection = +1; // buy
| |||
}
| |||
| |||
Filter[bar] = filterdirection; // remember new direction
| |||
| |||
// convert 2 last values from WPR into [-1,+1] range
| |||
const double old = (wpr[0] + 50) / 50; // +1.0 -1.0
| |||
const double last = (wpr[1] + 50) / 50; // +1.0 -1.0
| |||
| |||
// bumps from up back to middle
| |||
if(filterdirection == -1
| |||
&& old >= 1.0 - Threshold && last <= 1.0 - Threshold)
| |||
{
| |||
UpBuffer[bar] = data[bar];
| |||
return -1; // sell
| |||
}
| |||
else
| |||
{
| |||
UpBuffer[bar] = EMPTY_VALUE;
| |||
}
| |||
| |||
// bumps from down back to middle
| |||
if(filterdirection == +1
| |||
&& old <= -1.0 + Threshold && last >= -1.0 + Threshold)
| |||
{
| |||
DownBuffer[bar] = data[bar];
| |||
return +1; // buy
| |||
}
| |||
else
| |||
{
| |||
DownBuffer[bar] = EMPTY_VALUE;
| |||
}
| |||
}
| |||
return 0; // no signal
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom indicator iteration function |
| |||
//+------------------------------------------------------------------+
| |||
int OnCalculate(const int rates_total,
| |||
const int prev_calculated,
| |||
const int begin,
| |||
const double &data[])
| |||
{
| |||
// wait until the subindicators are calculated for all bars
| |||
if(BarsCalculated(handleEMA3) != rates_total
| |||
|| BarsCalculated(handleFractals) != rates_total)
| |||
{
| |||
return prev_calculated;
| |||
}
| |||
| |||
ArraySetAsSeries(data, true);
| |||
| |||
if(prev_calculated == 0)
| |||
{
| |||
ArrayInitialize(UpBuffer, EMPTY_VALUE);
| |||
ArrayInitialize(DownBuffer, EMPTY_VALUE);
| |||
ArrayInitialize(Filter, 0);
| |||
| |||
// find signals on history
| |||
for(int i = rates_total - FractalOrder - 1; i >= 0; --i)
| |||
{
| |||
MarkSignals(i, Offset, data);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
for(int i = 0; i < rates_total - prev_calculated; ++i)
| |||
{
| |||
UpBuffer[i] = EMPTY_VALUE;
| |||
DownBuffer[i] = EMPTY_VALUE;
| |||
Filter[i] = 0;
| |||
}
| |||
| |||
// find signals on new bar or on every tick (if Offset == 0)
| |||
if(rates_total != prev_calculated
| |||
|| Offset == 0)
| |||
{
| |||
// copy data from subordinate indicators into our buffer
| |||
MarkSignals(0, Offset, data);
| |||
}
| |||
}
| |||
| |||
return rates_total;
| |||
}
| |||
//+------------------------------------------------------------------+
|