//+------------------------------------------------------------------+
//|                                        Williama PriceTrapper.mq4 |
//|                              Based on the strategie of Williama  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright ""
#property link      ""

//---- input parameters
extern int       pips=15; // number of pips between each level
extern double    lots=0.1;
extern int       NbLevels=3; // Number of levels of the pending orders (for each target, buy and sell)
extern bool      UseProfitTarget=true;
extern int       ProfitTarget=10; //Minimum profit target, in pips. Whatever happen, at least this profit is made (unless we run out of free margin...).
extern bool      UsePartialProfitTarget=false;
extern int       First_Target = 10;
extern int       Target_Increment = 10;
extern double    Close_Lots = 0.01;
extern bool      ContinueTrading=true;
extern bool      UseEntryTime=false;
extern int       EntryTime=0;

bool Enter=true;
int nextTP;

int Magic=17663;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   nextTP = First_Target;
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   int ticket, cpt, profit, total=0, BuyGoalProfit, SellGoalProfit, PipsLot;
   double BuyGoal=0, SellGoal=0, spread=(Ask-Bid)/Point, InitialPrice=0;
//----
  
   if(pips<MarketInfo(Symbol(),MODE_STOPLEVEL)+spread) pips=1+MarketInfo(Symbol(),MODE_STOPLEVEL)+spread;
   if(lots<MarketInfo(Symbol(),MODE_MINLOT)) lots=MarketInfo(Symbol(),MODE_MINLOT);
   for(cpt=1;cpt<NbLevels;cpt++) PipsLot+=cpt*pips;
   //check Initial Price and Take partial profit if necessary
   for(cpt=0;cpt<OrdersTotal();cpt++)
   {
      OrderSelect(cpt,SELECT_BY_POS,MODE_TRADES);
      if(OrderMagicNumber()==Magic && OrderSymbol()==Symbol())
      {
         total++;
         if(!InitialPrice) InitialPrice=StrToDouble(OrderComment());
         if(UsePartialProfitTarget && UseProfitTarget && OrderType()<2)
         {
            double val=getPipValue(OrderOpenPrice(),OrderType());
//          if(Use_Max_Loss && Max_Loss > 0) killTrade(val,OrderTicket());
//          if(Move_Stops) checkStops(val,OrderTicket());
            takeProfit(val,OrderTicket()); 
         }
      }
   }
   if(total<1 && Enter && (!UseEntryTime || (UseEntryTime && Hour()==EntryTime))) //we can set up a new "price catcher"
   {
      if(AccountFreeMargin()<(10000*lots))
      {
         Print("Not enough free margin to begin");
         return(0);
      }
      InitialPrice=Ask;
      SellGoal=InitialPrice-(NbLevels+1)*pips*Point;
      BuyGoal=InitialPrice+(NbLevels+1)*pips*Point;
      for(cpt=1;cpt<=NbLevels;cpt++)
      {
         OrderSend(Symbol(),OP_BUYSTOP,lots,InitialPrice+cpt*pips*Point,2,SellGoal,BuyGoal,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),Magic,0,Green);
         OrderSend(Symbol(),OP_SELLSTOP,lots,InitialPrice-cpt*pips*Point,2,BuyGoal+spread*Point,SellGoal+spread*Point,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),Magic,0,Green);
      }
    } // initial setup done
    else
    {
      BuyGoal=InitialPrice+pips*(NbLevels+1)*Point;
      SellGoal=InitialPrice-pips*(NbLevels+1)*Point;
      total=OrdersHistoryTotal();
      for(cpt=0;cpt<total;cpt++)
      {
         OrderSelect(cpt,SELECT_BY_POS,MODE_HISTORY);
         if(OrderMagicNumber()==Magic && OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice) {EndSession();return(0);}
      }
      
      if(UseProfitTarget && CheckProfits(lots,OP_SELL,true,InitialPrice)>ProfitTarget) {EndSession();return(0);}
      
      BuyGoalProfit=CheckProfits(lots,OP_BUY,false,InitialPrice);
      SellGoalProfit=CheckProfits(lots,OP_SELL,false,InitialPrice);
      if(BuyGoalProfit<ProfitTarget)
      {
         for(cpt=NbLevels;cpt>=0 && BuyGoalProfit<ProfitTarget;cpt--)
         {
            if(Ask<=(InitialPrice+(cpt*pips-MarketInfo(Symbol(),MODE_STOPLEVEL))*Point))
            {
               ticket=OrderSend(Symbol(),OP_BUYSTOP,lots,InitialPrice+cpt*pips*Point,2,SellGoal,BuyGoal,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),Magic,0,Green);
            }
            if(ticket>0) BuyGoalProfit+=lots*(BuyGoal-InitialPrice-cpt*pips*Point)/Point;
         }
      }
      if(SellGoalProfit<ProfitTarget)
      {
         for(cpt=NbLevels;cpt>=0 && SellGoalProfit<ProfitTarget;cpt--)
         {
            if(Bid>=(InitialPrice-(cpt*pips-MarketInfo(Symbol(),MODE_STOPLEVEL))*Point))
            {
               ticket=OrderSend(Symbol(),OP_SELLSTOP,lots,InitialPrice-cpt*pips*Point,2,BuyGoal+spread*Point,SellGoal+spread*Point,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),Magic,0,Green);
            }
            if(ticket>0) SellGoalProfit+=lots*(InitialPrice-cpt*pips*Point-SellGoal-spread*Point)/Point;
         }
      }
   }
   string sComment   = "";
   string sep         = "----------------------------------------\n";
   string nl         = "\n";
   sComment = "Williama EA v0.2" + nl;
   sComment = sComment + "Lots=" + DoubleToStr(lots,2) + nl;
   sComment = sComment + "Buy Goal= " + DoubleToStr(BuyGoal,4) + nl; 
   sComment = sComment + "Buy Goal Profit (in pips)=" + BuyGoalProfit + nl + nl;
   sComment = sComment + "Sell Goal= " + DoubleToStr(SellGoal,4) + nl; 
   sComment = sComment + "Sell Goal Profit (in pips)=" + SellGoalProfit + nl + nl;
   sComment = sComment + "Pips of each level=" + pips + nl;
   sComment = sComment + "Number of levels for each goal: " + NbLevels + nl;
   sComment = sComment + sep;  
   Comment(sComment);
//----
   return(0);
  }
//+------------------------------------------------------------------+

int CheckProfits(double lots, int Goal, bool Current, double InitialPrice)
{
   int profit=0, cpt;
   if(Current)//return current profit
   {
      for(cpt=0;cpt<OrdersTotal();cpt++)
      {
         OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
         if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
         {
            if(OrderType()==OP_BUY) profit+=(Bid-OrderOpenPrice())/Point*OrderLots()/lots;
            if(OrderType()==OP_SELL) profit+=(OrderOpenPrice()-Ask)/Point*OrderLots()/lots;
         }
      }
      return(profit);
   }
   else
   {
      if(Goal==OP_BUY)
      {
         for(cpt=0;cpt<OrdersTotal();cpt++)
         {
            OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
            if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
            {
               if(OrderType()==OP_BUY) profit+=(OrderTakeProfit()-OrderOpenPrice())/Point*OrderLots()/lots;
               if(OrderType()==OP_SELL) profit-=(OrderStopLoss()-OrderOpenPrice())/Point*OrderLots()/lots;
               if(OrderType()==OP_BUYSTOP) profit+=(OrderTakeProfit()-OrderOpenPrice())/Point*OrderLots()/lots;
            }
         }
         return(profit);
      }
      else
      {
         for(cpt=0;cpt<OrdersTotal();cpt++)
         {
            OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
            if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
            {
               if(OrderType()==OP_BUY) profit-=(OrderOpenPrice()-OrderStopLoss())/Point*OrderLots()/lots;
               if(OrderType()==OP_SELL) profit+=(OrderOpenPrice()-OrderTakeProfit())/Point*OrderLots()/lots;
               if(OrderType()==OP_SELLSTOP) profit+=(OrderOpenPrice()-OrderTakeProfit())/Point*OrderLots()/lots;
            }
         }
         return(profit);
      }
   }
}

bool EndSession()
{
   int cpt, total=OrdersTotal();
   for(cpt=0;cpt<total;cpt++)
   {
      OrderSelect(cpt,SELECT_BY_POS,MODE_TRADES);
      if(OrderSymbol()==Symbol() && OrderType()>1) OrderDelete(OrderTicket());
      else if(OrderSymbol()==Symbol() && OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,Red);
      else if(OrderSymbol()==Symbol() && OrderType()==OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
      }
      if(!ContinueTrading)  Enter=false;
      return(true);
}


double getPipValue(double ord,int dir)
{
   double val;
   RefreshRates();
   if(dir == 1) val=(NormalizeDouble(ord,Digits) - NormalizeDouble(Ask,Digits));
   else val=(NormalizeDouble(Bid,Digits) - NormalizeDouble(ord,Digits));
   val = val/Point;
   return(val);   
}

//========== FUNCTION takeProfit
void takeProfit(int current_pips, int ticket)
{
   if(OrderSelect(ticket, SELECT_BY_TICKET))
   {

      if(current_pips >= nextTP && current_pips < (nextTP + Target_Increment))
      {
         if(OrderType()==1)
         {
            if(OrderClose(ticket, Close_Lots, Ask, 3, YellowGreen))
            nextTP+=Target_Increment;
            else
            Print("Error closing order : ",GetLastError()); 
         } 
         else
         {
            if(OrderClose(ticket, Close_Lots, Bid, 3, YellowGreen))
            nextTP+=Target_Increment;
            else
            Print("Error closing order : ",GetLastError()); 
         }
              
      }

   }
}

