forked from LengKundee/NUNA
187 lines
6.4 KiB
MQL5
187 lines
6.4 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| SpeedOscillator.mq5 |
|
||
|
|
//| Copyright 2021, MetaQuotes Ltd. |
|
||
|
|
//| https://www.mql5.com |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2021, MetaQuotes Ltd."
|
||
|
|
#property link "https://www.mql5.com"
|
||
|
|
#property version "2.30"
|
||
|
|
|
||
|
|
//--- indicator settings
|
||
|
|
#property indicator_separate_window
|
||
|
|
#property indicator_buffers 5
|
||
|
|
#property indicator_plots 2
|
||
|
|
#property indicator_type1 DRAW_HISTOGRAM
|
||
|
|
#property indicator_color1 clrDodgerBlue
|
||
|
|
#property indicator_style1 STYLE_SOLID
|
||
|
|
#property indicator_width1 1
|
||
|
|
#property indicator_type2 DRAW_LINE
|
||
|
|
#property indicator_color2 clrRed
|
||
|
|
#property indicator_style2 STYLE_DOT
|
||
|
|
#property indicator_width2 1
|
||
|
|
//--- input parameters
|
||
|
|
input int InpMAperiod = 100; // Moving average period
|
||
|
|
input ENUM_MA_METHOD InpMAmethod = MODE_SMA; // Moving average mode
|
||
|
|
input int InpSPeriod = 400; // Backward-sampling period
|
||
|
|
//--- indicator buffers
|
||
|
|
double AvgPosBuffer[];
|
||
|
|
double AvgNegBuffer[];
|
||
|
|
double SO[];
|
||
|
|
double ExtMABuffer[];
|
||
|
|
double Distance[];
|
||
|
|
//--- handles
|
||
|
|
int ExtMAHandle;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Speed Oscillator initialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnInit()
|
||
|
|
{
|
||
|
|
//--- indicator buffers mapping
|
||
|
|
SetIndexBuffer(0, SO, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(1, Distance, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(2, AvgPosBuffer, INDICATOR_CALCULATIONS);
|
||
|
|
SetIndexBuffer(3, AvgNegBuffer, INDICATOR_CALCULATIONS);
|
||
|
|
SetIndexBuffer(4, ExtMABuffer, INDICATOR_CALCULATIONS);
|
||
|
|
//--- sets first bar from what index will be drawn
|
||
|
|
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpSPeriod);
|
||
|
|
//--- get MA handles
|
||
|
|
ExtMAHandle = iMA(NULL, 0, InpMAperiod, 0, InpMAmethod, PRICE_CLOSE);
|
||
|
|
//--- name for DataWindow and indicator subwindow label
|
||
|
|
PlotIndexSetString(0, PLOT_LABEL, "Speed(" + string(InpMAperiod) + ")");
|
||
|
|
PlotIndexSetString(1, PLOT_LABEL, "Distance(%)");
|
||
|
|
IndicatorSetString(INDICATOR_SHORTNAME, "SO(" + string(InpMAperiod) + ")");
|
||
|
|
//--- sets drawing line to empty value
|
||
|
|
PlotIndexSetDouble (0, PLOT_EMPTY_VALUE ,0.0);
|
||
|
|
PlotIndexSetDouble (1, PLOT_EMPTY_VALUE ,0.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Speed Oscillator iteration function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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[])
|
||
|
|
{
|
||
|
|
//--- get ma buffers
|
||
|
|
if(CopyBuffer(ExtMAHandle, 0, 0, rates_total-1, ExtMABuffer) <=0)
|
||
|
|
{
|
||
|
|
Print("not all MA copied. Will try on next tick Error =", GetLastError());
|
||
|
|
return(0);
|
||
|
|
}
|
||
|
|
if(prev_calculated == 0)
|
||
|
|
{
|
||
|
|
ArrayInitialize(AvgPosBuffer, 0);
|
||
|
|
ArrayInitialize(AvgNegBuffer, 0);
|
||
|
|
ArrayInitialize(SO, 0);
|
||
|
|
}
|
||
|
|
//--- SpeedOscillator
|
||
|
|
int i;
|
||
|
|
int pos_count = 0;
|
||
|
|
int neg_count = 0;
|
||
|
|
double pos_sum = 0;
|
||
|
|
double neg_sum = 0;
|
||
|
|
int j = 1;
|
||
|
|
//--- One-time calculations, all rates history.
|
||
|
|
if(prev_calculated == 0)
|
||
|
|
{
|
||
|
|
for(i = InpSPeriod + 1; i < rates_total && !IsStopped(); i++)
|
||
|
|
{
|
||
|
|
pos_count = 0;
|
||
|
|
neg_count = 0;
|
||
|
|
pos_sum = 0;
|
||
|
|
neg_sum = 0;
|
||
|
|
j = i;
|
||
|
|
while((pos_count < InpSPeriod || neg_count < InpSPeriod) && j > 1)
|
||
|
|
{
|
||
|
|
j--;
|
||
|
|
double diff = ExtMABuffer[j] - ExtMABuffer[j - 1];
|
||
|
|
if(diff > 0 && pos_count < InpSPeriod)
|
||
|
|
{
|
||
|
|
pos_count++;
|
||
|
|
pos_sum += diff;
|
||
|
|
}
|
||
|
|
if(diff < 0 && neg_count < InpSPeriod)
|
||
|
|
{
|
||
|
|
neg_count++;
|
||
|
|
neg_sum += diff;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
AvgPosBuffer[i] = pos_sum / InpSPeriod;
|
||
|
|
AvgNegBuffer[i] = neg_sum / InpSPeriod;
|
||
|
|
if(ExtMABuffer[i] - ExtMABuffer[i - 1] > 0)
|
||
|
|
{
|
||
|
|
SO[i] = (ExtMABuffer[i] - ExtMABuffer[i - 1]) / AvgPosBuffer[i];
|
||
|
|
}
|
||
|
|
else
|
||
|
|
if(ExtMABuffer[i] - ExtMABuffer[i - 1] < 0)
|
||
|
|
{
|
||
|
|
SO[i] = -((ExtMABuffer[i] - ExtMABuffer[i - 1]) / AvgNegBuffer[i]);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SO[i] = 0;
|
||
|
|
}
|
||
|
|
Distance[i] = ((close[i] - ExtMABuffer[i]) / close[i]) * 100;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Main calculations, i.e. every tick thereafter, calculate current tick's values [rates_total-1]
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(i = rates_total - 1; i < rates_total && !IsStopped(); i++)
|
||
|
|
{
|
||
|
|
pos_count = 0;
|
||
|
|
neg_count = 0;
|
||
|
|
pos_sum = 0;
|
||
|
|
neg_sum = 0;
|
||
|
|
j = i;
|
||
|
|
while((pos_count < InpSPeriod || neg_count < InpSPeriod) && j > 1)
|
||
|
|
{
|
||
|
|
j--;
|
||
|
|
double diff = ExtMABuffer[j] - ExtMABuffer[j - 1];
|
||
|
|
if(diff > 0 && pos_count < InpSPeriod)
|
||
|
|
{
|
||
|
|
pos_count++;
|
||
|
|
pos_sum += diff;
|
||
|
|
}
|
||
|
|
if(diff < 0 && neg_count < InpSPeriod)
|
||
|
|
{
|
||
|
|
neg_count++;
|
||
|
|
neg_sum += diff;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
AvgPosBuffer[i] = pos_sum / InpSPeriod;
|
||
|
|
AvgNegBuffer[i] = neg_sum / InpSPeriod;
|
||
|
|
if(ExtMABuffer[i] - ExtMABuffer[i - 1] > 0)
|
||
|
|
{
|
||
|
|
SO[i] = (ExtMABuffer[i] - ExtMABuffer[i - 1]) / AvgPosBuffer[i];
|
||
|
|
}
|
||
|
|
else
|
||
|
|
if(ExtMABuffer[i] - ExtMABuffer[i - 1] < 0)
|
||
|
|
{
|
||
|
|
SO[i] = -((ExtMABuffer[i] - ExtMABuffer[i - 1]) / AvgNegBuffer[i]);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SO[i] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- always do current tick's distance
|
||
|
|
Distance[rates_total - 1] = ((close[rates_total - 1] - ExtMABuffer[rates_total - 1]) / close[rates_total - 1]) * 100;
|
||
|
|
|
||
|
|
|
||
|
|
//--- return value of prev_calculated for next call
|
||
|
|
return(rates_total);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|