EMA of Custom Variable

 

Good evening,

I am attempting to write a HHLLS (Higher High Lower Low EA). 

First HHS and LLS are calculated as below.

double High1 = iHigh(Symbol(), Period(), 1); 
double High2 = iHigh(Symbol(), Period(), 2); 

double Low1 = iLow(Symbol(), Period(), 1); 
double Low2 = iLow(Symbol(), Period(), 2); 

double CurrentHH = iHigh(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
double CurrentLH = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
double CurrentLL = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));
double CurrentHL = iHigh(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));

double HHS = MathAbs(High1 > High2) * ((High1 - CurrentLH) / (CurrentHH - CurrentLH)) * 100;
double LLS = MathAbs(Low1 < Low2) * ((CurrentHL - Low1) / (CurrentHL - CurrentLL)) * 100;

Next I want to calculate the 20 Period EMA of HHS and LLS. When HHSValue crosses above LLSValue then a BUY signal is triggered. 

Although I am struggling to calculate the EMA for HHS and LLS. 

Below is the my full code. I would appreciate it immensely if someone could assist with the correct formula to calculate EMA for HHS and LLS.

#include <Trade\Trade.mqh>
CTrade trade;

// Input parameters
input int TIMEMASTER = 60;
input int PERIOD = 20; 
input int SHORTSL = 30000;
input int SHORTTP = 10000;
input ENUM_MA_METHOD Inp_MA_ma_method = MODE_EMA; // MA: smoothing type
input ENUM_APPLIED_PRICE Inp_MA_applied_price = PRICE_CLOSE; // MA: type of price

int bars_calculated = 0;

double stop_loss = SHORTSL * _Point;
double take_profit = SHORTTP * _Point;

double ª_alpha;

datetime lastTradeTime = 0;

void OnTick()
{
    double lotMaster;
    double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);

    if (accountBalance < 2500000) {
        lotMaster = MathRound(accountBalance / 250);
        if (lotMaster < 1) lotMaster = 1;
    } else if (lotMaster > 50) {
        lotMaster = 50;
    }

    ª_alpha = 2.0/(PERIOD+1.0);

    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    double High1 = iHigh(Symbol(), Period(), 1); 
    double High2 = iHigh(Symbol(), Period(), 2); 

    double Low1 = iLow(Symbol(), Period(), 1); 
    double Low2 = iLow(Symbol(), Period(), 2); 

    double CurrentHH = iHigh(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
    double CurrentLH = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
    double CurrentLL = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));
    double CurrentHL = iHigh(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));

    double HHS = MathAbs(High1 > High2) * ((High1 - CurrentLH) / (CurrentHH - CurrentLH)) * 100;
    double LLS = MathAbs(Low1 < Low2) * ((CurrentHL - Low1) / (CurrentHL - CurrentLL)) * 100;
    
    // Store custom values in buffers
    static double HHSBuffer[];
    static double LLSBuffer[];
    static datetime bufferTime[];

    int bufferSize = PERIOD;
    ArrayResize(HHSBuffer, bufferSize);
    ArrayResize(LLSBuffer, bufferSize);
    ArrayResize(bufferTime, bufferSize);
    
    ArraySetAsSeries(HHSBuffer,true);
    ArraySetAsSeries(LLSBuffer,true);

    // Shift data in buffers
    for (int i = bufferSize - 1; i > 0; i--) {
        HHSBuffer[i] = HHSBuffer[i - 1];
        LLSBuffer[i] = LLSBuffer[i - 1];
        bufferTime[i] = bufferTime[i - 1];
    }

    // Insert latest values
    HHSBuffer[0] = HHS;
    LLSBuffer[0] = LLS;
    bufferTime[0] = TimeCurrent();

    // Calculate 20-period moving average of HHS and LLS
    double HHS_MA = 0;
    double LLS_MA = 0;

    for (int i = 0; i < PERIOD; i++) {
        HHS_MA += HHSBuffer[i];
        LLS_MA += LLSBuffer[i];
          
    }

    HHS_MA /= PERIOD;
    LLS_MA /= PERIOD;

    double HHSValue = NormalizeDouble(HHS_MA, 4);
    double LLSValue = NormalizeDouble(LLS_MA, 4);
    

    Comment(Symbol(), ",", Period(), "\n", 
           "HHS: ", DoubleToString(HHS, Digits()), "\n", 
           "LLS: ", DoubleToString(LLS, Digits()), "\n", 
           "HHSValue: ", DoubleToString(HHSValue, Digits()), "\n", 
           "LLSValue: ", DoubleToString(LLSValue, Digits()), "\n");
           

    if (HHSValue > LLSValue && TimeCurrent() - lastTradeTime >= TIMEMASTER) {
        trade.Buy(lotMaster, NULL, Ask, (Bid - stop_loss), (Ask + take_profit), NULL);
        lastTradeTime = TimeCurrent();
    }
}

  
 
ّIn the "Include" folder, there is a default "MovingAverages.mqh" file. You can use the ExponentialMA() function inside it to calculate EMA of any series. Note that you should also pass the "previous value" of your series to the ExponentialMA() function.
 
As another approach you can move calculation of your custom values into a separate indicator, and then create iMA on top of that indicator in your EA and read smoothed lines. BTW, HHLLS indicator does already exist in the codebase.
 

You are in for a huge amount of headache and pain. Nearly all HH LL algos are repainting. You need to find a sophisticated indicator instead of taking this approach in my humble opinion. You need to at least backtest the algorithm before you dare to go ahead with an EA, but continue this if it's just for a learning project.

 

Since you say you're struggling to generate an EMA value, we should help with a simple example (in this case I'm sure you mean you want to generate an EMA for conditions, and not apply an EMA calculation on another buffer)



input int MA_Period = 20;

double ma_buf[];

int handle = INVALID_HANDLE;


int OnInit() {
    handle = iMA(_Symbol, _Period, MA_Period, 0, MODE_EMA, PRICE_CLOSE);

    ArraySetAsSeries(ma_buf, true);  
    
    return (INIT_SUCCEEDED);
}

void OnDeinit(const int reason){

    IndicatorRelease(handle);
    ArrayFree(ma_buf);
    Comment("");

}

void OnTick() {

    if (CopyBuffer(handle, 0, 0, 2, ma_buf)==-1) {
        Print("problem loading EMA");
        GetLastError();
    }


    double ema_latest_bar = ma_buf[0];
    double ema_penultimate_bar = ma_buf[1];
    
    string str = "EMA value on the current bar: " + DoubleToString(ema_latest_bar) + "\n" + "EMA value on the penultimate bar: " + DoubleToString(ema_penultimate_bar);
    
    Comment(str);
}
 

Thank you all for responding on my question. I've tried to implement everyone's advice but still can't get it to work.

Conor on the example you provided, you have PRICE_CLOSE as the input:

input int MA_Period = 20;

double ma_buf[];

int handle = INVALID_HANDLE;


int OnInit() {
    handle = iMA(_Symbol, _Period, MA_Period, 0, MODE_EMA, PRICE_CLOSE);

    ArraySetAsSeries(ma_buf, true);  
    
    return (INIT_SUCCEEDED);
}

In my case, I tried to implement HHS and LLS instead of PRICE_CLOSE. I also tried replacing your whole iMA() formula and just have handle = HHS (and another for LLS).

double HHS = MathAbs(High1 > High2) * ((High1 - CurrentLH) / (CurrentHH - CurrentLH)) * 100;
double LLS = MathAbs(Low1 < Low2) * ((CurrentHL - Low1) / (CurrentHL - CurrentLL)) * 100;

MovingAverages.mqh provides 2 examples

//+------------------------------------------------------------------+
//| Exponential Moving Average                                       |
//+------------------------------------------------------------------+
double ExponentialMA(const int position,const int period,const double prev_value,const double &price[])
  {
   double result=0.0;
//--- check period
   if(period>0)
     {
      double pr=2.0/(period+1.0);
      result=price[position]*pr+prev_value*(1-pr);
     }

   return(result);
  }

and

//+------------------------------------------------------------------+
//|  Exponential moving average on price array                       |
//+------------------------------------------------------------------+
int ExponentialMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[])
  {
//--- check period
   if(period<=1 || period>(rates_total-begin))
      return(0);
//--- save and clear 'as_series' flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);

   ArraySetAsSeries(price,false);
   ArraySetAsSeries(buffer,false);
//--- calculate start position
   int    start_position;
   double smooth_factor=2.0/(1.0+period);

   if(prev_calculated==0)  // first calculation or number of bars was changed
     {
      //--- set empty value for first bars
      for(int i=0; i<begin; i++)
         buffer[i]=0.0;
      //--- calculate first visible value
      start_position=period+begin;
      buffer[begin] =price[begin];

      for(int i=begin+1; i<start_position; i++)
         buffer[i]=price[i]*smooth_factor+buffer[i-1]*(1.0-smooth_factor);
     }
   else
      start_position=prev_calculated-1;
//--- main loop
   for(int i=start_position; i<rates_total; i++)
      buffer[i]=price[i]*smooth_factor+buffer[i-1]*(1.0-smooth_factor);
//--- restore as_series flags
   ArraySetAsSeries(price,as_series_price);
   ArraySetAsSeries(buffer,as_series_buffer);
//---
   return(rates_total);
  }

I've tried every possible way of implementing both of these methods to calculate the EMA.

Could you please give me more guidance on how I could implement it? 

Please forgive my ignorance!

 

here's a working example using that function:


#include <MovingAverages.mqh>

int bars;

input int iPeriods = 10;
input int EMA_Period = 20;


double high_shifts[];
double low_shifts[];


double ema_buffer_HH[];
double ema_buffer_LL[];
datetime time[];


//+----------------------------------------------------
--------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  // bars = Bars(Symbol(), Period());
   bars = 200;
   
   ArrayResize(high_shifts, bars);
   ArrayResize(low_shifts, bars);
   ArrayResize(time, bars);
   ArrayResize(ema_buffer_LL, bars);  
   ArrayResize(ema_buffer_HH, bars);
   
   ArraySetAsSeries(ema_buffer_LL, true);
   ArraySetAsSeries(ema_buffer_HH, true);  
   ArraySetAsSeries(high_shifts, true);
   ArraySetAsSeries(low_shifts, true);
   ArraySetAsSeries(time, true);
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if (CopyTime(_Symbol, _Period, 0, bars, time) <= 0){
      Print("Failed to copy time data.");
   }


    for (int i = bars-1; i >= 0; i--){

            high_shifts[i] = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, iPeriods, i));
            low_shifts[i] = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, iPeriods, i));

            if(i < bars - 1){
            
              ema_buffer_HH[i] = ExponentialMA(i, EMA_Period, ema_buffer_HH[i + 1], high_shifts);
              ema_buffer_LL[i] = ExponentialMA(i, EMA_Period, ema_buffer_LL[i + 1], low_shifts);
            }
    }


   double ema_of_HHS = ema_buffer_HH[0];
   double ema_of_LLS = ema_buffer_LL[0];

   string s = "HHs (latest bar): " + DoubleToString(high_shifts[0]) + "\n\n" + "EMA of HHS: " + DoubleToString(ema_of_HHS) + "\n" + "EMA of LLS: " + DoubleToString(ema_of_LLS);
   
   Comment(s);
  }
//+------------------------------------------------------------------+


but as others have hinted - use an indicator to calculate the buffers, because the speed of calculation in an EA when going through a loop is extremely slow and can cause a lot of problems


u can do this if you only care about the most recent value

void OnTick()
  {

   high_shifts[0] = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, iPeriods, 0));
   low_shifts[0] = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, iPeriods, 0));
            
   ema_buffer_HH[0] = ExponentialMA(0, EMA_Period, ema_buffer_HH[1], high_shifts);
   ema_buffer_LL[0] = ExponentialMA(0, EMA_Period, ema_buffer_LL[1], low_shifts);

   double ema_of_HHS = ema_buffer_HH[0];
   double ema_of_LLS = ema_buffer_LL[0];

   string s = "HHs (latest bar): " + DoubleToString(high_shifts[0]) + "\n\n" + "EMA of HHS: " + DoubleToString(ema_of_HHS) + "\n" + "EMA of LLS: " + DoubleToString(ema_of_LLS);
   
   Comment(s);
  }
 

offtopic - but looks like you make a mistake in your logic here:

    double CurrentHH = iHigh(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
    double CurrentLH = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_HIGH, PERIOD, 0)); 
    double CurrentLL = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));
    double CurrentHL = iHigh(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));

changed:

    double CurrentHH = iHigh(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_HIGH, PERIOD, 0));
    double CurrentLH = iHigh(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0)); 
    double CurrentLL = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, PERIOD, 0));
    double CurrentHL = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_HIGH, PERIOD, 0)); 
 

Thank you kindly Conor, I really appreciate you taking the time to work through my code and for giving advice! 

It looks like you are calculating the EMA of the Highest High (Hh) and Lowest Low (Ll) in the example you provided, what I'm trying to make EMA of is the final HH and LL calculations


First, first calculates two values, HH and LL:


HH. For bars with the high price greater than the previous high (otherwise 0):

HH = (Hc - Hl)/(Hh-Hl),

Where Hc is the current bar’s high price, Hl and Hh are the lowest and the highest high prices over a certain period.


LL. For bars with the low price less than the previous low (otherwise 0):

LL = (Lh - Lc)/(Lh-Ll),

Where Lc is the current low price, Ll and Lh are the lowest and the highest low prices over a certain period.


Both variables are then smoothed with a moving average, resulting in two main plots HHS and LLS. 


Below is essentially the indicator code I'm trying to convert into an EA to trade when a crossover occurs.

I will work through the examples you provided in detail tomorrow and see how I can implement it.

Thank you again for taking the time to assist, I cannot describe how thankful I am.

//------------------------------------------------------------------
#property copyright   "© mladen, 2018"
#property link        "mladenfx@gmail.com"
#property description "Higher Highs & Lower Lows"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   3
#property indicator_label1  "Fill zone"
#property indicator_type1   DRAW_FILLING
#property indicator_color1  C'235,255,235',C'255,235,235'
#property indicator_label2  "HH value"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrMediumSeaGreen
#property indicator_width2  2
#property indicator_label3  "LL value"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrOrangeRed
#property indicator_width3  2

//
//--- input parameters
//

input int inpPeriod = 20; // Period

//
//--- buffers declarations
//

double valhh[],valll[],fillu[],filld[];
double ª_alpha;
//------------------------------------------------------------------
// Custom indicator initialization function
//------------------------------------------------------------------

int OnInit()
{
   //
   //--- indicator buffers mapping
   //
         SetIndexBuffer(0,fillu,INDICATOR_DATA);
         SetIndexBuffer(1,filld,INDICATOR_DATA);
         SetIndexBuffer(2,valhh,INDICATOR_DATA);
         SetIndexBuffer(3,valll,INDICATOR_DATA);
            ª_alpha = 2.0/(inpPeriod+1.0);
   //        
   //--- indicator short name assignment
   //
   IndicatorSetString(INDICATOR_SHORTNAME,"Higher Highs & Lower Lows ("+(string)inpPeriod+")");
   return (INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { }

//------------------------------------------------------------------
//  Custom indicator 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[])
{
   int start= prev_calculated-1; if (start<0) start=0; for (int i=start; i<rates_total && !_StopFlag; i++)
   {
      double _hhmin,_hhmax,_llmin,_llmax;
         _hhMinMax.calculate(high[i],high[i],inpPeriod,_hhmin,_hhmax,i);
         _llMinMax.calculate(low[i] ,low[i] ,inpPeriod,_llmin,_llmax,i);

         //
         //---
         //
        
         if (i>0)
         {        
            double _hhval = (high[i]>high[i-1]) ? 100*(high[i]-_hhmin)/(_hhmax-_hhmin) : 0;
            double _llval = (low[i] <low[i-1] ) ? 100*(_llmax -low[i])/(_llmax-_llmin) : 0;
            valhh[i] = fillu[i] = valhh[i-1] + ª_alpha*(_hhval-valhh[i-1]);
            valll[i] = filld[i] = valll[i-1] + ª_alpha*(_llval-valll[i-1]);
         }
         else valhh[i] = valll[i] = 0;            
   }
   return (rates_total);
}

//------------------------------------------------------------------
//    Custom function(s)
//------------------------------------------------------------------
//
//---
//

class cMinMax
{
   private :
      int    originalPeriod;
      int    period;
      int    prevbar;
      double currmin;
      double currmax;
      double prevmax;
      double prevmin;
      double minArray[];
      double maxArray[];
        
   public :
      cMinMax() { originalPeriod = prevbar = INT_MIN;       return; }
     ~cMinMax() { ArrayFree(minArray); ArrayFree(maxArray); return; }
    
      //
      //
      //
    
      void calculate(double valueMin, double valueMax, int forPeriod, double& min, double& max, int i)
      {
         if (prevbar!=i)
         {
            prevbar = i;
               if (originalPeriod!=forPeriod)
               {
                     originalPeriod =  forPeriod;
                     period         = (forPeriod>0) ? forPeriod : 1;
                     prevmin        = valueMin;
                     prevmax        = valueMax;
                     currmin        = valueMin;
                     currmax        = valueMax;
                           ArrayResize(minArray,period-1); ArrayInitialize(minArray,valueMin);
                           ArrayResize(maxArray,period-1); ArrayInitialize(maxArray,valueMax);
               }
               if (period>1)
               {
                  int _pos = (i) % (period-1);
                     minArray[_pos] = currmin;
                     maxArray[_pos] = currmax;
                     prevmin        = minArray[ArrayMinimum(minArray)];
                     prevmax        = maxArray[ArrayMaximum(maxArray)];
               }
               else  { prevmin = valueMin; prevmax = valueMax; }
         }

         //
         //
         //
            
         currmin = valueMin;
         currmax = valueMax;
            max = (prevmax>valueMax) ? prevmax : valueMax;
            min = (prevmin<valueMin) ? prevmin : valueMin;
         return;
     }
};
cMinMax _hhMinMax;
cMinMax _llMinMax;
//------------------------------------------------------------------
 

what I've showed is basically an example showing how to use "ExponentialMA" from the mqh library on any buffer you want. hence the example to get you there


C0mput3r #:


Below is essentially the indicator code I'm trying to convert into an EA to trade when a crossover occurs.

This isn't the correct approach. It's completely unnecessary and will be an unneeded amount of stress. You need to make an iCustom in the EA to call the ex5 of the indicator you want to use in the EA.


input int inpPeriod = 20;

double HH[];
double LL[];

int handle;

int OnInit(){

    handle = iCustom(_Symbol, _Period, "Examples//[indicator name]", inpPeriod );

    
    return(INIT_SUCCEEDED);
}


void OnTick() {

    // take signals for the current bar
    if (CopyBuffer(handle, 2, 0, 1, HH) < 0) {
        Print("UNABLE TO GET ENOUGH REQUESTED DATA FOR HH SIGNAL. REVERTING.");
    }

    if (CopyBuffer(handle, 3, 0, 1, LL) < 0) {
        Print("UNABLE TO GET ENOUGH REQUESTED DATA FOR LL SIGNAL. REVERTING.");
    }

}