//+------------------------------------------------------------------+
//|                                               och_SuperTrend.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

#property strict

#define OCH_BASE_BALANCE          0
#define OCH_BASE_FREEMARGIN       1
#define OCH_BASE_EQUITY           2
#define OCH_BASE_CUSTOM           3
#define SUPERTREND_MTF "xSuperTrend MTF"
#define SUPERTREND     "xSuperTrend"
#define HAS             "download\Heiken_Ashi_Smoothed"

enum MT4_TIMEFRAME
{
   MT4_PERIOD_M1  = PERIOD_M5,   // 5 minutes
   MT4_PERIOD_M15 = PERIOD_M15,  // 15 minutes
   MT4_PERIOD_M30 = PERIOD_M30,  // 30 minutes
   MT4_PERIOD_H1  = PERIOD_H1,   // 1 hour
   MT4_PERIOD_H4  = PERIOD_H4,   // 4 hours
   MT4_PERIOD_D1  = PERIOD_D1,    // 1 day
   MT4_PERIOD_W1  = PERIOD_W1    // 1 week
};

enum ENUM_MONEY_METHOD
{
    MONEY_METHOD_LOWER_LOTS   = 0,       // Lower lots
    MONEY_METHOD_FIXED_LOTS   = 1,       // Fixed lots
    MONEY_METHOD_PERCENTAGE   = 3,       // Percentage of Balance
    MONEY_METHOD_SQUARE       = 4        // Fixed Lot * square of balance
};

enum ENUM_SIGNAL
{
    SIGNAL_NONE,
    SIGNAL_OPEN_LONG,
    SIGNAL_OPEN_SHORT,
    SIGNAL_SNOWBALL_LONG,
    SIGNAL_SNOWBALL_SHORT
};

extern string               Rules_Comment             = "********** Rules ************************";
extern int                  MagicNumber               = 4848;
//extern MT4_TIMEFRAME        Trading_TimeFrame         = PERIOD_H1;                                           // Trading timeframe
extern string               Session_Open_time_Comment = "See : http://www.forexmarkethours.com/GMT_hours/02/"; // Source
extern bool                 AutoCalc_London_Open_time = true;                                                  // AutoCalc London Open Time 
extern int                  London_Open               = 7;                                                     // London Open Time in hours if previous = false
extern int                  Order_time_gap            = -30;                                                   // Set minutes from London open time to place trade
extern string               MM_Comment                = "********** Money Management *************";
extern ENUM_MONEY_METHOD    Money_Method              = MONEY_METHOD_FIXED_LOTS;                               // Money Management Method
extern double               Lots                      = 0.01;                                                  // Lots size for Method 2 and 4 
extern double               Risk                      = 2;                                                     // Risk in percentage
extern double               RR                        = 0;                                                     // RiskReward : if <>0 TP_pips = SL_pips * RR;
extern int                  SL_points                 = 0;                                                     // Stop loss in POINTS (not in pips)
extern int                  TP_points                 = 0;                                                     // Take profits in POINTS (not in pips)


ENUM_SIGNAL signal    = SIGNAL_NONE;
datetime    lasttime  = NULL;
int         slippage  = 50;
MqlDateTime order_time;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   double _London_Open;
   
   
   if (MathAbs(Order_time_gap) > 60) {
     Print(__FUNCSIG__ + ":: Order_time_gap cannot be greater than 60! This expert will quit.");
     return(INIT_FAILED);
   }
     
   TimeToStruct(TimeCurrent(), order_time);
   
   if (AutoCalc_London_Open_time)
     _London_Open = (8 * 3600) + TimeGMTOffset() + (Order_time_gap * 60);
   else 
     _London_Open = (London_Open * 3600) + (Order_time_gap * 60);
   
   order_time.hour = int(MathFloor(_London_Open/3600));
   order_time.min  = int(((_London_Open/3600) - order_time.hour) * 60) ;
   
   Print(__FUNCSIG__+":: order_time.hour = " + IntegerToString(order_time.hour) + " order_time.min = " + IntegerToString(order_time.min));
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
      CheckTradingCondition(); // 1
      ProceedTradingSignal();  // 2
      
  }
//+------------------------------------------------------------------+

bool och_NewBar(string _symbol, ENUM_TIMEFRAMES _timeframe, datetime& _lasttime)
  {
   
   if(iTime(_symbol,_timeframe,0)!=_lasttime)
     {
      _lasttime=iTime(_symbol,_timeframe,0);
      return (true);
     }
   else
      return (false);
  }
  
void CheckTradingCondition()
{
 
 //int cnt=0;
 
 int OrderPosition=0;
 MqlDateTime current_time;
  
  TimeToStruct(TimeCurrent(), current_time);

  if (current_time.hour == order_time.hour && current_time.min == order_time.min)    // If current time= London Open then  



                     if ( ! OrderSelect(OrderPosition, SELECT_BY_POS) )  {

                         signal = SIGNAL_OPEN_SHORT;                   // Open trade then
         
                        }

}


             


void ProceedTradingSignal()
{
  if (signal == SIGNAL_OPEN_SHORT) OpenBearishOrder();
  
  
  if (signal == SIGNAL_OPEN_LONG)  OpenBullishOrder();
  
}






bool OpenBullishOrder()
{
 double open_buy_price     = Ask;
 double sl_buy             = (SL_points !=0)? Ask - (SL_points * Point()):0;
 double tp_buy             = (TP_points !=0)? Ask + (TP_points * Point()):0; tp_buy = (RR != 0)?Ask + (SL_points * RR * Point()):tp_buy; 
 
 double lot                = CalculateLot();
 if (OrderSend(Symbol(), OP_BUY,  lot, open_buy_price,  slippage, sl_buy, tp_buy, "Auto", MagicNumber,   0, clrBlue) == -1){
  Print(__FUNCSIG__ + ":: Error while trying to place a new order : Errorcode = " + IntegerToString(GetLastError())); 
  return(false);
 }
 
 signal = SIGNAL_NONE;
 
 return(true);
}




bool OpenBearishOrder()
{
 double open_sell_price     = Bid;
 double sl_sell             = (SL_points !=0)? Bid + (SL_points * Point()):0;
 double tp_sell             = (TP_points !=0)? Bid - (TP_points * Point()):0; tp_sell = (RR != 0)?Ask - (SL_points * RR * Point()):tp_sell; 
 
 double lot                = CalculateLot();
 
 if (OrderSend(Symbol(), OP_SELL,  lot, open_sell_price,  slippage, sl_sell, tp_sell, "Auto", MagicNumber,   0, clrRed) == -1){
   Print(__FUNCSIG__ + ":: Error while trying to place a new order : Errorcode = " + IntegerToString(GetLastError())); 
   return(false);

 }

signal = SIGNAL_NONE;

  return(true);
}







bool CloseBullishOrders()
{
  for (int i=OrdersTotal(); i>=0; i--){
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
      if (OrderType() == OP_BUY && OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
        if (!OrderClose(OrderTicket(), OrderLots(), Bid, slippage, clrYellow)) return(false);
    } 
  }
signal = SIGNAL_NONE;

  return(true);
}


bool CloseBearishOrders()
{
  for (int i=OrdersTotal(); i>=0; i--){
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
      if (OrderType() == OP_SELL && OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
        if (!OrderClose(OrderTicket(), OrderLots(), Ask, slippage, clrYellow)) return(false);
    } 
  }
  return(true);
}


double CalculateLot(int base_amount = OCH_BASE_BALANCE, double amount = 0)
{
   double trade_volume=0;
  
   switch(Money_Method){
     case MONEY_METHOD_LOWER_LOTS   : trade_volume = MarketInfo(Symbol(),MODE_MINLOT);break;
     case MONEY_METHOD_FIXED_LOTS   : trade_volume = Lots; break;
     case MONEY_METHOD_PERCENTAGE   : trade_volume = och_CalcLotsMM(Symbol(), Risk, SL_points, base_amount, amount); break;
     case MONEY_METHOD_SQUARE       : trade_volume = och_CalcLotsSquare(Symbol(), Lots, base_amount, amount); break;
     
     default : return(trade_volume);
   }   
     
   return(trade_volume);
}

double och_CalcLotsMM(string _symbol, double _risk, int _stoplosspips, int _och_base_amount, double amount = 0)
{
 double lots=0;
 double pipvalue = MarketInfo(Symbol(), MODE_TICKVALUE);
 double base_amount=0;
 
 if (_och_base_amount == OCH_BASE_BALANCE)    base_amount =  AccountBalance();
 if (_och_base_amount == OCH_BASE_FREEMARGIN) base_amount =  AccountFreeMargin();
 if (_och_base_amount == OCH_BASE_EQUITY    ) base_amount =  AccountEquity();
 if (_och_base_amount == OCH_BASE_CUSTOM    ) base_amount =  amount;
 
 
 if (_stoplosspips !=0 && pipvalue !=0)
   lots = base_amount * _risk/100/_stoplosspips/pipvalue;
 
 if (MarketInfo( _symbol, MODE_LOTSTEP ) == 0) 
    Print(__FUNCSIG__ + "::WARNING! : " + _symbol + " MODE_LOTSTEP = 0");
 else 
    lots = lots - MathMod( lots, MarketInfo( _symbol, MODE_LOTSTEP ) );
 
 lots = MathMax(MarketInfo(_symbol, MODE_MINLOT),MathMin(lots,MarketInfo( _symbol, MODE_MAXLOT)));
 
 
 return(lots);
}

double och_CalcLotsSquare(string _symbol, double _lots, int _och_base_amount, double amount = 0)
{
 double base_amount=0;
 if (_och_base_amount == OCH_BASE_BALANCE)    base_amount =  AccountBalance();
 if (_och_base_amount == OCH_BASE_FREEMARGIN) base_amount =  AccountFreeMargin();
 if (_och_base_amount == OCH_BASE_EQUITY    ) base_amount =  AccountEquity();
 if (_och_base_amount == OCH_BASE_CUSTOM    ) base_amount =  amount;
 
 return(NormalizeDouble(_lots * MathSqrt(base_amount / 1000),2));
}

