//+------------------------------------------------------------------+
//|                                             Double Crossover.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
//--- System time frames
#define TF_1            PERIOD_D1
#define TF_2            PERIOD_M15

#define LOT_MULTILPLE   1

//+------------------------------------------------------------------+
//| Custom enumerations                                              |
//+------------------------------------------------------------------+
//--- What trading style should we follow when opening our positions, trend following or mean reverting?
enum STRATEGY_MODES
  {
   TREND = 0,             //Trend Following Mode
   MEAN_REVERTING = 1     //Mean Reverting Mode
  };

//--- Which time frame should we consult, when determining if we should close our position?
enum CLOSING_TIME_FRAME
  {
   HIGHER_TIME_CLOSE = 0, //Close on higher time frames
   LOWER_TIME_CLOSE = 1   //Close on lower time frames
  };

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input group "Technical Indicators"
input int ma_1_period = 10;   //Higher Time Frame Period
input int ma_1_gap    = 20;   //Higher Time Frame Period Gap

input int ma_2_period = 10;   //Lower Time Frame Period
input int ma_2_gap    = 20;   //Lower Time Frame Period Gap

input group "Strategy Settings"
input STRATEGY_MODES     strategy_mode = 0;  //Strategy Operation Mode
input CLOSING_TIME_FRAME closing_tf    = 0;  //Strategy Closing Timeframe

input group "Money Management Settings"
input ENUM_TIMEFRAMES TF_3 =    PERIOD_H4; //Risk Time Frame
input int HISTORICAL_BARS  =           10; //Historical bars for risk calculation

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int      ma_c_1_handle,ma_c_2_handle,ma_c_3_handle,ma_c_4_handle;
double   ma_c_1[],ma_c_2[],ma_c_3[],ma_c_4[];
double   volume_min;
double   bid,ask;
int      state;

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade Trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   volume_min     = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   ma_c_1_handle  = iMA(Symbol(),TF_1,(ma_1_period + ma_1_gap),0,MODE_SMA,PRICE_CLOSE);
   ma_c_2_handle  = iMA(Symbol(),TF_1,ma_1_period,0,MODE_SMA,PRICE_CLOSE);
   ma_c_3_handle  = iMA(Symbol(),TF_2,(ma_2_period + ma_2_gap),0,MODE_SMA,PRICE_CLOSE);
   ma_c_4_handle  = iMA(Symbol(),TF_2,ma_2_period,0,MODE_SMA,PRICE_CLOSE);
   state          = -1;
//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   IndicatorRelease(ma_c_1_handle);
   IndicatorRelease(ma_c_2_handle);
   IndicatorRelease(ma_c_3_handle);
   IndicatorRelease(ma_c_4_handle);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   datetime current_time = iTime(Symbol(),TF_2,0);
   static datetime time_stamp;

   if(time_stamp != current_time)
     {
      time_stamp = current_time;
      update();
     }
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Find a trading signal                                            |
//+------------------------------------------------------------------+
void find_setup(double padding)
  {
   if(PositionsTotal() == 0)
     {
      //--- Reset the system state
      state = -1;

      //--- Bullish on the higher time frame
      if(ma_c_1[0] > ma_c_2[0])
        {
         //--- Trend following mode
         if((ma_c_3[0] > ma_c_4[0]) && (strategy_mode == 0))
           {
            Trade.Buy(volume_min,Symbol(),ask,(bid - padding),0,"");
            state = 1;
           }
         //--- Mean reverting mode
         if((ma_c_3[0] < ma_c_4[0]) && (strategy_mode == 1))
           {
            Trade.Buy(volume_min,Symbol(),ask,(bid - padding),0,"");
            state = 1;
           }
        }

      //--- Bearish on the higher time frame
      if(ma_c_1[0] < ma_c_2[0])
        {
         //--- Trend following mode
         if((ma_c_3[0] < ma_c_4[0]) && (strategy_mode == 0))
           {
            Trade.Sell(volume_min,Symbol(),bid,(ask + padding),0,"");
            state = 0;
           }
         //--- Mean reverting mode
         if((ma_c_3[0] > ma_c_4[0]) && (strategy_mode == 1))
           {
            Trade.Sell(volume_min,Symbol(),bid,(ask + padding),0,"");
            state = 0;
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Manage our open positions                                        |
//+------------------------------------------------------------------+
void manage_setup(void)
  {
  //Does the position exist?
  if(PositionSelect(Symbol()))
   {
      //Get the current stop loss
      double current_sl = PositionGetDouble(POSITION_SL);
      double padding = get_padding();
      double new_sl;
      
   
      //Sell position
      if((state == 0))
      {
         new_sl = (ask + padding);
         
         if(new_sl < current_sl) Trade.PositionModify(Symbol(),new_sl,0);
      }

      //Buy position
      if((state == 1))
      {
         new_sl = (bid - padding);
         
         if(new_sl > current_sl) Trade.PositionModify(Symbol(),new_sl,0);
      }
  
  
   if(closing_tf == 0)
     {
      if((state ==0) && (ma_c_1[0] > ma_c_2[0]))
         Trade.PositionClose(Symbol());
      if((state ==1) && (ma_c_1[0] < ma_c_2[0]))
         Trade.PositionClose(Symbol());
     }

   else
      if(closing_tf == 1)
        {
         if((state ==0) && (ma_c_3[0] > ma_c_4[0]))
            Trade.PositionClose(Symbol());
         if((state ==1) && (ma_c_3[0] < ma_c_4[0]))
            Trade.PositionClose(Symbol());
        }
   }
  }

//+------------------------------------------------------------------+
//| Get the stop loss size to use                                    |
//+------------------------------------------------------------------+
double get_padding(void)
  {
   vector high = vector::Zeros(10);
   vector low = vector::Zeros(10);
   low.CopyRates(Symbol(),TF_3,COPY_RATES_LOW,0,HISTORICAL_BARS);
   high.CopyRates(Symbol(),TF_3,COPY_RATES_HIGH,0,HISTORICAL_BARS);
   vector var = high - low;
   double padding = var.Mean();
   return(padding);
  }

//+------------------------------------------------------------------+
//| Update our technical indicators and positions                    |
//+------------------------------------------------------------------+
void update(void)
  {

//Update technical indicators and market readings
   CopyBuffer(ma_c_2_handle,0,0,1,ma_c_2);
   CopyBuffer(ma_c_1_handle,0,0,1,ma_c_1);
   CopyBuffer(ma_c_4_handle,0,0,1,ma_c_4);
   CopyBuffer(ma_c_3_handle,0,0,1,ma_c_3);
   bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
   ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   double padding = get_padding();

//Find an open position
   if(PositionsTotal() == 0)
      find_setup(padding);

//Manage our open positions
   else
      if(PositionsTotal() > 0)
         manage_setup();
  }
//+------------------------------------------------------------------+