Author: Copyright 2021, MetaQuotes Ltd.
Indicators Used
Moving average indicator
0 Views
0 Downloads
0 Favorites
SO
//+------------------------------------------------------------------+
//|                                              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);
  }
//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---