//+------------------------------------------------------------------+
//|                                                 SDS_UMM_ver1.mq4 |
//|                                                         Zen_Leow |
//|                                                                  |
//+------------------------------------------------------------------+
/*
Indicators: 
1. 200 SMA (option to change period by user)
2. ADR - 50 pips or greater on the previous 10 days
3. PSAR - this can be optional to use with the SMA (user defined) that allows trades only to be taken when both indicators agree

R/R ratio: 1:1 

Stop loss: (user defined) will be using 100 pips to include spread

Take profit: (user defined) will be using 100 pips after covering spread

Pairs:
All that have an ADR equal to or greater than 50 pips

Broker: Personal preference (will test using IBFX w/10K starting balance)

Money Management: Each contract will be equal to .1 lot. (option to change lot size per user)

Example using MM: To begin open 1 contract for each pair in the direction of the indicator(s). If a win is obtained, continue with 1 contract. If a loss is obtained in a given pair then increase 1 contract for the next trade. Continue to add 1 contract if consecutive losses. Once a win is generated after a loss reverse contract size by 1 until the contract size returns back to the beginning of 1 thus eliminating all the losing trades.

Exaple of opening a trade:

Long - at the open of a new candle if the previous candle is > 200 SMA (optional to add the PSAR and trade only when both agree)

Short - at the open of a new candle if the previous candle is < 200 SMA
(optional to add the PSAR and trade only when both agree)

Let the position run until either the take profit or stop loss is hit.
*/

#property copyright "Zen_Leow"
#property link      ""
#include <stdlib.mqh>
#include <stderror.mqh>

extern int       EA_MAGIC_NUM = 275931;
extern int       MA_Period = 200;
extern int       MA_TYPE = MODE_SMA;
extern bool      UsePSAR = true;
extern int       ADR_Days = 10;
extern int       Min_Range = 50;

extern int       Start_Hour = 0;
extern int       Start_Minute = 0;

extern double    Slippage = 3.0;
extern int       TakeProfit = 100;
extern int       StopLoss = 100;

extern int       LotSizeFactor = 1;
extern double    Lots = 0.1;

string msg = "";
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   WriteComment();
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }

void WriteComment()
{
   msg = "";
   
   msg = msg + "Average Range of "+ADR_Days+" days: "+GetAverageRange(ADR_Days);
   msg = msg +" \nLotSizeFactor: "+LotSizeFactor;
   if (UsePSAR)
   {
      msg = msg +" \nPSAR used?: YES";
   }
   else
   {
      msg = msg +" \nPSAR used?: NO";
   }
   msg = msg + "\nStart_Hour: "+Start_Hour;
   msg = msg + "\nStart_Minute: "+Start_Minute;
   
   Comment(msg);
}

int GetAverageRange(int DaysNum)
{
   int range = 0;
   for(int i=1;i<=DaysNum;i++)
   {
      range = range + ((iHigh(NULL,PERIOD_D1,i) - iLow(NULL,PERIOD_D1,i)) / Point);
   }
   range = range / DaysNum;
   return (range);
}

double GetMAValue(int index)
{
   return (iMA(NULL,0,MA_Period,0,MA_TYPE,PRICE_CLOSE,index));
}

double GetSARValue(int index)
{
   return (iSAR(NULL,0,0.02,0.2,index));
}

bool ShouldBuy()
{
   if (Close[1] > GetMAValue(1) && GetAverageRange(ADR_Days) >= Min_Range)
   {
      if (UsePSAR) 
      {
         if(Low[1] > GetSARValue(1))
         {
            return (true);
         }
         else
         {
            return (false);
         }
      }
      else
      {
         return (true);
      }
   }
   return (false);
}

bool ShouldSell()
{
   if (Close[1] < GetMAValue(1) && GetAverageRange(ADR_Days) >= Min_Range)
   {
      if (UsePSAR) 
      {
         if(High[1] < GetSARValue(1))
         {
            return (true);
         }
         else
         {
            return (false);
         }
      }
      else
      {
         return (true);
      }
   }
   return (false);
}

int GetLotSizeFactor()
{
   int histotal = OrdersHistoryTotal();
   if (histotal > 0)
   {
      for(int cnt=histotal-1;cnt>=0;cnt--) // retrieve closed orders counting from the last.
      {
         if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
            {
               if(OrderProfit() < 0) // latest order close was a loss
               {
                  LotSizeFactor = LotSizeFactor + 1;
                  return (LotSizeFactor);
               }
               else // latest order closed was a win
               {
                  LotSizeFactor = LotSizeFactor - 1;
                  if (LotSizeFactor <= 0)
                  {
                     LotSizeFactor = 1;
                  }
                  return (LotSizeFactor);
               }
            }
         }
      }
   }
   return (LotSizeFactor); // no trades recorded in history just return the starting number.
}

bool DecideToOpenTrade()
{
   int total = OrdersTotal();
   if (total > 0)
   {
      for(int cnt=0;cnt<total;cnt++)
      {
         if(OrderSelect(cnt,SELECT_BY_POS))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM) // currently there's a trade running, don't add to it.
            {
               return (false);
            }
         }
      }
   }
   // in case trades has already opened and closed within the candle
   int histotal = OrdersHistoryTotal();
   if (histotal > 0)
   {
      for(cnt=0;cnt<histotal;cnt++)
      {
         if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
            {
               if (Time[0] <= OrderOpenTime()) // don't open a new position if we're still on the same candle
               {
                  return (false);
               }
            }
         }
      }
   }
   return (true);
}

void SendOrders (int BuyOrSell, double LotSize, double PriceToOpen, double Slippage, double SL_Price, double TP_Price, string comments, datetime ExpirationTime)
{
   int PositionType, ticket, errorType;
   
   if (BuyOrSell == OP_BUY)
   {  
      PositionType = OP_BUY;
      Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Buy Order: "+Symbol()+", "+PositionType+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Green");
      ticket=OrderSend(Symbol(),PositionType,LotSize,PriceToOpen,Slippage,SL_Price,TP_Price,comments,EA_MAGIC_NUM,ExpirationTime,Green);
      if(ticket>0)
      {
         if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
         {
            
            Print("BUY order opened : ",OrderOpenPrice());
            msg = ticket + ": Buy position opened on "+Symbol()+" at "+ Day()+"/"+Month()+"/"+Year()+" - "+Hour()+":"+Minute()+":"+Seconds();
            WriteToLogFile(msg);
            Start_Hour = 0;
            Start_Minute = 0;
         }
      }
      else 
      {  
         errorType = GetLastError();
         Print("Error opening BUY order : ", ErrorDescription(errorType));
         msg = "CANNOT open BUY position on "+Symbol()+" at "+ Day()+"/"+Month()+"/"+Year()+" - "+Hour()+":"+Minute()+":"+Seconds();
         WriteToLogFile(msg);
      }
   }
   if (BuyOrSell == OP_SELL)
   {  
      PositionType = OP_SELL;
      Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Sell Order: "+Symbol()+", "+PositionType+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Red");
      ticket=OrderSend(Symbol(),PositionType,LotSize,PriceToOpen,Slippage,SL_Price,TP_Price,comments,EA_MAGIC_NUM,ExpirationTime,Red);
      if(ticket>0)
      {
         if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
         {
            
            Print("Sell order opened : ",OrderOpenPrice());
            msg = ticket + ": Sell position opened on "+Symbol()+" at "+ Day()+"/"+Month()+"/"+Year()+" - "+Hour()+":"+Minute()+":"+Seconds();
            WriteToLogFile(msg);
            Start_Hour = 0;
            Start_Minute = 0;
         }
      }
      else 
      {  
         errorType = GetLastError();
         Print("Error opening SELL order : ", ErrorDescription(errorType));
         msg = "CANNOT open SELL position on "+Symbol()+" at "+ Day()+"/"+Month()+"/"+Year()+" - "+Hour()+":"+Minute()+":"+Seconds();
         WriteToLogFile(msg);
      }
   }
}

void WriteToLogFile(string input)
{
   string filename = "SDS_MM-"+Symbol()+"-"+Day()+"-"+Month()+"-"+Year()+".log";
   int handle = FileOpen(filename,FILE_READ|FILE_WRITE);
   if (handle>1)
   {
      FileSeek(handle, 0, SEEK_END); // go to end of file
      FileWrite(handle, input);
      FileClose(handle);
   }
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   WriteComment();
//----
   int CurrentHour = TimeHour(TimeCurrent());
   int CurrentMinute = TimeMinute(TimeCurrent());
   if (CurrentHour == Start_Hour && CurrentMinute == Start_Minute)
   {
      double PriceToOpen;
      double TakeProfitPrice;
      double StopLossPrice;
      
      if (ShouldBuy())
      {
         if (DecideToOpenTrade())
         {
            PriceToOpen = Ask;
            if (TakeProfit == 0)
            {
               TakeProfitPrice = 0;
            }
            else
            {
               TakeProfitPrice = PriceToOpen + (TakeProfit * Point);
               TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
            }
            if (StopLoss == 0)
            {
               StopLossPrice = 0;
            }
            else
            {
               StopLossPrice = PriceToOpen - (StopLoss * Point);
               StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
            }
            SendOrders(OP_BUY, Lots * GetLotSizeFactor(), PriceToOpen, Slippage, StopLossPrice, TakeProfitPrice, "SDS_MM_Buy_"+EA_MAGIC_NUM, 0);
         }
      }
      if (ShouldSell())
      {
         if (DecideToOpenTrade())
         {
            PriceToOpen = Bid;
            if (TakeProfit==0)
            {
               TakeProfitPrice = 0;
            }
            else
            {
               TakeProfitPrice = PriceToOpen - (TakeProfit * Point);
               TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
            }
            if (StopLoss==0)
            {
               StopLossPrice = 0;
            }
            else
            {
               StopLossPrice = PriceToOpen + (StopLoss * Point);
               StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
            }
            SendOrders(OP_SELL, Lots * GetLotSizeFactor(), PriceToOpen, Slippage, StopLossPrice, TakeProfitPrice, "SDS_MM_Sell_"+EA_MAGIC_NUM, 0);
         }
      }
   }
//----
   return(0);
}
//+------------------------------------------------------------------+