//+------------------------------------------------------------------+
//|                                                 OpenBreakout.mq4 |
//|                                                         Scorpion |
//|                                              www.fxfisherman.com |
//+------------------------------------------------------------------+
#property copyright "Scorpion"
#property link      "http://www.fxfisherman.com"
#include <stdlib.mqh>
#define ts_mode_disable 0
#define ts_mode_fixed_sl 1
#define ts_mode_atr 2
#define ts_mode_half_volatility 3
#define ts_mode_breakout 4
//---- input parameters
extern string    _______Position_______;
extern double    Pip_Value=10;
extern double    Lots=1;
extern int       TP=0;
extern int       SL=0;
int       SL_Mode=1;
extern string    _______Session_______;
extern int From_Hour=13;
extern int From_Min=0;
extern int To_Hour=18;
extern int To_Min=30;
extern string    ______TrailingStop_____;
extern int       TS_Mode=0;       // 0 = disabled, 1 = Fixed SL, 2 = ATR, 3 = Half Volatility, 4 = Breakout Yesterday Hi/Lo
extern int       TS_Trigger=15;
int              TS_Sensitivity=3;
double           TS_DynamicFactor=0.5;   // applied only if TrailingStopMode = 2 or 3
int              Evaluate_Interval=0; // -1 chart, 0 tick, > 0 specified min
extern string    _______Indicators______;
extern int       Breakout_Pips = 5;
string expert_name = "OpenBreakout 1";
int main_magic;
int open_slippage=5;
int close_slippage=10;
datetime dtNextEvaluate;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   main_magic = 1003000 + GetTimeframeConstant(Period()) + GetSymbolConstant(Symbol());
   watermark();
   return(0);
  }
  
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
  
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
 
  // control entry orders
  int ticket = OrderTicketByMagicNum(main_magic);
  
  // control trailing stops of market orders
  ticket = OrderTicketByMagicNum(main_magic);
  if (ticket > 0) ControlTrailingStop(ticket, SL, TS_Mode, TS_Trigger, TS_DynamicFactor, TS_Sensitivity);
  
  // analyse chart
  bool AnalyseNow;
  datetime TimeNow = CurTime();
  if (Evaluate_Interval==0)
  {
    AnalyseNow=true;
  }else if (TimeNow >= dtNextEvaluate) {
    AnalyseNow=true;
    if (Evaluate_Interval>0)
    {
      dtNextEvaluate=TimeNow - (TimeNow % (Evaluate_Interval*60)) + (Evaluate_Interval*60);
    } else {
      dtNextEvaluate=TimeNow - (TimeNow % (Period()*60)) + (Period()*60);
    }
  }
  bool IsBuy, IsSell, IsCloseBought, IsCloseSold;
  if(AnalyseNow)
  {
    static datetime last_cross;
    if (last_cross != Time[0])
    {
      if (Bid >= Open[0] + (Breakout_Pips * Point))
      {
        last_cross = Time[0];
        IsBuy=True;        
      }else if(Bid <= Open[0] - (Breakout_Pips * Point)){
        last_cross = Time[0];
        IsSell=True;
      }
    }
    IsCloseBought = IsSell;
    IsCloseSold = IsBuy;
    
    double From_Time = From_Hour + (From_Min/60);
    double To_Time = To_Hour + (To_Min/60);
    double Cur_Time = Hour() + (Minute()/60);
    if (!(From_Time <= Cur_Time && Cur_Time <= To_Time))
    {
      IsBuy = False;
      IsSell = False;
    }
  }
  
  // check for exit and cancellation of orders
  if (ticket > 0)
  {
    if (OrderSelectEx(ticket,SELECT_BY_TICKET,MODE_TRADES)==false) return(0);  
    if (OrderType() == OP_BUY && IsCloseBought)
    {
      Alert(expert_name, ": Close order #", ticket," at ", Bid);
      CloseNow(ticket);
    } else if (OrderType() == OP_SELL && IsCloseSold) {
      Alert(expert_name, ": Close order #", ticket," at ", Ask);
      CloseNow(ticket);
    }
  }
  
  // check for entry ( enough money > safe mode off > signal given > enter) 
  if (AccountFreeMargin()>=(100 * Pip_Value * Lots))
  {
    ticket = OrderTicketByMagicNum(main_magic);
    if (ticket==0)
    {
      static int prev_time;
      static int prev_type;
      if (IsBuy && !IsSell && prev_type != OP_BUY) {
        ticket = BuyNow();
        if (ticket > 0)
        {
          prev_time = CurTime();
          prev_type = OP_BUY;
        }
        Alert(expert_name, ": Buy ", Symbol()," at ", Ask);
      } else if(IsSell && !IsBuy && prev_type != OP_SELL) {
        ticket = SellNow();
        if (ticket > 0)
        {
          prev_time = CurTime();
          prev_type = OP_SELL;
        }
        Alert(expert_name, ": Sell ", Symbol()," at ", Bid);
      } else if(IsSell && IsBuy) {
        Print("Error: Buy and sell signals are issued at the same time!");
      }
    }
  }else{
    Alert("Error: insufficient fund. Free Margin = ", AccountFreeMargin());
  }
  
  return(0);
}
//+------------------------------------------------------------------+
//| Buy                                                              |
//+------------------------------------------------------------------+
int BuyNow()
{
    double TrueSL, TrueTP;
    TrueSL = Get_SL(OP_BUY, Ask, SL, SL_Mode, TS_DynamicFactor);
    if (TP > 0) TrueTP = Bid+(TP*Point);
    int ticket = OrderSendEx(Symbol(), OP_BUY, Lots, Ask, open_slippage*Point, TrueSL, TrueTP, expert_name + " " + Symbol() + Period(), main_magic, 0, Yellow);
    return(ticket);
}
//+------------------------------------------------------------------+
//| Sell                                                             |
//+------------------------------------------------------------------+
int SellNow()
{
  double TrueSL, TrueTP;
  TrueSL = Get_SL(OP_SELL, Bid, SL, SL_Mode, TS_DynamicFactor);
  if (TP > 0) TrueTP = Bid-(TP*Point);
  int ticket = OrderSendEx(Symbol(), OP_SELL, Lots, Bid, open_slippage*Point, TrueSL, TrueTP, expert_name + " " + Symbol() + Period(), main_magic, 0, Yellow);
  return(ticket);
}
//+------------------------------------------------------------------+
//| Close                                                            |
//+------------------------------------------------------------------+
bool CloseNow(int ticket)
{
  if (OrderSelectEx(ticket, SELECT_BY_TICKET))
  {
    if (OrderType() == OP_BUY)
    {
      OrderCloseEx(ticket, OrderLots(), Bid, close_slippage);
    }else if (OrderType() == OP_SELL){
      OrderCloseEx(ticket, OrderLots(), Ask, close_slippage);
    }
  }
}
//+------------------------------------------------------------------+
//| Control trailing stop                                            |
//+------------------------------------------------------------------+
void ControlTrailingStop(int ticket, double SL, int TS_Mode, int TS_Trigger, double TS_DynamicFactor, int TS_Sensitivity)
{
  if (ticket == 0 || TS_Mode == 0) return;
  
  double ts;
  if (OrderSelectEx(ticket, SELECT_BY_TICKET, MODE_TRADES)==false) return;
  if (OrderType() == OP_BUY)
  {
    ts = Get_SL(OP_BUY, Bid, SL, TS_Mode, TS_DynamicFactor);
    if ((ts >= OrderStopLoss() + TS_Sensitivity*Point) && (ts > 0)  && (Bid >= OrderOpenPrice() + TS_Trigger*Point )) 
    {
      if (Bid - ts >= 5 * Point)
      {
        OrderModifyEx(ticket, OrderOpenPrice(), ts, OrderTakeProfit(), 0);
      }else if(Bid <= ts){
        CloseNow(ticket);
      }
    }
    
  }else if(OrderType() == OP_SELL){
    ts = Get_SL(OP_SELL, Ask, SL, TS_Mode, TS_DynamicFactor);
    if ((ts <= OrderStopLoss() - TS_Sensitivity*Point) && (ts > 0) && (Ask <= OrderOpenPrice() - TS_Trigger*Point))
    {
      if (ts - Ask >= 5 * Point)
      {
        OrderModifyEx(ticket, OrderOpenPrice(), ts, OrderTakeProfit(), 0);
      }else if(ts <= Ask){
        CloseNow(ticket);
      }
    }
  }
  
}
double Get_SL(int order_type, double price, double sl, int sl_mode, double sl_dynamicfactor)
{
  if (sl_mode == 0) return(0);
  
  double ts;
  double ma_0, hh, ll;
  if (order_type == OP_BUY)
  {
    switch (sl_mode)
    {
      case ts_mode_fixed_sl: if(sl > 0) ts = Bid-(Point*sl); break;
      case ts_mode_atr: ts = Low[0] - (sl_dynamicfactor * iATR(NULL,0,14,0)); break;
      case ts_mode_half_volatility: ts = Low[0] - (sl_dynamicfactor *(High[0]-Low[0])); break;
      case ts_mode_breakout: ts = Low[1] - Point; break;
    }
  }else if(order_type == OP_SELL){
  
    switch (sl_mode)
    {
      case ts_mode_fixed_sl: if(sl > 0) ts = Ask+(Point*sl); break;
      case ts_mode_atr: ts = High[0] + (sl_dynamicfactor * iATR(NULL,0,14,0)); break;
      case ts_mode_half_volatility: ts = High[0] + (sl_dynamicfactor *(High[0]-Low[0])); break;
      case ts_mode_breakout: ts = High[1] + Point; break;
    }
  }
  return(ts);
}
//+------------------------------------------------------------------+
//| Extended order execution functions for used in multiple pairs    |
//| with automatic retry attempts.                                   |
//+------------------------------------------------------------------+
int OrderSendEx(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration=0, color arrow_color=CLR_NONE) {
  if(!WaitWhileBusy())
  {
    Print("Error in OrderSendEx(): Timeout encountered");
    return(-1);
  }
  SetBusyState();
  int ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
  Sleep(5000);
  if (ticket==-1)
  {
    ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
    Sleep(5000);
  }
  ReleaseBusyState();  
  return(ticket);
}
bool OrderCloseEx(int ticket, double lots, double price, int slippage, color Color=CLR_NONE)
{
  if(!WaitWhileBusy())
  {
    Print("Error in OrderCloseEx(): Timeout encountered");
    return(false);
  }
  SetBusyState();
  bool ret = OrderClose(ticket, lots, price, slippage, Color);
  Sleep(5000);
  if (ret==false)
  {
    ret = OrderClose(ticket, lots, price, slippage, Color);
    Sleep(5000);
  }
  ReleaseBusyState();  
  return(ret);
}
bool OrderModifyEx( int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)
{
  if(!WaitWhileBusy())
  {
    Print("Error in OrderModifyEx(): Timeout encountered");
    return(false);
  }
  SetBusyState();
  bool ret = OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color);
  if(ret)
  {
    Sleep(5000);
  }else{
    Print("Error in OrderModifyEx(): ", LastErrorText());
  }
  ReleaseBusyState();  
  return(ret);
}
//+------------------------------------------------------------------+
//| Extended OrderSelect()                                           |
//+------------------------------------------------------------------+
bool OrderSelectEx(int index, int select, int pool = MODE_TRADES)
{
  if (OrderSelect(index,select,pool)==true)
  {
    return(true);
  }else{
    Print("Error: Order #", index ," cannot be selected. ", LastErrorText());
  }
}
//+------------------------------------------------------------------+
//| Calling state functions                                          |
//+------------------------------------------------------------------+
bool WaitWhileBusy()
{
   datetime OldCurTime;
   int timeoutsec=15;
   
   OldCurTime=CurTime();
   while (GlobalVariableCheck("InTrade") || !IsTradeAllowed()) {
      if(OldCurTime + timeoutsec <= CurTime()) {
         return(false); 
      }
      Sleep(1000);
   }
   return(true);
}
void SetBusyState()
{
  GlobalVariableSet("InTrade", CurTime());  // set lock indicator
}
void ReleaseBusyState()
{
  GlobalVariableDel("InTrade");   // clear lock indicator
}
//+------------------------------------------------------------------+
//| Get order ticket by magic number                                 |
//+------------------------------------------------------------------+
int OrderTicketByMagicNum(int magic_number) {
  for(int i=0;i<OrdersTotal();i++)
  {
    if (OrderSelect(i, SELECT_BY_POS) == false) continue;
    if (OrderMagicNumber() == magic_number) return(OrderTicket());
  }   
      
}
//+------------------------------------------------------------------+
//| Time frame interval appropriation function                       |
//+------------------------------------------------------------------+
int GetTimeframeConstant(int chart_period) {
   switch(chart_period) {
      case 1:  // M1
         return(50);
      case 5:  // M5
         return(100);
      case 15:
         return(150);
      case 30:
         return(200);
      case 60:
         return(250);
      case 240:
         return(300);
      case 1440:
         return(350);
      case 10080:
         return(400);
      case 43200:
         return(450);
   }
}
//+------------------------------------------------------------------+
//| Symbol to index                                                  |
//+------------------------------------------------------------------+
int GetSymbolConstant(string symbol) {
	if(symbol=="EURUSD" || symbol=="mEURUSD" || symbol=="EURUSDm") {	return(1);
	} else if(symbol=="GBPUSD" || symbol=="GBPUSDm") { return(2);
	} else if(symbol=="USDCHF" || symbol=="USDCHFm") {	return(3);
	} else if(symbol=="USDJPY" || symbol=="USDJPYm") {	return(4);
	} else if(symbol=="USDCAD" || symbol=="USDCADm") {	return(5);
	} else if(symbol=="AUDUSD" || symbol=="AUDUSDm") {	return(6);
	} else if(symbol=="CHFJPY" || symbol=="CHFJPYm") {	return(7);
	} else if(symbol=="EURAUD" || symbol=="EURAUDm") {	return(8);
	} else if(symbol=="EURCAD" || symbol=="EURCADm") {	return(9);
	} else if(symbol=="EURCHF" || symbol=="EURCHFm") {	return(10);
	} else if(symbol=="EURGBP" || symbol=="EURGBPm") {	return(11);
	} else if(symbol=="EURJPY" || symbol=="EURJPYm") {	return(12);
  } else if(symbol=="GBPCHF" || symbol=="GBPCHFm") {	return(13);
	} else if(symbol=="GBPJPY" || symbol=="GBPJPYm") {	return(14);
	} else if(symbol=="GOLD"   || symbol=="GOLDm") {	return(15);
	} else {Print("Error: Unexpected symbol."); return(0);
	}
}
//+------------------------------------------------------------------+
//| Get last error description                                       |
//+------------------------------------------------------------------+
string LastErrorText()
{
  return(ErrorDescription(GetLastError()));
}
void watermark()
  {
   ObjectCreate("fxfisherman", OBJ_LABEL, 0, 0, 0);
   ObjectSetText("fxfisherman", "fxfisherman.com", 11, "Lucida Handwriting", RoyalBlue);
   ObjectSet("fxfisherman", OBJPROP_CORNER, 2);
   ObjectSet("fxfisherman", OBJPROP_XDISTANCE, 5);
   ObjectSet("fxfisherman", OBJPROP_YDISTANCE, 10);
   return(0);
  }
             
            
Comments