//+------------------------------------------------------------------+
//|                                                                  |
//|                                3pSAR_EA.mq4 - Ver 1.0            |
//|                                                                  |

//| Description of EA

//| Time Frame
//| M1, M15 and H1
 
//| Indicator
//| parabolic SAR changed to 0.01 and 0.1
 
//| Entry Strategy
//| When H1 and M15 are in the same direction then every time that M1 changes in that direction,
//| enter a trade at the completion of the candle.
 
//| Exit Strategy
//| At this stage apply a default Trailing Stop of 15 pips.
//| The TS must be enabled the minute it is applied, and not wait to trail at Break Even, to negate the need for a SL.
  
//+------------------------------------------------------------------+


#property copyright "Robert Hill"
#property link      "None"
#include <stdlib.mqh>
#include <stderror.mqh> 

// This makes code easier to read


extern string  Expert_Name    = "3pSar_EA_v1.0";
extern int     MagicNumberBase = 10000;
//+---------------------------------------------------+
//|Money Management                                   |
//+---------------------------------------------------+
extern double  Lots=0.1;

//+---------------------------------------------------+
//|Indicator Variables                                |
//| Change these to try your own system               |
//| or add more if you like                           |
//+---------------------------------------------------+
extern string  ps1 = "--pSAR inputs--";
extern int     pSAR_Step = 0.01;
extern double  pSAR_Max = 0.1;
extern int     pSAR1_TimeFrame = 60;
extern int     pSAR2_TimeFrame = 15;
extern int     pSAR3_TimeFrame = 1;


//+---------------------------------------------------+
//|Profit controls                                    |
//+---------------------------------------------------+
extern string  st6 = "--Profit Controls--";
extern double  StopLoss=15;
extern double  TakeProfit=0;
extern int     Slippage=3;
extern int     MaxTrades = 1;

//+---------------------------------------------------+
//|General controls                                   |
//+---------------------------------------------------+
int            MagicNumber=0;
string         setup;
int            TradesInThisSymbol = 0;
datetime       timeprev = 0;

//+---------------------------------------------------+
//|  Indicator values for signals and filters         |
//|  Add or Change to test your system                |
//+---------------------------------------------------+

//+------------------------------------------------------------------+
//| Calculate MagicNumber, setup comment and assign RSI Period       |
//|                                                                  |
//+------------------------------------------------------------------+
int init()
{

	MagicNumber = MagicNumberBase + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period()); 
   setup=Expert_Name + Symbol() + "_" + func_TimeFrame_Val2String(func_TimeFrame_Const2Val(Period()));
    
 return(0);
}

int deinit()
{
 return(0);
}

//+------------------------------------------------------------------+
//| CheckExitCondition                                               |
//|
//| BUY
//|  The exit comes one of two ways.
//|  Most common 8 MA go through the yellow mid keltner band,
//|  but occasionally the 2 MA will go through first.
//|  But which ever goes through first it should be the exit.
//|
//| SELL
//|
//+------------------------------------------------------------------+
int CheckExitCondition(int cmd)
{
   
   return (false);
}

//+------------------------------------------------------------------+
//| CheckEntryCondition                                              |
//|                                                                  |
//| Indicators used                                                  |
//| pSAR                                                             |
//| When H1 and M15 are in the same direction then
//| every time that M1 changes in that direction,
//| enter a trade at the completion of the candle.
//+------------------------------------------------------------------+
  
bool CheckEntryCondition(int cmd)
{
   double pSAR_H1, pSAR_M15, pSAR_M1, pSAR_M1Prev;
   
   pSAR_H1 = iSAR(Symbol(), pSAR1_TimeFrame, pSAR_Step, pSAR_Max, 1);
   pSAR_M15 = iSAR(Symbol(), pSAR2_TimeFrame, pSAR_Step, pSAR_Max, 1);
   pSAR_M1 = iSAR(Symbol(), pSAR3_TimeFrame, pSAR_Step, pSAR_Max, 1);
   pSAR_M1Prev = iSAR(Symbol(), pSAR3_TimeFrame, pSAR_Step, pSAR_Max, 2);
                         
   switch (cmd)
   {
     case OP_BUY  : if (pSAR_H1 < Bid)
                    {
                       if (pSAR_M15 < Bid)
                       {
                          if (pSAR_M1 < Bid && pSAR_M1Prev > Bid) return (true);
                       }
                    }
                    break;
     case OP_SELL : if (pSAR_H1 > Bid)
                    {
                       if (pSAR_M15 > Bid)
                       {
                          if (pSAR_M1 > Bid && pSAR_M1Prev < Bid) return (true);
                       }
                    }   }
   
   return (false);
}
  
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Start                                                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int start()
{ 


// Only run once per completed bar

     if(timeprev==Time[0]) return(0);
     timeprev = Time[0];
     
//+------------------------------------------------------------------+
//| Check for Open Position                                          |
//+------------------------------------------------------------------+

     HandleOpenPositions();
     
// Check if any open positions were not closed

     TradesInThisSymbol = CheckOpenPositions();
  
// Only allow 1 trade per Symbol

     if(TradesInThisSymbol >= MaxTrades) {
       return(0);}
   
 //+------------------------------------------------------------------+
//| Friday No trade zone                                             |
//+------------------------------------------------------------------+


	if (CheckEntryCondition(OP_BUY)==true)
	{
		   OpenBuyOrder(Lots, StopLoss,TakeProfit, Slippage, setup, MagicNumber, Green);
		   return(0);
	}

   
	if (CheckEntryCondition(OP_SELL)==true)
	{
         OpenSellOrder(Lots, StopLoss,TakeProfit, Slippage, setup, MagicNumber, Red);
	}

  return(0);
}


//+------------------------------------------------------------------+
//| OpenBuyOrder                                                     |
//| If Stop Loss or TakeProfit are used the values are calculated    |
//| for each trade                                                   |
//+------------------------------------------------------------------+
int OpenBuyOrder(double mLots, double mStopLoss, double mTakeProfit, int mSlippage, string mComment, int mMagic, color mColor)
{
   int err,ticket;
   double myStopLoss = 0, myTakeProfit = 0;
   
   RefreshRates();
   myStopLoss = StopLong(Bid,mStopLoss);
   myTakeProfit = TakeLong(Bid,mTakeProfit);
 // Normalize all price / stoploss / takeprofit to the proper # of digits.
   if (Digits > 0) 
   {
     myStopLoss = NormalizeDouble( myStopLoss, Digits);
     myTakeProfit = NormalizeDouble( myTakeProfit, Digits); 
   }
   ticket=OrderSend(Symbol(),OP_BUY,mLots,Ask,mSlippage,myStopLoss,myTakeProfit,mComment,mMagic,0,mColor); 
   if (ticket > 0)
   {
    if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) 
     {
      Print("BUY order opened : ", OrderOpenPrice( ));
//      PlaySound("Alert.wav");
     }
   }
   else
   {
      err = GetLastError();
      Print("Error opening BUY order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); 
   }
   
   return(ticket);
}

//+------------------------------------------------------------------+
//| OpenSellOrder                                                    |
//| If Stop Loss or TakeProfit are used the values are calculated    |
//| for each trade                                                   |
//+------------------------------------------------------------------+
int OpenSellOrder(double mLots, double mStopLoss, double mTakeProfit, int mSlippage, string mComment, int mMagic, color mColor)
{
   int err, ticket;
   double myBid, myAsk, myStopLoss = 0, myTakeProfit = 0;
   
   myStopLoss = StopShort(Ask,mStopLoss);
   myTakeProfit = TakeShort(Ask,mTakeProfit);
   
 // Normalize all price / stoploss / takeprofit to the proper # of digits.
   if (Digits > 0) 
   {
     myStopLoss = NormalizeDouble( myStopLoss, Digits);
     myTakeProfit = NormalizeDouble( myTakeProfit, Digits); 
   }
   ticket=OrderSend(Symbol(),OP_SELL,mLots,Bid,mSlippage,myStopLoss,myTakeProfit,mComment,mMagic,0,mColor); 
   if (ticket > 0)
   {
     if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) 
     {
      Print("Sell order opened : ", OrderOpenPrice());
//      PlaySound("Alert.wav");
     }
   }
   else
   {
      err = GetLastError();
      Print("Error opening Sell order [" + mComment + "]: (" + err + ") " + ErrorDescription(err));
   }
   
   return(ticket);
}


double StopLong(double price,int stop)
{
 if(stop==0)
  return(0);
 else
  return(price-(stop*Point));
}

double StopShort(double price,int stop)
{
 if(stop==0)
  return(0);
 else
  return(price+(stop*Point));
}

double TakeLong(double price,int take)
{
 if(take==0)
  return(0);
 else
  return(price+(take*Point));
}

double TakeShort(double price,int take)
{
 if(take==0)
  return(0);
 else
  return(price-(take*Point));
}

//+------------------------------------------------------------------+
//| Handle Open Positions                                            |
//| Check if any open positions need to be closed or modified        |
//+------------------------------------------------------------------+
int HandleOpenPositions()
{
   int cnt, ticket, ExitRule;
   double ol;
   
   for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
   {
      OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol() != Symbol()) continue;
      if ( OrderMagicNumber() != MagicNumber)  continue;
      
      ticket = OrderTicket();
      ol = OrderLots();
      if(OrderType() == OP_BUY)
      {
            
         if (CheckExitCondition(OP_BUY) == true)
          {
              CloseOrder(ticket,ol,OP_BUY);
          }

          else
          {
               HandleTrailingStop(OP_BUY,ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit());
          }
      }

      if(OrderType() == OP_SELL)
      {
          if (CheckExitCondition(OP_SELL) == true)
          {
             CloseOrder(ticket,ol,OP_SELL);
          }
          else
          {
               HandleTrailingStop(OP_SELL,ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit());
          }
      }
   }
}

//+------------------------------------------------------------------+
//| Check Open Position Controls                                     |
//+------------------------------------------------------------------+
  
int CheckOpenPositions()
{
   int cnt, total;
   int NumTrades;
   
   NumTrades = 0;
   total=OrdersTotal();
   for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
     {
      OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
      if ( OrderSymbol() != Symbol()) continue;
      if ( OrderMagicNumber() != MagicNumber)  continue;
      
      if(OrderType() == OP_BUY )  NumTrades++;
      if(OrderType() == OP_SELL )  NumTrades++;
             
     }
     return (NumTrades);
  }
  

int CloseOrder(int ticket,double numLots,int cmd)
{
	bool result;
   int CloseCnt, err;
   double myPrice;
   
   // try to close 3 Times
      
    CloseCnt = 0;
    while (CloseCnt < 3)
    {
      if (cmd == OP_BUY) myPrice = Bid;
      if (cmd == OP_SELL) myPrice = Ask;
      if (Digits > 0)  myPrice = NormalizeDouble( myPrice, Digits);
      if ( OrderClose(ticket,numLots,myPrice,Slippage,Violet) == true)
         CloseCnt = 3;
      else
      {
         err=GetLastError();
         if (err > 0)	
		   {
            Print(" Error closing order : (", err , ") " + ErrorDescription(err));
            Sleep(5000);
			   RefreshRates(); 
		   }
		   CloseCnt++;
		}
	}  
	 
   return(0);

}

//+------------------------------------------------------------------+
//| HandleTrailingStop                                               |
//| Type 1 moves the stoploss without delay.                         |
//| Type 2 waits for price to move the amount of the trailStop       |
//| before moving stop loss then moves like type 1                   |
//| Type 3 uses up to 3 levels for trailing stop                     |
//|      Level 1 Move stop to 1st level                              |
//|      Level 2 Move stop to 2nd level                              |
//|      Level 3 Trail like type 1 by fixed amount other than 1      |
//| Type 4 Move stop to breakeven + Lockin, no trail                 |
//| Type 5 uses steps for 1, every step pip move moves stop 1 pip    |
//| Type 6 Uses EMA to set trailing stop                             |
//+------------------------------------------------------------------+
void HandleTrailingStop(int type, int ticket, double op, double os, double tp)
{
/*
   switch (TrailingStopType)
   {
     case 1 :
*/     
      Immediate_TrailingStop (type, ticket, op, os, tp);
//              break;
/*
     case 2 : Delayed_TrailingStop (type, ticket, op, os, tp);
              break;
     case 3 : ThreeLevel_TrailingStop (type, ticket, op, os, tp);
              break;
     case 4 : BreakEven_TrailingStop (type, ticket, op, os, tp);
              break;
	  case 5 : eTrailingStop (type, ticket, op, os, tp);
              break;
	  case 6 : MA_TrailingStop (type, ticket, op, os, tp);
              break;
	  case 7 : pSAR_TrailingStop (type, ticket, op, os, tp);
              break;
	}
*/
}
//+------------------------------------------------------------------+
//|                                       Immediate_TrailingStop.mq4 |
//|                                  Copyright © 2006, Forex-TSD.com |
//|                         Written by MrPip,robydoby314@yahoo.com   |
//|                                                                  |   
//| Moves the stoploss without delay.                                |
//+------------------------------------------------------------------+
void Immediate_TrailingStop(int type, int ticket, double op, double os, double tp)
{

   double pt, pp, BuyStop, SellStop;

   pp = MarketInfo(Symbol(), MODE_POINT);
   
   if (type==OP_BUY)
   {
     pt = StopLoss * pp;
     if(Bid-os > pt)
     {
       BuyStop = Bid - pt;
       if (Digits > 0) BuyStop = NormalizeDouble( BuyStop, Digits);
		 BuyStop = ValidStopLoss(OP_BUY,Bid, BuyStop);   
       if (os < BuyStop) ModifyOrder(ticket,op,BuyStop,tp,LightGreen);
		 return;
	  }
   }
   if (type==OP_SELL)
   {
     pt = StopLoss * pp;
     if(os - Ask > pt)
     {
       SellStop = Ask + pt;
       if (Digits > 0) SellStop = NormalizeDouble( SellStop, Digits);
       SellStop = ValidStopLoss(OP_SELL, Ask, SellStop);  
       if (os > SellStop) ModifyOrder(ticket,op,SellStop,tp,DarkOrange);
		 return;
     }
   }   
}

int ModifyOrder(int ord_ticket,double op, double price,double tp, color mColor)
{
    int CloseCnt, err;
    
    CloseCnt=0;
    while (CloseCnt < 3)
    {
       if (OrderModify(ord_ticket,op,price,tp,0,mColor)== true)
       {
         CloseCnt = 3;
       }
       else
       {
          err=GetLastError();
          Print(CloseCnt," Error modifying order : (", err , ") " + ErrorDescription(err));
          Sleep(5000);
          if (err>0) CloseCnt++;
       }
    }
}

double ValidStopLoss(int type, double price, double SL)
{

   double mySL;
   double minstop, pp;
   
   pp = MarketInfo(Symbol(), MODE_POINT);
   minstop = MarketInfo(Symbol(),MODE_STOPLEVEL);
   
   mySL = SL;
   if (type == OP_BUY)
   {
		 if((price - mySL) < minstop*pp) mySL = price - minstop*pp;
   }
   if (type == OP_SELL)
   {
       if((mySL-price) < minstop*pp)  mySL = price + minstop*pp;  
   }

   return(NormalizeDouble(mySL,MarketInfo(Symbol(), MODE_DIGITS)));   
}

int func_Symbol2Val(string symbol)
 {
   string mySymbol = StringSubstr(symbol,0,6);
   
	if(mySymbol=="AUDCAD") return(1);
	if(mySymbol=="AUDJPY") return(2);
	if(mySymbol=="AUDNZD") return(3);
	if(mySymbol=="AUDUSD") return(4);
	if(mySymbol=="CHFJPY") return(5);
	if(mySymbol=="EURAUD") return(6);
	if(mySymbol=="EURCAD") return(7);
	if(mySymbol=="EURCHF") return(8);
	if(mySymbol=="EURGBP") return(9);
	if(mySymbol=="EURJPY") return(10);
	if(mySymbol=="EURUSD") return(11);
	if(mySymbol=="GBPCHF") return(12);
	if(mySymbol=="GBPJPY") return(13);
	if(mySymbol=="GBPUSD") return(14);
	if(mySymbol=="NZDJPY") return(15);
	if(mySymbol=="NZDUSD") return(16);
	if(mySymbol=="USDCAD") return(17);
	if(mySymbol=="USDCHF") return(18);
	if(mySymbol=="USDJPY") return(19);
   Comment("unexpected Symbol");
	return(999);
}

//+------------------------------------------------------------------+
//| Time frame interval appropriation  function                      |
//+------------------------------------------------------------------+

int func_TimeFrame_Const2Val(int Constant ) {
   switch(Constant) {
      case 1:  // M1
         return(1);
      case 5:  // M5
         return(2);
      case 15:
         return(3);
      case 30:
         return(4);
      case 60:
         return(5);
      case 240:
         return(6);
      case 1440:
         return(7);
      case 10080:
         return(8);
      case 43200:
         return(9);
   }
}

//+------------------------------------------------------------------+
//| Time frame string appropriation  function                               |
//+------------------------------------------------------------------+

string func_TimeFrame_Val2String(int Value ) {
   switch(Value) {
      case 1:  // M1
         return("PERIOD_M1");
      case 2:  // M1
         return("PERIOD_M5");
      case 3:
         return("PERIOD_M15");
      case 4:
         return("PERIOD_M30");
      case 5:
         return("PERIOD_H1");
      case 6:
         return("PERIOD_H4");
      case 7:
         return("PERIOD_D1");
      case 8:
         return("PERIOD_W1");
      case 9:
         return("PERIOD_MN1");
   	default: 
   		return("undefined " + Value);
   }
}

//+------------------------------------------------------------------+


