//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www,forex-station.com"
#property link      "www,forex-station.com"

//
//
//
//
//

#import "kernel32.dll"
int  GetTimeZoneInformation(int& TZInfoArray[]);
#import

//
//
//
//
//

#define TIME_ZONE_ID_UNKNOWN   0
#define TIME_ZONE_ID_STANDARD  1
#define TIME_ZONE_ID_DAYLIGHT  2

//
//
//
//
//

extern bool   EcnBroker        = true;
extern bool   UseAutoMagic     = true;
extern int    ManualMagic      = 5010100;
extern bool   SignalMail       = false;  
extern bool   EachTickMode     = false;
extern double Lots             = 0.01;
extern int    Slippage         = 3;
extern bool   StopLossMode     = true;
extern int    StopLoss         = 50;
extern bool   TakeProfitMode   = true;
extern int    TakeProfit       = 200;
extern bool   TrailingStopMode = true;
extern int    TrailingStop     = 30;
extern double MaximumRisk      = 0.001;
extern double DecreaseFactor   = 3;
extern int    MaxOrders        = 1;
extern bool   emergencystoploss= false;

extern string note1            = "Indicator & Settings used for open";

extern int    StochK           = 5;
extern int    StochD           = 3;
extern int    StochSlow        = 3;
extern int    StochMaMode      = 0;
extern double stochOs          = 25;
extern double stochOb          = 75;

extern string note2            = "Indicators & settings used for close";

extern string comments         = "Comments on true or false"; 
extern bool   CommentsOn       = true;   

extern string _time            = "Time Filter";
input uint StartHour   =  0; // Start hour
input uint StartMinute =  0; // Start minute
input uint StartSecond =  0; // Start second
input uint EndHour     = 24; // Ending hour
input uint EndMinute   =  0; // Ending minute
input uint EndSecond   =  0; // Ending second
bool dummyResult;

//
//
//
//
//

#define SIGNAL_NONE 0
#define SIGNAL_BUY  1
#define SIGNAL_SELL 2
#define SIGNAL_CLOSEBUY  3
#define SIGNAL_CLOSESELL 4

//
//
//
//
//

int    BarCount;
int    Current;
int    digit = 0;
int    ortype;
int    MagicNumber;
int    TZInfoArray[43];

bool   TickCheck = false;

string s_symbol;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

int init() 
{
   BarCount = Bars;
   if (EachTickMode) Current = 0; 
                else Current = 1;
   
   //
   //
   //
   //
   //
                
   s_symbol = Symbol();
   if (UseAutoMagic) MagicNumber = GetMagic();
               else  MagicNumber = ManualMagic; 
   
return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

int deinit() 
{ 

    Comment(" ");

return(0); 
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

int start() 
{
   if (!IsDllsAllowed()) 
   {
     Alert("DLLs are disabled.  To enable  check the box in the tools/options/expert advisors on your chart");
     return(0);
   }
  
   //
   //
   //
   //
   //
   
   double PointRatio;
   double __Point;
   if (StringSubstr(s_symbol,0,2)=="_t") s_symbol = StringSubstr(s_symbol,2);
   digit  = MarketInfo(s_symbol,MODE_DIGITS);
   if (digit==2 || digit==4) PointRatio = 1;
   if (digit==3 || digit==5) PointRatio = 10;
   if (digit==6)             PointRatio = 100;
   __Point  = MarketInfo(s_symbol,MODE_POINT) * PointRatio;  
                
   //
   //
   //
   //
   //
   
   if (EachTickMode && Bars != BarCount) EachTickMode = false;
   int Total = OrdersTotal();
   
   //+------------------------------------------------------------------+
   //| Signal Begin                                                     |
   //+------------------------------------------------------------------+
   //
   //
    
      int Order = SIGNAL_NONE;
      double StochMainCur        = iStochastic(s_symbol,0,StochK,StochD,StochSlow,StochMaMode,1,MODE_MAIN,  Current);
      double StochSignalCur      = iStochastic(s_symbol,0,StochK,StochD,StochSlow,StochMaMode,1,MODE_SIGNAL,Current);
      double StochMainPrev       = iStochastic(s_symbol,0,StochK,StochD,StochSlow,StochMaMode,1,MODE_MAIN,  Current+1);
      double StochSignalPrev     = iStochastic(s_symbol,0,StochK,StochD,StochSlow,StochMaMode,1,MODE_SIGNAL,Current+1);
      
      int orderOpenBar = iBarShift(s_symbol,0,OrderOpenTime(),true);

      if (StochMainPrev<StochSignalPrev && StochMainCur>StochSignalCur)  Order = SIGNAL_BUY;
      if (StochMainPrev>StochSignalPrev && StochMainCur<StochSignalCur)  Order = SIGNAL_SELL;
      if (Order == SIGNAL_NONE) return(0);
      if (!checkTimeLimits(StartHour,StartMinute,StartSecond,EndHour,EndMinute,EndSecond,TimeCurrent())) Order = SIGNAL_NONE;
      if (CommentsOn) ShowComments();
   
         
     

   //+------------------------------------------------------------------+
   //|                                                                  |
   //+------------------------------------------------------------------+
   //
   //Buy
   
   if (Order == SIGNAL_BUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) 
   {
     if (ScanTrades() < MaxOrders) 
     {
     
     //
     //
     //
     //
     //
     
       if (AccountFreeMargin() < (100 * Lots)) {Print("We have no money. Free Margin = ", AccountFreeMargin());return(0);}
       
       //
       //
       //
       //
       //
       
       double BStopLossLevel   = Ask - StopLoss   * __Point;
       double BTakeProfitLevel = Ask + TakeProfit * __Point;
       
       //
       //
       //
       //
       //
       
       if (!EcnBroker) 
       dummyResult=OrderSend(s_symbol,OP_BUY,LotsOptimized(),NormalizeDouble(Ask,digit),Slippage*__Point,NormalizeDouble(BStopLossLevel,digit),  
                                    NormalizeDouble(BTakeProfitLevel,digit),"Buy(#" + MagicNumber + ")",MagicNumber,0,DodgerBlue);
       else
       {
       int buyTicket    = OrderSend(s_symbol,OP_BUY,LotsOptimized(),NormalizeDouble(Ask,digit),Slippage*__Point,0,0,"buy",MagicNumber,0,Blue);
       if  (buyTicket  >= 0)
       bool buyOrderMod = OrderModify(buyTicket,OrderOpenPrice(),NormalizeDouble(BStopLossLevel,digit),NormalizeDouble(BTakeProfitLevel,digit),0,CLR_NONE);
    
       if (OrderSelect(buyTicket, SELECT_BY_TICKET, MODE_TRADES)) Print("BUY order opened : ", OrderOpenPrice()); else Print("Error opening BUY order : ", GetLastError());
       }
       
       if (EachTickMode)  TickCheck = True;
       if (!EachTickMode) BarCount  = Bars;
       
       return(0);
      }
   }

   //Sell
   //
   //
   //
   //
   
   if (Order == SIGNAL_SELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) 
   {
      if (ScanTrades() < MaxOrders) 
      {
      
      //
      //
      //
      //
      //
         
         if (AccountFreeMargin() < (1000 * Lots)) {Print("We have no money. Free Margin = ", AccountFreeMargin());return(0);}
         
         //
         //
         //
         //
         //
         
         double SStopLossLevel   = Bid + StopLoss   * __Point;
         double STakeProfitLevel = Bid - TakeProfit * __Point;
         
         //
         //
         //
         //
         //
         
         if (!EcnBroker)
         dummyResult=OrderSend(s_symbol,OP_SELL,LotsOptimized(),NormalizeDouble(Bid,digit),Slippage*__Point,NormalizeDouble(SStopLossLevel,digit),  
                                        NormalizeDouble(STakeProfitLevel,digit),"Sell(#" + MagicNumber + ")",MagicNumber,0,DeepPink);
         
         
         else
         {
		   int sellTicket    = OrderSend(s_symbol,OP_SELL,LotsOptimized(),NormalizeDouble(Bid,digit),Slippage*__Point,0,0,"Sell(#" + MagicNumber + ")", MagicNumber, 0, DeepPink);
         if(sellTicket    >= 0) 
         bool sellOrderMod = OrderModify(sellTicket,OrderOpenPrice(),NormalizeDouble(SStopLossLevel,digit),NormalizeDouble(STakeProfitLevel,digit),0,CLR_NONE);
         if (OrderSelect(sellTicket, SELECT_BY_TICKET, MODE_TRADES)) Print("SELL order opened : ", OrderOpenPrice()); 
         else Print("Error opening SELL order : ", GetLastError());
         }
         
         if (EachTickMode)  TickCheck = True;
         if (!EachTickMode) BarCount  = Bars;
         return(0);
      }
   }

   //
   //
   //
   //
   //
   
   bool IsTrade = false;
   for (int i = 0; i < Total; i ++) 
   {
      dummyResult=OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if (OrderType() <= OP_SELL &&  OrderSymbol()    == s_symbol    ) 
      {
        if (OrderType() == OP_BUY && OrderMagicNumber()== MagicNumber ) 
        {
         
            //
            //
            //
            //
            //
            
            if (orderOpenBar > 3)       
            {
               if (emergencystoploss == true) { if ((OrderOpenPrice() > Bid)) { Order = SIGNAL_CLOSEBUY; }}      
               if (StochMainCur < StochSignalCur)  Order = SIGNAL_CLOSEBUY;   
            }
            
            //
            //
            //
            //
            //
            
            if (Order == SIGNAL_CLOSEBUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) 
            {
               dummyResult=OrderClose(OrderTicket(), OrderLots(), Bid, Slippage*__Point, MediumSeaGreen);
               if (SignalMail) SendMail("[Signal Alert]", "[" + s_symbol + "] " + DoubleToStr(Bid, Digits) + " Close Buy");
               if (EachTickMode)  TickCheck = true;
               if (!EachTickMode) BarCount  = Bars;
               IsTrade = false;
               return(0);
            }
            
            //
            //
            //
            //
            //
            
            if(TrailingStopMode && TrailingStop > 0) {                 
               if(Bid - OrderOpenPrice() > __Point * TrailingStop) {
                  if(OrderStopLoss() < Bid - __Point * TrailingStop) {
                     dummyResult=OrderModify(OrderTicket(), OrderOpenPrice(), Bid - __Point * TrailingStop, OrderTakeProfit(), 0, MediumSeaGreen);
                     if (!EachTickMode) BarCount = Bars;
                     return(0);
                  }
               }
            }
            } 
            else 
            {
         
            if(OrderType()==OP_SELL && OrderMagicNumber()==MagicNumber)
            {
           
            //
            //
            //
            //
            //
            
            if (orderOpenBar > 3)
            {
               if (emergencystoploss == true) { if ((OrderOpenPrice() < Ask))  { Order = SIGNAL_CLOSESELL; }}
               if (StochMainCur > StochSignalCur)  Order = SIGNAL_CLOSESELL;   
            }
            
            //
            //
            //
            //
            //

            if (Order == SIGNAL_CLOSESELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) 
            {
               dummyResult=OrderClose(OrderTicket(), OrderLots(), Ask, Slippage*__Point, DarkOrange);
               if (SignalMail) SendMail("[Signal Alert]", "[" + s_symbol + "] " + DoubleToStr(Ask, Digits) + " Close Sell");
               if (EachTickMode) TickCheck = True;
               if (!EachTickMode) BarCount = Bars;
               IsTrade = false;
               return(0);
            }
               
            //
            //
            //
            //
            //
            
            if (TrailingStopMode && TrailingStop > 0) 
               {                 
               if((OrderOpenPrice() - Ask) > (__Point * TrailingStop)) {
                  if((OrderStopLoss() > (Ask + __Point * TrailingStop)) || (OrderStopLoss() == 0)) {
                     dummyResult=OrderModify(OrderTicket(), OrderOpenPrice(), Ask + __Point * TrailingStop, OrderTakeProfit(), 0, DarkOrange);
                     if (!EachTickMode) BarCount = Bars;
                     return(0);
                  }
               }
            }
         }
       }
     }
   }

   if (!EachTickMode) BarCount = Bars;
return(0);
}

//
//
//
//
//

int ScanTrades()
{   
   int total = OrdersTotal();
   int numords = 0;
      
   for(int cnt=0; cnt<total; cnt++) 
   {        
   dummyResult=OrderSelect(cnt, SELECT_BY_POS);            
   if(OrderSymbol() == s_symbol && OrderType() <= OP_SELLSTOP && OrderMagicNumber() == MagicNumber) 
   numords++;
   }
return(numords);
}  

//
//
//
//
//

double LotsOptimized()
{
   double lot_min  = MarketInfo(Symbol(),MODE_MINLOT);
   double lot_max  = MarketInfo(Symbol(),MODE_MAXLOT);
   double lot_step = MarketInfo(Symbol(),MODE_LOTSTEP);
   double contract = MarketInfo(Symbol(),MODE_LOTSIZE);
   double lot      = Lots;
   int    orders   = HistoryTotal();     // history orders total
   int    losses   = 0;                  // number of losses orders without a break
   
   //
   //
   //
   //
   //
   
   if(lot_min < 0.0 || lot_max <= 0.0 || lot_step <= 0.0) 
   {
   Print("CalculateVolume: invalid MarketInfo() results [",lot_min,",",lot_max,",",lot_step,"]");
   return(0);
   }
   if(AccountLeverage() <= 0)
   {
   Print("CalculateVolume: invalid AccountLeverage() [",AccountLeverage(),"]");
   return(0);
   }
   
   //
   //
   //
   //
   //
   
   if (MaximumRisk > 0)
   {
   lot = NormalizeDouble(AccountFreeMargin() * MaximumRisk * AccountLeverage()/contract,2);
   }
   
   if(DecreaseFactor>0)
   {
      for(int i=orders-1;i>=0;i--)
      {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }
      if(OrderSymbol()!= s_symbol || OrderType() > OP_SELL) continue;
      
      //
      //
      //
      //
      //
      
      if(OrderProfit() > 0) break;
      if(OrderProfit() < 0) losses++;
      }
      
   if(losses > 1) lot = NormalizeDouble(lot - lot * losses/DecreaseFactor,2);
   }
   
   //
   //
   //
   //
   //
   
   lot=NormalizeDouble(lot/lot_step,0) * lot_step;
   if(lot < lot_min) lot = lot_min;
   if(lot > lot_max) lot = lot_max;
   
return(lot);
} 

//
//
//
//
//

int GetMagic() 
{

   if (StringFind(s_symbol, "CADJPY") >= 0) return(1933921);
   if (StringFind(s_symbol,  "CADCHF") >= 0) return(1933922);
   
   if (StringFind(s_symbol,  "GOLD") >= 0)   return(1933931);
   if (StringFind(s_symbol, "SILVER") >= 0) return(1933932);
   
   if (StringFind(s_symbol, "NZDJPY") >= 0) return(1933941);
   if (StringFind(s_symbol, "NZDUSD") >= 0) return(1933942);
   
   if (StringFind(s_symbol , "CHFJPY") >= 0) return(1933951);   
   if (StringFind(s_symbol , "EURAUD") >= 0) return(1933961);
   if (StringFind(s_symbol , "EURCAD") >= 0) return(1933962);
   if (StringFind(s_symbol , "EURUSD") >= 0) return(1933963);
   if (StringFind(s_symbol , "EURGBP") >= 0) return(1933964);
   if (StringFind(s_symbol , "EURCHF") >= 0) return(1933965);
   if (StringFind(s_symbol , "EURNZD") >= 0) return(1933966);
   if (StringFind(s_symbol , "EURJPY") >= 0) return(1933967);
   
   if (StringFind(s_symbol , "GBPUSD") >= 0) return(1933971);
   if (StringFind(s_symbol , "GBPCHF") >= 0) return(1933972);
   if (StringFind(s_symbol , "GBPJPY") >= 0) return(1933973);
   
   if (StringFind(s_symbol , "USDCHF") >= 0) return(1933981);
   if (StringFind(s_symbol , "USDJPY") >= 0) return(1933982);
   if (StringFind(s_symbol , "USDCAD") >= 0) return(1933983);

   if (StringFind(s_symbol , "AUDUSD") >= 0) return(1933991);
   if (StringFind(s_symbol , "AUDNZD") >= 0) return(1933992);
   if (StringFind(s_symbol , "AUDCAD") >= 0) return(1933993);
   if (StringFind(s_symbol , "AUDCHF") >= 0) return(1933994);
   if (StringFind(s_symbol , "AUDJPY") >= 0) return(1933995);
   
return(ManualMagic);
}

//
//
//
//
//

bool checkTimeLimits(uint startHour, uint endHour, datetime timeToCheck) { return(checkTimeLimits(startHour,0,0,endHour,0,0,timeToCheck)); }
bool checkTimeLimits(uint startHour, uint startMinute, uint endHour, uint endMinute, datetime timeToCheck) { return(checkTimeLimits(startHour,startMinute,0,endHour,endMinute,0,timeToCheck)); }
bool checkTimeLimits(uint startHour, uint startMinute, uint startSecond, uint endHour, uint endMinute, uint endSecond, datetime timeToCheck)
{
   bool answer = false;
   MqlDateTime tempTime; TimeToStruct(timeToCheck,tempTime);
      datetime startTime,endTime,checkTime;
               startTime = _ctMinMax(startHour,0,24)    *3600+_ctMinMax(startMinute,0,60) *60+_ctMinMax(startSecond,0,60);
               endTime   = _ctMinMax(endHour,0,24)      *3600+_ctMinMax(endMinute,0,60)   *60+_ctMinMax(endSecond,0,60);
               checkTime = _ctMinMax(tempTime.hour,0,24)*3600+_ctMinMax(tempTime.min,0,60)*60+_ctMinMax(tempTime.sec,0,60);
               
   if (startTime>endTime)
          answer = (checkTime>=startTime || checkTime<=endTime);
   else   answer = (checkTime>=startTime && checkTime<=endTime);
   return(answer);
}
uint _ctMinMax(uint value, uint min, uint max) { return((uint)MathMax(MathMin(value,max),min)); }

//
//
//
//
//

double TimeZoneLocal()
{     
      //
      //
      //
      //
      //

	   switch(GetTimeZoneInformation(TZInfoArray))
	   {
	        case TIME_ZONE_ID_UNKNOWN: 
	        Print("Error obtaining PC timezone from GetTimeZoneInformation in kernel32.dll. Returning 0");
		     return(0);

	        case TIME_ZONE_ID_STANDARD:
		     return(TZInfoArray[0]/(-60.0));
	
	        case TIME_ZONE_ID_DAYLIGHT:
		     return((TZInfoArray[0]+TZInfoArray[42])/(-60.0));
		
 	        default:
		     Print("Unkown return value from GetTimeZoneInformation in kernel32.dll. Returning 0");
		     return(0);
	   }
}

// 
//
//
//
//

double TimeZoneServer()
{
	int ServerToLocalDiffMinutes = (TimeCurrent()-TimeLocal())/60;
	int nHalfHourDiff            = MathRound(ServerToLocalDiffMinutes/30.0);
	
	//
	//
	//
	//
	//
	
	ServerToLocalDiffMinutes = nHalfHourDiff*30;
	
return(TimeZoneLocal() + ServerToLocalDiffMinutes/60.0);
}

// 
//
//
//
//

datetime iTimeGMT(double TZLocal, double TZServer)
{

	    datetime dtGmtFromLocal = TimeLocal() - TZLocal*3600;
	    datetime dtGmtFromServer = TimeCurrent() - TZServer*3600;

       if (dtGmtFromLocal > dtGmtFromServer + 300)
	    {
		   return(dtGmtFromLocal);
	    }
	    else
	    {
		  return(dtGmtFromServer);
	}	
}
  

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void ShowComments()
{ 
   if (IsTesting() && !IsVisualMode()) return;
   if (IsTesting()) return;
   
   string symbol   = Symbol(); if (StringSubstr(symbol,0,2)=="_t") symbol = StringSubstr(symbol,2);
  	double modifier = 1;
  	int    digits   = MarketInfo(symbol,MODE_DIGITS);
   if (digits==3 || digits==5) modifier = 10.0;
   
   //
   //
   //
   //
   //
   
   string strLocal  = TimeToStr(TimeLocal(),TIME_DATE|TIME_MINUTES|TIME_SECONDS);
	string strServer = TimeToStr(TimeCurrent(),TIME_DATE|TIME_MINUTES|TIME_SECONDS);
	string strGMT    = TimeToStr(TimeGMT(),TIME_DATE|TIME_MINUTES|TIME_SECONDS);
	
	
	string strLocalTimeZone;
	if (TimeZoneLocal() > 0)   strLocalTimeZone  = StringConcatenate("Local timezone: GMT plus  ", TimeZoneLocal()," hours");
	if (TimeZoneLocal() == 0)  strLocalTimeZone  = "Local timezone: GMT";
	if (TimeZoneLocal() < 0)   strLocalTimeZone  = StringConcatenate("Local timezone: GMT minus ",-TimeZoneLocal()," hours");
	
	string strServerTimeZone;
	if (TimeZoneServer() > 0)  strServerTimeZone = StringConcatenate("Server timezone: GMT plus  ", TimeZoneServer()," hours");
	if (TimeZoneServer() == 0) strServerTimeZone = "Server timezone: GMT";
  	if (TimeZoneServer() < 0)  strServerTimeZone = StringConcatenate("Server timezone: GMT minus ",-TimeZoneServer()," hours");
   
  	//
  	//
  	//
  	//
  	//
  
   if(MarketInfo(Symbol(),MODE_SWAPLONG) > 0)                                  string    swap="longs,";
                                                                               else      swap="shorts.";
   if(MarketInfo(Symbol(),MODE_SWAPLONG) < 0 && MarketInfo(Symbol(),MODE_SWAPSHORT) < 0) swap="your broker. ";
   
   //
   //
   //
   //
   //  
   
   string sComment   = "";
   string sp         = "---------------------------------------------------\n";
   string NL         = "\n";
   
   
   sComment = sComment + sp;
   sComment = sComment + "Stoch Ea" + NL; 
   sComment = sComment + sp;
   sComment = sComment + "Currency Pair:  " +symbol+ NL;
   sComment = sComment + sp;
   sComment = sComment + "Market Analysis" + NL;
   sComment = sComment + "Swap favors " + swap + NL; 
   sComment = sComment + "Swap Long      = " + DoubleToStr(MarketInfo(symbol,MODE_SWAPLONG),2) + NL; 
   sComment = sComment + "Swap Short     = " + DoubleToStr(MarketInfo(symbol,MODE_SWAPSHORT),2) + NL; 
   sComment = sComment + "Current Spread = " + DoubleToStr(MarketInfo(symbol,MODE_SPREAD)/ modifier,2) + NL;  
   sComment = sComment + sp;
   sComment = sComment + "Time Information" + NL;
   sComment = sComment + strLocalTimeZone  + NL;
   sComment = sComment + strServerTimeZone + NL;
   sComment = sComment + "Local time from PC clock = " +strLocal+ NL;
   sComment = sComment + "Broker server time         =  " +strServer+ NL;
   sComment = sComment + "GMT time                    =  " +strGMT+ NL;
   sComment = sComment + sp;
   sComment = sComment + "Have a great trading day" + NL;
   sComment = sComment + sp; 
   
   Comment(sComment);  
}