//+------------------------------------------------------------------+
//|                                       Profit Generator 3.3.2.mq4 |
//|                                                                  |
//|                 No Copyright, created 20 March 2006, Open Source |
//|                                         http://www.forex-tsd.com |
//|                                       http://www.tradingintl.com |
//|                                                                  | 
//|        Freely receive, Freely give. Please post updated version. |
//|                  Default Settings on EURUSD, GBPUSD, and USDCHF  |
//+------------------------------------------------------------------+


#property copyright "Created in 2006, Open Source Project"
#property link      "http://www.forex-tsd.com"
#include <stdlib.mqh>
#include <WinUser32.mqh>

///////////////////////////////////////////////////Variables//////////////////////////////
extern string  EAname="Pro-Gen_3";
extern int     ID_BASE=100000; // Change this number if running more than one EA on the same pair
extern int     LongBar=15; // sets the minimum length of the bar
extern double     BarOpenPercent=0.50;// Set this to determine the percent of the bar which the trade takes place.
extern int     MaxTrades=1;          //maximum number of trades open at a time
extern double  lots=0.1; // This number will not matter if using Money Management 
extern int     stoploss=20,takeprofit=100;
extern bool    MM = true; //Use Money Management or not
extern double  Risk = 10; //percent of available margin to risk.
extern int     PairsTraded=0; //if set to 0 then std MM.  If set to the number of Pairs traded then the risk is divided amongst the number of pairs.

extern bool    UseClose=false; // This will use the SuperClose().  
extern int     TSactivation=40,TrailPips=5; // TSactivation will set the point where the TS will start. 

extern bool    UseHourTrade = false; // Time filter
extern int     FromHourTrade = 7; // start trading on this hour
extern int     ToHourTrade = 20; // end trading on this hour

extern bool    UseSimpleTF=false;
extern int     period=0; // leave this number as zero to use the period from the chart.
extern bool    OneTradeperPeriod=false;  //This will only allow one new trade per period.
extern bool    Alerts=false,AlertOnlyMode=false;// Alerts will alert when trade signal is present.  AOM will not place trades, but will alert to the platform
extern bool    WeekendMode=true;//True=Will close all trades on and after the hour to close.
extern int     hour_to_close=21;
extern bool    EMAconfirm=false; // Uses EMA direction to confirm trades. eg. If Low EMA (lower of two MAperiods)>HighEMA then the market is bearish.
extern int     LowEMA=10;// lower of EMA TF
extern int     HighEMA=16;// higher of EMA TF
extern int     EMAtf=0;// if 0 then it uses the chart TF, otherwise it will use the period based on period settings.
extern bool    UseStoOpen=false;
extern int     StoTF=1;
extern bool    Reverse=true;// reverses orders regardless of ALL signal direction
extern bool    UseObsoleteMethod=True;
extern bool    OMwhenLossOnly=false;
extern int     ObsoleteMinutes=10;

extern bool Use50maFilter=true;
extern int  MApips=10;

extern bool UseTE=false;
extern int badtrades=2;
extern int ReEnter=2;

string      xname,start;
int         ID;
int         bar;//tracks the period where a trade was placed. 
double      Hi, Lo, Op;
int         tsTicket[21];
double      tsPrice[21];
bool        tsok[21];
bool        lopen,sopen;
int         TEticket[40];
double      TEpips[40];
int         TEtype[40];
double      TEopen[40];
bool        TEclosed[40];
datetime    ot;
//bool hedged;
bool bad;
//////////////////////////////////////////////////////////////////////////////////////////////
int init(){
    ID=ID_BASE+P(period);
    start=TimeToStr(CurTime(),TIME_DATE|TIME_SECONDS);
    xname=EAname+"_"+DoubleToStr(ID,0);
  //  Comment("\n",xname," started @ ",start,"\n","Floating P&L: ",profit(),"\n",presentpos());
   ot=CurTime();
   
}


/////////////START FUNCTION///////////////////START FUNCTION//////////////////////START FUNCTION/////  
 
           
int CheckOpen(int f){ 
 
   if(lopen){
      stoopen(1);
      return;
   }
   if(sopen){
      stoopen(2);
      return;
   }
   double lwma=iMA(NULL,0,50,0,MODE_LWMA,MODE_CLOSE,0);
   int x=0;
   Hi = iHigh(NULL, P(period), x); 
   Lo = iLow (NULL, P(period), x);  
   Op = iOpen(NULL, P(period), x);
//Print("CHECKOPEN()");
//   Print(Hi, ",", Lo); // This shows how the value of hi and lo changes during the day
//   Comment("if (",(Hi-Lo)," > ",LongBar*Point," && ",Op," < ",Hi+Lo/2," && ",Ask," < ",Op);

   if( (Hi-Lo > LongBar*Point && Op < baropen(1) && Ask < Op) && ( !EMAconfirm || EMA(1,P(EMAtf))> EMA(2,P(EMAtf))  )&&  
   (!Use50maFilter || Ask > lwma+MApips*Point) ){

      if(f==1){
         
         if(!UseStoOpen){
            openorder(1);
         }else{
            lopen=true;
            stoopen(1);
         }
      }
      else if(f==2){
         return(1);
      }
      
   }
   else if( (Hi-Lo > LongBar*Point && Op > baropen(2)&& Bid > Op) && ( !EMAconfirm || EMA(1,P(EMAtf))< EMA(2,P(EMAtf)) ) 
   && (!Use50maFilter || Bid < lwma-MApips*Point) ){
    //  Print("shrtOPEN");
      if(f==1){
         
         if(!UseStoOpen){
            openorder(2);
         }else{
            sopen=true;
            stoopen(2);
         }
      }
      else if(f==2){
         return(2);
      }
      
   }
//   Comment(Hi-Lo," > ",LongBar*Point," && ",Op," > ",baropen(2)," && ",Bid," > ",Op);
   return(0); 
}
//////////////////////////////////////////////////////////////////////////////////////////////

double baropen(int t){
   double barpr;
   if(t==1){
      barpr= Lo + (Hi-Lo) * BarOpenPercent;
     // Print("Lo ",Lo," + ",(Hi-Lo) * BarOpenPercent / 100);
   }
   
   else if(t==2){
      barpr= Hi - (Hi-Lo) * BarOpenPercent;
   }
   return(barpr);
}
//////////////////////////////////////////////////////////////////////////////////////////////

void stoopen(int t){
   
   double sto1,sto2;
   sto1=iStochastic(NULL,P(StoTF),5,3,3,MODE_SMA,0,MODE_MAIN,0);
   sto2=iStochastic(NULL,P(StoTF),5,3,3,MODE_SMA,0,MODE_SIGNAL,0);
   Print("stoopen() ",sto1, "   " , sto2);
   if( t==1 ){
      if(sto1>sto2){
         openorder(1);
         Print("open order on sto");
      }
   }
   else if( t==2 ){
      if(sto1<sto2){
         openorder(2);
         Print("open order on sto");
      }
   }
}
/////////////////////////////////////////////////////////////////////////////////////////////  
int okp(string sym){
   int ret;
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderMagicNumber()==ID){
            if(OrderSymbol()==sym){
               if(OrderType()==OP_BUY)ret=1;
               else if(OrderType()==OP_SELL)ret=2;
            }
         }
      }
   }
   return(ret);
}

bool CMC(string sym,int t){
   if(sym=="EURUSD"){
      if( okp("GBPUSD") != t && okp("GBPUSD")!=0)return(false);
      if( okp("USDCHF")  ==t && okp("USDCHF")!=0)return(false);
   }
   else if(sym=="GBPUSD"){
      if( okp("EURUSD") != t && okp("EURUSD")!=0)return(false);
      if( okp("USDCHF")  ==t && okp("USDCHF")!=0)return(false);
   }
   else if(sym=="USDCHF"){
      if( okp("EURUSD") == t && okp("EURUSD")!=0)return(false);
      if( okp("GBPUSD")  ==t && okp("GPBUSD")!=0)return(false);
   }
   return(true);
}
void openorder(int f){
   double sl,tp;int res;
   //string comm="Pro-Gen_"+DoubleToStr(ID,0);
   if( !CMC(Symbol(),f) )return;
   if( MM ) lots = LotSize();
   if(Reverse){
      if(f==1)f=2;
      else if(f==2)f=1;
   }
   if(f==2){
      while(res<=0){
         if(stoploss==0){sl=0;}else{sl=Bid+stoploss*Point;}
         if(takeprofit==0){tp=0;}else{tp=Bid-takeprofit*Point;}
         if(UseClose)tp=Bid-(takeprofit*2)*Point;
         if(!AlertOnlyMode){
            res=OrderSend(Symbol(),OP_SELL,lots,Bid,2,sl,tp,xname,ID,0,Red); 
            
         }
         if(res<=0){
            int error=GetLastError();
            Print("Error = ",ErrorDescription(error));
            if(error==134)break;
            Sleep(1000);
            RefreshRates();
         }
      }
      if(Alerts || AlertOnlyMode){
         Alert("PG Short Signal on ",Symbol());
      }   
      lopen=false;sopen=false;
      bar=iBars(NULL,P(period));
   }
   else if(f==1){
      while(res<=0){
         if(stoploss==0){sl=0;}else{sl=Ask-stoploss*Point;}
         if(takeprofit==0){tp=0;}else{tp=Ask+takeprofit*Point;}
         if(UseClose)tp=Ask+(takeprofit*2)*Point;
         if(!AlertOnlyMode){
            res=OrderSend(Symbol(),OP_BUY,lots,Ask,2,sl,tp,xname,ID,0,Blue);
            
         }
         if(res<=0){
            error=GetLastError();
            Print("Error = ",ErrorDescription(error));
            if(error==134)break;
            Sleep(1000);
            RefreshRates();
            
         }
      }
      if(Alerts || AlertOnlyMode){
         Alert("PG Long Signal on ",Symbol());
      }   
      lopen=false;sopen=false;
      bar=iBars(NULL,P(period));
   }
}
//////////////////////////////////////////////////////////////////////////////////////////////           

void CloseOrder(int ord){
   bool res;
   if (ord==1){
      while(!res){
         res = OrderClose(OrderTicket(),OrderLots(),Bid,3,White); // close 
         if(!res){
            int error=GetLastError();
            Print("Error = ",ErrorDescription(error));
            if(error!=135)break;
            else if(error==135){
               Sleep(1000);
               RefreshRates();
            }
         }
      }
   }
   if (ord==2) { 
      while(!res){                         // MA BUY signals
         res = OrderClose(OrderTicket(),OrderLots(),Ask,3,White); // close 
         if(!res){
            error=GetLastError();
            Print("Error = ",ErrorDescription(error));
            if(error!=135)break;
            else if(error==135){
               Sleep(1000);
               RefreshRates();
            }    
         }      
      }  
   }    
}        
//////////////////////////////////////////////////////////////////////////////////////////////
int P(int peri){ //added the ability to control PeriodTF for different functions.
   if(!UseSimpleTF) {
      if(peri==0) return(Period()); 
      else return(peri);
   }   
   if(UseSimpleTF) {
      if(peri==0) return(Period());
      if(peri==1) return(1);//M1
      if(peri==2) return(5);//M5
      if(peri==3) return(15);//M15
      if(peri==4) return(30);//M30
      if(peri==5) return(60);//H1
      if(peri==6) return(240);//H4
      if(peri==7) return(1440);//Daily
      if(peri==8) return(10080);//weekly
      if(peri==9) return(43200);//monthly
      return(Period());
   }
}
//////////////////////////////////////////////////////////////////////////////////////////////
int orderscnt(){
   int cnt=0;
   for(int i =0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
         if(OrderSymbol()==Symbol() && ID==OrderMagicNumber()){
            cnt++;
         }
      }
   }
   return(cnt);
}
//////////////////////////////////////////////////////////////////////////////////////////////
void CloseAllTrades(){
   Print("CloseAllTrades()");
   for(int i =0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
         if(OrderSymbol()==Symbol() && ID==OrderMagicNumber()){
            if(OrderType()==OP_BUY){
               CloseOrder(1);
            }else{
               CloseOrder(2);
            }  
         }  
      }  
   }  
}  
////////////////////////////////////////////////////////////////////////////////////////////// 
double LotSize(){
   double lotMM;
   if(PairsTraded==0){
      lotMM = MathCeil(AccountFreeMargin() * Risk / 10000) / 10;
   } else {
      lotMM = MathCeil(AccountFreeMargin() * Risk / 10000 /PairsTraded) / 10 ;
   }
   if (lotMM < 0.1) lotMM = lots;
   if (lotMM > 1.0) lotMM = MathCeil(lotMM);
   if  (lotMM > 100) lotMM = 100;
   return (lotMM);
} 
   
//////////////////////////////////////////////////////////////////////////////////////////////

void SuperClose(){
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==ID){//Pulls in order that meets the criteria for processing
            int num=0;int pos=0;
            for(int b=0;b<21;b++){// this (loopB) compares the ticket# of the selected order against the number stored in the ticket array
               if(tsTicket[b]==OrderTicket() ){
                  num++; pos=b;// if ticket numbers match, pos is the position in the array where the trailing data is stored
                  //Print("(",pos,") Ticket ",tsTicket[pos]," found.  SL is ",tsPrice[pos]);
                  break;
               }  
            }
            if(num==0){ // if the loopB did not find a matching ticket number it is time to initialize the data
               for(int j=0;j<21;j++){
                  if(tsTicket[j]==0){// this is looking for the earliest instance within the array to store the data
                     pos=j;  
                     break;
                  }
               }
               tsTicket[pos]=OrderTicket();// setting the ticket number
               tsok[pos]=false;// this is to determine when trailing kicks in
               Print("(",pos,") New ticket initialized = ",tsTicket[pos]);
            }
            if (OrderType()==OP_SELL) {
               if (!tsok[pos] && (OrderOpenPrice()-Ask>=TSactivation*Point || TSactivation==0 ) ) {// if the trailing factor is false, but it has hit the activation point continue
                  tsPrice[pos]=Ask+TrailPips*Point;// this is the new trailinf stop price
                  tsok[pos]=true;// it's ok to proceed with trailing stop
                  if(TrailPips>8){// if this distance from the current price to the new stop, then modify the order.
                     ModifyStopLoss(Ask+TrailPips*Point);//modifies order
                  }
               }
               if (tsok[pos] && Ask+TrailPips*Point < tsPrice[pos] ){//if the position is gaining in profit
                  tsPrice[pos]=Ask+TrailPips*Point;
                  if(TrailPips>8){ 
                     ModifyStopLoss(Ask+TrailPips*Point);
                  }
               }
               if (tsok[pos] && Ask >= tsPrice[pos] ){// if the postion hits the stop price
                  CloseOrder(2);
                  Print("Short Order ",tsTicket[pos]," Closed from TS");
               }
            }
            if (OrderType()==OP_BUY) {// reverse of SELL
               if(!tsok[pos] && (Bid-OrderOpenPrice() >= TSactivation*Point  || TSactivation==0 ) ) {
                  tsPrice[pos]=Bid-TrailPips*Point;
                  tsok[pos]=true;
                  if(TrailPips>8){
                     ModifyStopLoss(Bid-TrailPips*Point);
                  }
               }
               if (tsok[pos] && Bid-TrailPips*Point > tsPrice[pos] ){
                  tsPrice[pos]=Bid-TrailPips*Point;
                  if(TrailPips > 8){
                     ModifyStopLoss(Bid-TrailPips*Point);
                  }
               }
               if (tsok[pos] && Bid <= tsPrice[pos] ){
                  CloseOrder(1);
                  Print("Long Order ",tsTicket[pos]," Closed from TS");
   }  }  }  }  }
   for(i=0;i<21;i++){// this searches the array for ticket numbers that are now obsolete due to an order that has closed
      if(tsTicket[i]>0){
         bool found=false;
         for(b=0;b<OrdersTotal();b++){
            OrderSelect(b,SELECT_BY_POS);
            if(tsTicket[i]==OrderTicket()){
               found=true;
             break;
            }
         }
         if(!found){// if there are matching ticket numbers in the trade pool and the array then nothing happens
            tsTicket[i]=0;tsPrice[i]=0;tsok[i]=false;// if there is an obolete ticket the the data is reset.  And the next new ticket data can occupy this space
           // Print("Array pos ",i," Cleaned");
}  }  }  }

//////////////////////////////////////////////////////////////////////////////////////////////
void ModifyStopLoss(double ldStop) {
  bool   fm;
  double ldOpen=OrderOpenPrice();
  double ldTake=OrderTakeProfit();
  fm=OrderModify(OrderTicket(), ldOpen, ldStop, ldTake, 0, Pink);
}

void sada(){
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==ID){
            if(CurTime()-OrderOpenTime() >= ObsoleteMinutes * 60){
               if(!OMwhenLossOnly || OrderProfit()<0){
                  if(OrderType()==OP_BUY){
                     if(CheckOpen(2)==2){
                        CloseOrder(1);
                        openorder(2);
                        Print("Order Swap due to sada");
                     }
                  }
                  else if(OrderType()==OP_SELL){
                     if(CheckOpen(2)==1){
                        CloseOrder(2);
                        openorder(1);
                        Print("Order Swap due to sada");
                     }
                  }
               }
            }
         }
      }
   }
}
   
//////////////////////////////////////////////////////////////////////////////////////////////
/*
string profit(){
   double pro; 
   for(int i =0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
         if(ID==OrderMagicNumber()){
            pro=pro+OrderProfit();
         }
      }
   }
   return(DoubleToStr(pro,2));
}*/
//////////////////////////////////////////////////////////////////////////////////////////////
double EMA(int Length1,int per){
   if(Length1==1)int L=LowEMA; 
   else if(Length1==2)L=HighEMA;
   return(iMA(Symbol(),per,L,0,MODE_EMA,PRICE_CLOSE,1));
}

//////////////////////////////////////////////////////////////////////////////////////////////
/*
string presentpos(){
   string pp;int cnt;
   static double h[30];
   for(int i =0;i<OrdersTotal();i++){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(ID==OrderMagicNumber()){
            cnt++;
            if(OrderProfit()> h[i]){
               string dir=" ( UP ) ";
            }else if(OrderProfit()< h[i]){
               dir=" ( DN ) ";
            }
            pp=pp+"\n"+OrderSymbol()+"  ("+DoubleToStr(OrderProfit(),2)+")"+dir;
            h[i]=OrderProfit();
         }
      }
   }
   if(cnt>0){
      return(pp);
   }else{
      return("\n"+"No Open Trades");
   }
}
 */  
//////////////////////////////////////////////////////////////////////////////////////////////
bool WE(){
   if(orderscnt()>0){
      if(DayOfWeek()>=5 && Hour()>=hour_to_close){
         CloseAllTrades();
         return(true);
      }
   }else{
      if(DayOfWeek()>=5 && Hour()>=hour_to_close -2){
         return(true);
      }
   }
   return(false); 
}
//////////////////////////////////////////////////////////////////////////////////////////////////// 
// Nicholishen nick@barker.net /////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
        //                                          //
////////////////////////////////////////////////////////////////////////////////////////////////////
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~TRADE EMULATION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TE(){
   if(!TE1()){
      if( 1==1)TEnew(1);
      else if( CheckOpen(2)==2) TEnew(2); 
   }
}

bool TE1(){
   bool ok=false;double sl;
   if(UseClose && TSactivation!=0)sl=TSactivation;else sl=stoploss;
   
   for(int i=0;i<200;i++){
      if(TEticket[i]!=0 && !TEclosed[i]){
            ok=true;
            if(TEtype[i]==1){
               TEpips[i]=Bid-TEopen[i];
               if(TEopen[i]-Bid>=sl*Point){TEclosed[i]=true;Print("TE trade closed from SL (",TEpips[i],")");Comment("");}
               if(Bid-TEopen[i]>=takeprofit*Point){TEclosed[i]=true;Print("TE trade closed from TP (",TEpips[i],")");Comment("");}
            }
            if(TEtype[i]==2){
               TEpips[i]=TEopen[i]-Ask;
               if(Ask-TEopen[i]>=sl*Point){TEclosed[i]=true;Print("TE trade closed from SL (",TEpips[i],")");}
               if(TEopen[i]-Ask>=takeprofit*Point){TEclosed[i]=true;Print("TE trade closed from SL (",TEpips[i],")");}
            }
            Comment("\n","TE Open Order: ",TEtype[i]," Tkt ",TEticket[i]," Profit ",TEpips[i]); 
      }
   }    
   if(ok)return(true);
   return(false);
}

void TEnew(int t){
         static int cnt;int pos;
         for(int i=0;i<40;i++){
            if(TEticket[i]==0){pos=i;break;}
         }
         cnt++;
         TEticket[pos]=cnt;
         if(t==1){TEtype[pos]=1;TEopen[pos]=Ask;}
         else if(t==2){TEtype[pos]=2;TEopen[pos]=Bid;}  
}

int TEprocnt(){
   int total;
   for(int i=39;i>=0;i--){
      if(TEticket[i]>0){
         if(TEpips[i]>0 && TEclosed[i])total++;
         if(TEpips[i]<0 && TEclosed[i])total=0; 
      }  
   }
   return(total);
}
void TEpurge(){
   for(int i=0;i<40;i++){
      TEticket[i]=0;
      TEpips[i]=0;
      TEtype[i]=0;
      TEopen[i]=0;
      TEclosed[i]=false;
      ot=CurTime();
      bad=false;
   }
}
   
int BadTrades(){
   for(int i=HistoryTotal();i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==ID){
            if(OrderOpenTime()>ot){
               if(OrderProfit()>0)int tr=0;
               if(OrderProfit()<0)tr++;
            }
         }
      }
   }
   return(tr);
}
//////////////START FUNCTION//////////////////START FUNCTION//////////////////START FUNCTION///////
int start(){
   int rderscnt=orderscnt();
   if( WeekendMode ){
      if( WE() )return(0);
   }   
   if( UseClose ){
      if(rderscnt>0)SuperClose();
   }
   if( UseHourTrade ){
      if((( FromHourTrade <= ToHourTrade ) && ( Hour() < FromHourTrade || Hour() > ToHourTrade ))
         || // Allow for Overnight Trading
         (( FromHourTrade >  ToHourTrade ) && ( Hour() < FromHourTrade && Hour() > ToHourTrade ))
        ) {
         return(0);
      }

   }

   if(rderscnt==0){
      if(UseTE){
         if(BadTrades()>=badtrades){
            if(TEprocnt()>=ReEnter){TEpurge();return(0);}
            TE();
            bad=true;
         }
      }
   }
   if(!bad && (rderscnt<MaxTrades) && (!OneTradeperPeriod || bar!=iBars(NULL,P(period))) ){
//    openorder(1);
      CheckOpen(1);
   }
   if( UseObsoleteMethod ){
      sada();
   }
}
//////////////////////////   





      